Bug Summary

File:builds/wireshark/wireshark/epan/dissectors/packet-dof.c
Warning:line 7127, column 25
Access to field 'opid_last' results in a dereference of a null pointer (loaded from variable 'ptr')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name packet-dof.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan/dissectors -isystem /builds/wireshark/wireshark/build/epan/dissectors -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /builds/wireshark/wireshark/epan -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-11-04-100346-3662-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-dof.c
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.
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13/* 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.
19 *
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".
27 *
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.
41 */
42
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.
53 *
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.
59 *
60 * The specification documents are also the easiest way (although
61 * maybe not the clearest) to expose fields to the Wireshark user.
62 * A consistent naming is used, which is:
63 *
64 * (spec)-pdu-(seq)-(field)
65 * For example: dof-2009-1-pdu-1-value
66 *
67 * Variable naming includes a protocol name to provide clarity.
68 *
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.
72 *
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:
76 *
77 * dissect_(spec)_(name)
78 */
79
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.
87 *
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.
93 *
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.
100 *
101 * The DPS dissector API extends to dissectors that are called by the DPS dissectors.
102 *
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.
106 *
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.
112 *
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.
117 */
118
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.
127 *
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.
132 *
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.
143 *
144 * 3. Security (Optional). Security sessions always exist inside of
145 * an DPS session. Security sessions are further divided into epochs, keys, etc.
146 *
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.
150 *
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.
155 *
156 * In order to make lookups easier, the most fine-grained 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.
161 *
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.
173 *
174 * In order to make lookups easier, each unique sender in the system is
175 * assigned a unique identifier.
176 */
177
178#include <config.h>
179
180#include <ctype.h>
181
182#include <wsutil/wsgcrypt.h>
183
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"
194
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.
199 */
200
201/**
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.
206 */
207
208/**
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.
217 */
218typedef uint8_t *dof_2009_1_pdu_19_sid;
219
220/**
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.
226 */
227typedef struct _dpp_opid
228{
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;
233
234/**
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.
239 */
240typedef struct _dof_transport_session
241{
242 /**
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).
247 */
248 int transport_id;
249
250 /**
251 * For new sessions, this is left zero. The DPS dissector will
252 * set this value.
253 */
254 uint32_t transport_session_id;
255
256 /**
257 * Timestamp of start of session.
258 */
259 nstime_t session_start_ts;
260
261 /**
262 * Whether negotiation is required on this session.
263 */
264 bool_Bool negotiation_required;
265
266 /**
267 * The frame number where negotiation was complete, or zero if not complete.
268 */
269 uint32_t negotiation_complete_at;
270
271 /**
272 * The time when negotiation was complete, or zero if not complete.
273 */
274 nstime_t negotiation_complete_at_ts;
275
276 /**
277 * Type of transport session.
278 */
279 bool_Bool is_streaming; /* Inverse is 'is_datagram'. */
280
281 /**
282 * Cardinality of transport session.
283 */
284 bool_Bool is_2_node; /* Inverse is 'is_n_node'. */
285} dof_transport_session;
286
287typedef struct _dof_transport_packet
288{
289 /**
290 * Source of packet (if known, default is server).
291 */
292 bool_Bool is_sent_by_client; /* Inverse is 'is_sent_by_server'. */
293
294 /**
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.
298 */
299 unsigned sender_id;
300 unsigned receiver_id;
301} dof_transport_packet;
302
303/**
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.
308 */
309typedef struct _dof_session_key_exchange_data
310{
311 /**
312 * The frame at which this becomes valid for initiator packets.
313 */
314 uint32_t i_valid;
315
316 /**
317 * The frame at which this becomes valid for responder packets.
318 */
319 uint32_t r_valid;
320
321 /**
322 * SECURITY MODE: The security mode for a secure session. Set
323 * by the key exchange dissector.
324 */
325 uint32_t security_mode;
326
327 /**
328 * SECURITY MODE INITIALIZATION DATA: Determined by the key exchange
329 * protocol and passed here for the reference of the security mode.
330 */
331 uint32_t security_mode_data_length;
332 uint8_t *security_mode_data;
333
334 /**
335 * SECURITY MODE DATA: Created and managed by the security mode
336 * dissector.
337 */
338 void *security_mode_key_data;
339
340 /**
341 * SESSION KEY: Pointer to seasonal data that holds the encryption key.
342 */
343 uint8_t *session_key;
344
345 /**
346 * The next security data in this session.
347 */
348 struct _dof_session_key_exchange_data *next;
349} dof_session_key_exchange_data;
350
351/**
352 * This structure contains security keys that should be tried with
353 * sessions that otherwise are not known.
354 */
355typedef struct _dof_session_key_data
356{
357 uint8_t *session_key;
358} dof_session_key_data;
359
360/**
361 * This structure contains security keys for groups.
362 */
363typedef struct _dof_group_data
364{
365 uint8_t *domain;
366 unsigned domain_length;
367 uint8_t *identity;
368 unsigned identity_length;
369 uint8_t *kek;
370} dof_group_data;
371
372/**
373 * This structure contains security keys for non-group identities.
374 */
375typedef struct _dof_identity_data
376{
377 uint8_t *domain;
378 unsigned domain_length;
379 uint8_t *identity;
380 unsigned identity_length;
381 uint8_t *secret;
382} dof_identity_data;
383
384/**
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.
390 */
391typedef struct _dof_security_data
392{
393 /* Array of session_keys. */
394 dof_session_key_data *session_key;
395 uint16_t session_key_count;
396
397 /* Array of group data. */
398 dof_group_data *group_data;
399 uint16_t group_data_count;
400
401 /* Array of identity data. */
402 dof_identity_data *identity_data;
403 uint16_t identity_data_count;
404
405 /* Global sessions. */
406 /*TODO: Figure this out */
407 /* dof_session_list* sessions; */
408} dof_security_data;
409
410/**
411 * This structure represents a key that is learned for a group and epoch.
412 */
413struct _dof_learned_group_data;
414typedef struct _dof_learned_group_auth_data
415{
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;
424
425/**
426 * This structure represents a group that is learned about.
427 */
428typedef struct _dof_learned_group_data
429{
430 unsigned domain_length;
431 uint8_t *domain;
432 unsigned group_length;
433 uint8_t *group;
434 uint32_t ssid;
435
436 dof_learned_group_auth_data *keys;
437 struct _dof_learned_group_data *next;
438} dof_learned_group_data;
439
440/**
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.
444 *
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.
450 *
451 * This structure is initialized to zero.
452 */
453struct _dof_session_data;
454typedef struct _dof_secure_session_data
455{
456 /**
457 * SSID: Zero is typically used for streaming sessions.
458 */
459 uint32_t ssid;
460
461 /**
462 * DOMAIN LENGTH: The length of the security domain, greater than
463 * zero for secure sessions. Set by the key exchange dissector.
464 */
465 unsigned domain_length;
466
467 /**
468 * DOMAIN: The security domain itself, seasonal storage, non-null
469 * for secure sessions. Set by the key exchange dissector.
470 */
471 uint8_t *domain;
472
473 /**
474 * SESSION SECURITY: This is a list of security data for this
475 * session, created by the key exchange protocol.
476 */
477 dof_session_key_exchange_data *session_security_data;
478 dof_session_key_exchange_data *session_security_data_last;
479
480 /**
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.
485 */
486 struct _dof_secure_session_data *next;
487 struct _dof_session_data *parent;
488 uint32_t original_session_id;
489 bool_Bool is_2_node;
490} dof_secure_session_data;
491
492/**
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.
496 *
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.
502 *
503 * This structure is initialized to zero.
504 */
505typedef struct _dof_session_data
506{
507 /**
508 * SESSION ID: Set when the session is created, required.
509 */
510 uint32_t session_id;
511
512 /**
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.
516 */
517 uint8_t dof_id;
518
519 /**
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.
523 */
524 dof_secure_session_data *secure_sessions;
525
526 /**
527 * Protocol-specific data.
528 */
529 GSList *data_list;
530} dof_session_data;
531
532/* DOF Security Structures. */
533/* Return structures for different packets. */
534
535typedef struct _dof_2008_16_security_3_1
536{
537 tvbuff_t *identity;
538} dof_2008_16_security_3_1;
539
540typedef struct _dof_2008_16_security_4
541{
542 tvbuff_t *identity;
543 tvbuff_t *nonce;
544} dof_2008_16_security_4;
545
546typedef struct _dof_2008_16_security_6_1
547{
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;
554
555typedef struct _dof_2008_16_security_6_2
556{
557 tvbuff_t *r_identity;
558 tvbuff_t *r_nonce;
559} dof_2008_16_security_6_2;
560
561
562/**
563 * This structure defines the address for Wireshark transports. There is no
564 * DPS information associated here.
565 */
566typedef struct _ws_node
567{
568 address addr;
569 uint32_t port;
570} ws_node;
571
572typedef struct _dof_session_list
573{
574 dof_session_data *session;
575 struct _dof_session_list *next;
576} dof_session_list;
577
578/**
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.
588 */
589typedef struct _dof_packet_data
590{
591 /**
592 * NON-DPS FIELDS, USED FOR WIRESHARK COMMUNICATION/PROCESSING
593 * Protocol-specific data.
594 */
595 wmem_list_t *data_list;
596
597 /**
598 * The Wireshark frame. Note that a single frame can have multiple DPS packets.
599 */
600 uint32_t frame;
601
602 /**
603 * The DPS frame/packet. This number is unique in the entire trace.
604 */
605 uint32_t dof_frame;
606
607 /**
608 * Packet linked list for all dps packets.
609 */
610 struct _dof_packet_data *next;
611
612 /**
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.
617 */
618 bool_Bool processed;
619
620 /**
621 * SUMMARY: An operation summary, displayed in the Operation History. This is seasonal
622 * data, managed by the DPP dissector.
623 */
624 const char *summary;
625
626 /**
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.
630 */
631 int sender_id;
632 int receiver_id;
633
634 /**
635 * DPP INFORMATION - CACHED INFORMATION
636 */
637 bool_Bool is_command; /* Inverse is 'is_response'. */
638 bool_Bool is_sent_by_initiator;
639
640 /**
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.
644 */
645 unsigned sender_sid_id;
646 unsigned receiver_sid_id;
647
648 /**
649 * SENDER SID/RECEIVER SID: The SID of the sender/receiver, or NULL if not known.
650 */
651 dof_2009_1_pdu_19_sid sender_sid;
652 dof_2009_1_pdu_19_sid receiver_sid;
653
654 /**
655 * Operation references.
656 */
657 bool_Bool has_opid;
658 dof_2009_1_pdu_20_opid op;
659 bool_Bool has_referenced_opid;
660 dof_2009_1_pdu_20_opid ref_op;
661
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;
668
669 /**
670 * SECURITY INFORMATION - CACHED
671 */
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;
679
680
681 /**
682 * OPERATION DATA: Generic data, seasonal, owned by the application protocol dissector
683 * for this packet.
684 */
685 void *opid_data;
686} dof_packet_data;
687
688
689/**
690 * This structure represents globals that are passed to all dissectors.
691 */
692typedef struct _dof_globals
693{
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_Bool decrypt_all_packets;
701 bool_Bool track_operations;
702 unsigned track_operations_window;
703} dof_globals;
704
705/**
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.
709 */
710typedef struct _dof_api_data
711{
712 /**
713 * TRANSPORT SESSION: Set by the transport dissector, required.
714 */
715 dof_transport_session *transport_session;
716
717 /**
718 * TRANSPORT PACKET: Set by the transport dissector, required.
719 */
720 dof_transport_packet *transport_packet;
721
722 /**
723 * DPS SESSION: Set by the DPS dissector.
724 */
725 dof_session_data *session;
726
727 /**
728 * DPS DATA: Set by the DPS dissector.
729 */
730 dof_packet_data *packet;
731
732 /**
733 * DPS SECURE SESSION: Set by the DPP dissector.
734 */
735 dof_secure_session_data *secure_session;
736} dof_api_data;
737
738/**
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.
743 *
744 * Structure for Security Mode of Operation dissectors.
745 */
746typedef enum _dof_secmode_context
747{
748 INITIALIZE,
749 HEADER,
750 TRAILER
751} dof_secmode_context;
752
753/* Seasonal, initialized to zero. */
754typedef struct _dof_secmode_api_data
755{
756 /**
757 * API VERSION: Set by the DPS dissector, required.
758 * MUST BE THE FIRST FIELD.
759 */
760 uint8_t version;
761
762 /**
763 * CONTEXT: Set the DPS dissector, required.
764 */
765 dof_secmode_context context;
766
767 /**
768 * SECURITY MODE OFFSET: The packet offset from the DPP header of the security mode.
769 */
770 unsigned security_mode_offset;
771
772 /**
773 * API DATA: Set by the DPS dissector, required.
774 */
775 dof_api_data *dof_api;
776
777 /**
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.
781 */
782 dof_secure_session_data *secure_session;
783
784 /**
785 * KEY EXCHANGE: Controlled by the caller, represents the key exchange
786 * for INITIALIZE mode.
787 */
788 dof_session_key_exchange_data *session_key_data;
789} dof_secmode_api_data;
790
791/* These should be the only non-static declarations in the file. */
792void proto_register_dof(void);
793void proto_reg_handoff_dof(void);
794
795/* Dissector routines. */
796static int dissect_2008_1_dsp_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
797static int dissect_2008_16_security_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
798static int dissect_2008_16_security_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
799static int dissect_2008_16_security_3_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
800static int dissect_2008_16_security_3_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
801static int dissect_2008_16_security_4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
802static int dissect_2008_16_security_5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
803static int dissect_2008_16_security_6_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
804static int dissect_2008_16_security_6_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
805static int dissect_2008_16_security_6_3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
806static int dissect_2008_16_security_7(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
807static int dissect_2008_16_security_8(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
808static int dissect_2008_16_security_9(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
809static int dissect_2008_16_security_10(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
810static int dissect_2008_16_security_11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
811static int dissect_2008_16_security_12(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
812static int dissect_2008_16_security_13(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
813static int dissect_2009_11_type_4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
814static int dissect_2009_11_type_5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
815
816static const char* dof_oid_create_standard_string(wmem_allocator_t* allocator, uint32_t bufferSize, const uint8_t *pOIDBuffer, packet_info *pinfo);
817static const char* dof_iid_create_standard_string(wmem_allocator_t* allocator, uint32_t bufferSize, const uint8_t *pIIDBuffer);
818static uint8_t dof_oid_create_internal(const char *oid, uint32_t *size, uint8_t *buffer);
819static void dof_oid_new_standard_string(const char *data, uint32_t *rsize, uint8_t **oid);
820static int read_c4(tvbuff_t *tvb, int offset, uint32_t *v, int *len);
821static void validate_c4(packet_info *pinfo, proto_item *pi, uint32_t, int len);
822static int read_c3(tvbuff_t *tvb, int offset, uint32_t *v, int *len);
823static void validate_c3(packet_info *pinfo, proto_item *pi, uint32_t, int len);
824static int read_c2(tvbuff_t *tvb, int offset, uint16_t *v, int *len);
825static void validate_c2(packet_info *pinfo, proto_item *pi, uint16_t, int len);
826
827static int dof_dissect_pdu(dissector_t dissector, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *result);
828static 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);
829
830#if 0 /* TODO not used yet */
831static void dof_session_add_proto_data(dof_session_data *session, int proto, void *proto_data);
832static void* dof_session_get_proto_data(dof_session_data *session, int proto);
833static void dof_session_delete_proto_data(dof_session_data *session, int proto);
834#endif
835
836static void dof_packet_add_proto_data(dof_packet_data *packet, int proto, void *proto_data);
837static void* dof_packet_get_proto_data(dof_packet_data *packet, int proto);
838
839/* DOF PROTOCOL STACK */
840#define DOF_PROTOCOL_STACK"DOF Protocol Stack" "DOF Protocol Stack"
841
842/**
843 * PORTS
844 * The following ports are registered with IANA and used to hook transport
845 * dissectors into the lower-level Wireshark transport dissectors.
846 *
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.
851 *
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.
856 */
857#define DOF_NEG_SEC_UDP_PORT_RANGE"3567,5567" "3567,5567" /* P2P + Multicast */
858#define DOF_P2P_NEG_SEC_TCP_PORT3567 3567
859/* Reserved UDP port 3568*/
860#define DOF_TUN_SEC_TCP_PORT3568 3568
861#define DOF_P2P_SEC_TCP_PORT5567 5567
862/* Reserved UDP port 8567*/
863#define DOF_TUN_NON_SEC_TCP_PORT8567 8567
864
865/* This is needed to register multicast sessions with the UDP handler. */
866static dissector_handle_t dof_udp_handle;
867
868static int proto_2008_1_dof;
869static int proto_2008_1_dof_tcp;
870static int proto_2008_1_dof_udp;
871
872static int hf_2008_1_dof_session;
873static int hf_2008_1_dof_is_2_node;
874static int hf_2008_1_dof_is_streaming;
875static int hf_2008_1_dof_is_from_client;
876static int hf_2008_1_dof_frame;
877static int hf_2008_1_dof_session_transport;
878
879static int ett_2008_1_dof;
880
881/* DOF Tunnel Protocol */
882
883/* UDP Registrations */
884#define TUNNEL_PROTOCOL_STACK"DOF Tunnel Protocol Stack" "DOF Tunnel Protocol Stack"
885#define TUNNEL_APPLICATION_PROTOCOL"DOF Tunnel Protocol" "DOF Tunnel Protocol"
886
887static dissector_table_t dof_tun_app_dissectors;
888
889/***** TUNNEL *****/
890static int proto_2012_1_tunnel;
891
892static int ett_2012_1_tunnel;
893
894static int hf_2012_1_tunnel_1_version;
895static int hf_2012_1_tunnel_1_length;
896
897/* DOF NETWORK PROTOCOL */
898#define DNP_MAX_VERSION1 1
899#define DOF_NETWORK_PROTOCOL"DOF Network Protocol" "DOF Network Protocol"
900
901static dissector_table_t dnp_dissectors;
902static dissector_table_t dnp_framing_dissectors;
903
904static int proto_2008_1_dnp;
905
906static int hf_2008_1_dnp_1_version;
907static int hf_2008_1_dnp_1_flag;
908
909static int ett_2008_1_dnp;
910static int ett_2008_1_dnp_header;
911
912/* DNP V0 */
913static int proto_2008_1_dnp_0;
914
915static int hf_2008_1_dnp_0_1_1_padding;
916static int hf_2008_1_dnp_0_1_1_version;
917
918/* DNP V1 */
919#define DNP_V1_DEFAULT_FLAGS(0) (0)
920static int proto_2009_9_dnp_1;
921
922static int hf_2009_9_dnp_1_flags;
923static int hf_2009_9_dnp_1_flag_length;
924static int hf_2009_9_dnp_1_length;
925static int hf_2009_9_dnp_1_flag_srcport;
926static int hf_2009_9_dnp_1_srcport;
927static int hf_2009_9_dnp_1_flag_dstport;
928static int hf_2009_9_dnp_1_dstport;
929
930static int ett_2009_9_dnp_1_flags;
931
932static 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((void*)0)
937};
938
939/* DOF PRESENTATION PROTOCOL */
940#define DOF_PRESENTATION_PROTOCOL"DOF Presentation Protocol" "DOF Presentation Protocol"
941
942static dissector_table_t dof_dpp_dissectors;
943
944static int proto_2008_1_dpp;
945
946static int hf_2008_1_dpp_sid_num;
947static int hf_2008_1_dpp_rid_num;
948static int hf_2008_1_dpp_sid_str;
949static int hf_2008_1_dpp_rid_str;
950static int hf_2008_1_dpp_first_command;
951static int hf_2008_1_dpp_last_command;
952static int hf_2008_1_dpp_first_response;
953static int hf_2008_1_dpp_last_response;
954static int hf_2008_1_dpp_related_frame;
955static int hf_2008_1_dpp_1_version;
956static int hf_2008_1_dpp_1_flag;
957
958static int ett_2008_1_dpp;
959static int ett_2008_1_dpp_1_header;
960
961/* DPP V0 */
962static int proto_2008_1_dpp_0;
963
964static int hf_2008_1_dpp_0_1_1_version;
965
966/* DPP V1 - RESERVED, NOT SUPPORTED */
967
968/* DPP V2 */
969#define DPP_V2_DEFAULT_FLAGS(0) (0)
970#define DPP_V2_SEC_FLAG_E(0x80) (0x80)
971#define DPP_V2_SEC_FLAG_D(0x08) (0x08)
972#define DPP_V2_SEC_FLAG_P(0x04) (0x04)
973#define DPP_V2_SEC_FLAG_A(0x02) (0x02)
974#define DPP_V2_SEC_FLAG_S(0x01) (0x01)
975
976static int proto_2009_12_dpp;
977static int proto_2009_12_dpp_common;
978
979/* TODO: The complete on final and final flags are not covered. */
980static int hf_2009_12_dpp_2_1_flags;
981static int hf_2009_12_dpp_2_1_flag_security;
982static int hf_2009_12_dpp_2_1_flag_opid;
983static int hf_2009_12_dpp_2_1_flag_seq;
984static int hf_2009_12_dpp_2_1_flag_retry;
985static int hf_2009_12_dpp_2_1_flag_cmdrsp;
986static int hf_2009_12_dpp_2_3_sec_flags;
987static int hf_2009_12_dpp_2_3_sec_flag_secure;
988static int hf_2009_12_dpp_2_3_sec_flag_rdid;
989static int hf_2009_12_dpp_2_3_sec_flag_partition;
990static int hf_2009_12_dpp_2_3_sec_flag_ssid;
991static int hf_2009_12_dpp_2_3_sec_flag_as;
992static int hf_2009_12_dpp_2_3_sec_ssid;
993static int hf_2009_12_dpp_2_3_sec_rdid;
994static int hf_2009_12_dpp_2_3_sec_remote_partition;
995static int hf_2009_12_dpp_2_3_sec_partition;
996static int hf_2009_12_dpp_2_1_opcnt;
997static int hf_2009_12_dpp_2_1_seq;
998static int hf_2009_12_dpp_2_1_retry;
999static int hf_2009_12_dpp_2_1_delay;
1000static int hf_2009_12_dpp_2_14_opcode;
1001
1002static int ett_2009_12_dpp_2_1_flags;
1003static int ett_2009_12_dpp_2_3_security;
1004static int ett_2009_12_dpp_2_3_sec_flags;
1005static int ett_2009_12_dpp_2_3_sec_remote_partition;
1006static int ett_2009_12_dpp_2_3_sec_partition;
1007static int ett_2009_12_dpp_2_opid;
1008static int ett_2009_12_dpp_2_opid_history;
1009
1010static int ett_2009_12_dpp_common;
1011
1012static 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((void*)0) }
1018};
1019
1020#define OP_2009_12_RESPONSE_FLAG(0x80) (0x80)
1021#define OP_2009_12_NODE_DOWN_CMD(0) (0)
1022#define OP_2009_12_NODE_DOWN_RSP((0x80)|(0)) (OP_2009_12_RESPONSE_FLAG(0x80)|OP_2009_12_NODE_DOWN_CMD(0))
1023#define OP_2009_12_SOURCE_LOST_CMD(1) (1)
1024#define OP_2009_12_SOURCE_LOST_RSP((0x80)|(1)) (OP_2009_12_RESPONSE_FLAG(0x80)|OP_2009_12_SOURCE_LOST_CMD(1))
1025#define OP_2009_12_RENAME_CMD(2) (2)
1026#define OP_2009_12_RENAME_RSP((0x80)|(2)) (OP_2009_12_RESPONSE_FLAG(0x80)|OP_2009_12_RENAME_CMD(2))
1027#define OP_2009_12_PING_CMD(3) (3)
1028#define OP_2009_12_PING_RSP((0x80)|(3)) (OP_2009_12_RESPONSE_FLAG(0x80)|OP_2009_12_PING_CMD(3))
1029#define OP_2009_12_CANCEL_ALL_CMD(4) (4)
1030#define OP_2009_12_CANCEL_ALL_RSP((0x80)|(4)) (OP_2009_12_RESPONSE_FLAG(0x80)|OP_2009_12_CANCEL_ALL_CMD(4))
1031#define OP_2009_12_HEARTBEAT_CMD(5) (5)
1032#define OP_2009_12_HEARTBEAT_RSP((0x80)|(5)) (OP_2009_12_RESPONSE_FLAG(0x80)|OP_2009_12_HEARTBEAT_CMD(5))
1033#define OP_2009_12_QUERY_CMD(6) (6)
1034#define OP_2009_12_QUERY_RSP((0x80)|(6)) (OP_2009_12_RESPONSE_FLAG(0x80)|OP_2009_12_QUERY_CMD(6))
1035#define OP_2009_12_SOURCE_FOUND_CMD(8) (8)
1036#define OP_2009_12_SOURCE_FOUND_RSP((0x80)|(8)) (OP_2009_12_RESPONSE_FLAG(0x80)|OP_2009_12_SOURCE_FOUND_CMD(8))
1037
1038static const value_string strings_2009_12_dpp_common_opcodes[] = {
1039 { OP_2009_12_NODE_DOWN_CMD(0), "DPP Node Down" },
1040 { OP_2009_12_NODE_DOWN_RSP((0x80)|(0)), "DPP Node Down Response (Illegal)" },
1041 { OP_2009_12_SOURCE_LOST_CMD(1), "DPP Source Lost" },
1042 { OP_2009_12_SOURCE_LOST_RSP((0x80)|(1)), "DPP Source Lost Response (Illegal)" },
1043 { OP_2009_12_SOURCE_FOUND_CMD(8), "DPP Source Found" },
1044 { OP_2009_12_SOURCE_FOUND_RSP((0x80)|(8)), "DPP Source Found Response (Illegal)" },
1045 { OP_2009_12_RENAME_CMD(2), "DPP Rename" },
1046 { OP_2009_12_RENAME_RSP((0x80)|(2)), "DPP Rename Response (Illegal)" },
1047 { OP_2009_12_PING_CMD(3), "DPP Ping" },
1048 { OP_2009_12_PING_RSP((0x80)|(3)), "DPP Ping Response" },
1049 { OP_2009_12_HEARTBEAT_CMD(5), "DPP Heartbeat" },
1050 { OP_2009_12_HEARTBEAT_RSP((0x80)|(5)), "DPP Heartbeat Response (Illegal)" },
1051 { OP_2009_12_QUERY_CMD(6), "DPP Query" },
1052 { OP_2009_12_QUERY_RSP((0x80)|(6)), "DPP Query Response" },
1053 { OP_2009_12_CANCEL_ALL_CMD(4), "DPP Cancel All" },
1054 { OP_2009_12_CANCEL_ALL_RSP((0x80)|(4)), "DPP Cancel All Response (Illegal)" },
1055 { 0, NULL((void*)0) }
1056};
1057
1058/* DOF APPLICATION PROTOCOL */
1059#define DOF_APPLICATION_PROTOCOL"DOF Application Protocol" "DOF Application Protocol"
1060
1061static dissector_table_t app_dissectors;
1062
1063static int proto_2008_1_app;
1064
1065static int hf_2008_1_app_version;
1066
1067/* DAP V0 (DSP - DOF SESSION PROTOCOL) */
1068/* Note that DSP is *always* appid 0 and so it violates the standard naming rule. */
1069static dissector_table_t dsp_option_dissectors;
1070
1071static int hf_2008_1_dsp_12_opcode;
1072static int hf_2008_1_dsp_attribute_code;
1073static int hf_2008_1_dsp_attribute_data;
1074static int hf_2008_1_dsp_value_length;
1075static int hf_2008_1_dsp_value_data;
1076
1077static 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((void*)0) }
1084};
1085
1086#define DOF_PROTOCOL_DSP0 0
1087#define DSP_OAP_FAMILY0x010000 0x010000
1088
1089static int proto_2008_1_dsp;
1090
1091#define OP_2008_1_RSP(0x80) (0x80)
1092#define OP_2008_1_QUERY_CMD0 0
1093#define OP_2008_1_QUERY_RSP((0x80)|0) (OP_2008_1_RSP(0x80)|OP_2008_1_QUERY_CMD0)
1094#define OP_2008_1_CONFIG_REQ1 1
1095#define OP_2008_1_CONFIG_ACK((0x80)|2) (OP_2008_1_RSP(0x80)|2)
1096#define OP_2008_1_CONFIG_NAK((0x80)|3) (OP_2008_1_RSP(0x80)|3)
1097#define OP_2008_1_CONFIG_REJ((0x80)|4) (OP_2008_1_RSP(0x80)|4)
1098#define OP_2008_1_TERMINATE_CMD5 5
1099#define OP_2008_1_TERMINATE_RSP((0x80)|5) (OP_2008_1_RSP(0x80)|OP_2008_1_TERMINATE_CMD5)
1100#define OP_2008_1_OPEN_CMD6 6
1101#define OP_2008_1_OPEN_RSP((0x80)|6) (OP_2008_1_RSP(0x80)|OP_2008_1_OPEN_CMD6)
1102#define OP_2008_1_OPEN_SECURE_RSP((0x80)|7) (OP_2008_1_RSP(0x80)|7)
1103
1104static const value_string strings_2008_1_dsp_opcodes[] = {
1105 { OP_2008_1_QUERY_CMD0, "DSP Query" },
1106 { OP_2008_1_QUERY_RSP((0x80)|0), "DSP Query Response" },
1107 { OP_2008_1_CONFIG_REQ1, "DSP Request" },
1108 { OP_2008_1_CONFIG_ACK((0x80)|2), "DSP ACK Response" },
1109 { OP_2008_1_CONFIG_NAK((0x80)|3), "DSP NAK Response" },
1110 { OP_2008_1_CONFIG_REJ((0x80)|4), "DSP REJ Response" },
1111 { OP_2008_1_TERMINATE_CMD5, "DSP Terminate/Close Request" },
1112 { OP_2008_1_TERMINATE_RSP((0x80)|5), "DSP Terminate/Close Response" },
1113 { OP_2008_1_OPEN_CMD6, "DSP Open" },
1114 { OP_2008_1_OPEN_RSP((0x80)|6), "DSP Open Response" },
1115 { OP_2008_1_OPEN_SECURE_RSP((0x80)|7), "DSP Open Secure Response" },
1116 { 0, NULL((void*)0) }
1117};
1118
1119#define DSP_AVP_AUTHENTICATION0 0
1120#define DSP_AVP_APPLICATION1 1
1121
1122#if 0 /* not used yet */
1123static const value_string strings_2008_1_dsp_attributes[] = {
1124 { DSP_AVP_AUTHENTICATION0, "Authentication Protocol" },
1125 { DSP_AVP_APPLICATION1, "Application Protocol" },
1126 { 0, NULL((void*)0) }
1127};
1128
1129static 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((void*)0) }
1133};
1134#endif
1135
1136static int ett_2008_1_dsp_12;
1137static int ett_2008_1_dsp_12_options;
1138static int ett_2008_1_dsp_12_option;
1139
1140/* DAP V1 (OAP - OBJECT ACCESS PROTOCOL V1) */
1141/* This is the defined protocol id for OAP. */
1142#define DOF_PROTOCOL_OAP_11 1
1143/* There are two "protocols", one hooks into DSP and the other to DOF. */
1144static int proto_oap_1;
1145static int proto_oap_1_dsp;
1146
1147/* OAP DSP protocol items. */
1148static int hf_oap_1_dsp_option;
1149
1150/* OAP protocol items. */
1151static int hf_oap_1_opcode;
1152
1153static int hf_oap_1_alias_size;
1154static int hf_oap_1_flags;
1155static int hf_oap_1_exception_internal_flag;
1156static int hf_oap_1_exception_final_flag;
1157static int hf_oap_1_exception_provider_flag;
1158static int hf_oap_1_cmdcontrol;
1159static int hf_oap_1_cmdcontrol_cache_flag;
1160static int hf_oap_1_cmdcontrol_verbosity_flag;
1161static int hf_oap_1_cmdcontrol_noexecute_flag;
1162static int hf_oap_1_cmdcontrol_ack_flag;
1163static int hf_oap_1_cmdcontrol_delay_flag;
1164static int hf_oap_1_cmdcontrol_heuristic_flag;
1165static int hf_oap_1_cmdcontrol_heuristic;
1166static int hf_oap_1_cmdcontrol_cache;
1167static int hf_oap_1_cmdcontrol_ackcnt;
1168static int hf_oap_1_cmdcontrol_ack;
1169
1170#if 0 /* not used yet */
1171static int hf_oap_1_opinfo_start_frame;
1172static int hf_oap_1_opinfo_end_frame;
1173static int hf_oap_1_opinfo_timeout;
1174#endif
1175
1176static int hf_oap_1_providerid;
1177static int ett_oap_1_1_providerid;
1178
1179static int hf_oap_1_objectid;
1180static int ett_oap_1_objectid;
1181
1182static int hf_oap_1_interfaceid;
1183static int hf_oap_1_itemid;
1184
1185#if 0 /* not used yet */
1186static int hf_oap_1_distance;
1187#endif
1188
1189static int hf_oap_1_alias;
1190static int hf_oap_1_alias_frame;
1191
1192static int hf_oap_1_subscription_delta;
1193static int hf_oap_1_update_sequence;
1194static int hf_oap_1_value_list;
1195
1196static int ett_oap_1_dsp;
1197static int ett_oap_1_dsp_options;
1198
1199static int ett_oap_1;
1200static int ett_oap_1_opinfo;
1201static int ett_oap_1_cmdcontrol;
1202static int ett_oap_1_cmdcontrol_flags;
1203static int ett_oap_1_cmdcontrol_ack;
1204static int ett_oap_1_alias;
1205
1206static 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((void*)0)
1214};
1215
1216static expert_field ei_oap_no_session;
1217
1218static GHashTable *oap_1_alias_to_binding;
1219
1220#define OAP_1_RESPONSE(0x80) (0x80)
1221#define OAP_1_CMD_ACTIVATE28 28
1222#define OAP_1_RSP_ACTIVATE(28|(0x80)) (OAP_1_CMD_ACTIVATE28|OAP_1_RESPONSE(0x80))
1223#define OAP_1_CMD_ADVERTISE5 5
1224#define OAP_1_RSP_ADVERTISE(5|(0x80)) (OAP_1_CMD_ADVERTISE5|OAP_1_RESPONSE(0x80))
1225#define OAP_1_CMD_CHANGE2 2
1226#define OAP_1_RSP_CHANGE(2|(0x80)) (OAP_1_CMD_CHANGE2|OAP_1_RESPONSE(0x80))
1227#define OAP_1_CMD_CONNECT4 4
1228#define OAP_1_RSP_CONNECT(4|(0x80)) (OAP_1_CMD_CONNECT4|OAP_1_RESPONSE(0x80))
1229#define OAP_1_CMD_DEFINE6 6
1230#define OAP_1_RSP_DEFINE(6|(0x80)) (OAP_1_CMD_DEFINE6|OAP_1_RESPONSE(0x80))
1231#define OAP_1_CMD_EXCEPTION9 9
1232#define OAP_1_RSP_EXCEPTION(9|(0x80)) (OAP_1_CMD_EXCEPTION9|OAP_1_RESPONSE(0x80))
1233#define OAP_1_CMD_FULL_CONNECT3 3
1234#define OAP_1_RSP_FULL_CONNECT(3|(0x80)) (OAP_1_CMD_FULL_CONNECT3|OAP_1_RESPONSE(0x80))
1235#define OAP_1_CMD_GET10 10
1236#define OAP_1_RSP_GET(10|(0x80)) (OAP_1_CMD_GET10|OAP_1_RESPONSE(0x80))
1237#define OAP_1_CMD_INVOKE12 12
1238#define OAP_1_RSP_INVOKE(12|(0x80)) (OAP_1_CMD_INVOKE12|OAP_1_RESPONSE(0x80))
1239#define OAP_1_CMD_OPEN14 14
1240#define OAP_1_RSP_OPEN(14|(0x80)) (OAP_1_CMD_OPEN14|OAP_1_RESPONSE(0x80))
1241#define OAP_1_CMD_PROVIDE16 16
1242#define OAP_1_RSP_PROVIDE(16|(0x80)) (OAP_1_CMD_PROVIDE16|OAP_1_RESPONSE(0x80))
1243#define OAP_1_CMD_REGISTER25 25
1244#define OAP_1_RSP_REGISTER(25|(0x80)) (OAP_1_CMD_REGISTER25|OAP_1_RESPONSE(0x80))
1245#define OAP_1_CMD_SET20 20
1246#define OAP_1_RSP_SET(20|(0x80)) (OAP_1_CMD_SET20|OAP_1_RESPONSE(0x80))
1247#define OAP_1_CMD_SIGNAL22 22
1248#define OAP_1_RSP_SIGNAL(22|(0x80)) (OAP_1_CMD_SIGNAL22|OAP_1_RESPONSE(0x80))
1249#define OAP_1_CMD_SUBSCRIBE24 24
1250#define OAP_1_RSP_SUBSCRIBE(24|(0x80)) (OAP_1_CMD_SUBSCRIBE24|OAP_1_RESPONSE(0x80))
1251#define OAP_1_CMD_WATCH30 30
1252#define OAP_1_RSP_WATCH(30|(0x80)) (OAP_1_CMD_WATCH30|OAP_1_RESPONSE(0x80))
1253
1254static const value_string oap_opcode_strings[] = {
1255 { OAP_1_CMD_ACTIVATE28, "OAP Activate" },
1256 { OAP_1_RSP_ACTIVATE(28|(0x80)), "OAP Activate Response (Illegal)" },
1257 { OAP_1_CMD_ADVERTISE5, "OAP Advertise" },
1258 { OAP_1_RSP_ADVERTISE(5|(0x80)), "OAP Advertise Response (Illegal)" },
1259 { OAP_1_CMD_CHANGE2, "OAP Change" },
1260 { OAP_1_RSP_CHANGE(2|(0x80)), "OAP Change Response (Illegal)" },
1261 { OAP_1_CMD_CONNECT4, "OAP Connect" },
1262 { OAP_1_RSP_CONNECT(4|(0x80)), "OAP Connect Response (Illegal)" },
1263 { OAP_1_CMD_DEFINE6, "OAP Define" },
1264 { OAP_1_RSP_DEFINE(6|(0x80)), "OAP Define Response" },
1265 { OAP_1_CMD_EXCEPTION9, "OAP Exception (Illegal)" },
1266 { OAP_1_RSP_EXCEPTION(9|(0x80)), "OAP Exception Response" },
1267 { OAP_1_CMD_FULL_CONNECT3, "OAP Full Connect" },
1268 { OAP_1_RSP_FULL_CONNECT(3|(0x80)), "OAP Full Connect Response (Illegal)" },
1269 { OAP_1_CMD_GET10, "OAP Get" },
1270 { OAP_1_RSP_GET(10|(0x80)), "OAP Get Response" },
1271 { OAP_1_CMD_INVOKE12, "OAP Invoke" },
1272 { OAP_1_RSP_INVOKE(12|(0x80)), "OAP Invoke Response" },
1273 { OAP_1_CMD_OPEN14, "OAP Open" },
1274 { OAP_1_RSP_OPEN(14|(0x80)), "OAP Open Response" },
1275 { OAP_1_CMD_PROVIDE16, "OAP Provide" },
1276 { OAP_1_RSP_PROVIDE(16|(0x80)), "OAP Provide Response (Illegal)" },
1277 { OAP_1_CMD_REGISTER25, "OAP Register" },
1278 { OAP_1_RSP_REGISTER(25|(0x80)), "OAP Register Response" },
1279 { OAP_1_CMD_SET20, "OAP Set" },
1280 { OAP_1_RSP_SET(20|(0x80)), "OAP Set Response" },
1281 { OAP_1_CMD_SIGNAL22, "OAP Signal" },
1282 { OAP_1_RSP_SIGNAL(22|(0x80)), "OAP Signal Response (Illegal)" },
1283 { OAP_1_CMD_SUBSCRIBE24, "OAP Subscribe" },
1284 { OAP_1_RSP_SUBSCRIBE(24|(0x80)), "OAP Subscribe Response" },
1285 { OAP_1_CMD_WATCH30, "OAP Watch" },
1286 { OAP_1_RSP_WATCH(30|(0x80)), "OAP Watch Response (Illegal)" },
1287
1288 { 0, NULL((void*)0) }
1289};
1290
1291typedef struct _alias_key
1292{
1293 uint32_t session;
1294 uint32_t sender;
1295 uint32_t alias;
1296} oap_1_alias_key;
1297
1298static unsigned oap_1_alias_hash_func(const void *ptr)
1299{
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);
1302}
1303
1304static int oap_1_alias_equal_func(const void *ptr1, const void *ptr2)
1305{
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;
1308
1309 if (key1->session != key2->session)
1310 return 0;
1311
1312 if (key1->sender != key2->sender)
1313 return 0;
1314
1315 if (key1->alias != key2->alias)
1316 return 0;
1317
1318 return 1;
1319}
1320
1321typedef struct
1322{
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;
1329
1330typedef struct oap_1_binding_list
1331{
1332 oap_1_binding *binding;
1333 struct oap_1_binding_list *next;
1334} oap_1_binding_list;
1335
1336typedef struct
1337{
1338 oap_1_binding *resolved_alias;
1339} oap_1_packet_data;
1340
1341static oap_1_binding* oap_1_resolve_alias(oap_1_alias_key *key);
1342
1343static int oap_1_tree_add_alias(dof_api_data *api_data, oap_1_packet_data *oap_packet _U___attribute__((unused)), dof_packet_data *packet, proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, uint8_t alias_length, uint8_t resolve)
1344{
1345 dof_session_data *session = api_data->session;
1346 proto_item *ti;
1347 proto_tree *options_tree;
1348
1349 if (alias_length == 0)
1350 /* TODO: Output error. */
1351 return offset;
1352
1353 if (session == NULL((void*)0))
1354 /* TODO: Output error. */
1355 return offset;
1356
1357 ti = proto_tree_add_item(tree, hf_oap_1_alias, tvb, offset, alias_length, ENC_BIG_ENDIAN0x00000000);
1358
1359 if (resolve)
1360 {
1361 oap_1_binding *binding = NULL((void*)0);
1362 oap_1_alias_key key;
1363 int i;
1364 uint32_t alias;
1365
1366 alias = 0;
1367 for (i = 0; i < alias_length; i++)
1368 alias = (alias << 8) | tvb_get_uint8(tvb, offset + i);
1369
1370 key.session = session->session_id;
1371 key.sender = packet->sender_id;
1372 key.alias = alias;
1373 binding = oap_1_resolve_alias(&key);
1374 /* Only a binding defined by this frame or an earlier one, as in the first pass */
1375 if (binding && binding->frame > pinfo->num)
1376 binding = NULL((void*)0);
1377
1378 if (binding)
1379 {
1380 options_tree = proto_item_add_subtree(ti, ett_oap_1_alias);
1381
1382 /* Decode the Interface */
1383 ti = proto_tree_add_bytes_format_value(tree, hf_oap_1_interfaceid, tvb, 0, 0, binding->iid, "%s", dof_iid_create_standard_string(pinfo->pool, binding->iid_length, binding->iid));
1384 proto_item_set_generated(ti);
1385
1386 /* Decode the Object ID */
1387 ti = proto_tree_add_bytes_format_value(tree, hf_oap_1_objectid, tvb, 0, 0, binding->oid, "%s", dof_oid_create_standard_string(pinfo->pool, binding->oid_length, binding->oid, pinfo));
1388 proto_item_set_generated(ti);
1389
1390 proto_tree_add_uint_format(options_tree, hf_oap_1_alias_frame,
1391 tvb, 0, 0, binding->frame,
1392 "This alias is defined in frame %u",
1393 binding->frame);
1394 }
1395 }
1396
1397 return offset + alias_length;
1398}
1399
1400static int oap_1_tree_add_interface(proto_tree *tree, tvbuff_t *tvb, int offset)
1401{
1402 uint8_t registry;
1403 uint8_t len;
1404
1405 registry = tvb_get_uint8(tvb, offset);
1406 len = registry & 0x03;
1407 /* XXX - The DOF specifications indicate "len [bits] equal to 0 is invalid"
1408 * Why is a length of 16 bytes used in that case? */
1409 if (len == 0)
1410 len = 16;
1411 else
1412 len = 1 << (len - 1);
1413
1414 proto_tree_add_item(tree, hf_oap_1_interfaceid, tvb, offset, 1 + len, ENC_NA0x00000000);
1415 return offset + 1 + len;
1416}
1417
1418static int oap_1_tree_add_binding(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int offset)
1419{
1420 /* uint8_t cl; */
1421
1422 offset = oap_1_tree_add_interface(tree, tvb, offset);
1423
1424#if 0 /* this seems to be dead code - check! */
1425 cl = tvb_get_uint8(tvb, offset);
1426 if (cl & 0x80)
1427 len = tvb_get_uint8(tvb, offset + 2);
1428 else
1429 len = tvb_get_uint8(tvb, offset + 1);
1430#endif
1431
1432 offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, tree,
1433 offset, hf_oap_1_objectid, ett_oap_1_objectid, NULL((void*)0));
1434 return offset;
1435}
1436
1437static int oap_1_tree_add_cmdcontrol(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset)
1438{
1439 proto_item *ti;
1440 proto_tree *opinfo_tree;
1441 uint8_t flags;
1442
1443 flags = tvb_get_uint8(tvb, offset);
1444
1445 ti = proto_tree_add_bitmask(tree, tvb, offset, hf_oap_1_cmdcontrol, ett_oap_1_cmdcontrol_flags, bitmask_oap_1_cmdcontrol_flags, ENC_NA0x00000000);
1446 opinfo_tree = proto_item_add_subtree(ti, ett_oap_1_cmdcontrol);
1447
1448 proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_cache_flag, tvb, offset, 1, ENC_NA0x00000000);
1449 proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_verbosity_flag, tvb, offset, 1, ENC_NA0x00000000);
1450 proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_noexecute_flag, tvb, offset, 1, ENC_NA0x00000000);
1451 proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_ack_flag, tvb, offset, 1, ENC_NA0x00000000);
1452 proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_delay_flag, tvb, offset, 1, ENC_NA0x00000000);
1453 proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_heuristic_flag, tvb, offset, 1, ENC_NA0x00000000);
1454
1455 offset += 1;
1456
1457 if (flags & 0x01)
1458 {
1459 /* Heuristic */
1460 int heur_len;
1461 uint16_t heur;
1462 proto_item *pi;
1463
1464 read_c2(tvb, offset, &heur, &heur_len);
1465 pi = proto_tree_add_uint_format(opinfo_tree, hf_oap_1_cmdcontrol_heuristic, tvb, offset, heur_len, heur, "Heuristic Value: %hu", heur);
1466 validate_c2(pinfo, pi, heur, heur_len);
1467 offset += heur_len;
1468 }
1469
1470 if (flags & 0x04)
1471 {
1472 /* Ack List */
1473 uint8_t ackcnt;
1474 uint8_t i;
1475
1476 proto_tree_add_item_ret_uint8(opinfo_tree, hf_oap_1_cmdcontrol_ackcnt, tvb, offset, 1, ENC_NA0x00000000, &ackcnt);
1477 offset += 1;
1478
1479 for (i = 0; i < ackcnt; i++)
1480 {
1481 offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, opinfo_tree,
1482 offset, hf_oap_1_cmdcontrol_ack, ett_oap_1_cmdcontrol_ack, NULL((void*)0));
1483 }
1484 }
1485
1486 if (flags & 0x40)
1487 {
1488 /* Cache Delay */
1489 int cache_len;
1490 uint16_t cache;
1491 proto_item *pi;
1492
1493 read_c2(tvb, offset, &cache, &cache_len);
1494 pi = proto_tree_add_uint_format(opinfo_tree, hf_oap_1_cmdcontrol_cache, tvb, offset, cache_len, cache, "Cache Delay: %hu", cache);
1495 validate_c2(pinfo, pi, cache, cache_len);
1496 offset += cache_len;
1497 }
1498
1499 return offset;
1500}
1501
1502/**
1503 * Define an alias. This routine is called for each Provide operation that includes an alias assignment.
1504 * It is also called for retries of Provide operations.
1505 * The alias is defined for the duration of the Provide. This means that if the operation is cancelled
1506 * then the alias should no longer be valid.
1507 * The alias is associated with an oap_session, an dof_node, and the alias itself. Aliases
1508 * may be reused as long as the previous use has expired, and so the list is stored in reverse
1509 * order.
1510 *
1511 * NOTE: The alias is passed as a structure pointer, and must be reallocated if it is stored in
1512 * the hash.
1513 */
1514static void oap_1_define_alias(dof_api_data *api_data, uint32_t alias, oap_1_binding *binding)
1515{
1516 /* The definer of an alias is the sender, in the session. */
1517 dof_session_data *session = api_data->session;
1518 dof_packet_data *packet = (dof_packet_data *)api_data->packet;
1519 uint32_t session_id;
1520 uint32_t sender_id;
1521 oap_1_alias_key key;
1522
1523 if (!session)
1524 return;
1525
1526 session_id = session->session_id;
1527 sender_id = packet->sender_id;
1528
1529 if (!binding)
1530 return;
1531
1532 key.session = session_id;
1533 key.sender = sender_id;
1534 key.alias = alias;
1535
1536 /* If there isn't an entry for the alias, then we need to create one.
1537 * The first entry will be the binding we are defining.
1538 */
1539 if (!g_hash_table_lookup(oap_1_alias_to_binding, &key))
1540 {
1541 oap_1_alias_key *alias_ptr = wmem_new0(wmem_file_scope(), oap_1_alias_key)((oap_1_alias_key*)wmem_alloc0((wmem_file_scope()), sizeof(oap_1_alias_key
)))
;
1542 memcpy(alias_ptr, &key, sizeof(oap_1_alias_key));
1543 g_hash_table_insert(oap_1_alias_to_binding, alias_ptr, binding);
1544 }
1545}
1546
1547/**
1548 * Given an oap_alias, resolve it to an oap_1_binding. This assumes that the destination of the
1549 * packet is the one that defined the alias.
1550 */
1551static oap_1_binding* oap_1_resolve_alias(oap_1_alias_key *key)
1552{
1553 /* The first lookup is inside the session based on defining node. */
1554 return (oap_1_binding *)g_hash_table_lookup(oap_1_alias_to_binding, key);
1555}
1556
1557/* DAP V128 (TEP - TICKET EXCHANGE PROTOCOL V1) */
1558#define DOF_PROTOCOL_TEP128 128
1559#define DSP_TEP_FAMILY0x000000 0x000000
1560static int proto_tep;
1561static int proto_tep_dsp;
1562
1563static int hf_dsp_option;
1564
1565static int ett_tep_operation;
1566static int hf_tep_operation;
1567static int hf_tep_operation_type;
1568static int hf_tep_opcode;
1569static int hf_tep_k;
1570static int hf_tep_c;
1571static int hf_tep_reject_code;
1572static int hf_tep_reject_data;
1573
1574static const true_false_string tep_optype_vals = { "DPP Response", "DPP Command" };
1575
1576/* TEP.2.1 */
1577static int ett_tep_2_1_domain;
1578static int hf_tep_2_1_domain;
1579static int ett_tep_2_1_initiator_block;
1580static int hf_tep_2_1_initiator_block;
1581static int hf_tep_2_1_ticket_confirmation;
1582
1583/* TEP.2.2 */
1584static int ett_tep_2_2_initiator_ticket;
1585static int hf_tep_2_2_initiator_ticket;
1586static int hf_tep_2_2_ticket_confirmation;
1587static int ett_tep_2_2_responder_initialization;
1588static int hf_tep_2_2_responder_initialization;
1589static int ett_tep_2_2_responder_block;
1590static int hf_tep_2_2_responder_block;
1591static int ett_tep_2_2_authenticator_initialization;
1592static int hf_tep_2_2_authenticator_initialization;
1593
1594/* TEP.2.2.1 */
1595static int hf_tep_2_2_1_state_identifier;
1596static int ett_tep_2_2_1_initial_state;
1597static int hf_tep_2_2_1_initial_state;
1598
1599static int hf_tep_session_key;
1600
1601static int ett_tep_dsp;
1602static int ett_tep_dsp_options;
1603static int ett_tep;
1604
1605#if 0 /* not used yet */
1606static const value_string tep_filter_existing[] = {
1607 { 1, "Include Existing Matches" },
1608 { 0, "Exclude Existing Matches" },
1609 { 0, NULL((void*)0) }
1610};
1611#endif
1612
1613#define TEP_OPCODE_RSP(0x80) (0x80)
1614#define TEP_OPCODE_C(0x20) (0x20)
1615#define TEP_OPCODE_K(0x10) (0x10)
1616#define TEP_PDU_REJECT((0x80)|0) (TEP_OPCODE_RSP(0x80)|0)
1617#define TEP_PDU_REQUEST(1) (1)
1618#define TEP_PDU_END_SESSION(5) (5)
1619#define TEP_PDU_SESSION_ENDING(6) (6)
1620
1621#define TEP_PDU_REQUEST_KEY((0x10)|(1)) (TEP_OPCODE_K(0x10)|TEP_PDU_REQUEST(1))
1622#define TEP_PDU_CONFIRM((0x20)|(1)) (TEP_OPCODE_C(0x20)|TEP_PDU_REQUEST(1))
1623#define TEP_PDU_ACCEPT((0x80)|(1)) (TEP_OPCODE_RSP(0x80)|TEP_PDU_REQUEST(1))
1624#define TEP_PDU_CONFIRM_ACK((0x80)|(0x20)|(1)) (TEP_OPCODE_RSP(0x80)|TEP_OPCODE_C(0x20)|TEP_PDU_REQUEST(1))
1625
1626static const value_string tep_opcode_strings[] = {
1627 { TEP_PDU_REJECT((0x80)|0), "TEP Reject" },
1628 { TEP_PDU_REQUEST(1), "TEP Request" },
1629 { TEP_PDU_END_SESSION(5), "TEP End Session" },
1630 { TEP_PDU_SESSION_ENDING(6), "TEP Session Ending" },
1631
1632 { TEP_PDU_REQUEST_KEY((0x10)|(1)), "TEP Rekey" },
1633 { TEP_PDU_CONFIRM((0x20)|(1)), "TEP Confirm" },
1634 { TEP_PDU_ACCEPT((0x80)|(1)), "TEP Accept" },
1635 { TEP_PDU_CONFIRM_ACK((0x80)|(0x20)|(1)), "TEP Confirm Ack" },
1636
1637 { 0, NULL((void*)0) }
1638};
1639
1640#if 0 /* not use yet */
1641static const value_string tep_error_strings[] = {
1642 { 1, "Parse Error" },
1643 { 2, "Access Denied" },
1644 { 3, "Duration Not Supported" },
1645 { 4, "Authentication Failed" },
1646 { 0, NULL((void*)0) }
1647};
1648#endif
1649
1650/* Initialized to zero. */
1651typedef struct tep_rekey_data
1652{
1653 /* Stored from the K bit of the Request PDU. */
1654 bool_Bool is_rekey;
1655
1656 /* Stored from the key request for non-secure rekeys. Otherwise 0 and NULL. */
1657 unsigned domain_length;
1658 uint8_t *domain;
1659
1660 /* Stored from the identity of the Request PDU. Seasonal. */
1661 uint8_t *i_identity;
1662 unsigned i_identity_length;
1663
1664 /* Stored from the nonce of the Request PDU. Seasonal. */
1665 uint8_t *i_nonce;
1666 uint8_t i_nonce_length;
1667
1668 /* Stored from the identity of the Request response PDU. Seasonal. */
1669 uint8_t *r_identity;
1670 unsigned r_identity_length;
1671
1672 /* Stored from the nonce of the Request response PDU. Seasonal. */
1673 uint8_t *r_nonce;
1674 uint8_t r_nonce_length;
1675
1676 uint16_t security_mode;
1677 uint32_t security_mode_data_length;
1678 uint8_t *security_mode_data;
1679
1680 /* Security session data for this rekey, if is_rekey is true. */
1681 dof_session_key_exchange_data *key_data;
1682} tep_rekey_data;
1683
1684/* DAP V129 (TRP - TICKET REQUEST PROTOCOL V2) */
1685#define DOF_PROTOCOL_TRP129 129
1686#define DSP_TRP_FAMILY0x030000 0x030000
1687typedef struct _trp_packet_data
1688{
1689 uint8_t *domain;
1690 unsigned domain_length;
1691 uint8_t *identity;
1692 unsigned identity_length;
1693 uint8_t *group;
1694 unsigned group_length;
1695 uint8_t *block_I;
1696 unsigned block_I_length;
1697 uint8_t *secret;
1698 bool_Bool kek_known;
1699} trp_packet_data;
1700
1701
1702static int proto_trp;
1703static int proto_trp_dsp;
1704
1705static int hf_trp_dsp_option;
1706
1707static int hf_trp_opcode;
1708static int hf_domain;
1709static int hf_identity_resolution;
1710static int hf_initiator_request;
1711static int hf_responder_request;
1712static int hf_initiator_ticket;
1713static int hf_responder_ticket;
1714static int hf_authentication_block;
1715static int hf_group_identifier;
1716static int hf_node_identifier;
1717static int hf_thb;
1718static int hf_tmin;
1719static int hf_tmax;
1720static int hf_trp_epoch;
1721static int hf_sidg;
1722static int hf_security_scope;
1723static int hf_security_mode;
1724static int hf_ssid;
1725#if 0 /* not used yet */
1726static int hf_initiator_pg;
1727#endif
1728static int hf_initiator_validation;
1729static int hf_responder_pg;
1730static int hf_responder_validation;
1731
1732static int hf_trp_errorcode;
1733static int hf_trp_duration;
1734#if 0 /* not used yet */
1735static int hf_trp_rnonce;
1736static int hf_trp_pnonce;
1737static int hf_trp_reqid;
1738static int hf_trp_provid;
1739static int hf_trp_perm_count;
1740static int hf_trp_perm_type;
1741static int hf_trp_perm_rcache;
1742static int hf_trp_perm_rsrp;
1743static int hf_trp_perm_rsrp_a;
1744static int hf_trp_perm_rsrp_u;
1745static int hf_trp_perm_rflags;
1746static int hf_trp_perm_pcache;
1747static int hf_trp_perm_psrp;
1748static int hf_trp_perm_psrp_a;
1749static int hf_trp_perm_psrp_u;
1750static int hf_trp_perm_psrp_b;
1751static int hf_trp_perm_psrp_s;
1752static int hf_trp_perm_pflags;
1753static int hf_trp_confirmation;
1754static int hf_trp_perm_pke;
1755static int hf_trp_perm_pka;
1756#endif
1757
1758static int ett_trp_dsp;
1759static int ett_trp;
1760static int ett_domain;
1761static int ett_identity_resolution;
1762static int ett_initiator_request;
1763static int ett_initiator_ticket;
1764static int ett_responder_request;
1765static int ett_responder_ticket;
1766static int ett_authentication_block;
1767static int ett_group_identifier;
1768static int ett_node_identifier;
1769static int ett_sidg;
1770static int ett_security_scope;
1771static int ett_security_mode;
1772static int ett_initiator_pg;
1773static int ett_initiator_validation;
1774static int ett_responder_pg;
1775static int ett_responder_validation;
1776
1777
1778static int ett_trp_permset;
1779static int ett_srp_flags;
1780static int ett_trp_ticket;
1781
1782static expert_field ei_trp_initiator_id_known;
1783static expert_field ei_trp_kek_discovered;
1784
1785#define TRP_RESPONSE(0x80) (0x80)
1786
1787#define TRP_RSP_REJECT((0x80)|0) (TRP_RESPONSE(0x80)|0)
1788#define TRP_CMD_REQUEST_KEK(1) (1)
1789#define TRP_RSP_REQUEST_KEK((0x80)|(1)) (TRP_RESPONSE(0x80)|TRP_CMD_REQUEST_KEK(1))
1790#define TRP_CMD_REQUEST_RANDOM(2) (2)
1791#define TRP_RSP_REQUEST_RANDOM((0x80)|(2)) (TRP_RESPONSE(0x80)|TRP_CMD_REQUEST_RANDOM(2))
1792#define TRP_CMD_REQUEST_SESSION(3) (3)
1793#define TRP_RSP_REQUEST_SESSION((0x80)|(3)) (TRP_RESPONSE(0x80)|TRP_CMD_REQUEST_SESSION(3))
1794#define TRP_CMD_REQUEST_SECURITY_SCOPES(4) (4)
1795#define TRP_RSP_REQUEST_SECURITY_SCOPES((0x80)|(4)) (TRP_RESPONSE(0x80)|TRP_CMD_REQUEST_SECURITY_SCOPES(4))
1796#define TRP_CMD_RESOLVE_CREDENTIAL(6) (6)
1797#define TRP_RSP_RESOLVE_CREDENTIAL((0x80)|(6)) (TRP_RESPONSE(0x80)|TRP_CMD_RESOLVE_CREDENTIAL(6))
1798#define TRP_CMD_REQUEST_LOCAL_DOMAIN(7) (7)
1799#define TRP_RSP_REQUEST_LOCAL_DOMAIN((0x80)|(7)) (TRP_RESPONSE(0x80)|TRP_CMD_REQUEST_LOCAL_DOMAIN(7))
1800#define TRP_CMD_REQUEST_REMOTE_DOMAIN(8) (8)
1801#define TRP_RSP_REQUEST_REMOTE_DOMAIN((0x80)|(8)) (TRP_RESPONSE(0x80)|TRP_CMD_REQUEST_REMOTE_DOMAIN(8))
1802#define TRP_RSP_REQUEST_DISCOVERED_REMOTE_DOMAIN((0x80)|0x0A) (TRP_RESPONSE(0x80)|0x0A)
1803#define TRP_CMD_VALIDATE_CREDENTIAL(9) (9)
1804#define TRP_RSP_VALIDATE_CREDENTIAL((0x80)|(9)) (TRP_RESPONSE(0x80)|TRP_CMD_VALIDATE_CREDENTIAL(9))
1805
1806static const value_string trp_opcode_strings[] = {
1807 { TRP_RSP_REJECT((0x80)|0), "Reject" },
1808
1809 { TRP_CMD_REQUEST_KEK(1), "TRP Request KEK" },
1810 { TRP_RSP_REQUEST_KEK((0x80)|(1)), "TRP Request KEK Response" },
1811
1812 { TRP_CMD_REQUEST_RANDOM(2), "TRP Request Random" },
1813 { TRP_RSP_REQUEST_RANDOM((0x80)|(2)), "TRP Request Random Response" },
1814
1815 { TRP_CMD_REQUEST_SESSION(3), "TRP Request Session" },
1816 { TRP_RSP_REQUEST_SESSION((0x80)|(3)), "TRP Request Session Response" },
1817
1818 { TRP_CMD_REQUEST_SECURITY_SCOPES(4), "TRP Request Security Scopes" },
1819 { TRP_RSP_REQUEST_SECURITY_SCOPES((0x80)|(4)), "TRP Request Security Scopes Response" },
1820
1821 { TRP_CMD_RESOLVE_CREDENTIAL(6), "TRP Resolve Credential" },
1822 { TRP_RSP_RESOLVE_CREDENTIAL((0x80)|(6)), "TRP Resolve Credential Response" },
1823
1824 { TRP_CMD_REQUEST_LOCAL_DOMAIN(7), "TRP Request Local Domain" },
1825 { TRP_RSP_REQUEST_LOCAL_DOMAIN((0x80)|(7)), "TRP Request Local Domain Response" },
1826
1827 { TRP_CMD_REQUEST_REMOTE_DOMAIN(8), "TRP Request Remote Domain" },
1828 { TRP_RSP_REQUEST_REMOTE_DOMAIN((0x80)|(8)), "TRP Request Remote Domain Response" },
1829 { TRP_RSP_REQUEST_DISCOVERED_REMOTE_DOMAIN((0x80)|0x0A), "TRP Request Discovered Remote Domain Response" },
1830
1831 { TRP_CMD_VALIDATE_CREDENTIAL(9), "TRP Validate Credential" },
1832 { TRP_RSP_VALIDATE_CREDENTIAL((0x80)|(9)), "TRP Validate Credential Response" },
1833
1834 { 0, NULL((void*)0) }
1835};
1836
1837static const value_string trp_error_strings[] = {
1838 { 1, "Parse Error" },
1839 { 2, "Access Denied" },
1840 { 3, "Unknown Initiator" },
1841 { 4, "Unknown Responder" },
1842 { 5, "Unknown Domain" },
1843 { 6, "High Load" },
1844 { 7, "Bad Mode" },
1845 { 8, "Incompatible Security Identifiers" },
1846 { 127, "Internal Error" },
1847
1848 { 0, NULL((void*)0) }
1849};
1850
1851/* DAP V130 (SGMP - SECURE GROUP MANAGEMENT PROTOCOL V1) */
1852#define DOF_PROTOCOL_SGMP130 130
1853typedef struct _sgmp_packet_data
1854{
1855 unsigned domain_length;
1856 uint8_t *domain;
1857
1858 unsigned group_length;
1859 uint8_t *group;
1860
1861 uint16_t epoch;
1862 uint8_t *kek;
1863
1864 unsigned I_length;
1865 uint8_t *I;
1866 unsigned A_length;
1867 uint8_t *A;
1868
1869 dof_session_data *request_session;
1870} sgmp_packet_data;
1871
1872static int proto_sgmp;
1873
1874static int hf_opcode;
1875static int hf_sgmp_domain;
1876static int hf_sgmp_epoch;
1877static int hf_initiator_block;
1878static int hf_sgmp_security_scope;
1879static int hf_initial_state;
1880static int hf_latest_version;
1881static int hf_desire;
1882static int hf_ticket;
1883static int hf_sgmp_tmin;
1884static int hf_tie_breaker;
1885static int hf_delay;
1886static int hf_key;
1887
1888static int ett_sgmp;
1889static int ett_sgmp_domain;
1890static int ett_initiator_block;
1891static int ett_sgmp_security_scope;
1892static int ett_initial_state;
1893static int ett_ticket;
1894
1895#define SGMP_RESPONSE(0x80) (0x80)
1896#define SGMP_CMD_HEARTBEAT(0) (0)
1897#define SGMP_RSP_HEARTBEAT((0)|(0x80)) (SGMP_CMD_HEARTBEAT(0)|SGMP_RESPONSE(0x80))
1898#define SGMP_CMD_EPOCH_CHANGED(1) (1)
1899#define SGMP_RSP_EPOCH_CHANGED((1)|(0x80)) (SGMP_CMD_EPOCH_CHANGED(1)|SGMP_RESPONSE(0x80))
1900#define SGMP_CMD_REKEY(2) (2)
1901#define SGMP_RSP_REKEY((2)|(0x80)) (SGMP_CMD_REKEY(2)|SGMP_RESPONSE(0x80))
1902#define SGMP_CMD_REQUEST_GROUP(3) (3)
1903#define SGMP_RSP_REQUEST_GROUP((3)|(0x80)) (SGMP_CMD_REQUEST_GROUP(3)|SGMP_RESPONSE(0x80))
1904#define SGMP_CMD_REKEY_EPOCH(5) (5)
1905#define SGMP_RSP_REKEY_EPOCH((5)|(0x80)) (SGMP_CMD_REKEY_EPOCH(5)|SGMP_RESPONSE(0x80))
1906#define SGMP_CMD_REKEY_MERGE(7) (7)
1907#define SGMP_RSP_REKEY_MERGE((7)|(0x80)) (SGMP_CMD_REKEY_MERGE(7)|SGMP_RESPONSE(0x80))
1908
1909static const value_string sgmp_opcode_strings[] = {
1910 { SGMP_CMD_HEARTBEAT(0), "SGMP Heartbeat" },
1911 { SGMP_RSP_HEARTBEAT((0)|(0x80)), "SGMP Heartbeat Response (Illegal)" },
1912 { SGMP_CMD_EPOCH_CHANGED(1), "SGMP Epoch Changed" },
1913 { SGMP_RSP_EPOCH_CHANGED((1)|(0x80)), "SGMP Epoch Changed Response (Illegal)" },
1914 { SGMP_CMD_REKEY(2), "SGMP Rekey" },
1915 { SGMP_RSP_REKEY((2)|(0x80)), "SGMP Rekey Response (Illegal)" },
1916 { SGMP_CMD_REQUEST_GROUP(3), "SGMP Request Group" },
1917 { SGMP_RSP_REQUEST_GROUP((3)|(0x80)), "SGMP Request Group Response" },
1918 { SGMP_CMD_REKEY_EPOCH(5), "SGMP Rekey Epoch" },
1919 { SGMP_RSP_REKEY_EPOCH((5)|(0x80)), "SGMP Rekey Epoch Response (Illegal)" },
1920 { SGMP_CMD_REKEY_MERGE(7), "SGMP Rekey Merge" },
1921 { SGMP_RSP_REKEY_MERGE((7)|(0x80)), "SGMP Rekey Merge Response (Illegal)" },
1922
1923 { 0, NULL((void*)0) }
1924};
1925
1926
1927#if 0 /* TODO not used yet */
1928static bool_Bool sgmp_validate_session_key(sgmp_packet_data *cmd_data, uint8_t *confirmation, uint8_t *kek, uint8_t *key)
1929{
1930 gcry_mac_hd_t hmac;
1931 gcry_error_t result;
1932
1933 result = gcry_mac_open(&hmac, GCRY_MAC_HMAC_SHA256, 0, NULL((void*)0));
1934 if (result != 0)
1935 return false0;
1936
1937 gcry_mac_setkey(hmac, kek, 32);
1938 gcry_mac_write(hmac, cmd_data->I, cmd_data->I_length);
1939 gcry_mac_write(hmac, cmd_data->A, cmd_data->A_length);
1940 gcry_mac_write(hmac, key, 32);
1941 result = gcry_mac_verify(hmac, confirmation, sizeof(confirmation));
1942 return result == 0;
1943}
1944#endif
1945
1946/* DOF SECURITY PROTOCOL */
1947#define DOF_SECURITY_PROTOCOL"DOF Security Protocol" "DOF Security Protocol"
1948static dissector_table_t dof_sec_dissectors;
1949#define AS_ASSIGNED_SSID0x40000000 0x40000000
1950
1951/* DOFSEC Vxxxx (CCM - COUNTER WITH CBC-MAC PROTOCOL V1) */
1952#define DOF_PROTOCOL_CCM24577 24577
1953#define DSP_CCM_FAMILY0x020000 0x020000
1954
1955static int proto_ccm_app;
1956static int proto_ccm;
1957static int proto_ccm_dsp;
1958
1959static int hf_ccm_dsp_option;
1960static int hf_ccm_dsp_strength_count;
1961static int hf_ccm_dsp_strength;
1962static int hf_ccm_dsp_e_flag;
1963static int hf_ccm_dsp_m_flag;
1964static int hf_ccm_dsp_tmax;
1965static int hf_ccm_dsp_tmin;
1966
1967static const value_string ccm_strengths[] = {
1968 { 1, "256-bit" },
1969 { 2, "192-bit" },
1970 { 3, "128-bit" },
1971 { 0, NULL((void*)0) }
1972};
1973static int hf_ccm_opcode;
1974
1975static int hf_epp_v1_ccm_flags;
1976static int hf_epp_v1_ccm_flags_manager;
1977static int hf_epp_v1_ccm_flags_period;
1978static int hf_epp_v1_ccm_flags_target;
1979static int hf_epp_v1_ccm_flags_next_nid;
1980static int hf_epp_v1_ccm_flags_packet;
1981static int hf_epp_v1_ccm_tnid;
1982static int hf_epp_v1_ccm_nnid;
1983static int hf_epp_v1_ccm_nid;
1984static int hf_epp_v1_ccm_slot;
1985static int hf_epp_v1_ccm_pn;
1986
1987static int ett_header;
1988static int ett_epp_v1_ccm_flags;
1989
1990static int ett_ccm_dsp_option;
1991static int ett_ccm_dsp;
1992static int ett_ccm;
1993
1994static expert_field ei_decode_failure;
1995
1996typedef struct _ccm_session_data
1997{
1998 unsigned protocol_id;
1999 gcry_cipher_hd_t cipher_data;
2000 GHashTable *cipher_data_table;
2001 /* Starts at 1, incrementing for each new key. */
2002 uint32_t period;
2003 /* Mapping from wire period to absolute periods. */
2004 uint32_t periods[8];
2005 uint8_t cipher;
2006 bool_Bool encrypted;
2007 uint8_t mac_len;
2008 uint32_t client_datagram_number;
2009 uint32_t server_datagram_number;
2010} ccm_session_data;
2011
2012typedef struct _ccm_packet_data
2013{
2014 uint32_t nid;
2015 uint32_t dn;
2016 uint32_t period;
2017} ccm_packet_data;
2018
2019/* The cipher handle is opaque, so the key bytes are kept for comparison. */
2020typedef struct _ccm_period_key
2021{
2022 gcry_cipher_hd_t cipher;
2023 uint8_t key[32];
2024} ccm_period_key;
2025
2026#define CCM_PDU_PROBE(0) (0)
2027
2028static const value_string ccm_opcode_strings[] = {
2029 { CCM_PDU_PROBE(0), "Probe" },
2030 { 0, NULL((void*)0) }
2031};
2032
2033/* DOF OBJECT IDENTIFIER (OID) */
2034#define DOF_OBJECT_IDENTIFIER"DOF Object Identifier" "DOF Object Identifier"
2035
2036static dissector_handle_t dof_oid_handle;
2037
2038static int oid_proto = -1;
2039
2040static int hf_oid_class;
2041static int hf_oid_header;
2042static int hf_oid_attribute;
2043static int hf_oid_length;
2044static int hf_oid_data;
2045static int hf_oid_all_attribute_data;
2046static int hf_oid_attribute_header;
2047static int hf_oid_attribute_attribute;
2048static int hf_oid_attribute_id;
2049static int hf_oid_attribute_length;
2050static int hf_oid_attribute_data;
2051static int hf_oid_attribute_oid;
2052
2053static int ett_oid;
2054static int ett_oid_header;
2055static int ett_oid_attribute;
2056static int ett_oid_attribute_header;
2057static int ett_oid_attribute_oid;
2058
2059/**
2060 * EXPERT INFOS
2061 * Expert infos are related to either a PDU type or a specification, and so
2062 * they are listed separately.
2063 */
2064#if 0
2065static expert_field ei_undecoded;
2066#endif
2067static expert_field ei_malformed;
2068static expert_field ei_implicit_no_op;
2069static expert_field ei_c2_c3_c4_format;
2070static expert_field ei_type_4_header_zero;
2071static expert_field ei_dof_10_flags_zero;
2072static expert_field ei_dof_dnp_length_short;
2073#if 0
2074static expert_field ei_dof_13_length_specified;
2075#endif
2076
2077static expert_field ei_dpp2_dof_10_flags_zero;
2078static expert_field ei_dpp_default_flags;
2079static expert_field ei_dpp_explicit_sender_sid_included;
2080static expert_field ei_dpp_explicit_receiver_sid_included;
2081static expert_field ei_dpp_no_security_context;
2082static expert_field ei_dof_6_timeout;
2083
2084static expert_field ei_security_3_1_invalid_stage;
2085static expert_field ei_security_4_invalid_bit;
2086static expert_field ei_security_13_out_of_range;
2087
2088/**
2089 * SOURCE IDENTIFIER (SID) SUPPORT
2090 * Source identifiers are used as part of operation tracking in the
2091 * DOF Protocol Stack. They are version independent, and associated with
2092 * a node in the DOF mesh network. Each session is associated with a SID.
2093 *
2094 * DPP Manages the SID information, since it is DPP that learns about SIDs.
2095 * SIDs are complicated because the can be 'unknown' for periods, and then
2096 * learned later. The requirement here is that all SIDs that can be known
2097 * are known by the second pass of the dissector (pinfo->visited != 0).
2098 *
2099 * There are two hash tables to map to an actual SID. The first goes
2100 * from sender information to SID ID. During the first pass multiple SID ID
2101 * may actually refer to the same SID, and so the system must be able to "patch"
2102 * these values as actual SIDs are learned. The second hash table goes from SID ID
2103 * to actual SID. This lookup is only known after a real SID has been learned.
2104 *
2105 * The hash tables are used in order to look up full SID information when only
2106 * partial information is known, and must support looking up in both directions
2107 * based on what is known from a particular PDU.
2108 */
2109static GHashTable *node_key_to_sid_id;
2110static GHashTable *sid_buffer_to_sid_id;
2111static GHashTable *sid_id_to_sid_buffer;
2112/* sid_id -> GSList of packets that store that id. Avoids scanning every DOF packet. */
2113static GHashTable *sid_id_to_packets;
2114
2115typedef struct _node_key_to_sid_id_key
2116{
2117 int transport_id;
2118 int transport_node_id;
2119 int dof_id;
2120 int dof_node_id;
2121 int dof_session_id;
2122} node_key_to_sid_id_key;
2123
2124static unsigned sender_key_hash_fn(const void *key)
2125{
2126 const node_key_to_sid_id_key *sid_key_ptr = (const node_key_to_sid_id_key *)key;
2127 unsigned result = 0;
2128
2129 result += g_int_hash(&(sid_key_ptr->transport_id));
2130 result += g_int_hash(&(sid_key_ptr->transport_node_id));
2131 result += g_int_hash(&(sid_key_ptr->dof_id));
2132 result += g_int_hash(&(sid_key_ptr->dof_node_id));
2133 result += g_int_hash(&(sid_key_ptr->dof_session_id));
2134
2135 return result;
2136}
2137
2138static unsigned sid_buffer_hash_fn(const void *key)
2139{
2140 /* The sid buffer is a length byte followed by data. */
2141 unsigned hash = 5381;
2142 const uint8_t *str = (const uint8_t *)key;
2143 uint16_t i;
2144
2145 for (i = 0; i <= str[0]; i++)
2146 hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
2147
2148 return hash;
2149}
2150
2151static gboolean sender_key_equal_fn(const void *key1, const void *key2)
2152{
2153 const node_key_to_sid_id_key *sid_key_ptr1 = (const node_key_to_sid_id_key *)key1;
2154 const node_key_to_sid_id_key *sid_key_ptr2 = (const node_key_to_sid_id_key *)key2;
2155
2156 if (sid_key_ptr1->transport_id != sid_key_ptr2->transport_id)
2157 return FALSE(0);
2158
2159 if (sid_key_ptr1->transport_node_id != sid_key_ptr2->transport_node_id)
2160 return FALSE(0);
2161
2162 if (sid_key_ptr1->dof_id != sid_key_ptr2->dof_id)
2163 return FALSE(0);
2164
2165 if (sid_key_ptr1->dof_node_id != sid_key_ptr2->dof_node_id)
2166 return FALSE(0);
2167
2168 if (sid_key_ptr1->dof_session_id != sid_key_ptr2->dof_session_id)
2169 return FALSE(0);
2170
2171 return TRUE(!(0));
2172}
2173
2174static gboolean sid_buffer_equal_fn(const void *key1, const void *key2)
2175{
2176 const uint8_t *sb1 = (const uint8_t *)key1;
2177 const uint8_t *sb2 = (const uint8_t *)key2;
2178
2179 if (sb1[0] != sb2[0])
2180 return FALSE(0);
2181
2182 return memcmp(sb1 + 1, sb2 + 1, sb1[0]) == 0;
2183}
2184
2185static unsigned dpp_next_sid_id = 1;
2186
2187/**
2188 * This routine is called for each reset (file load, capture) and is responsible
2189 * for allocating the SID support hash tables. Previous information is freed
2190 * if needed.
2191 */
2192static void dpp_reset_sid_support(void)
2193{
2194 dpp_next_sid_id = 1;
2195
2196 if (node_key_to_sid_id != NULL((void*)0))
2197 {
2198 g_hash_table_destroy(node_key_to_sid_id);
2199 node_key_to_sid_id = NULL((void*)0);
2200 }
2201
2202 if (sid_buffer_to_sid_id != NULL((void*)0))
2203 {
2204 g_hash_table_destroy(sid_buffer_to_sid_id);
2205 sid_buffer_to_sid_id = NULL((void*)0);
2206 }
2207
2208 if (sid_id_to_sid_buffer != NULL((void*)0))
2209 {
2210 g_hash_table_destroy(sid_id_to_sid_buffer);
2211 sid_id_to_sid_buffer = NULL((void*)0);
2212 }
2213
2214 if (sid_id_to_packets != NULL((void*)0))
2215 {
2216 g_hash_table_destroy(sid_id_to_packets);
2217 sid_id_to_packets = NULL((void*)0);
2218 }
2219
2220 /* The value is not allocated, so does not need to be freed. */
2221 node_key_to_sid_id = g_hash_table_new_full(sender_key_hash_fn, sender_key_equal_fn, g_free, NULL((void*)0));
2222 sid_buffer_to_sid_id = g_hash_table_new_full(sid_buffer_hash_fn, sid_buffer_equal_fn, g_free, NULL((void*)0));
2223 sid_id_to_sid_buffer = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL((void*)0), NULL((void*)0));
2224 sid_id_to_packets = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL((void*)0), (GDestroyNotify)g_slist_free);
2225}
2226
2227/**
2228 * OPERATION IDENTIFIER SUPPORT
2229 * Operation identifiers are an extension of a SID, and represent each separate
2230 * operation in the DOF. They are identified by a SID and an operation count.
2231 * Like SIDs, they are independent of version (at least in meaning, the formatting
2232 * may change).
2233 *
2234 * The hash is used to look up common operation information each time an operation
2235 * is seen in any packet.
2236 */
2237static GHashTable *dpp_opid_to_packet_data;
2238
2239static unsigned dpp_opid_hash_fn(const void *opid)
2240{
2241 const dof_2009_1_pdu_20_opid *ptr = (const dof_2009_1_pdu_20_opid *)opid;
2242 return g_int_hash(&ptr->op_sid_id) + g_int_hash(&ptr->op_cnt);
2243}
2244
2245static gboolean dpp_opid_equal_fn(const void *opid1, const void *opid2)
2246{
2247 const dof_2009_1_pdu_20_opid *ptr1 = (const dof_2009_1_pdu_20_opid *)opid1;
2248 const dof_2009_1_pdu_20_opid *ptr2 = (const dof_2009_1_pdu_20_opid *)opid2;
2249 if (ptr1->op_cnt != ptr2->op_cnt)
2250 return FALSE(0);
2251 if (ptr1->op_sid_id != ptr2->op_sid_id)
2252 return FALSE(0);
2253
2254 return TRUE(!(0));
2255}
2256
2257static void dpp_reset_opid_support(void)
2258{
2259 if (dpp_opid_to_packet_data != NULL((void*)0))
2260 {
2261 /* Clear it out. Note that this calls the destroy functions for each element. */
2262 g_hash_table_destroy(dpp_opid_to_packet_data);
2263 dpp_opid_to_packet_data = NULL((void*)0);
2264 }
2265
2266 dpp_opid_to_packet_data = g_hash_table_new_full(dpp_opid_hash_fn, dpp_opid_equal_fn, NULL((void*)0), NULL((void*)0));
2267}
2268
2269/**
2270 * NON-SECURE SESSION LOOKUP SUPPORT
2271 */
2272static GHashTable *dof_ns_session_lookup;
2273
2274/**
2275 * NON-SECURE DPS SESSION
2276 * This is defined by the transport session and the DNP port information.
2277 */
2278typedef struct _dof_ns_session_key
2279{
2280 unsigned transport_session_id;
2281 unsigned client;
2282 unsigned server;
2283 bool_Bool is_secure;
2284} dof_ns_session_key;
2285
2286static dof_session_data* dof_ns_session_retrieve(unsigned transport_session_id, unsigned client, unsigned server)
2287{
2288 dof_ns_session_key lookup_key;
2289 dof_session_data *value;
2290
2291 /* Build a (non-allocated) key to do the lookup. */
2292 lookup_key.transport_session_id = transport_session_id;
2293 lookup_key.client = client;
2294 lookup_key.server = server;
2295
2296 value = (dof_session_data *)g_hash_table_lookup(dof_ns_session_lookup, &lookup_key);
2297 if (value)
2298 {
2299 /* We found a match. */
2300 return value;
2301 }
2302
2303 return NULL((void*)0);
2304}
2305
2306static void dof_ns_session_define(unsigned transport_session_id, unsigned client, unsigned server, dof_session_data *session_data)
2307{
2308 dof_ns_session_key *key;
2309
2310 /* No match, need to add a key. */
2311 key = g_new0(dof_ns_session_key, 1)((dof_ns_session_key *) g_malloc0_n ((1), sizeof (dof_ns_session_key
)))
;
2312 key->transport_session_id = transport_session_id;
2313 key->client = client;
2314 key->server = server;
2315
2316 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
2317 g_hash_table_insert(dof_ns_session_lookup, key, session_data);
2318}
2319
2320/* COMMON PDU DISSECTORS */
2321
2322/* Security.1 */
2323static int hf_security_1_permission_type;
2324static int hf_security_1_length;
2325static int hf_security_1_data;
2326
2327static const value_string dof_2008_16_permission_type[] = {
2328 { 1, "Binding" },
2329 { 3, "IAM" },
2330 { 5, "ACTAS" },
2331 { 128, "Requestor" },
2332 { 130, "Provider" },
2333 { 131, "Define" },
2334 { 133, "Tunnel Domain" },
2335 { 0, NULL((void*)0) }
2336};
2337
2338/* Security.2 */
2339static int hf_security_2_count;
2340static int ett_security_2_permission;
2341static int hf_security_2_permission;
2342
2343/* Security.3.1 */
2344static int hf_security_3_1_credential_type;
2345static int hf_security_3_1_stage;
2346static int ett_security_3_1_security_node_identifier;
2347static int hf_security_3_1_security_node_identifier;
2348
2349/* Security.3.2 */
2350static int hf_security_3_2_credential_type;
2351static int hf_security_3_2_stage;
2352static int hf_security_3_2_length;
2353static int hf_security_3_2_public_data;
2354
2355/* Security.4 */
2356static int hf_security_4_l;
2357static int hf_security_4_f;
2358static int hf_security_4_ln;
2359static int ett_security_4_identity;
2360static int hf_security_4_identity;
2361static int hf_security_4_nonce;
2362static int ett_security_4_permission_set;
2363static int hf_security_4_permission_set;
2364
2365/* Security.5 */
2366static int hf_security_5_mac;
2367static int hf_security_5_key;
2368
2369/* Security.6.1 */
2370static int hf_security_6_1_desired_duration;
2371static int ett_security_6_1_desired_security_mode;
2372static int hf_security_6_1_desired_security_mode;
2373static int ett_security_6_1_initiator_request;
2374static int hf_security_6_1_initiator_request;
2375
2376/* Security.6.2 */
2377static int ett_security_6_2_responder_request;
2378static int hf_security_6_2_responder_request;
2379
2380/* Security.6.3 */
2381static int hf_security_6_3_granted_duration;
2382static int ett_security_6_3_session_security_scope;
2383static int hf_security_6_3_session_security_scope;
2384static int ett_security_6_3_initiator_validation;
2385static int hf_security_6_3_initiator_validation;
2386static int ett_security_6_3_responder_validation;
2387static int hf_security_6_3_responder_validation;
2388
2389/* Security.9 */
2390static int hf_security_9_length;
2391static int hf_security_9_initial_state;
2392
2393/* Security.10 */
2394static int hf_security_10_count;
2395static int hf_security_10_permission_group_identifier;
2396
2397/* Security.11 */
2398static int hf_security_11_count;
2399static int ett_security_11_permission_security_scope;
2400static int hf_security_11_permission_security_scope;
2401
2402/* Security.12 */
2403static int hf_security_12_m;
2404
2405static const value_string dof_2008_16_security_12_m[] = {
2406 { 0, "Reference" },
2407 { 1, "Relative" },
2408 { 2, "Absolute" },
2409 { 3, "Continued" },
2410 { 0, NULL((void*)0) }
2411};
2412
2413static int hf_security_12_count;
2414static int hf_security_12_permission_group_identifier;
2415
2416static bool_Bool
2417dof_sessions_destroy_cb(wmem_allocator_t *allocator _U___attribute__((unused)), wmem_cb_event_t event _U___attribute__((unused)), void *user_data)
2418{
2419 ccm_session_data *ccm_data = (ccm_session_data*) user_data;
2420 if (ccm_data->cipher_data)
2421 gcry_cipher_close(ccm_data->cipher_data);
2422 if (ccm_data->cipher_data_table) {
2423 g_hash_table_destroy(ccm_data->cipher_data_table);
2424 }
2425 /* unregister this callback */
2426 return false0;
2427}
2428
2429static void dof_cipher_data_destroy (void *data)
2430{
2431 ccm_period_key *period_key = (ccm_period_key *)data;
2432
2433 if (period_key->cipher)
2434 gcry_cipher_close(period_key->cipher);
2435 g_free(period_key)(__builtin_object_size ((period_key), 0) != ((size_t) - 1)) ?
g_free_sized (period_key, __builtin_object_size ((period_key
), 0)) : (g_free) (period_key)
;
2436}
2437
2438static ccm_period_key *ccm_period_key_new(const uint8_t *session_key)
2439{
2440 ccm_period_key *pk = g_new0(ccm_period_key, 1)((ccm_period_key *) g_malloc0_n ((1), sizeof (ccm_period_key)
))
;
2441
2442 if (gcry_cipher_open(&pk->cipher, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0))
2443 {
2444 g_free(pk)(__builtin_object_size ((pk), 0) != ((size_t) - 1)) ? g_free_sized
(pk, __builtin_object_size ((pk), 0)) : (g_free) (pk)
;
2445 return NULL((void*)0);
2446 }
2447 if (gcry_cipher_setkey(pk->cipher, session_key, 32))
2448 {
2449 gcry_cipher_close(pk->cipher);
2450 g_free(pk)(__builtin_object_size ((pk), 0) != ((size_t) - 1)) ? g_free_sized
(pk, __builtin_object_size ((pk), 0)) : (g_free) (pk)
;
2451 return NULL((void*)0);
2452 }
2453 memcpy(pk->key, session_key, 32);
2454 return pk;
2455}
2456
2457static int dissect_2008_1_dsp_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2458{
2459 proto_item *parent = proto_tree_get_parent(tree);
2460 uint8_t attribute_code = tvb_get_uint8(tvb, 0);
2461 uint16_t attribute_data = tvb_get_ntohs(tvb, 1);
2462 uint8_t option_length = tvb_get_uint8(tvb, 3);
2463
2464 /* Add the generic representation of the fields. */
2465 proto_tree_add_item(tree, hf_2008_1_dsp_attribute_code, tvb, 0, 1, ENC_NA0x00000000);
2466 proto_tree_add_item(tree, hf_2008_1_dsp_attribute_data, tvb, 1, 2, ENC_BIG_ENDIAN0x00000000);
2467 proto_tree_add_item(tree, hf_2008_1_dsp_value_length, tvb, 3, 1, ENC_NA0x00000000);
2468
2469 /* Append description to the parent. */
2470 proto_item_append_text(parent, " (Code=%s/Data=0x%04x)", val_to_str(pinfo->pool, attribute_code, strings_2008_1_dsp_attribute_codes, "%u"), attribute_data);
2471
2472 if (option_length)
2473 {
2474 proto_tree_add_item(tree, hf_2008_1_dsp_value_data, tvb, 4, option_length, ENC_NA0x00000000);
2475
2476 /* call the next dissector */
2477 tvb_set_reported_length(tvb, option_length + 4);
2478 dissector_try_uint(dsp_option_dissectors, (attribute_code << 16) | attribute_data, tvb, pinfo, tree);
2479 }
2480 return option_length + 4;
2481}
2482
2483/**
2484 * Security.1: Permission. This is the base type for
2485 * permissions, and supports extension.
2486 */
2487static int dissect_2008_16_security_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2488{
2489 unsigned offset = 0;
2490 bool_Bool has_length;
2491 uint16_t length;
2492
2493 /* Permission Type */
2494 {
2495 int start = offset;
2496 uint16_t value;
2497 int val_len;
2498 proto_item *pi;
2499 offset = read_c2(tvb, offset, &value, &val_len);
2500 has_length = (bool_Bool)(value % 2);
2501 pi = proto_tree_add_uint(tree, hf_security_1_permission_type, tvb, start, offset - start, value);
2502 validate_c2(pinfo, pi, value, val_len);
2503 }
2504
2505 if (!has_length)
2506 return offset;
2507
2508 /* Length */
2509 {
2510 int start = offset;
2511 uint16_t value;
2512 int value_len;
2513 proto_item *pi;
2514 offset = read_c2(tvb, offset, &value, &value_len);
2515 length = value;
2516 pi = proto_tree_add_uint(tree, hf_security_1_length, tvb, start, offset - start, value);
2517 validate_c2(pinfo, pi, value, value_len);
2518 }
2519
2520 /* Data */
2521 proto_tree_add_item(tree, hf_security_1_data, tvb, offset, length, ENC_NA0x00000000);
2522 offset += length;
2523
2524 return offset;
2525}
2526
2527/**
2528 * Security.2: Permission Request.
2529 */
2530static int dissect_2008_16_security_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2531{
2532 unsigned offset = 0;
2533 uint16_t count;
2534
2535 /* Count */
2536 {
2537 int start = offset;
2538 uint16_t value;
2539 int length;
2540 proto_item *pi;
2541 offset = read_c2(tvb, offset, &value, &length);
2542 count = value;
2543 pi = proto_tree_add_uint(tree, hf_security_2_count, tvb, start, offset - start, value);
2544 validate_c2(pinfo, pi, value, length);
2545 }
2546
2547 while (count--)
2548 {
2549 proto_item *ti = proto_tree_add_item(tree, hf_security_2_permission, tvb, offset, -1, ENC_NA0x00000000);
2550 proto_tree *subtree = proto_item_add_subtree(ti, ett_security_2_permission);
2551 tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
2552 int len = dissect_2008_16_security_1(next_tvb, pinfo, subtree, NULL((void*)0));
2553 proto_item_set_len(ti, len);
2554 offset += len;
2555 }
2556
2557 return offset;
2558}
2559
2560/**
2561 * Security.3.1: Base Credential Format.
2562 * Returns: dof_2008_16_security_3_1
2563 */
2564static int dissect_2008_16_security_3_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2565{
2566 unsigned offset = 0;
2567 uint8_t stage;
2568 proto_item *ti;
2569 dof_2008_16_security_3_1 *return_data = (dof_2008_16_security_3_1 *)data;
2570
2571 /* Credential Type */
2572 {
2573 int start = offset;
2574 uint16_t value;
2575 int length;
2576 proto_item *pi;
2577 offset = read_c2(tvb, offset, &value, &length);
2578 pi = proto_tree_add_uint(tree, hf_security_3_1_credential_type, tvb, start, offset - start, value);
2579 validate_c2(pinfo, pi, value, length);
2580 }
2581
2582 /* Stage */
2583 ti = proto_tree_add_item_ret_uint8(tree, hf_security_3_1_stage, tvb, offset, 1, ENC_NA0x00000000, &stage);
2584 offset += 1;
2585
2586 if (stage != 0)
2587 expert_add_info(pinfo, ti, &ei_security_3_1_invalid_stage);
2588
2589 /* Security Node Identifier */
2590 {
2591 int block_length;
2592 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2593 proto_tree *subtree;
2594 ti = proto_tree_add_item(tree, hf_security_3_1_security_node_identifier, tvb, offset, 0, ENC_NA0x00000000);
2595 subtree = proto_item_add_subtree(ti, ett_security_3_1_security_node_identifier);
2596 block_length = dissect_2008_16_security_8(start, pinfo, subtree, NULL((void*)0));
2597 proto_item_set_len(ti, block_length);
2598 offset += block_length;
2599 tvb_set_reported_length(start, block_length);
2600 if (return_data)
2601 return_data->identity = start;
2602 }
2603
2604 return offset;
2605}
2606
2607/**
2608 * Security.3.2: Identity Resolution.
2609 */
2610int dissect_2008_16_security_3_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2611{
2612 unsigned offset = 0;
2613 uint16_t length;
2614
2615 /* Credential Type */
2616 {
2617 int start = offset;
2618 uint16_t value;
2619 int val_len;
2620 proto_item *pi;
2621 offset = read_c2(tvb, offset, &value, &val_len);
2622 pi = proto_tree_add_uint(tree, hf_security_3_2_credential_type, tvb, start, offset - start, value);
2623 validate_c2(pinfo, pi, value, val_len);
2624 }
2625
2626 /* Stage */
2627 proto_tree_add_item(tree, hf_security_3_2_stage, tvb, offset, 1, ENC_NA0x00000000);
2628 offset += 1;
2629
2630 /* Length */
2631 {
2632 int start = offset;
2633 uint16_t value;
2634 int value_len;
2635 proto_item *pi;
2636 offset = read_c2(tvb, offset, &value, &value_len);
2637 length = value;
2638 pi = proto_tree_add_uint(tree, hf_security_3_2_length, tvb, start, offset - start, value);
2639 validate_c2(pinfo, pi, value, value_len);
2640 }
2641
2642 /* Public Data */
2643 proto_tree_add_item(tree, hf_security_3_2_public_data, tvb, offset, length, ENC_NA0x00000000);
2644 offset += length;
2645
2646 return offset;
2647}
2648
2649/**
2650 * Security.4: Key Request. Returns: dof_2008_16_security_4
2651 */
2652static int dissect_2008_16_security_4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2653{
2654 unsigned offset = 0;
2655 uint8_t flag;
2656 dof_2008_16_security_4 *return_data = (dof_2008_16_security_4 *)data;
2657
2658 flag = tvb_get_uint8(tvb, offset);
2659 if (flag & 0x30)
2660 expert_add_info(pinfo, tree, &ei_security_4_invalid_bit);
2661
2662 proto_tree_add_item(tree, hf_security_4_l, tvb, offset, 1, ENC_NA0x00000000);
2663 proto_tree_add_item(tree, hf_security_4_f, tvb, offset, 1, ENC_NA0x00000000);
2664 proto_tree_add_item(tree, hf_security_4_ln, tvb, offset, 1, ENC_NA0x00000000);
2665 offset += 1;
2666
2667 {
2668 int block_length;
2669 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2670 proto_item *ti;
2671 proto_tree *subtree;
2672 dof_2008_16_security_3_1 return_3_1;
2673
2674 ti = proto_tree_add_item(tree, hf_security_4_identity, tvb, offset, 0, ENC_NA0x00000000);
2675 subtree = proto_item_add_subtree(ti, ett_security_4_identity);
2676
2677 block_length = dissect_2008_16_security_3_1(start, pinfo, subtree, &return_3_1);
2678 proto_item_set_len(ti, block_length);
2679 offset += block_length;
2680 if (return_data)
2681 {
2682 return_data->identity = return_3_1.identity;
2683 }
2684 }
2685
2686 {
2687 tvbuff_t *start = tvb_new_subset_length(tvb, offset, (flag & 0x0F) + 1);
2688 if (return_data)
2689 return_data->nonce = start;
2690
2691 proto_tree_add_item(tree, hf_security_4_nonce, start, 0, (flag & 0x0F) + 1, ENC_NA0x00000000);
2692 offset += (flag & 0x0F) + 1;
2693 }
2694
2695 {
2696 int block_length;
2697 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2698 proto_item *ti;
2699 proto_tree *subtree;
2700
2701 ti = proto_tree_add_item(tree, hf_security_4_permission_set, tvb, offset, 0, ENC_NA0x00000000);
2702 subtree = proto_item_add_subtree(ti, ett_security_4_permission_set);
2703 block_length = dissect_2008_16_security_2(start, pinfo, subtree, NULL((void*)0));
2704 proto_item_set_len(ti, block_length);
2705 offset += block_length;
2706 }
2707
2708 return offset;
2709}
2710
2711/**
2712 * Security.5: Key Grant.
2713 */
2714static int dissect_2008_16_security_5(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree, void *data _U___attribute__((unused)))
2715{
2716 unsigned offset = 0;
2717
2718 proto_tree_add_item(tree, hf_security_5_mac, tvb, offset, 32, ENC_NA0x00000000);
2719 offset += 32;
2720
2721 proto_tree_add_item(tree, hf_security_5_key, tvb, offset, 32, ENC_NA0x00000000);
2722 offset += 32;
2723
2724 return offset;
2725}
2726
2727/**
2728 * Security.6.1: Session Initiator Block.
2729 * Returns dof_2008_16_security_6_1
2730 */
2731static int dissect_2008_16_security_6_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2732{
2733 unsigned offset = 0;
2734
2735 /* Allocate the return structure. */
2736 dof_2008_16_security_6_1 *return_data = (dof_2008_16_security_6_1 *)data;
2737
2738 /* Desired Duration */
2739 proto_tree_add_item(tree, hf_security_6_1_desired_duration, tvb, offset, 1, ENC_NA0x00000000);
2740 offset += 1;
2741
2742 /* Desired Security Mode */
2743 {
2744 int block_length;
2745 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2746 proto_item *ti;
2747 proto_tree *subtree;
2748
2749 ti = proto_tree_add_item(tree, hf_security_6_1_desired_security_mode, tvb, offset, 0, ENC_NA0x00000000);
2750 subtree = proto_item_add_subtree(ti, ett_security_6_1_desired_security_mode);
2751
2752 block_length = dissect_2008_16_security_13(start, pinfo, subtree, NULL((void*)0));
2753 offset += block_length;
2754 tvb_set_reported_length(start, block_length);
2755 proto_item_set_len(ti, block_length);
2756
2757 if (return_data)
2758 {
2759 return_data->security_mode = tvb_get_ntohs(start, 1);
2760 return_data->security_mode_data_length = block_length - 4;
2761 return_data->security_mode_data = (uint8_t *)tvb_memdup(wmem_file_scope(), start, 4, block_length - 4);
2762 }
2763 }
2764
2765 /* Initiator Request */
2766 {
2767 int block_length;
2768 dof_2008_16_security_4 output;
2769 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2770 proto_item *ti;
2771 proto_tree *subtree;
2772
2773 ti = proto_tree_add_item(tree, hf_security_6_1_initiator_request, tvb, offset, 0, ENC_NA0x00000000);
2774 subtree = proto_item_add_subtree(ti, ett_security_6_1_initiator_request);
2775
2776 block_length = dissect_2008_16_security_4(start, pinfo, subtree, &output);
2777 proto_item_set_len(ti, block_length);
2778 offset += block_length;
2779 if (return_data)
2780 {
2781 return_data->i_identity = output.identity;
2782 return_data->i_nonce = output.nonce;
2783 }
2784 }
2785
2786 return offset;
2787}
2788
2789/**
2790 * Security.6.2: Session Responder Block.
2791 * Returns dof_2008_16_security_6_2
2792 */
2793static int dissect_2008_16_security_6_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2794{
2795 unsigned offset = 0;
2796 dof_2008_16_security_6_2 *return_data = (dof_2008_16_security_6_2 *)data;
2797
2798 /* Responder Request */
2799 {
2800 int block_length;
2801 dof_2008_16_security_4 output;
2802 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2803 proto_item *ti;
2804 proto_tree *subtree;
2805
2806 ti = proto_tree_add_item(tree, hf_security_6_2_responder_request, tvb, offset, 0, ENC_NA0x00000000);
2807 subtree = proto_item_add_subtree(ti, ett_security_6_2_responder_request);
2808
2809 block_length = dissect_2008_16_security_4(start, pinfo, subtree, &output);
2810 proto_item_set_len(ti, block_length);
2811 offset += block_length;
2812 if (return_data)
2813 {
2814 return_data->r_identity = output.identity;
2815 return_data->r_nonce = output.nonce;
2816 }
2817 }
2818
2819 return offset;
2820}
2821
2822/**
2823 * Security.6.3: Authentication Response Block.
2824 */
2825static int dissect_2008_16_security_6_3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2826{
2827 unsigned offset = 0;
2828
2829 /* Granted Duration */
2830 proto_tree_add_item(tree, hf_security_6_3_granted_duration, tvb, offset, 1, ENC_NA0x00000000);
2831 offset += 1;
2832
2833 /* Session Security Scope */
2834 {
2835 int block_length;
2836 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2837 proto_item *ti;
2838 proto_tree *subtree;
2839
2840 ti = proto_tree_add_item(tree, hf_security_6_3_session_security_scope, tvb, offset, 0, ENC_NA0x00000000);
2841 subtree = proto_item_add_subtree(ti, ett_security_6_3_session_security_scope);
2842 block_length = dissect_2008_16_security_10(start, pinfo, subtree, NULL((void*)0));
2843 proto_item_set_len(ti, block_length);
2844 offset += block_length;
2845 }
2846
2847 /* Initiator Validation */
2848 {
2849 int block_length;
2850 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2851 proto_item *ti;
2852 proto_tree *subtree;
2853
2854 ti = proto_tree_add_item(tree, hf_security_6_3_initiator_validation, tvb, offset, 0, ENC_NA0x00000000);
2855 subtree = proto_item_add_subtree(ti, ett_security_6_3_initiator_validation);
2856 block_length = dissect_2008_16_security_11(start, pinfo, subtree, NULL((void*)0));
2857 proto_item_set_len(ti, block_length);
2858 offset += block_length;
2859 }
2860
2861 /* Responder Validation */
2862 {
2863 int block_length;
2864 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2865 proto_item *ti;
2866 proto_tree *subtree;
2867
2868 ti = proto_tree_add_item(tree, hf_security_6_3_responder_validation, tvb, offset, 0, ENC_NA0x00000000);
2869 subtree = proto_item_add_subtree(ti, ett_security_6_3_responder_validation);
2870 block_length = dissect_2008_16_security_11(start, pinfo, subtree, NULL((void*)0));
2871 proto_item_set_len(ti, block_length);
2872 offset += block_length;
2873 }
2874
2875 return offset;
2876}
2877
2878/**
2879 * Security.7: Security Domain.
2880 */
2881static int dissect_2008_16_security_7(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2882{
2883 /* Parse the base type. */
2884 int block_length;
2885
2886 block_length = dissect_2009_11_type_4(tvb, pinfo, tree, NULL((void*)0));
2887
2888 return block_length;
2889}
2890
2891/**
2892 * Security.8: Security Node Identifier.
2893 */
2894static int dissect_2008_16_security_8(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2895{
2896 /* Parse the base type. */
2897 int block_length;
2898
2899 block_length = dissect_2009_11_type_4(tvb, pinfo, tree, NULL((void*)0));
2900
2901 return block_length;
2902}
2903
2904/**
2905 * Security.9: Security Mode of Operation Initialization.
2906 * If the packet info has knowledge of the active security mode
2907 * of operation then this datagram can be further decoded.
2908 */
2909static int dissect_2008_16_security_9(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2910{
2911 unsigned offset = 0;
2912 uint16_t length;
2913
2914 /* Length */
2915 {
2916 int start = offset;
2917 uint16_t value;
2918 int value_len;
2919 proto_item *pi;
2920 offset = read_c2(tvb, offset, &value, &value_len);
2921 length = value;
2922 pi = proto_tree_add_uint(tree, hf_security_9_length, tvb, start, offset - start, value);
2923 validate_c2(pinfo, pi, value, value_len);
2924 }
2925
2926 if (length > 0)
2927 {
2928 proto_tree_add_item(tree, hf_security_9_initial_state, tvb, offset, length, ENC_NA0x00000000);
2929 offset += length;
2930 }
2931
2932 return offset;
2933}
2934
2935/**
2936 * Security.10: Security Scope.
2937 */
2938static int dissect_2008_16_security_10(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2939{
2940 unsigned offset = 0;
2941 uint16_t count;
2942
2943 /* Count */
2944 {
2945 int start = offset;
2946 uint16_t value;
2947 int length;
2948 proto_item *pi;
2949 offset = read_c2(tvb, offset, &value, &length);
2950 count = value;
2951 pi = proto_tree_add_uint(tree, hf_security_10_count, tvb, start, offset - start, value);
2952 validate_c2(pinfo, pi, value, length);
2953 }
2954
2955 while (count--)
2956 {
2957 const char *def = "";
2958
2959 int start = offset;
2960 uint32_t value;
2961 int length;
2962 proto_item *pi;
2963
2964 offset = read_c4(tvb, offset, &value, &length);
2965
2966 switch (value)
2967 {
2968 case 0x3FFFFFFF:
2969 def = " (all scopes)";
2970 break;
2971 case 0x3FFFFFFE:
2972 def = " (doesn't mask)";
2973 break;
2974 case 0x3FFFFFFD:
2975 def = " (session scope)";
2976 break;
2977 }
2978
2979 pi = proto_tree_add_uint_format_value(tree, hf_security_10_permission_group_identifier, tvb, start, offset - start, value, "%u%s", value, def);
2980 validate_c4(pinfo, pi, value, length);
2981 }
2982
2983 return offset;
2984}
2985
2986/**
2987 * Security.11: Permission Validation.
2988 */
2989static int dissect_2008_16_security_11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
2990{
2991 unsigned offset = 0;
2992 uint16_t count;
2993
2994 /* Count */
2995 {
2996 int start = offset;
2997 uint16_t value;
2998 int length;
2999 proto_item *pi;
3000 offset = read_c2(tvb, offset, &value, &length);
3001 count = value;
3002 pi = proto_tree_add_uint(tree, hf_security_11_count, tvb, start, offset - start, value);
3003 validate_c2(pinfo, pi, value, length);
3004 }
3005
3006 while (count--)
3007 {
3008 proto_item *ti = proto_tree_add_item(tree, hf_security_11_permission_security_scope, tvb, offset, -1, ENC_NA0x00000000);
3009 proto_tree *subtree = proto_item_add_subtree(ti, ett_security_11_permission_security_scope);
3010 tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
3011 int len;
3012 len = dissect_2008_16_security_12(next_tvb, pinfo, subtree, NULL((void*)0));
3013 proto_item_set_len(ti, len);
3014 offset += len;
3015 }
3016
3017 return offset;
3018}
3019
3020/**
3021 * Security.12: Permission Security Scope.
3022 */
3023static int dissect_2008_16_security_12(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
3024{
3025 unsigned offset = 0;
3026 uint8_t m = tvb_get_uint8(tvb, offset) >> 6;
3027 uint16_t count = tvb_get_uint8(tvb, offset) & 0x3F;
3028 proto_item *pi;
3029
3030 proto_tree_add_item(tree, hf_security_12_m, tvb, offset, 1, ENC_NA0x00000000);
3031 proto_tree_add_item(tree, hf_security_12_count, tvb, offset, 1, ENC_NA0x00000000);
3032 offset += 1;
3033
3034 if (m == 0)
3035 return offset;
3036
3037 while (count--)
3038 {
3039 const char *def = "";
3040
3041 int start = offset;
3042 uint32_t value;
3043 int length;
3044 offset = read_c4(tvb, offset, &value, &length);
3045
3046 switch (value)
3047 {
3048 case 0x3FFFFFFF:
3049 def = " (all scopes)";
3050 break;
3051 case 0x3FFFFFFE:
3052 def = " (doesn't mask)";
3053 break;
3054 case 0x3FFFFFFD:
3055 def = " (session scope)";
3056 break;
3057 }
3058
3059 pi = proto_tree_add_uint_format_value(tree, hf_security_12_permission_group_identifier, tvb, start, offset - start, value, "%u%s", value, def);
3060 validate_c4(pinfo, pi, value, length);
3061 }
3062
3063 return offset;
3064}
3065
3066/**
3067 * Security.13: Security Mode of Operation Negotiation.
3068 */
3069static int dissect_2008_16_security_13(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
3070{
3071 /* Parse the base type. */
3072 int block_length;
3073 uint16_t attribute_data;
3074
3075 /* TODO: Skipping this first byte means that no other encryption modes can be supported. */
3076 attribute_data = tvb_get_ntohs(tvb, 1);
3077 if (attribute_data < 0x6000 || attribute_data >= 0x7000)
3078 expert_add_info(pinfo, tree, &ei_security_13_out_of_range);
3079
3080 block_length = dissect_2008_1_dsp_1(tvb, pinfo, tree);
3081
3082 return block_length;
3083}
3084
3085/**
3086 * Dissects a buffer that is pointing at an OID.
3087 * Adds a subtree with detailed information about the fields of
3088 * the OID,
3089 * returns the length of the OID,
3090 * and appends text to the tree (really a tree item) that is
3091 * passed in that gives a more accurate description of the OID.
3092 * Note that the tree already shows the bytes of the OID, so if
3093 * no additional information can be displayed then it should not
3094 * be.
3095 *
3096 * If 'tree' is NULL then just return the length.
3097 */
3098// NOLINTNEXTLINE(misc-no-recursion)
3099static int dissect_2009_11_type_4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
3100{
3101 proto_item *ti;
3102 int start_offset = 0;
3103 unsigned offset = 0;
3104 uint32_t oid_class;
3105 int oid_class_len;
3106 uint8_t oid_len_byte;
3107 proto_tree *oid_tree = tree;
3108 proto_tree *header_tree;
3109
3110 if (tree)
3111 {
3112 ti = proto_tree_get_parent(tree);
3113 proto_item_set_text(ti, "Object ID: %s", dof_oid_create_standard_string(pinfo->pool, tvb_captured_length(tvb), tvb_get_ptr(tvb, 0, tvb_captured_length(tvb)), pinfo));
3114 }
3115
3116 offset = read_c4(tvb, offset, &oid_class, &oid_class_len);
3117 ti = proto_tree_add_uint_format(oid_tree, hf_oid_class, tvb, start_offset, offset - start_offset, oid_class, "Class: %u", oid_class);
3118 validate_c4(pinfo, ti, oid_class, oid_class_len);
3119
3120 oid_len_byte = tvb_get_uint8(tvb, offset);
3121 ti = proto_tree_add_uint_format(oid_tree, hf_oid_header, tvb,
3122 offset, 1, oid_len_byte, "Header: 0x%02x (%sLength=%d)", oid_len_byte, oid_len_byte & 0x80 ? "Attribute, " : "", oid_len_byte & 0x3F);
3123
3124 header_tree = proto_item_add_subtree(ti, ett_oid_header);
3125 proto_tree_add_item(header_tree, hf_oid_attribute, tvb, offset, 1, ENC_NA0x00000000);
3126 proto_tree_add_item(header_tree, hf_oid_length, tvb, offset, 1, ENC_NA0x00000000);
3127 offset += 1;
3128
3129 /* Validate the flag byte */
3130 if (oid_len_byte & 0x40)
3131 {
3132 /* Type.4 Malformed (bit mandated zero). */
3133 expert_add_info(pinfo, ti, &ei_type_4_header_zero);
3134 }
3135
3136 if ((oid_len_byte & 0x3F) > 0)
3137 {
3138 /* Add the raw data. */
3139 proto_tree_add_item(oid_tree, hf_oid_data, tvb, offset, oid_len_byte & 0x3F, ENC_NA0x00000000);
3140 offset += oid_len_byte & 0x3F;
3141 }
3142
3143 /* Check for attributes */
3144 if (oid_len_byte & 0x80)
3145 {
3146 /* Read attributes, adding them to oid_tree. */
3147 uint8_t flag;
3148
3149 do
3150 {
3151 tvbuff_t *packet = tvb_new_subset_remaining(tvb, offset);
3152 proto_tree *attribute_tree;
3153 int attribute_length;
3154
3155 ti = proto_tree_add_item(tree, hf_oid_all_attribute_data, tvb, offset, -1, ENC_NA0x00000000);
3156 attribute_tree = proto_item_add_subtree(ti, ett_oid_attribute);
3157 flag = tvb_get_uint8(tvb, offset);
3158 increment_dissection_depth(pinfo);
3159 attribute_length = dissect_2009_11_type_5(packet, pinfo, attribute_tree);
3160 decrement_dissection_depth(pinfo);
3161 proto_item_set_len(ti, (const int)attribute_length);
3162 offset += attribute_length;
3163 }
3164 while (flag & 0x80);
3165 }
3166
3167 if (tree)
3168 {
3169 ti = proto_tree_get_parent(tree);
3170 proto_item_set_len(ti, offset - start_offset);
3171 }
3172
3173 /* TODO: Add the description. */
3174 /* proto_item_append_text( oid_tree, ": %s", "TODO" ); */
3175 return offset;
3176}
3177
3178/**
3179 * Dissects a buffer that is pointing at an attribute.
3180 * Adds a subtree with detailed information about the fields of
3181 * the attribute,
3182 * returns the new offset,
3183 * and appends text to the tree (really a tree item) that is
3184 * passed in that gives a more accurate description of the
3185 * attribute.
3186 * Note that the tree already shows the bytes of the OID, so if
3187 * no additional information can be displayed then it should not
3188 * be.
3189 *
3190 * If 'tree' is NULL then just return the length.
3191 */
3192// NOLINTNEXTLINE(misc-no-recursion)
3193static int dissect_2009_11_type_5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3194{
3195 proto_item *ti;
3196 unsigned offset = 0;
3197 uint8_t attribute_id_byte;
3198 uint8_t attribute_length_byte;
3199 proto_tree *oid_tree = tree;
3200 proto_tree *header_tree;
3201
3202 attribute_id_byte = tvb_get_uint8(tvb, offset);
3203 ti = proto_tree_add_uint_format(oid_tree, hf_oid_attribute_header, tvb,
3204 offset, 1, attribute_id_byte, "Header: 0x%02x (%sLength=%d)", attribute_id_byte, attribute_id_byte & 0x80 ? "Attribute, " : "", attribute_id_byte & 0x3F);
3205
3206 header_tree = proto_item_add_subtree(ti, ett_oid_attribute_header);
3207 proto_tree_add_item(header_tree, hf_oid_attribute_attribute, tvb, offset, 1, ENC_NA0x00000000);
3208 proto_tree_add_item(header_tree, hf_oid_attribute_id, tvb, offset, 1, ENC_NA0x00000000);
3209 offset += 1;
3210
3211 attribute_length_byte = tvb_get_uint8(tvb, offset);
3212 proto_tree_add_item(oid_tree, hf_oid_attribute_length, tvb, offset, 1, ENC_NA0x00000000);
3213 offset += 1;
3214
3215 switch (attribute_id_byte & 0x7F)
3216 {
3217 case 1:
3218 /* TODO: Check length */
3219 proto_tree_add_item(oid_tree, hf_oid_attribute_data, tvb, offset, attribute_length_byte, ENC_NA0x00000000);
3220 offset += attribute_length_byte;
3221 break;
3222
3223 case 0:
3224 case 2:
3225 {
3226 tvbuff_t *packet = tvb_new_subset_length(tvb, offset, attribute_length_byte);
3227 proto_tree *attribute_tree;
3228
3229 ti = proto_tree_add_item(tree, hf_oid_attribute_oid, tvb, offset, -1, ENC_NA0x00000000);
3230 attribute_tree = proto_item_add_subtree(ti, ett_oid_attribute_oid);
3231 increment_dissection_depth(pinfo);
3232 offset += dissect_2009_11_type_4(packet, pinfo, attribute_tree, NULL((void*)0));
3233 decrement_dissection_depth(pinfo);
3234 }
3235 break;
3236
3237 default:
3238 proto_tree_add_item(oid_tree, hf_oid_attribute_data, tvb, offset, attribute_length_byte, ENC_NA0x00000000);
3239 offset += attribute_length_byte;
3240 }
3241
3242 return offset;
3243}
3244
3245
3246/* Transport Session ID */
3247static dof_globals globals;
3248
3249/* Static Methods. */
3250
3251static dof_packet_data* create_packet_data(packet_info *pinfo);
3252static int dof_dissect_dnp_length(tvbuff_t *tvb, packet_info *pinfo, uint8_t version, unsigned *offset);
3253#define VALIDHEX(c)( ((c) >= '0' && (c) <= '9') || ((c) >= 'A' &&
(c) <= 'F') || ((c) >= 'a' && (c) <= 'f') )
( ((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f') )
3254
3255
3256/* Configuration structures. These tables allow for security
3257 * mode templates, security keys, and secrets to be configured.
3258 */
3259
3260static bool_Bool decrypt_all_packets;
3261static bool_Bool track_operations;
3262static unsigned track_operations_window = 5;
3263static uint32_t next_dof_frame = 1;
3264
3265/* Structure for security mode of operation templates. */
3266typedef struct _secmode_field_t {
3267 char *domain;
3268 char *identity;
3269 char *kek;
3270} secmode_field_t;
3271
3272static secmode_field_t *secmode_list;
3273static unsigned num_secmode_list;
3274
3275/* Structure for security keys. */
3276typedef struct _seckey_field_t {
3277 char *key;
3278} seckey_field_t;
3279
3280/* Structure for secrets (for identities) */
3281typedef struct _identsecret_field_t {
3282 char *domain;
3283 char *identity;
3284 char *secret;
3285} identsecret_field_t;
3286
3287typedef struct _tcp_ignore_data
3288{
3289 uint32_t sequence;
3290 bool_Bool ignore;
3291 struct _tcp_ignore_data *next;
3292} tcp_ignore_data;
3293
3294typedef struct _tcp_dof_packet_ref
3295{
3296 /* A single TCP frame can contain multiple packets. We must
3297 * be able to keep track of them all.
3298 */
3299 dof_api_data api_data;
3300
3301 int start_offset;
3302 dof_transport_packet transport_packet;
3303 struct _tcp_dof_packet_ref *next;
3304} tcp_dof_packet_ref;
3305
3306/**
3307 * This structure exists for TCP packets and allows matching Wireshark frames to
3308 * DPS packets.
3309 */
3310typedef struct _tcp_packet_data
3311{
3312 /* Packets are ignored based on the starting TCP SEQ (sequence of first byte). */
3313 tcp_ignore_data *from_client_ignore_list;
3314 tcp_ignore_data *from_server_ignore_list;
3315
3316 /* DPS packet structures contained within a TCP frame. */
3317 tcp_dof_packet_ref *dof_packets;
3318} tcp_packet_data;
3319
3320/**
3321 * This structure exists for UDP sessions and allows for advanced stream handling
3322 * and matching Wireshark frames to DPS packets.
3323 */
3324typedef struct _udp_session_data
3325{
3326 /* This must be the first structure, as a pointer to this type is stored in each DPS packet. */
3327 dof_transport_session common;
3328
3329 /* For the associated TCP conversation, this tracks the client and server
3330 * addresses.
3331 */
3332 ws_node server;
3333} udp_session_data;
3334
3335/* This structure exists for TCP sessions and allows for advanced stream handling
3336 * and matching Wireshark frames to DPS packets.
3337 */
3338typedef struct _tcp_session_data
3339{
3340 /* This must be the first structure, as a pointer to this type is stored in each DPS packet. */
3341 dof_transport_session common;
3342
3343 /* This flag is used to determine that an entire TCP session is NOT OpenDOF.
3344 * Because of TCP/IP negotiation in the DPS it is easy to confuse arbitrary
3345 * protocols as OpenDOF. Once it is determined that it is not then this
3346 * flag can be set, which will turn off all the OpenDOF dissectors.
3347 */
3348 bool_Bool not_dps;
3349
3350 /* For the associated TCP conversation, this tracks the client and server
3351 * addresses.
3352 */
3353 ws_node client, server;
3354
3355 /* TCP sequence numbers, used to detect retransmissions. These are only valid
3356 * during the first pass through the packets.
3357 */
3358 uint32_t from_client_seq;
3359 uint32_t from_server_seq;
3360
3361} tcp_session_data;
3362
3363static dof_security_data global_security;
3364
3365static unsigned count_hex_bytes(char *str);
3366
3367/* Global DPS data structures for security keys. */
3368static seckey_field_t *seckey_list;
3369static unsigned num_seckey_list;
3370
3371/* Global DPS data structures for identity secrets. */
3372static identsecret_field_t *identsecret_list;
3373static unsigned num_identsecret_list;
3374
3375
3376/* Callbacks for Configuration security templates. */
3377UAT_CSTRING_CB_DEF(secmode_list, domain, secmode_field_t)static void secmode_list_domain_set_cb(void* rec, const char*
buf, unsigned len, const void* u1 __attribute__((unused)), const
void* u2 __attribute__((unused))) { char* new_buf = g_strndup
(buf,len); (__builtin_object_size (((((secmode_field_t*)rec)->
domain)), 0) != ((size_t) - 1)) ? g_free_sized ((((secmode_field_t
*)rec)->domain), __builtin_object_size (((((secmode_field_t
*)rec)->domain)), 0)) : (g_free) ((((secmode_field_t*)rec)
->domain)); (((secmode_field_t*)rec)->domain) = new_buf
; } static void secmode_list_domain_tostr_cb(void* rec, char*
* out_ptr, unsigned* out_len, const void* u1 __attribute__((unused
)), const void* u2 __attribute__((unused))) { if (((secmode_field_t
*)rec)->domain ) { *out_ptr = g_strdup_inline ((((secmode_field_t
*)rec)->domain)); *out_len = (unsigned)strlen((((secmode_field_t
*)rec)->domain)); } else { *out_ptr = g_strdup_inline ("")
; *out_len = 0; } }
3378UAT_CSTRING_CB_DEF(secmode_list, identity, secmode_field_t)static void secmode_list_identity_set_cb(void* rec, const char
* buf, unsigned len, const void* u1 __attribute__((unused)), const
void* u2 __attribute__((unused))) { char* new_buf = g_strndup
(buf,len); (__builtin_object_size (((((secmode_field_t*)rec)->
identity)), 0) != ((size_t) - 1)) ? g_free_sized ((((secmode_field_t
*)rec)->identity), __builtin_object_size (((((secmode_field_t
*)rec)->identity)), 0)) : (g_free) ((((secmode_field_t*)rec
)->identity)); (((secmode_field_t*)rec)->identity) = new_buf
; } static void secmode_list_identity_tostr_cb(void* rec, char
** out_ptr, unsigned* out_len, const void* u1 __attribute__((
unused)), const void* u2 __attribute__((unused))) { if (((secmode_field_t
*)rec)->identity ) { *out_ptr = g_strdup_inline ((((secmode_field_t
*)rec)->identity)); *out_len = (unsigned)strlen((((secmode_field_t
*)rec)->identity)); } else { *out_ptr = g_strdup_inline (""
); *out_len = 0; } }
3379UAT_CSTRING_CB_DEF(secmode_list, kek, secmode_field_t)static void secmode_list_kek_set_cb(void* rec, const char* buf
, unsigned len, const void* u1 __attribute__((unused)), const
void* u2 __attribute__((unused))) { char* new_buf = g_strndup
(buf,len); (__builtin_object_size (((((secmode_field_t*)rec)->
kek)), 0) != ((size_t) - 1)) ? g_free_sized ((((secmode_field_t
*)rec)->kek), __builtin_object_size (((((secmode_field_t*)
rec)->kek)), 0)) : (g_free) ((((secmode_field_t*)rec)->
kek)); (((secmode_field_t*)rec)->kek) = new_buf; } static void
secmode_list_kek_tostr_cb(void* rec, char** out_ptr, unsigned
* out_len, const void* u1 __attribute__((unused)), const void
* u2 __attribute__((unused))) { if (((secmode_field_t*)rec)->
kek ) { *out_ptr = g_strdup_inline ((((secmode_field_t*)rec)->
kek)); *out_len = (unsigned)strlen((((secmode_field_t*)rec)->
kek)); } else { *out_ptr = g_strdup_inline (""); *out_len = 0
; } }
3380
3381static void secmode_list_post_update_cb(void)
3382{
3383}
3384
3385static bool_Bool secmode_list_update_cb(void *r, char **err)
3386{
3387 secmode_field_t *rec = (secmode_field_t *)r;
3388 uint32_t size;
3389
3390 *err = NULL((void*)0);
3391
3392 size = (uint32_t)strlen(rec->domain);
3393 if (!VALIDHEX(rec->domain[0])( ((rec->domain[0]) >= '0' && (rec->domain[0
]) <= '9') || ((rec->domain[0]) >= 'A' && (rec
->domain[0]) <= 'F') || ((rec->domain[0]) >= 'a' &&
(rec->domain[0]) <= 'f') )
)
3394 {
3395 /* dof_oid_create_internal() returns 0 for a valid OID string. */
3396 if (dof_oid_create_internal(rec->domain, &size, NULL((void*)0)))
3397 {
3398 *err = g_strdup("Invalid domain [must be valid OID].")g_strdup_inline ("Invalid domain [must be valid OID].");
3399 return false0;
3400 }
3401 }
3402 else if (!count_hex_bytes(rec->domain))
3403 {
3404 *err = g_strdup("Invalid domain [must be valid OID].")g_strdup_inline ("Invalid domain [must be valid OID].");
3405 return false0;
3406 }
3407
3408 size = (uint32_t)strlen(rec->identity);
3409 if (!VALIDHEX(rec->identity[0])( ((rec->identity[0]) >= '0' && (rec->identity
[0]) <= '9') || ((rec->identity[0]) >= 'A' &&
(rec->identity[0]) <= 'F') || ((rec->identity[0]) >=
'a' && (rec->identity[0]) <= 'f') )
)
3410 {
3411 /* dof_oid_create_internal() returns 0 for a valid OID string. */
3412 if (dof_oid_create_internal(rec->identity, &size, NULL((void*)0)))
3413 {
3414 *err = g_strdup("Invalid identity [must be valid OID].")g_strdup_inline ("Invalid identity [must be valid OID].");
3415 return false0;
3416 }
3417 }
3418 else if (!count_hex_bytes(rec->identity))
3419 {
3420 *err = g_strdup("Invalid identity [must be valid OID].")g_strdup_inline ("Invalid identity [must be valid OID].");
3421 return false0;
3422 }
3423
3424 if (count_hex_bytes(rec->kek) != 32)
3425 {
3426 *err = g_strdup("Invalid KEK [must be 32 byte key].")g_strdup_inline ("Invalid KEK [must be 32 byte key].");
3427 return false0;
3428 }
3429 return true1;
3430}
3431
3432static void* secmode_list_copy_cb(void *n, const void *o, size_t siz _U___attribute__((unused)))
3433{
3434 secmode_field_t *new_rec = (secmode_field_t *)n;
3435 const secmode_field_t *old_rec = (const secmode_field_t *)o;
3436
3437 new_rec->domain = g_strdup(old_rec->domain)g_strdup_inline (old_rec->domain);
3438 new_rec->identity = g_strdup(old_rec->identity)g_strdup_inline (old_rec->identity);
3439 new_rec->kek = g_strdup(old_rec->kek)g_strdup_inline (old_rec->kek);
3440
3441 return new_rec;
3442}
3443
3444static void secmode_list_free_cb(void *r)
3445{
3446 secmode_field_t *rec = (secmode_field_t *)r;
3447
3448 g_free(rec->domain)(__builtin_object_size ((rec->domain), 0) != ((size_t) - 1
)) ? g_free_sized (rec->domain, __builtin_object_size ((rec
->domain), 0)) : (g_free) (rec->domain)
;
3449 g_free(rec->identity)(__builtin_object_size ((rec->identity), 0) != ((size_t) -
1)) ? g_free_sized (rec->identity, __builtin_object_size (
(rec->identity), 0)) : (g_free) (rec->identity)
;
3450 g_free(rec->kek)(__builtin_object_size ((rec->kek), 0) != ((size_t) - 1)) ?
g_free_sized (rec->kek, __builtin_object_size ((rec->kek
), 0)) : (g_free) (rec->kek)
;
3451}
3452
3453
3454/* Callbacks for security keys. */
3455UAT_CSTRING_CB_DEF(seckey_list, key, seckey_field_t)static void seckey_list_key_set_cb(void* rec, const char* buf
, unsigned len, const void* u1 __attribute__((unused)), const
void* u2 __attribute__((unused))) { char* new_buf = g_strndup
(buf,len); (__builtin_object_size (((((seckey_field_t*)rec)->
key)), 0) != ((size_t) - 1)) ? g_free_sized ((((seckey_field_t
*)rec)->key), __builtin_object_size (((((seckey_field_t*)rec
)->key)), 0)) : (g_free) ((((seckey_field_t*)rec)->key)
); (((seckey_field_t*)rec)->key) = new_buf; } static void seckey_list_key_tostr_cb
(void* rec, char** out_ptr, unsigned* out_len, const void* u1
__attribute__((unused)), const void* u2 __attribute__((unused
))) { if (((seckey_field_t*)rec)->key ) { *out_ptr = g_strdup_inline
((((seckey_field_t*)rec)->key)); *out_len = (unsigned)strlen
((((seckey_field_t*)rec)->key)); } else { *out_ptr = g_strdup_inline
(""); *out_len = 0; } }
3456
3457static void seckey_list_post_update_cb(void)
3458{
3459}
3460
3461static bool_Bool seckey_list_update_cb(void *r, char **err)
3462{
3463 seckey_field_t *rec = (seckey_field_t *)r;
3464
3465 *err = NULL((void*)0);
3466 if (count_hex_bytes(rec->key) != 32)
3467 {
3468 *err = g_strdup("Invalid secret [must be 32 bytes].")g_strdup_inline ("Invalid secret [must be 32 bytes].");
3469 return false0;
3470 }
3471 return true1;
3472}
3473
3474static void* seckey_list_copy_cb(void *n, const void *o, size_t siz _U___attribute__((unused)))
3475{
3476 seckey_field_t *new_rec = (seckey_field_t *)n;
3477 const seckey_field_t *old_rec = (const seckey_field_t *)o;
3478
3479 new_rec->key = g_strdup(old_rec->key)g_strdup_inline (old_rec->key);
3480
3481 return new_rec;
3482}
3483
3484static void seckey_list_free_cb(void *r)
3485{
3486 seckey_field_t *rec = (seckey_field_t *)r;
3487
3488 g_free(rec->key)(__builtin_object_size ((rec->key), 0) != ((size_t) - 1)) ?
g_free_sized (rec->key, __builtin_object_size ((rec->key
), 0)) : (g_free) (rec->key)
;
3489}
3490
3491
3492/* Callbacks for identity secrets. */
3493UAT_CSTRING_CB_DEF(identsecret_list, domain, identsecret_field_t)static void identsecret_list_domain_set_cb(void* rec, const char
* buf, unsigned len, const void* u1 __attribute__((unused)), const
void* u2 __attribute__((unused))) { char* new_buf = g_strndup
(buf,len); (__builtin_object_size (((((identsecret_field_t*)rec
)->domain)), 0) != ((size_t) - 1)) ? g_free_sized ((((identsecret_field_t
*)rec)->domain), __builtin_object_size (((((identsecret_field_t
*)rec)->domain)), 0)) : (g_free) ((((identsecret_field_t*)
rec)->domain)); (((identsecret_field_t*)rec)->domain) =
new_buf; } static void identsecret_list_domain_tostr_cb(void
* rec, char** out_ptr, unsigned* out_len, const void* u1 __attribute__
((unused)), const void* u2 __attribute__((unused))) { if (((identsecret_field_t
*)rec)->domain ) { *out_ptr = g_strdup_inline ((((identsecret_field_t
*)rec)->domain)); *out_len = (unsigned)strlen((((identsecret_field_t
*)rec)->domain)); } else { *out_ptr = g_strdup_inline ("")
; *out_len = 0; } }
3494UAT_CSTRING_CB_DEF(identsecret_list, identity, identsecret_field_t)static void identsecret_list_identity_set_cb(void* rec, const
char* buf, unsigned len, const void* u1 __attribute__((unused
)), const void* u2 __attribute__((unused))) { char* new_buf =
g_strndup(buf,len); (__builtin_object_size (((((identsecret_field_t
*)rec)->identity)), 0) != ((size_t) - 1)) ? g_free_sized (
(((identsecret_field_t*)rec)->identity), __builtin_object_size
(((((identsecret_field_t*)rec)->identity)), 0)) : (g_free
) ((((identsecret_field_t*)rec)->identity)); (((identsecret_field_t
*)rec)->identity) = new_buf; } static void identsecret_list_identity_tostr_cb
(void* rec, char** out_ptr, unsigned* out_len, const void* u1
__attribute__((unused)), const void* u2 __attribute__((unused
))) { if (((identsecret_field_t*)rec)->identity ) { *out_ptr
= g_strdup_inline ((((identsecret_field_t*)rec)->identity
)); *out_len = (unsigned)strlen((((identsecret_field_t*)rec)->
identity)); } else { *out_ptr = g_strdup_inline (""); *out_len
= 0; } }
3495UAT_CSTRING_CB_DEF(identsecret_list, secret, identsecret_field_t)static void identsecret_list_secret_set_cb(void* rec, const char
* buf, unsigned len, const void* u1 __attribute__((unused)), const
void* u2 __attribute__((unused))) { char* new_buf = g_strndup
(buf,len); (__builtin_object_size (((((identsecret_field_t*)rec
)->secret)), 0) != ((size_t) - 1)) ? g_free_sized ((((identsecret_field_t
*)rec)->secret), __builtin_object_size (((((identsecret_field_t
*)rec)->secret)), 0)) : (g_free) ((((identsecret_field_t*)
rec)->secret)); (((identsecret_field_t*)rec)->secret) =
new_buf; } static void identsecret_list_secret_tostr_cb(void
* rec, char** out_ptr, unsigned* out_len, const void* u1 __attribute__
((unused)), const void* u2 __attribute__((unused))) { if (((identsecret_field_t
*)rec)->secret ) { *out_ptr = g_strdup_inline ((((identsecret_field_t
*)rec)->secret)); *out_len = (unsigned)strlen((((identsecret_field_t
*)rec)->secret)); } else { *out_ptr = g_strdup_inline ("")
; *out_len = 0; } }
3496
3497static void identsecret_list_post_update_cb(void)
3498{
3499}
3500
3501static bool_Bool identsecret_list_update_cb(void *r, char **err)
3502{
3503 identsecret_field_t *rec = (identsecret_field_t *)r;
3504 uint32_t size;
3505
3506 *err = NULL((void*)0);
3507
3508 size = (uint32_t)strlen(rec->domain);
3509 if (!VALIDHEX(rec->domain[0])( ((rec->domain[0]) >= '0' && (rec->domain[0
]) <= '9') || ((rec->domain[0]) >= 'A' && (rec
->domain[0]) <= 'F') || ((rec->domain[0]) >= 'a' &&
(rec->domain[0]) <= 'f') )
)
3510 {
3511 if (dof_oid_create_internal(rec->domain, &size, NULL((void*)0)))
3512 {
3513 *err = g_strdup("Invalid domain [must be valid OID].")g_strdup_inline ("Invalid domain [must be valid OID].");
3514 return false0;
3515 }
3516 }
3517 else if (!count_hex_bytes(rec->domain))
3518 {
3519 *err = g_strdup("Invalid domain [must be valid OID].")g_strdup_inline ("Invalid domain [must be valid OID].");
3520 return false0;
3521 }
3522
3523 size = (uint32_t)strlen(rec->identity);
3524 if (!VALIDHEX(rec->identity[0])( ((rec->identity[0]) >= '0' && (rec->identity
[0]) <= '9') || ((rec->identity[0]) >= 'A' &&
(rec->identity[0]) <= 'F') || ((rec->identity[0]) >=
'a' && (rec->identity[0]) <= 'f') )
)
3525 {
3526 if (dof_oid_create_internal(rec->identity, &size, NULL((void*)0)))
3527 {
3528 *err = g_strdup("Invalid identity [must be valid OID].")g_strdup_inline ("Invalid identity [must be valid OID].");
3529 return false0;
3530 }
3531 }
3532 else if (!count_hex_bytes(rec->identity))
3533 {
3534 *err = g_strdup("Invalid identity [must be valid OID].")g_strdup_inline ("Invalid identity [must be valid OID].");
3535 return false0;
3536 }
3537
3538 if (count_hex_bytes(rec->secret) != 32)
3539 {
3540 *err = g_strdup("Invalid secret [must be 32 byte key].")g_strdup_inline ("Invalid secret [must be 32 byte key].");
3541 return false0;
3542 }
3543 return true1;
3544}
3545
3546static void* identsecret_list_copy_cb(void *n, const void *o, size_t siz _U___attribute__((unused)))
3547{
3548 identsecret_field_t *new_rec = (identsecret_field_t *)n;
3549 const identsecret_field_t *old_rec = (const identsecret_field_t *)o;
3550
3551 new_rec->domain = g_strdup(old_rec->domain)g_strdup_inline (old_rec->domain);
3552 new_rec->identity = g_strdup(old_rec->identity)g_strdup_inline (old_rec->identity);
3553 new_rec->secret = g_strdup(old_rec->secret)g_strdup_inline (old_rec->secret);
3554
3555 return new_rec;
3556}
3557
3558static void identsecret_list_free_cb(void *r)
3559{
3560 identsecret_field_t *rec = (identsecret_field_t *)r;
3561
3562 g_free(rec->domain)(__builtin_object_size ((rec->domain), 0) != ((size_t) - 1
)) ? g_free_sized (rec->domain, __builtin_object_size ((rec
->domain), 0)) : (g_free) (rec->domain)
;
3563 g_free(rec->identity)(__builtin_object_size ((rec->identity), 0) != ((size_t) -
1)) ? g_free_sized (rec->identity, __builtin_object_size (
(rec->identity), 0)) : (g_free) (rec->identity)
;
3564 g_free(rec->secret)(__builtin_object_size ((rec->secret), 0) != ((size_t) - 1
)) ? g_free_sized (rec->secret, __builtin_object_size ((rec
->secret), 0)) : (g_free) (rec->secret)
;
3565}
3566
3567static void init_addr_port_tables(void);
3568
3569/* The IP transport protocols need to assign SENDER ID based on the
3570 * transport address. This requires a hash lookup from address/port to ID.
3571 */
3572
3573static GHashTable *addr_port_to_id;
3574
3575typedef struct _addr_port_key
3576{
3577 address addr;
3578 uint16_t port;
3579} addr_port_key;
3580
3581static unsigned addr_port_key_hash_fn(const void *key)
3582{
3583 const addr_port_key *addr_key = (const addr_port_key *)key;
3584 unsigned result = 0;
3585 unsigned port_as_int = addr_key->port;
3586 unsigned type_as_int = addr_key->addr.type;
3587
3588 result += g_int_hash(&port_as_int);
3589 result += g_int_hash(&type_as_int);
3590
3591 {
3592 unsigned hash = 5381;
3593 const uint8_t *str = (const uint8_t *)addr_key->addr.data;
3594
3595 for (int i = 0; i < addr_key->addr.len; i++)
3596 hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
3597
3598 result += hash;
3599 }
3600
3601 return result;
3602}
3603
3604static gboolean addr_port_key_equal_fn(const void *key1, const void *key2)
3605{
3606 const addr_port_key *addr_key_ptr1 = (const addr_port_key *)key1;
3607 const addr_port_key *addr_key_ptr2 = (const addr_port_key *)key2;
3608
3609 if (addr_key_ptr1->port != addr_key_ptr2->port)
3610 return FALSE(0);
3611
3612 return addresses_equal(&addr_key_ptr1->addr, &addr_key_ptr2->addr);
3613}
3614
3615static void addr_port_key_free_fn(void *key)
3616{
3617 addr_port_key *addr_port = (addr_port_key *)key;
3618 g_free(addr_port->addr.priv)(__builtin_object_size ((addr_port->addr.priv), 0) != ((size_t
) - 1)) ? g_free_sized (addr_port->addr.priv, __builtin_object_size
((addr_port->addr.priv), 0)) : (g_free) (addr_port->addr
.priv)
;
3619 g_free(addr_port)(__builtin_object_size ((addr_port), 0) != ((size_t) - 1)) ? g_free_sized
(addr_port, __builtin_object_size ((addr_port), 0)) : (g_free
) (addr_port)
;
3620}
3621
3622static void init_addr_port_tables(void)
3623{
3624 /* This routine is called each time the system is reset (file load, capture)
3625 * and so it should take care of freeing any of our persistent stuff.
3626 */
3627 if (addr_port_to_id != NULL((void*)0))
3628 {
3629 /* Clear it out. Note that this calls the destroy functions for each element. */
3630 g_hash_table_destroy(addr_port_to_id);
3631 addr_port_to_id = NULL((void*)0);
3632 }
3633
3634 /* The value is not allocated, so does not need to be freed. */
3635 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((void*)0));
3636}
3637
3638static unsigned next_addr_port_id = 1;
3639
3640#define EP_COPY_ADDRESS(alloc, to, from){ uint8_t *EP_COPY_ADDRESS_data; (to)->type = (from)->type
; (to)->len = (from)->len; EP_COPY_ADDRESS_data = (uint8_t
*) wmem_alloc(alloc,(from)->len); memcpy(EP_COPY_ADDRESS_data
, (from)->data, (from)->len); (to)->priv = EP_COPY_ADDRESS_data
; (to)->data = (to)->priv; }
{ \
3641 uint8_t *EP_COPY_ADDRESS_data; \
3642 (to)->type = (from)->type; \
3643 (to)->len = (from)->len; \
3644 EP_COPY_ADDRESS_data = (uint8_t*) wmem_alloc(alloc,(from)->len); \
3645 memcpy(EP_COPY_ADDRESS_data, (from)->data, (from)->len); \
3646 (to)->priv = EP_COPY_ADDRESS_data; \
3647 (to)->data = (to)->priv; \
3648 }
3649
3650/* Return the transport ID, a unique number for each transport sender.
3651 */
3652static unsigned assign_addr_port_id(wmem_allocator_t* allocator, address *addr, uint16_t port)
3653{
3654 addr_port_key lookup_key;
3655 addr_port_key *key;
3656 unsigned value;
3657
3658 /* ensure the address contains actual data */
3659 if (addr->type == AT_NONE)
3660 return 0;
3661
3662 /* Build a (non-allocated) key to do the lookup. */
3663
3664 EP_COPY_ADDRESS(allocator, &lookup_key.addr, addr){ uint8_t *EP_COPY_ADDRESS_data; (&lookup_key.addr)->type
= (addr)->type; (&lookup_key.addr)->len = (addr)->
len; EP_COPY_ADDRESS_data = (uint8_t*) wmem_alloc(allocator,(
addr)->len); memcpy(EP_COPY_ADDRESS_data, (addr)->data,
(addr)->len); (&lookup_key.addr)->priv = EP_COPY_ADDRESS_data
; (&lookup_key.addr)->data = (&lookup_key.addr)->
priv; }
;
3665 lookup_key.port = port;
3666
3667 value = GPOINTER_TO_UINT(g_hash_table_lookup(addr_port_to_id, &lookup_key))((guint) (gulong) (g_hash_table_lookup(addr_port_to_id, &
lookup_key)))
;
3668 if (value)
3669 {
3670 /* We found a match. */
3671 return value;
3672 }
3673
3674 /* No match, need to add a key. */
3675 key = g_new0(addr_port_key, 1)((addr_port_key *) g_malloc0_n ((1), sizeof (addr_port_key)));
3676 copy_address(&key->addr, addr);
3677 key->port = port;
3678
3679 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
3680 g_hash_table_insert(addr_port_to_id, key, GUINT_TO_POINTER(next_addr_port_id)((gpointer) (gulong) (next_addr_port_id)));
3681 return next_addr_port_id++;
3682}
3683
3684/* Wireshark Configuration Dialog Routines*/
3685
3686static bool_Bool identsecret_chk_cb(void *r _U___attribute__((unused)), const char *p _U___attribute__((unused)), unsigned len _U___attribute__((unused)), const void *u1 _U___attribute__((unused)), const void *u2 _U___attribute__((unused)), char **err _U___attribute__((unused)))
3687{
3688#if 0
3689 char** protos;
3690 char* line = ep_strndup(p, len);
3691 unsigned num_protos, i;
3692
3693 g_strstrip(line)g_strchomp (g_strchug (line));
3694 ascii_strdown_inplace(line);
3695
3696 protos = ep_strsplit(line, ":", 0);
3697
3698 for (num_protos = 0; protos[num_protos]; num_protos++)
3699 g_strstrip(protos[num_protos])g_strchomp (g_strchug (protos[num_protos]));
3700
3701 if (!num_protos)
3702 {
3703 *err = g_strdup("No protocols given")g_strdup_inline ("No protocols given");
3704 return false0;
3705 }
3706
3707 for (i = 0; i < num_protos; i++)
3708 {
3709 if (!find_dissector(protos[i]))
3710 {
3711 *err = g_strdup("Could not find dissector for: '%s'", protos[i]);
3712 return false0;
3713 }
3714 }
3715#endif
3716 return true1;
3717}
3718
3719/* Utility Methods */
3720
3721/* Bytes consumed from start to end. Zero when the range is inverted, so a short field cannot wrap into a huge allocation. */
3722static unsigned dof_consumed_length(unsigned end, unsigned start)
3723{
3724 if (end < start)
3725 return 0;
3726 return end - start;
3727}
3728
3729static unsigned count_hex_bytes(char *str)
3730{
3731 unsigned total = 0;
3732
3733 while (str != NULL((void*)0) && *str != '\0' && *str != '#')
3734 {
3735 if (!g_ascii_isxdigit(*str)((g_ascii_table[(guchar) (*str)] & G_ASCII_XDIGIT) != 0))
3736 {
3737 str += 1;
3738 continue;
3739 }
3740
3741 if (!g_ascii_isxdigit(str[1])((g_ascii_table[(guchar) (str[1])] & G_ASCII_XDIGIT) != 0
)
)
3742 return 0;
3743
3744 if (total == UINT_MAX(2147483647 *2U +1U))
3745 return 0;
3746
3747 total += 1;
3748 str += 2;
3749 }
3750
3751 return total;
3752}
3753
3754static void parse_hex_string(char *str, uint8_t **ptr, unsigned *len)
3755{
3756 unsigned j = 0;
3757 *len = count_hex_bytes(str);
3758 *ptr = (uint8_t *)g_malloc0(*len);
3759
3760 while (j < *len)
3761 {
3762 int high, low;
3763
3764 if (!g_ascii_isxdigit(*str)((g_ascii_table[(guchar) (*str)] & G_ASCII_XDIGIT) != 0))
3765 {
3766 str += 1;
3767 continue;
3768 }
3769
3770 high = ws_xton(str[0]);
3771 low = ws_xton(str[1]);
3772 (*ptr)[j++] = (high << 4) | low;
3773 str += 2;
3774 }
3775}
3776
3777/* OID and IID Parsing */
3778
3779static const uint8_t OALString_HexChar[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
3780
3781#define IS_PRINTABLE(c)( ((uint8_t)c) >= 32U && ((uint8_t)c) < 127U ) ( ((uint8_t)c) >= 32U && ((uint8_t)c) < 127U )
3782#define IS_ESCAPED(c)( (c) == '(' || (c) == ')' || (c) == '[' || (c) == ']' || (c)
== '{' || (c) == '}' || (c) == '\\' || (c) == '|' )
( (c) == '(' || (c) == ')' || (c) == '[' || (c) == ']' || (c) == '{' || (c) == '}' || (c) == '\\' || (c) == '|' )
3783#define DOFOBJECTID_MAX_CLASS_SIZE(4) (4)
3784#define MAX_OID_DATA_SIZE(63) (63)
3785#define OID_DATA_LEN_MASK((63)) (MAX_OID_DATA_SIZE(63))
3786
3787#define ObjectID_DataToStringLength( data, dataSize )ObjectID_DataToString( (data), (dataSize), ((void*)0) ) ObjectID_DataToString( (data), (dataSize), NULL((void*)0) )
3788#define OALString_HexDigitToChar(c)(OALString_HexChar[(c)]) (OALString_HexChar[(c)])
3789#define DOFObjectIDAttribute_IsValid( attribute )((attribute).id < DOFOBJECTIDATTRIBUTE_INVALID) ((attribute).id < DOFOBJECTIDATTRIBUTE_INVALID)
3790#define DOFObjectIDAttribute_GetValueSize( attribute )((attribute).dataSize) ((attribute).dataSize)
3791#define DOFObjectIDAttribute_GetValue( attribute )((attribute).data) ((attribute).data)
3792#define DOFObjectIDAttribute_GetType( attribute )((DOFObjectIDAttributeType)(attribute).id) ((DOFObjectIDAttributeType)(attribute).id)
3793
3794typedef enum DOFObjectIDAttributeID_t
3795{
3796 /**
3797 * Provider attribute. This attribute identifies an object as being
3798 * provided by a specific service provider. The associated data must
3799 * be an object identifier.
3800 */
3801 DOFOBJECTIDATTRIBUTE_PROVIDER = 0,
3802
3803 /**
3804 * Session attribute. This attribute associates the object with the
3805 * specified session. The associated data must be exactly 16 bytes long.
3806 */
3807 DOFOBJECTIDATTRIBUTE_SESSION = 1,
3808
3809 /**
3810 * Group attribute. This attribute is normally used in association
3811 * with the BROADCAST object identifier. It defines a target that is
3812 * a multicast group in the DOF network (as opposed to the transport).
3813 * The associated data must be an object identifier.
3814 */
3815 DOFOBJECTIDATTRIBUTE_GROUP = 2,
3816
3817 /**
3818 * Invalid, used to signal that an error has occurred.
3819 */
3820 DOFOBJECTIDATTRIBUTE_INVALID = 128
3821} DOFObjectIDAttributeType;
3822typedef uint32_t DOFObjectIDClass;
3823
3824typedef struct DOFObjectID_t
3825{
3826 uint32_t refCount;
3827 uint16_t len; /* Actual length of oid's wire representation. Max is 32707: 4 + 1 + 63 + (127 * 257). */
3828 uint8_t oid[]; /* Extends beyond end of this defined structure, so oid MUST be last structure member! */
3829} DOFObjectID_t;
3830
3831typedef DOFObjectID_t *DOFObjectID;
3832
3833typedef uint8_t DOFObjectIDAttributeDataSize;
3834
3835typedef struct DOFObjectIDAttribute_t
3836{
3837 uint8_t id; /**< Attribute Identifier. Intentionally defined as uint8 for size, but holds all valid values for DOFObjectIDAttributeType. **/
3838 DOFObjectIDAttributeDataSize dataSize; /**< Size of the attribute data. **/
3839 const uint8_t *data; /**< Attribute data. **/
3840} DOFObjectIDAttribute;
3841
3842/**
3843* Read variable-length value from buffer.
3844*
3845* @param maxSize [in] Maximum size of value to be read
3846* @param bufLength [in,out] Input: size of buffer, output: size of value in buffer
3847* @param buffer [in] Actual buffer
3848* @return Uncompressed value if buffer size is valid (or 0 on error)
3849*/
3850static uint32_t OALMarshal_UncompressValue(uint8_t maxSize, uint32_t *bufLength, const uint8_t *buffer)
3851{
3852 uint32_t value = 0;
3853 uint8_t used = 0;
3854 uint8_t size = maxSize;
3855 uint8_t mask;
3856
3857 switch (buffer[0] >> 6)
3858 {
3859 case 0x02:
3860 /* Two Bytes */
3861 if (maxSize > 2)
3862 mask = 0x3F;
3863 else
3864 mask = 0x7F;
3865 size = 2;
3866 break;
3867
3868 case 0x03:
3869 /* Three/Four Bytes */
3870 if (maxSize > 2)
3871 mask = 0x3F;
3872 else
3873 mask = 0x7F;
3874 break;
3875
3876 default:
3877 /* One Byte */
3878 size = 1;
3879 mask = 0x7F;
3880 break;
3881 }
3882
3883 /* Sanity check */
3884 if (size > *bufLength)
3885 return 0;
3886
3887 value = buffer[used++] & mask;
3888 while (used < size)
3889 value = (value << 8) | buffer[used++];
3890
3891 *bufLength = used;
3892 return (value);
3893}
3894
3895static uint32_t DOFObjectID_GetClassSize(DOFObjectID self)
3896{
3897 uint32_t size = self->len;
3898
3899 (void)OALMarshal_UncompressValue(DOFOBJECTID_MAX_CLASS_SIZE(4), &size, self->oid);
3900
3901 return size;
3902}
3903
3904static uint32_t DOFObjectID_GetDataSize(const DOFObjectID self)
3905{
3906 return ((*((const uint8_t *)self->oid + DOFObjectID_GetClassSize(self))) & OID_DATA_LEN_MASK((63)));
3907}
3908
3909static uint32_t ObjectID_DataToString(const uint8_t *data, uint32_t dataSize, char *pBuf)
3910{
3911 uint32_t len = 0, i, nonprintable, escaped;
3912
3913 /* Determine if the data is printable... */
3914 for (i = 0, nonprintable = 0, escaped = 0; i < dataSize; i++)
3915 {
3916 if (!IS_PRINTABLE(data[i])( ((uint8_t)data[i]) >= 32U && ((uint8_t)data[i]) <
127U )
)
3917 nonprintable++;
3918 else if (IS_ESCAPED(data[i])( (data[i]) == '(' || (data[i]) == ')' || (data[i]) == '[' ||
(data[i]) == ']' || (data[i]) == '{' || (data[i]) == '}' || (
data[i]) == '\\' || (data[i]) == '|' )
)
3919 escaped++;
3920 }
3921 if (nonprintable == 0)
3922 {
3923 /* Printable, so copy as a string, escaping where necessary. */
3924 if (pBuf)
3925 {
3926 for (i = 0; i < dataSize; i++)
3927 {
3928 if (IS_ESCAPED(data[i])( (data[i]) == '(' || (data[i]) == ')' || (data[i]) == '[' ||
(data[i]) == ']' || (data[i]) == '{' || (data[i]) == '}' || (
data[i]) == '\\' || (data[i]) == '|' )
)
3929 {
3930 pBuf[len++] = '\\';
3931 pBuf[len++] = data[i];
3932 }
3933 else
3934 pBuf[len++] = data[i];
3935 }
3936 }
3937 else
3938 {
3939 len = dataSize + escaped; /* Count escaped characters twice. */
3940 }
3941 }
3942 else
3943 {
3944 /* Non-printable, so format as hex string. */
3945 if (pBuf)
3946 {
3947 pBuf[len++] = '{';
3948 for (i = 0; i < dataSize; i++)
3949 {
3950 pBuf[len++] = OALString_HexDigitToChar((data[i] >> 4) & 0x0F)(OALString_HexChar[((data[i] >> 4) & 0x0F)]);
3951 pBuf[len++] = OALString_HexDigitToChar((data[i]) & 0x0F)(OALString_HexChar[((data[i]) & 0x0F)]);
3952 }
3953 pBuf[len++] = '}';
3954 }
3955 else
3956 {
3957 len = dataSize * 2 + 2;
3958 }
3959 }
3960 return len;
3961}
3962
3963static const uint8_t* DOFObjectID_GetData(const DOFObjectID self)
3964{
3965 if (DOFObjectID_GetDataSize(self) > 0)
3966 return (const uint8_t *)self->oid + DOFObjectID_GetClassSize(self) + 1; /* 1: length of length byte. */
3967
3968 return NULL((void*)0);
3969}
3970
3971static uint32_t DOFObjectID_GetIDClass(const DOFObjectID self)
3972{
3973 uint32_t size = 4;
3974
3975 return OALMarshal_UncompressValue(DOFOBJECTID_MAX_CLASS_SIZE(4), &size, self->oid);
3976}
3977
3978static bool_Bool DOFObjectID_HasAttributes(const DOFObjectID self)
3979{
3980 if (!self)
3981 return false0;
3982
3983 /* bit 7: next attribute flag. */
3984 return (bool_Bool)(((*(const uint8_t *)((const uint8_t *)(self->oid) + DOFObjectID_GetClassSize(self))) & 0x80) != 0);
3985}
3986
3987static uint8_t DOFObjectID_GetBaseSize(const DOFObjectID oid)
3988{
3989 return DOFObjectID_GetClassSize(oid) + 1 + DOFObjectID_GetDataSize(oid);
3990}
3991
3992static uint8_t DOFObjectID_GetAttributeCount(const DOFObjectID self)
3993{
3994 uint8_t retVal = 0;
3995
3996 /* Note: No OID can duplicate an attribute ID. Legal attribute IDs can be from 0-126. So max count fits in uint8. */
3997 if (self && DOFObjectID_HasAttributes(self))
3998 {
3999 const uint8_t *pNextAttribute = (const uint8_t *)self->oid + DOFObjectID_GetBaseSize(self);
4000
4001 ++retVal;
4002 while (*pNextAttribute & 0x80) /* bit 7: next attribute present flag. */
4003 {
4004 ++retVal;
4005 pNextAttribute += (2 + *((const uint8_t *)pNextAttribute + 1)); /* 2: attribute marshalling overhead. */
4006 }
4007 }
4008
4009 return retVal;
4010}
4011
4012static DOFObjectIDAttribute DOFObjectID_GetAttributeAtIndex(const DOFObjectID self, uint8_t attribute_index)
4013{
4014 DOFObjectIDAttribute retAttributeDescriptor = { DOFOBJECTIDATTRIBUTE_INVALID, 0, NULL((void*)0) };
4015
4016 /* Note: No OID can duplicate an attribute ID. Legal attribute IDs can be from 0-127. So max index fits in uint8. */
4017 if (self && attribute_index < DOFOBJECTIDATTRIBUTE_INVALID)
4018 {
4019 if (DOFObjectID_HasAttributes(self))
4020 {
4021 uint8_t count = 0;
4022 const uint8_t *pNextAttribute = (const uint8_t *)self->oid + DOFObjectID_GetBaseSize(self);
4023
4024 while (1) /* Parse through the N Attributes. */
4025 {
4026 if (attribute_index == count++)
4027 {
4028 retAttributeDescriptor.id = *pNextAttribute & 0x7F;
4029 retAttributeDescriptor.dataSize = (DOFObjectIDAttributeDataSize) * ((const uint8_t *)pNextAttribute + 1);
4030 retAttributeDescriptor.data = (const uint8_t *)pNextAttribute + 2; /* 2: attr marshalling overhead. */
4031 break; /* Success. */
4032 }
4033 if (!(*pNextAttribute & 0x80))
4034 break; /* Fail: no more Attributes */
4035 pNextAttribute += (2 + *((const uint8_t *)pNextAttribute + 1));
4036 }
4037 }
4038 }
4039
4040 return retAttributeDescriptor;
4041}
4042
4043static void DOFObjectID_Destroy(DOFObjectID self _U___attribute__((unused)))
4044{
4045 /* Ephemeral memory doesn't need to be freed. */
4046}
4047
4048static void DOFObjectID_InitStruct(DOFObjectID newObjID, uint32_t dataLen)
4049{
4050 newObjID->refCount = 1;
4051 newObjID->len = dataLen;
4052}
4053
4054static DOFObjectID DOFObjectID_Create_Unmarshal(wmem_allocator_t* allocator, uint32_t *length, const uint8_t *buffer)
4055{
4056 uint32_t len = *length;
4057
4058 /* Legal OID described at buffer must have at least 2 bytes. */
4059 if (buffer && len >= 2)
4060 {
4061 uint32_t classSize = len;
4062 uint32_t classv = OALMarshal_UncompressValue(DOFOBJECTID_MAX_CLASS_SIZE(4), &classSize, buffer);
4063
4064 /* Legal OID described at buffer must have its class representation be correctly compressed. */
4065 if (1)
4066 {
4067 uint32_t computedSize;
4068
4069 /* Above call won't return 3 because DOFOBJECTID_MAX_CLASS_SIZE (4) was passed in. */
4070 computedSize = classSize + 1; /* 1: length of length byte. */
4071 /* Legal OID described at buffer must have enough bytes to describe its OID class. */
4072 if (len >= computedSize)
4073 {
4074 uint8_t lenByte = buffer[classSize];
4075
4076 /* Legal OID described at buffer must have its length byte bit 6 be 0. */
4077 if (!(lenByte & 0x40))
4078 {
4079 bool_Bool hasAttr;
4080 uint8_t dataLen = lenByte & OID_DATA_LEN_MASK((63));
4081
4082 /* Legal broadcast OID described at buffer must have no base data, though it can have attribute(s)*/
4083 if ((classv == 0) && (dataLen > 0))
4084 goto notvalid;
4085 computedSize += dataLen;
4086 hasAttr = lenByte & 0x80; /* Valid OID base; check attributes. */
4087 while (hasAttr)
4088 {
4089 /* Legal OID described at buffer must have enough bytes to hold each new found attribute. */
4090 if (len >= computedSize + 2) /* 2: attribute marshalling overhead. */
4091 {
4092 hasAttr = buffer[computedSize] & 0x80; /* bit 7: next attribute present flag. */
4093 computedSize += (2 + buffer[computedSize + 1]);
4094 }
4095 else
4096 goto notvalid;
4097 }
4098 /* Legal OID described at buffer must have enough buffer bytes, final check.
4099 * len is stored in a uint16_t; reject anything that would truncate it.
4100 */
4101 if (computedSize > UINT16_MAX(65535))
4102 goto notvalid;
4103 if (len >= computedSize)
4104 {
4105 DOFObjectID newObjID = (DOFObjectID)wmem_alloc0(allocator, sizeof(DOFObjectID_t) + (sizeof(uint8_t) * (computedSize + 1)));
4106 /* Adds space for null-terminator, just in case. */
4107
4108 *length = computedSize;
4109 if (newObjID)
4110 {
4111 DOFObjectID_InitStruct(newObjID, computedSize);
4112 memcpy(newObjID->oid, buffer, computedSize);
4113 newObjID->oid[computedSize] = 0;
4114 return newObjID; /* Success. */
4115 }
4116 /* buffer describes valid OID, but due to alloc failure we cannot return the newly created OID*/
4117 goto allocErrorOut;
4118 }
4119 }
4120 }
4121 }
4122 }
4123notvalid:
4124 /* buffer does not describe a valid OID, but do not log a message. The caller may have called us to find out if the
4125 buffer does or does not obey the rules of a valid OID. He learns that by our NULL return. */
4126allocErrorOut :
4127 *length = 0;
4128
4129 return NULL((void*)0);
4130}
4131
4132static DOFObjectID DOFObjectID_Create_Bytes(wmem_allocator_t* allocator, uint32_t bufferSize, const uint8_t *pOIDBuffer)
4133{
4134 uint32_t len = bufferSize;
4135 DOFObjectID rval = DOFObjectID_Create_Unmarshal(allocator, &len, pOIDBuffer);
4136
4137 if (rval)
4138 {
4139 if (len != bufferSize)
4140 {
4141 DOFObjectID_Destroy(rval);
4142 rval = NULL((void*)0);
4143 }
4144 }
4145 return rval;
4146}
4147
4148// NOLINTNEXTLINE(misc-no-recursion)
4149static uint32_t ObjectID_ToStringLength(const DOFObjectID oid, packet_info *pinfo)
4150{
4151 uint32_t len = 0;
4152
4153 /* Note: All these string functions can be exercised with objectid_test.c, which outputs the string to console. */
4154 len = 7 /* [{xx}: and trailing ] */ + ObjectID_DataToStringLength(DOFObjectID_GetData(oid),ObjectID_DataToString( (DOFObjectID_GetData(oid)), (DOFObjectID_GetDataSize
(oid)), ((void*)0) )
4155 DOFObjectID_GetDataSize(oid))ObjectID_DataToString( (DOFObjectID_GetData(oid)), (DOFObjectID_GetDataSize
(oid)), ((void*)0) )
;
4156 if (DOFObjectID_GetIDClass(oid) & 0xFF000000)
4157 len += 6; /* Six more hex digits. */
4158 else if (DOFObjectID_GetIDClass(oid) & 0xFF0000)
4159 len += 4; /* Four more hex digits. */
4160 else if (DOFObjectID_GetIDClass(oid) & 0xFF00)
4161 len += 2; /* Two more hex digits. */
4162 increment_dissection_depth(pinfo);
4163 /* Handle Attributes, if any. */
4164 if (DOFObjectID_HasAttributes(oid))
4165 {
4166 uint8_t i; /* Max attribute count is under uint8. */
4167 uint8_t attributeCount = DOFObjectID_GetAttributeCount(oid);
4168
4169 len += 2; /* surrounding ( ) */
4170 for (i = 0; i < attributeCount; i++)
4171 {
4172 DOFObjectID embedOID;
4173 DOFObjectIDAttribute avpDescriptor = DOFObjectID_GetAttributeAtIndex(oid, i);
4174
4175 if (!DOFObjectIDAttribute_IsValid(avpDescriptor)((avpDescriptor).id < DOFOBJECTIDATTRIBUTE_INVALID))
4176 break; /* Done with Attributes. If here, some error took place. */
4177
4178 if (i)
4179 len++;
4180 len += 5; /* {xx}: */
4181 /* Handle embedded Object IDs. */
4182 embedOID = DOFObjectID_Create_Bytes(pinfo->pool, DOFObjectIDAttribute_GetValueSize(avpDescriptor)((avpDescriptor).dataSize),
4183 DOFObjectIDAttribute_GetValue(avpDescriptor)((avpDescriptor).data));
4184 if (embedOID)
4185 {
4186 len += ObjectID_ToStringLength(embedOID, pinfo); /* Recurse to compute string rep length of found OID. */
4187 DOFObjectID_Destroy(embedOID);
4188 }
4189 else
4190 {
4191 /* Hex Data. */
4192 len += ObjectID_DataToStringLength(DOFObjectIDAttribute_GetValue(avpDescriptor),ObjectID_DataToString( (((avpDescriptor).data)), (((avpDescriptor
).dataSize)), ((void*)0) )
4193 DOFObjectIDAttribute_GetValueSize(avpDescriptor))ObjectID_DataToString( (((avpDescriptor).data)), (((avpDescriptor
).dataSize)), ((void*)0) )
;
4194 }
4195 } /* end for(). */
4196 }
4197 decrement_dissection_depth(pinfo);
4198
4199 return len;
4200}
4201
4202static uint32_t InterfaceID_ToString(const uint8_t *iid, uint32_t iid_size, char *pBuf)
4203{
4204 uint32_t len = 0;
4205 unsigned iid_len = iid[0] & 0x03;
4206 unsigned i;
4207
4208 /* Same lengths as in oap_1_tree_add_interface */
4209 if (iid_len == 0)
4210 iid_len = 16;
4211 else if (iid_len == 3)
4212 iid_len = 4;
4213 if (iid_len > iid_size - 1)
4214 iid_len = iid_size - 1;
4215
4216 pBuf[len++] = '[';
4217 pBuf[len++] = '{';
4218
4219 pBuf[len++] = OALString_HexDigitToChar((iid[0] >> 6) & 0x0F)(OALString_HexChar[((iid[0] >> 6) & 0x0F)]);
4220 pBuf[len++] = OALString_HexDigitToChar((iid[0] >> 2) & 0x0F)(OALString_HexChar[((iid[0] >> 2) & 0x0F)]);
4221
4222 pBuf[len++] = '}';
4223 pBuf[len++] = ':';
4224 pBuf[len++] = '{';
4225
4226 /* Data */
4227 for (i = 0; i < iid_len; i++)
4228 {
4229 pBuf[len++] = OALString_HexDigitToChar((iid[i + 1] >> 4) & 0x0F)(OALString_HexChar[((iid[i + 1] >> 4) & 0x0F)]);
4230 pBuf[len++] = OALString_HexDigitToChar(iid[i + 1] & 0x0F)(OALString_HexChar[(iid[i + 1] & 0x0F)]);
4231 }
4232
4233 pBuf[len++] = '}';
4234 pBuf[len++] = ']';
4235
4236 return len;
4237}
4238
4239// NOLINTNEXTLINE(misc-no-recursion)
4240static uint32_t ObjectID_ToString(const DOFObjectID oid, char *pBuf, packet_info *pinfo)
4241{
4242 DOFObjectIDClass oidClass;
4243 uint32_t len = 0;
4244
4245 pBuf[len++] = '[';
4246 pBuf[len++] = '{';
4247 /* Class */
4248 oidClass = DOFObjectID_GetIDClass(oid);
4249 if (oidClass & 0xFF000000)
4250 {
4251 pBuf[len++] = OALString_HexDigitToChar((oidClass >> 28) & 0x0F)(OALString_HexChar[((oidClass >> 28) & 0x0F)]);
4252 pBuf[len++] = OALString_HexDigitToChar((oidClass >> 24) & 0x0F)(OALString_HexChar[((oidClass >> 24) & 0x0F)]);
4253 }
4254 if (oidClass & 0xFFFF0000)
4255 {
4256 pBuf[len++] = OALString_HexDigitToChar((oidClass >> 20) & 0x0F)(OALString_HexChar[((oidClass >> 20) & 0x0F)]);
4257 pBuf[len++] = OALString_HexDigitToChar((oidClass >> 16) & 0x0F)(OALString_HexChar[((oidClass >> 16) & 0x0F)]);
4258 }
4259 if (oidClass & 0xFFFFFF00)
4260 {
4261 pBuf[len++] = OALString_HexDigitToChar((oidClass >> 12) & 0x0F)(OALString_HexChar[((oidClass >> 12) & 0x0F)]);
4262 pBuf[len++] = OALString_HexDigitToChar((oidClass >> 8) & 0x0F)(OALString_HexChar[((oidClass >> 8) & 0x0F)]);
4263 }
4264 pBuf[len++] = OALString_HexDigitToChar((oidClass >> 4) & 0x0F)(OALString_HexChar[((oidClass >> 4) & 0x0F)]);
4265 pBuf[len++] = OALString_HexDigitToChar((oidClass) & 0x0F)(OALString_HexChar[((oidClass) & 0x0F)]);
4266 pBuf[len++] = '}';
4267 pBuf[len++] = ':';
4268 /* Data */
4269 len += ObjectID_DataToString(DOFObjectID_GetData(oid), DOFObjectID_GetDataSize(oid), &pBuf[len]);
4270 /* Handle Attributes, if any. */
4271 if (DOFObjectID_HasAttributes(oid))
4272 {
4273 uint8_t i;
4274 uint8_t attributeCount = DOFObjectID_GetAttributeCount(oid);
4275
4276 pBuf[len++] = '(';
4277 for (i = 0; i < attributeCount; i++)
4278 {
4279 DOFObjectID embedOID;
4280 DOFObjectIDAttribute avpDescriptor = DOFObjectID_GetAttributeAtIndex(oid, i);
4281
4282 if (!DOFObjectIDAttribute_IsValid(avpDescriptor)((avpDescriptor).id < DOFOBJECTIDATTRIBUTE_INVALID))
4283 break; /* Done with Attributes. If here, some error took place. */
4284
4285 if (i)
4286 pBuf[len++] = '|';
4287 pBuf[len++] = '{';
4288 pBuf[len++] = OALString_HexDigitToChar((DOFObjectIDAttribute_GetType(avpDescriptor) >> 4) & 0x0F)(OALString_HexChar[((((DOFObjectIDAttributeType)(avpDescriptor
).id) >> 4) & 0x0F)])
;
4289 pBuf[len++] = OALString_HexDigitToChar((DOFObjectIDAttribute_GetType(avpDescriptor)) & 0x0F)(OALString_HexChar[((((DOFObjectIDAttributeType)(avpDescriptor
).id)) & 0x0F)])
;
4290 pBuf[len++] = '}';
4291 pBuf[len++] = ':';
4292
4293 /* Handle embedded Object IDs. */
4294 embedOID = DOFObjectID_Create_Bytes(pinfo->pool, DOFObjectIDAttribute_GetValueSize(avpDescriptor)((avpDescriptor).dataSize),
4295 DOFObjectIDAttribute_GetValue(avpDescriptor)((avpDescriptor).data));
4296 if (embedOID)
4297 {
4298 increment_dissection_depth(pinfo);
4299 len += ObjectID_ToString(embedOID, &pBuf[len], pinfo); /* Recurse to output string rep of found OID. */
4300 decrement_dissection_depth(pinfo);
4301 DOFObjectID_Destroy(embedOID);
4302 }
4303 else
4304 {
4305 /* Hex Data. */
4306 len += ObjectID_DataToString(DOFObjectIDAttribute_GetValue(avpDescriptor)((avpDescriptor).data),
4307 DOFObjectIDAttribute_GetValueSize(avpDescriptor)((avpDescriptor).dataSize), &pBuf[len]);
4308 }
4309 } /* end for(). */
4310 pBuf[len++] = ')';
4311 }
4312 pBuf[len++] = ']';
4313
4314 return len;
4315}
4316
4317static const char* dof_iid_create_standard_string(wmem_allocator_t* allocator, uint32_t bufferSize, const uint8_t *pIIDBuffer)
4318{
4319 char *pRetval;
4320 unsigned len = 9 + (bufferSize - 1) * 2; /* Alias is always [{AA}:{01234567}] */
4321
4322 pRetval = (char *)wmem_alloc(allocator, len + 1);
4323 if (pRetval)
4324 {
4325 len = InterfaceID_ToString(pIIDBuffer, bufferSize, pRetval);
4326 pRetval[len] = 0;
4327 }
4328
4329 return pRetval;
4330}
4331
4332static const char* dof_oid_create_standard_string(wmem_allocator_t* allocator, uint32_t bufferSize, const uint8_t *pOIDBuffer, packet_info *pinfo)
4333{
4334 DOFObjectID oid;
4335 char *pRetval;
4336 uint32_t len = bufferSize;
4337
4338 oid = DOFObjectID_Create_Unmarshal(allocator, &len, pOIDBuffer);
4339 if (!oid)
4340 return "Illegal OID";
4341
4342 len = ObjectID_ToStringLength(oid, pinfo);
4343 /* Use PCRMem_Alloc() and not DOFMem_Alloc() because app caller will be freeing memory with PCRMem_Destroy(). */
4344 pRetval = (char *)wmem_alloc(allocator, len + 1);
4345 if (pRetval)
4346 {
4347 ObjectID_ToString(oid, pRetval, pinfo);
4348 pRetval[len] = 0;
4349 }
4350
4351 return pRetval;
4352}
4353
4354struct parseCtx
4355{
4356 const char *oid;
4357 uint8_t *buffer;
4358 uint32_t buffLen;
4359 uint32_t oidLen;
4360 uint32_t currOidPos;
4361 uint32_t currBufferPos;
4362 unsigned depth;
4363};
4364
4365/* Operations on OID string */
4366#define PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) ( (ctx)->oid[(ctx)->currOidPos] )
4367#define PARSECTX_PEEK_NEXT_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos+1] ) ( (ctx)->oid[(ctx)->currOidPos+1] )
4368#define PARSECTX_READ_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos++] ) ( (ctx)->oid[(ctx)->currOidPos++] )
4369#define PARSECTX_GET_CURRENT_POS_OID(ctx)( (ctx)->oid+(ctx)->currOidPos ) ( (ctx)->oid+(ctx)->currOidPos )
4370#define PARSECTX_STEP_OID(ctx, count)((ctx)->currOidPos+=(count))((ctx)->currOidPos+=(count))
4371
4372/* Operations on DOFObjectID buffer */
4373#define PARSECTX_GET_CURRENT_POS_BUF(ctx)( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos
: ((void*)0) )
( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos: NULL((void*)0) )
4374#define PARSECTX_STEP_BUF(ctx, count)( (ctx)->currBufferPos+=(count))( (ctx)->currBufferPos+=(count))
4375#define PARSECTX_WRITE_AT_POS_BUF(ctx, pos, value)do{ if((ctx)->buffer) *(pos) = (value); } while(0) do{ if((ctx)->buffer) *(pos) = (value); } while(0)
4376#define PARSECTX_OR_AT_POS_BUF(ctx, pos, value)do{ if((ctx)->buffer) *(pos) |= (value); } while(0) do{ if((ctx)->buffer) *(pos) |= (value); } while(0)
4377#define PARSECTX_WRITE_BUF(ctx, value)( ((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos
++] = (value): (ctx)->currBufferPos++ )
( ((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos++] = (value): (ctx)->currBufferPos++ )
4378#define PARSECTX_CHECK_LEN(ctx, len)(((ctx)->buffer)? (((ctx)->currBufferPos+len <= (ctx
)->buffLen)? 0: 1): 0)
(((ctx)->buffer)? (((ctx)->currBufferPos+len <= (ctx)->buffLen)? 0: 1): 0)
4379
4380/* Operation to read from OID straight to buffer */
4381#define PARSECTX_WRITE_BUF_FROM_OID(ctx)(((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos
++] = (ctx)->oid[(ctx)->currOidPos]: ((ctx)->currBufferPos
++),((ctx)->currOidPos++))
(((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos++] = (ctx)->oid[(ctx)->currOidPos]: ((ctx)->currBufferPos++),((ctx)->currOidPos++))
4382
4383#define IS_DIGIT(c)(((c) >= '0' && (c) <= '9')) (((c) >= '0' && (c) <= '9'))
4384#define DIGIT2VALUE(c)(c-48) (c-48)
4385
4386#define HEX2VALUE(c)( ((((c) >= '0' && (c) <= '9')))? (c-48) : ((c)
>= 'A' && (c) <= 'F')? (c-55): (c-87) )
( (IS_DIGIT(c)(((c) >= '0' && (c) <= '9')))? DIGIT2VALUE(c)(c-48) : ((c) >= 'A' && (c) <= 'F')? (c-55): (c-87) )
4387#define VALIDHEXSEP(c)( (c) == ' ' || (c) == ':' || (c) == '-' ) ( (c) == ' ' || (c) == ':' || (c) == '-' )
4388#define VALIDHEX(c)( ((c) >= '0' && (c) <= '9') || ((c) >= 'A' &&
(c) <= 'F') || ((c) >= 'a' && (c) <= 'f') )
( ((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f') )
4389#define VALIDHEXBYTE(s)( ( (((s)[0]) >= '0' && ((s)[0]) <= '9') || (((
s)[0]) >= 'A' && ((s)[0]) <= 'F') || (((s)[0]) >=
'a' && ((s)[0]) <= 'f') ) && ( (((s)[1]) >=
'0' && ((s)[1]) <= '9') || (((s)[1]) >= 'A' &&
((s)[1]) <= 'F') || (((s)[1]) >= 'a' && ((s)[1
]) <= 'f') ) )
( VALIDHEX((s)[0])( (((s)[0]) >= '0' && ((s)[0]) <= '9') || (((s)
[0]) >= 'A' && ((s)[0]) <= 'F') || (((s)[0]) >=
'a' && ((s)[0]) <= 'f') )
&& VALIDHEX((s)[1])( (((s)[1]) >= '0' && ((s)[1]) <= '9') || (((s)
[1]) >= 'A' && ((s)[1]) <= 'F') || (((s)[1]) >=
'a' && ((s)[1]) <= 'f') )
)
4390#define VALIDNUMBER(c)((c) >= '0' && (c) <= '9') ((c) >= '0' && (c) <= '9')
4391
4392#define VALIDASCIICHAR(c)(((uint8_t)c) >= 32 && ((uint8_t)c) <= 126 ) (((uint8_t)c) >= 32 && ((uint8_t)c) <= 126 )
4393
4394#define IS_ESCAPED(c)( (c) == '(' || (c) == ')' || (c) == '[' || (c) == ']' || (c)
== '{' || (c) == '}' || (c) == '\\' || (c) == '|' )
( (c) == '(' || (c) == ')' || (c) == '[' || (c) == ']' || (c) == '{' || (c) == '}' || (c) == '\\' || (c) == '|' )
4395
4396static uint8_t parseFormatOID(struct parseCtx *ctx);
4397
4398static uint8_t parseHexField(struct parseCtx *ctx)
4399{
4400 /* Hex fields start with { and end with } can contain space, dash and colon*/
4401 if (PARSECTX_READ_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos++] ) == '{' && PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) != '}')
4402 {
4403 while (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) != '}')
4404 {
4405 if (VALIDHEXBYTE(PARSECTX_GET_CURRENT_POS_OID(ctx))( ( (((( (ctx)->oid+(ctx)->currOidPos ))[0]) >= '0' &&
((( (ctx)->oid+(ctx)->currOidPos ))[0]) <= '9') || (
((( (ctx)->oid+(ctx)->currOidPos ))[0]) >= 'A' &&
((( (ctx)->oid+(ctx)->currOidPos ))[0]) <= 'F') || (
((( (ctx)->oid+(ctx)->currOidPos ))[0]) >= 'a' &&
((( (ctx)->oid+(ctx)->currOidPos ))[0]) <= 'f') ) &&
( (((( (ctx)->oid+(ctx)->currOidPos ))[1]) >= '0' &&
((( (ctx)->oid+(ctx)->currOidPos ))[1]) <= '9') || (
((( (ctx)->oid+(ctx)->currOidPos ))[1]) >= 'A' &&
((( (ctx)->oid+(ctx)->currOidPos ))[1]) <= 'F') || (
((( (ctx)->oid+(ctx)->currOidPos ))[1]) >= 'a' &&
((( (ctx)->oid+(ctx)->currOidPos ))[1]) <= 'f') ) )
)
4406 {
4407 if (PARSECTX_CHECK_LEN(ctx, 1)(((ctx)->buffer)? (((ctx)->currBufferPos+1 <= (ctx)->
buffLen)? 0: 1): 0)
== 0)
4408 {
4409 PARSECTX_WRITE_BUF(ctx, HEX2VALUE(PARSECTX_PEEK_CHAR_OID(ctx)) << 4 | HEX2VALUE(PARSECTX_PEEK_NEXT_CHAR_OID(ctx)))( ((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos
++] = (( ((((( (ctx)->oid[(ctx)->currOidPos] )) >= '0'
&& (( (ctx)->oid[(ctx)->currOidPos] )) <= '9'
)))? (( (ctx)->oid[(ctx)->currOidPos] )-48) : ((( (ctx)
->oid[(ctx)->currOidPos] )) >= 'A' && (( (ctx
)->oid[(ctx)->currOidPos] )) <= 'F')? (( (ctx)->oid
[(ctx)->currOidPos] )-55): (( (ctx)->oid[(ctx)->currOidPos
] )-87) ) << 4 | ( ((((( (ctx)->oid[(ctx)->currOidPos
+1] )) >= '0' && (( (ctx)->oid[(ctx)->currOidPos
+1] )) <= '9')))? (( (ctx)->oid[(ctx)->currOidPos+1]
)-48) : ((( (ctx)->oid[(ctx)->currOidPos+1] )) >= 'A'
&& (( (ctx)->oid[(ctx)->currOidPos+1] )) <=
'F')? (( (ctx)->oid[(ctx)->currOidPos+1] )-55): (( (ctx
)->oid[(ctx)->currOidPos+1] )-87) )): (ctx)->currBufferPos
++ )
;
4410 PARSECTX_STEP_OID(ctx, 2)((ctx)->currOidPos+=(2));
4411
4412 if (VALIDHEXSEP(PARSECTX_PEEK_CHAR_OID(ctx))( (( (ctx)->oid[(ctx)->currOidPos] )) == ' ' || (( (ctx
)->oid[(ctx)->currOidPos] )) == ':' || (( (ctx)->oid
[(ctx)->currOidPos] )) == '-' )
)
4413 {
4414 if (PARSECTX_PEEK_NEXT_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos+1] ) == '}')
4415 {
4416 /* no separator after byte block */
4417 return 1;
4418 }
4419 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4420 }
4421 }
4422 else
4423 {
4424 return 1;
4425 }
4426 }
4427 else
4428 {
4429 return 1;
4430 }
4431 }
4432 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4433 return 0;
4434 }
4435 return 1;
4436}
4437
4438static uint8_t parseStringField(struct parseCtx *ctx)
4439{
4440 /* Copy into buffer until end or */
4441 while (ctx->currOidPos < (ctx->oidLen - 1))
4442 {
4443 char curr = PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] );
4444 if (curr == ']' || curr == '(')
4445 {
4446 break; /* End of string field */
4447 }
4448 else if (curr == '\\')
4449 {
4450 /* Handle escaped char */
4451 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4452 if (!IS_ESCAPED(PARSECTX_PEEK_CHAR_OID(ctx))( (( (ctx)->oid[(ctx)->currOidPos] )) == '(' || (( (ctx
)->oid[(ctx)->currOidPos] )) == ')' || (( (ctx)->oid
[(ctx)->currOidPos] )) == '[' || (( (ctx)->oid[(ctx)->
currOidPos] )) == ']' || (( (ctx)->oid[(ctx)->currOidPos
] )) == '{' || (( (ctx)->oid[(ctx)->currOidPos] )) == '}'
|| (( (ctx)->oid[(ctx)->currOidPos] )) == '\\' || (( (
ctx)->oid[(ctx)->currOidPos] )) == '|' )
|| PARSECTX_CHECK_LEN(ctx, 1)(((ctx)->buffer)? (((ctx)->currBufferPos+1 <= (ctx)->
buffLen)? 0: 1): 0)
!= 0)
4453 return 1;
4454 PARSECTX_WRITE_BUF_FROM_OID(ctx)(((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos
++] = (ctx)->oid[(ctx)->currOidPos]: ((ctx)->currBufferPos
++),((ctx)->currOidPos++))
;
4455 }
4456 else
4457 {
4458 if (VALIDASCIICHAR(curr)(((uint8_t)curr) >= 32 && ((uint8_t)curr) <= 126
)
&& PARSECTX_CHECK_LEN(ctx, 1)(((ctx)->buffer)? (((ctx)->currBufferPos+1 <= (ctx)->
buffLen)? 0: 1): 0)
== 0)
4459 PARSECTX_WRITE_BUF_FROM_OID(ctx)(((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos
++] = (ctx)->oid[(ctx)->currOidPos]: ((ctx)->currBufferPos
++),((ctx)->currOidPos++))
;
4460 else
4461 return 1;
4462 }
4463 }
4464 return 0;
4465}
4466
4467static uint8_t OALMarshal_GetCompressedValueSize(uint8_t maxSize, uint32_t value)
4468{
4469 uint8_t lenbytes = (1 + (value > 0x7F) + (value > 0x3FFF));
4470 if (lenbytes > 2)
4471 return (maxSize);
4472 return (lenbytes);
4473}
4474
4475static uint32_t OALMarshal_CompressValue(uint8_t maxSize, uint32_t value, uint32_t bufLength, uint8_t *buffer)
4476{
4477 uint8_t lenSize = OALMarshal_GetCompressedValueSize(maxSize, value);
4478
4479 if (bufLength < lenSize)
4480 return 0;
4481 switch (lenSize)
4482 {
4483 case 4:
4484 *(buffer++) = (uint8_t)((value >> 24) & 0x3F) | 0xC0;
4485 *(buffer++) = (uint8_t)((value >> 16) & 0xFF);
4486 *(buffer++) = (uint8_t)((value >> 8) & 0xFF);
4487 *(buffer++) = (uint8_t)(value & 0xFF);
4488 break;
4489
4490 case 3:
4491 *(buffer++) = (uint8_t)((value >> 16) & 0x3F) | 0xC0;
4492 *(buffer++) = (uint8_t)((value >> 8) & 0xFF);
4493 *(buffer++) = (uint8_t)(value & 0xFF);
4494 break;
4495
4496 case 2:
4497 if (maxSize == 2)
4498 {
4499 *(buffer++) = (uint8_t)((value >> 8) & 0x7F) | 0x80;
4500 }
4501 else
4502 {
4503 *(buffer++) = (uint8_t)((value >> 8) & 0x3F) | 0x80;
4504 }
4505 *(buffer++) = (uint8_t)(value & 0xFF);
4506 break;
4507
4508 case 1:
4509 *(buffer++) = (uint8_t)(value & 0x7F);
4510 break;
4511
4512 default:
4513 /* Invalid computed size! */
4514 break;
4515 }
4516 return (lenSize);
4517}
4518
4519static uint8_t parseOIDClass(struct parseCtx *ctx)
4520{
4521 if (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) == '{' && PARSECTX_PEEK_NEXT_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos+1] ) != '}')
4522 {
4523 /* Hex */
4524 uint8_t classSize = 0;
4525 uint32_t oidClass = 0;
4526 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4527 while (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) != '}')
4528 {
4529 if (VALIDHEXBYTE(PARSECTX_GET_CURRENT_POS_OID(ctx))( ( (((( (ctx)->oid+(ctx)->currOidPos ))[0]) >= '0' &&
((( (ctx)->oid+(ctx)->currOidPos ))[0]) <= '9') || (
((( (ctx)->oid+(ctx)->currOidPos ))[0]) >= 'A' &&
((( (ctx)->oid+(ctx)->currOidPos ))[0]) <= 'F') || (
((( (ctx)->oid+(ctx)->currOidPos ))[0]) >= 'a' &&
((( (ctx)->oid+(ctx)->currOidPos ))[0]) <= 'f') ) &&
( (((( (ctx)->oid+(ctx)->currOidPos ))[1]) >= '0' &&
((( (ctx)->oid+(ctx)->currOidPos ))[1]) <= '9') || (
((( (ctx)->oid+(ctx)->currOidPos ))[1]) >= 'A' &&
((( (ctx)->oid+(ctx)->currOidPos ))[1]) <= 'F') || (
((( (ctx)->oid+(ctx)->currOidPos ))[1]) >= 'a' &&
((( (ctx)->oid+(ctx)->currOidPos ))[1]) <= 'f') ) )
)
4530 {
4531 oidClass <<= 8;
4532 oidClass += (HEX2VALUE(PARSECTX_PEEK_CHAR_OID(ctx))( ((((( (ctx)->oid[(ctx)->currOidPos] )) >= '0' &&
(( (ctx)->oid[(ctx)->currOidPos] )) <= '9')))? (( (
ctx)->oid[(ctx)->currOidPos] )-48) : ((( (ctx)->oid[
(ctx)->currOidPos] )) >= 'A' && (( (ctx)->oid
[(ctx)->currOidPos] )) <= 'F')? (( (ctx)->oid[(ctx)->
currOidPos] )-55): (( (ctx)->oid[(ctx)->currOidPos] )-87
) )
<< 4 | HEX2VALUE(PARSECTX_PEEK_NEXT_CHAR_OID(ctx))( ((((( (ctx)->oid[(ctx)->currOidPos+1] )) >= '0' &&
(( (ctx)->oid[(ctx)->currOidPos+1] )) <= '9')))? ((
(ctx)->oid[(ctx)->currOidPos+1] )-48) : ((( (ctx)->
oid[(ctx)->currOidPos+1] )) >= 'A' && (( (ctx)->
oid[(ctx)->currOidPos+1] )) <= 'F')? (( (ctx)->oid[(
ctx)->currOidPos+1] )-55): (( (ctx)->oid[(ctx)->currOidPos
+1] )-87) )
);
4533 PARSECTX_STEP_OID(ctx, 2)((ctx)->currOidPos+=(2));
4534
4535 if (VALIDHEXSEP(PARSECTX_PEEK_CHAR_OID(ctx))( (( (ctx)->oid[(ctx)->currOidPos] )) == ' ' || (( (ctx
)->oid[(ctx)->currOidPos] )) == ':' || (( (ctx)->oid
[(ctx)->currOidPos] )) == '-' )
)
4536 {
4537 if (PARSECTX_PEEK_NEXT_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos+1] ) == '}')
4538 {
4539 /* no separator after byte block */
4540 return 1;
4541 }
4542 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4543 }
4544 }
4545 else
4546 {
4547 return 1;
4548 }
4549 }
4550 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4551
4552 classSize = OALMarshal_GetCompressedValueSize(4, oidClass);
4553 if (PARSECTX_CHECK_LEN(ctx, classSize)(((ctx)->buffer)? (((ctx)->currBufferPos+classSize <=
(ctx)->buffLen)? 0: 1): 0)
== 0)
4554 {
4555 if (PARSECTX_GET_CURRENT_POS_BUF(ctx)( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos
: ((void*)0) )
)
4556 classSize = OALMarshal_CompressValue(4, oidClass, classSize, PARSECTX_GET_CURRENT_POS_BUF(ctx)( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos
: ((void*)0) )
);
4557
4558 PARSECTX_STEP_BUF(ctx, classSize)( (ctx)->currBufferPos+=(classSize));
4559 }
4560
4561 return 0;
4562 }
4563 else
4564 {
4565 /* Number */
4566 uint8_t classSize = 0;
4567 uint32_t oidClass = 0;
4568 while (IS_DIGIT(PARSECTX_PEEK_CHAR_OID(ctx))(((( (ctx)->oid[(ctx)->currOidPos] )) >= '0' &&
(( (ctx)->oid[(ctx)->currOidPos] )) <= '9'))
)
4569 {
4570 oidClass *= 10;
4571 oidClass += DIGIT2VALUE(PARSECTX_PEEK_CHAR_OID(ctx))(( (ctx)->oid[(ctx)->currOidPos] )-48);
4572 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4573 }
4574
4575 classSize = OALMarshal_GetCompressedValueSize(4, oidClass);
4576 if (PARSECTX_CHECK_LEN(ctx, classSize)(((ctx)->buffer)? (((ctx)->currBufferPos+classSize <=
(ctx)->buffLen)? 0: 1): 0)
== 0)
4577 {
4578 if (PARSECTX_GET_CURRENT_POS_BUF(ctx)( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos
: ((void*)0) )
)
4579 classSize = OALMarshal_CompressValue(4, oidClass, classSize, PARSECTX_GET_CURRENT_POS_BUF(ctx)( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos
: ((void*)0) )
);
4580
4581 PARSECTX_STEP_BUF(ctx, classSize)( (ctx)->currBufferPos+=(classSize));
4582 }
4583
4584 return 0;
4585 }
4586}
4587
4588static uint8_t parseAttributeID(struct parseCtx *ctx)
4589{
4590 if (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) == '{')
4591 {
4592 return parseHexField(ctx);
4593 }
4594 else
4595 {
4596 uint8_t avpid = 0;
4597 while (IS_DIGIT(PARSECTX_PEEK_CHAR_OID(ctx))(((( (ctx)->oid[(ctx)->currOidPos] )) >= '0' &&
(( (ctx)->oid[(ctx)->currOidPos] )) <= '9'))
)
4598 {
4599 avpid *= 10;
4600 avpid += DIGIT2VALUE(PARSECTX_PEEK_CHAR_OID(ctx))(( (ctx)->oid[(ctx)->currOidPos] )-48);
4601 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4602 }
4603
4604 if (PARSECTX_CHECK_LEN(ctx, 1)(((ctx)->buffer)? (((ctx)->currBufferPos+1 <= (ctx)->
buffLen)? 0: 1): 0)
== 0)
4605 {
4606 PARSECTX_WRITE_BUF(ctx, avpid)( ((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos
++] = (avpid): (ctx)->currBufferPos++ )
;
4607 return 0;
4608 }
4609 }
4610 return 1;
4611}
4612
4613// NOLINTNEXTLINE(misc-no-recursion)
4614static uint8_t parseAttributeData(struct parseCtx *ctx)
4615{
4616 uint8_t ret;
4617 ctx->depth++;
4618 /* Preference text, not packet data. A deep OID must fail the parse, not abort. */
4619 if (ctx->depth >= prefs.gui_max_tree_depth)
4620 {
4621 ctx->depth--;
4622 return 1;
4623 }
4624 if (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) == '[')
4625 {
4626 ret = parseFormatOID(ctx);
4627 }
4628 else if (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) == '{')
4629 {
4630 ret = parseHexField(ctx);
4631 }
4632 else
4633 {
4634 ret = parseStringField(ctx);
4635 }
4636 ctx->depth--;
4637 return ret;
4638}
4639
4640// NOLINTNEXTLINE(misc-no-recursion)
4641static uint8_t parseAttribute(struct parseCtx *ctx)
4642{
4643 if (parseAttributeID(ctx) == 0)
4644 {
4645 /* separated by ':' */
4646 if (PARSECTX_READ_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos++] ) == ':' && PARSECTX_CHECK_LEN(ctx, 1)(((ctx)->buffer)? (((ctx)->currBufferPos+1 <= (ctx)->
buffLen)? 0: 1): 0)
== 0)
4647 {
4648 uint8_t *length = PARSECTX_GET_CURRENT_POS_BUF(ctx)( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos
: ((void*)0) )
;
4649 if (length == NULL((void*)0))
4650 return 0;
4651
4652 PARSECTX_STEP_BUF(ctx, 1)( (ctx)->currBufferPos+=(1));
4653
4654 if (parseAttributeData(ctx) == 0)
4655 {
4656 PARSECTX_WRITE_AT_POS_BUF(ctx, length, (uint8_t)(PARSECTX_GET_CURRENT_POS_BUF(ctx) - (length + 1)))do{ if((ctx)->buffer) *(length) = ((uint8_t)(( ((ctx)->
buffer)? (ctx)->buffer+(ctx)->currBufferPos: ((void*)0)
) - (length + 1))); } while(0)
;
4657 return 0;
4658 }
4659 }
4660 }
4661 return 1;
4662}
4663
4664// NOLINTNEXTLINE(misc-no-recursion)
4665static uint8_t parseAttributes(struct parseCtx *ctx)
4666{
4667 /* AVPs surrounded by '(' ')' but needs at least an avp */
4668 if (PARSECTX_READ_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos++] ) == '(' && PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) != ')')
4669 {
4670 while (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) != ')')
4671 {
4672 uint8_t *avpID = PARSECTX_GET_CURRENT_POS_BUF(ctx)( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos
: ((void*)0) )
;
4673 if (avpID == NULL((void*)0))
4674 return 0;
4675
4676 if (parseAttribute(ctx) != 0)
4677 return 1;
4678
4679 /* multiple separated by '|' */
4680 if (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) == '|' && PARSECTX_PEEK_NEXT_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos+1] ) != ')')
4681 {
4682 PARSECTX_OR_AT_POS_BUF(ctx, avpID, 0x80)do{ if((ctx)->buffer) *(avpID) |= (0x80); } while(0); /* set that there is a next attribute */
4683 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4684 }
4685 }
4686 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4687 return 0;
4688 }
4689 return 1;
4690}
4691
4692// NOLINTNEXTLINE(misc-no-recursion)
4693static uint8_t parseFormatOID(struct parseCtx *ctx)
4694{
4695 /* oid must start with '[' */
4696 if (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) == '[')
4697 {
4698 PARSECTX_STEP_OID(ctx, 1)((ctx)->currOidPos+=(1));
4699 /* Get class id */
4700 if (parseOIDClass(ctx) == 0)
4701 {
4702 /* separated by ':' */
4703 if (PARSECTX_READ_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos++] ) == ':' && PARSECTX_CHECK_LEN(ctx, 1)(((ctx)->buffer)? (((ctx)->currBufferPos+1 <= (ctx)->
buffLen)? 0: 1): 0)
== 0)
4704 {
4705 uint8_t *length = PARSECTX_GET_CURRENT_POS_BUF(ctx)( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos
: ((void*)0) )
;
4706 PARSECTX_STEP_BUF(ctx, 1)( (ctx)->currBufferPos+=(1));
4707
4708 /* Get data */
4709 if (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) == '{')
4710 {
4711 /* hex data */
4712 if (parseHexField(ctx) != 0)
4713 return 1;
4714 }
4715 else
4716 {
4717 /* string data */
4718 if (parseStringField(ctx) != 0)
4719 return 1;
4720 }
4721
4722 /* Write length */
4723 if (length == NULL((void*)0))
4724 return 0;
4725 PARSECTX_WRITE_AT_POS_BUF(ctx, length, (uint8_t)(PARSECTX_GET_CURRENT_POS_BUF(ctx) - (length + 1)))do{ if((ctx)->buffer) *(length) = ((uint8_t)(( ((ctx)->
buffer)? (ctx)->buffer+(ctx)->currBufferPos: ((void*)0)
) - (length + 1))); } while(0)
;
4726
4727 /* Check if attributes exist */
4728 if (PARSECTX_PEEK_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos] ) == '(')
4729 {
4730 PARSECTX_OR_AT_POS_BUF(ctx, length, 0x80)do{ if((ctx)->buffer) *(length) |= (0x80); } while(0); /* set that there are attributes */
4731 if (parseAttributes(ctx) != 0)
4732 return 1;
4733 }
4734
4735 /* Ends with ] */
4736 if (PARSECTX_READ_CHAR_OID(ctx)( (ctx)->oid[(ctx)->currOidPos++] ) == ']')
4737 {
4738 return 0;
4739 }
4740 }
4741 }
4742 }
4743 return 1;
4744}
4745
4746static uint8_t dof_oid_create_internal(const char *oid, uint32_t *size, uint8_t *buffer)
4747{
4748 struct parseCtx ctx = {0};
4749
4750 ctx.oid = oid;
4751 ctx.buffer = buffer;
4752
4753 if (oid)
4754 {
4755 if (size)
4756 {
4757 ctx.buffLen = (*size);
4758 ctx.oidLen = (uint32_t)strlen(oid);
4759 if (PARSECTX_PEEK_CHAR_OID(&ctx)( (&ctx)->oid[(&ctx)->currOidPos] ) == '[')
4760 {
4761 /* Format OID */
4762 if (parseFormatOID(&ctx) == 0)
4763 {
4764 (*size) = ctx.currBufferPos;
4765 return 0;
4766 }
4767 }
4768 else if (PARSECTX_PEEK_CHAR_OID(&ctx)( (&ctx)->oid[(&ctx)->currOidPos] ) == '{')
4769 {
4770 /* HEX OID */
4771 if (parseHexField(&ctx) == 0)
4772 {
4773 (*size) = ctx.currBufferPos;
4774 return 0;
4775 }
4776 }
4777 (*size) = 0;
4778 }
4779 }
4780 return 1;
4781}
4782
4783static void dof_oid_new_standard_string(const char *data, uint32_t *rsize, uint8_t **oid)
4784{
4785 if (data)
4786 {
4787 uint8_t err;
4788 uint32_t size = 0;
4789
4790 /* Call parseInternal to find out how big the buffer needs to be. */
4791 err = dof_oid_create_internal(data, &size, NULL((void*)0));
4792
4793 if (err == 0)
4794 {
4795 /* Create the DOFObjectID using the size that was just computed. */
4796 *oid = (uint8_t *)g_malloc(size + 1); /* Adds space for null-terminator, just in case. */
4797
4798 if (*oid)
4799 {
4800 /* Now that the size is computed and the DOFObjectID is created, call parseInternal again to fill the oid buffer. */
4801 err = dof_oid_create_internal(data, &size, *oid);
4802
4803 if (err == 0)
4804 {
4805 *rsize = size;
4806 return;
4807 }
4808
4809 g_free(*oid)(__builtin_object_size ((*oid), 0) != ((size_t) - 1)) ? g_free_sized
(*oid, __builtin_object_size ((*oid), 0)) : (g_free) (*oid)
;
4810 }
4811 }
4812 }
4813
4814 *rsize = 0;
4815 *oid = NULL((void*)0);
4816}
4817
4818/* Binary Parsing Support */
4819
4820/**
4821 * Read a compressed 32-bit quantity (PDU Type.3).
4822 * Since the value is variable length, the new offset is
4823 * returned. The value can also be returned, along with the size, although
4824 * NULL is allowed for those parameters.
4825 */
4826static int read_c4(tvbuff_t *tvb, int offset, uint32_t *v, int *L)
4827{
4828 uint32_t val = 0;
4829 uint8_t len = 0;
4830 uint8_t b = tvb_get_uint8(tvb, offset++);
4831 int i;
4832
4833 if ((b & 0x80) == 0)
4834 {
4835 len = 1;
4836 b = b & 0x7F;
4837 }
4838 else if ((b & 0x40) == 0)
4839 {
4840 len = 2;
4841 b = b & 0x3F;
4842 }
4843 else
4844 {
4845 len = 4;
4846 b = b & 0x3F;
4847 }
4848
4849 val = b;
4850 for (i = 1; i < len; i++)
4851 val = (val << 8) | tvb_get_uint8(tvb, offset++);
4852
4853 if (L)
4854 *L = len;
4855 if (v)
4856 *v = val;
4857 return offset;
4858}
4859
4860/**
4861 * Validate PDU Type.3
4862 * Validates the encoding.
4863 * Add Expert Info if format invalid
4864 * This also validates Spec Type.3.1.
4865 */
4866static void validate_c4(packet_info *pinfo, proto_item *pi, uint32_t val, int len)
4867{
4868 if (len > 1 && val < 0x80)
4869 {
4870 /* SPEC Type.3.1 Violation. */
4871 expert_add_info_format(pinfo, pi, &ei_c2_c3_c4_format, "DOF Violation: Type.3.1: Compressed 32-bit Compression Mandatory.");
4872 }
4873
4874 if (len > 2 && val < 0x4000)
4875 {
4876 /* SPEC Type.3.1 Violation. */
4877 expert_add_info_format(pinfo, pi, &ei_c2_c3_c4_format, "DOF Violation: Type.3.1: Compressed 32-bit Compression Mandatory.");
4878 }
4879}
4880
4881/**
4882 * Reads a compressed 24-bit quantity (PDU Type.2).
4883 * Since the value is variable length, the new offset is
4884 * returned.
4885 * The value can also be returned, along with the size, although
4886 * NULL is allowed for those parameters.
4887 */
4888static int read_c3(tvbuff_t *tvb, int offset, uint32_t *v, int *L)
4889{
4890 uint32_t val = 0;
4891 uint8_t len = 0;
4892 uint8_t b = tvb_get_uint8(tvb, offset++);
4893 int i;
4894
4895 if ((b & 0x80) == 0)
4896 {
4897 len = 1;
4898 b = b & 0x7F;
4899 }
4900 else if ((b & 0x40) == 0)
4901 {
4902 len = 2;
4903 b = b & 0x3F;
4904 }
4905 else
4906 {
4907 len = 3;
4908 b = b & 0x3F;
4909 }
4910
4911 val = b;
4912 for (i = 1; i < len; i++)
4913 val = (val << 8) | tvb_get_uint8(tvb, offset++);
4914
4915 if (L)
4916 *L = len;
4917 if (v)
4918 *v = val;
4919 return offset;
4920}
4921
4922/**
4923 * Validate PDU Type.2
4924 * Validates the encoding.
4925 * Adds Expert Info if format invalid
4926 * This also validates Spec Type.2.1.
4927 */
4928static void validate_c3(packet_info *pinfo, proto_item *pi, uint32_t val, int len)
4929{
4930 if (len > 1 && val < 0x80)
4931 {
4932 /* SPEC Type.2.1 Violation. */
4933 expert_add_info_format(pinfo, pi, &ei_c2_c3_c4_format, "DOF Violation: Type.2.1: Compressed 24-bit Compression Mandatory." );
4934 }
4935
4936 if (len > 2 && val < 0x4000)
4937 {
4938 /* SPEC Type.2.1 Violation. */
4939 expert_add_info_format(pinfo, pi, &ei_c2_c3_c4_format, "DOF Violation: Type.2.1: Compressed 24-bit Compression Mandatory.");
4940 }
4941}
4942
4943/**
4944 * Reads a compressed 16-bit quantity (PDU Type.1).
4945 * Since the value is variable length, the new offset is
4946 * returned. The value can also be returned, along with the size, although
4947 * NULL is allowed for those parameters.
4948 */
4949static int read_c2(tvbuff_t *tvb, int offset, uint16_t *v, int *L)
4950{
4951 uint16_t val = 0;
4952 uint8_t b = tvb_get_uint8(tvb, offset++);
4953 if (b & 0x80)
4954 {
4955 b = b & 0x7F;
4956 val = (b << 8) | tvb_get_uint8(tvb, offset++);
4957 if (L)
4958 *L = 2;
4959 }
4960 else
4961 {
4962 val = b;
4963 if (L)
4964 *L = 1;
4965 }
4966
4967 if (v)
4968 *v = val;
4969 return offset;
4970}
4971
4972/**
4973 * Validates PDU Type.1
4974 * Validates the encoding.
4975 * Adds Expert Info if format invalid
4976 * This also validates Spec Type.1.1.
4977 */
4978static void validate_c2(packet_info *pinfo, proto_item *pi, uint16_t val, int len)
4979{
4980 if (len > 1 && val < 0x80)
4981 {
4982 /* SPEC Type.1.1 Violation. */
4983 expert_add_info_format(pinfo, pi, &ei_c2_c3_c4_format, "DOF Violation: Type.1.1: Compressed 16-bit Compression Mandatory." );
4984 }
4985}
4986
4987static void sid_packet_index_add(unsigned sid_id, dof_packet_data *packet)
4988{
4989 GSList *list;
4990
4991 if (sid_id == 0 || packet
30.1
'packet' is not equal to NULL
== NULL((void*)0) || sid_id_to_packets == NULL((void*)0))
30
Assuming 'sid_id' is not equal to 0
31
Assuming 'sid_id_to_packets' is not equal to NULL
32
Taking false branch
4992 return;
4993
4994 list = (GSList *)g_hash_table_lookup(sid_id_to_packets, GUINT_TO_POINTER(sid_id)((gpointer) (gulong) (sid_id)));
4995 g_hash_table_steal(sid_id_to_packets, GUINT_TO_POINTER(sid_id)((gpointer) (gulong) (sid_id)));
4996 list = g_slist_prepend(list, packet);
33
Value assigned to field 'opid_first'
4997 g_hash_table_insert(sid_id_to_packets, GUINT_TO_POINTER(sid_id)((gpointer) (gulong) (sid_id)), list);
4998}
4999
5000/* Move every packet that stored sid_id_incorrect over to sid_id_correct. */
5001static void retarget_sid_id(unsigned sid_id_incorrect, unsigned sid_id_correct)
5002{
5003 GSList *saved;
5004 GSList *l;
5005
5006 if (sid_id_incorrect == 0 || sid_id_incorrect == sid_id_correct || sid_id_to_packets == NULL((void*)0))
5007 return;
5008
5009 saved = g_slist_copy((GSList *)g_hash_table_lookup(sid_id_to_packets, GUINT_TO_POINTER(sid_id_incorrect)((gpointer) (gulong) (sid_id_incorrect))));
5010 for (l = saved; l; l = l->next)
5011 {
5012 dof_packet_data *ptr = (dof_packet_data *)l->data;
5013
5014 if (ptr->sender_sid_id == sid_id_incorrect)
5015 ptr->sender_sid_id = sid_id_correct;
5016 if (ptr->receiver_sid_id == sid_id_incorrect)
5017 ptr->receiver_sid_id = sid_id_correct;
5018 if (ptr->op.op_sid_id == sid_id_incorrect)
5019 ptr->op.op_sid_id = sid_id_correct;
5020 if (ptr->ref_op.op_sid_id == sid_id_incorrect)
5021 ptr->ref_op.op_sid_id = sid_id_correct;
5022
5023 sid_packet_index_add(sid_id_correct, ptr);
5024 }
5025 g_slist_free(saved);
5026 g_hash_table_remove(sid_id_to_packets, GUINT_TO_POINTER(sid_id_incorrect)((gpointer) (gulong) (sid_id_incorrect)));
5027
5028 /* Senders that were given the provisional id get the correct one in
5029 * later packets too. */
5030 if (node_key_to_sid_id != NULL((void*)0))
5031 {
5032 GHashTableIter iter;
5033 void *value;
5034
5035 g_hash_table_iter_init(&iter, node_key_to_sid_id);
5036 while (g_hash_table_iter_next(&iter, NULL((void*)0), &value))
5037 {
5038 if (GPOINTER_TO_UINT(value)((guint) (gulong) (value)) == sid_id_incorrect)
5039 g_hash_table_iter_replace(&iter, GUINT_TO_POINTER(sid_id_correct)((gpointer) (gulong) (sid_id_correct)));
5040 }
5041 }
5042}
5043
5044/**
5045 * Given a packet data, and assuming that all of the prerequisite information is known,
5046 * assign a SID ID to the packet if not already assigned.
5047 * A SID ID is the *possibility* of a unique SID, but until the SID is learned the
5048 * association is not made. Further, multiple SID ID may end up referring to the
5049 * same SID, in which case the assignment must be repaired.
5050 */
5051static void assign_sid_id(dof_api_data *api_data)
5052{
5053 node_key_to_sid_id_key lookup_key;
5054 node_key_to_sid_id_key *key;
5055 dof_session_data *session;
5056 dof_packet_data *packet;
5057 unsigned value;
5058
5059 /* Validate input. These represent dissector misuse, not decoding problems. */
5060 /* TODO: Diagnostic/programmer message. */
5061 if (!api_data || !api_data->packet || !api_data->session)
5062 return;
5063
5064 session = api_data->session;
5065 packet = (dof_packet_data *)api_data->packet;
5066
5067
5068 /* Check if the sender_sid_id is already assigned, if so we are done. */
5069 if (!packet->sender_sid_id)
5070 {
5071 /* Build a (non-allocated) key to do the lookup. */
5072 lookup_key.transport_id = api_data->transport_session->transport_id;
5073 lookup_key.transport_node_id = api_data->transport_packet->sender_id;
5074 lookup_key.dof_id = session->dof_id;
5075 lookup_key.dof_node_id = packet->sender_id;
5076 lookup_key.dof_session_id = session->session_id;
5077
5078 value = GPOINTER_TO_UINT(g_hash_table_lookup(node_key_to_sid_id, &lookup_key))((guint) (gulong) (g_hash_table_lookup(node_key_to_sid_id, &
lookup_key)))
;
5079 if (value)
5080 {
5081 void *sid_id_key = GUINT_TO_POINTER(value)((gpointer) (gulong) (value));
5082 void *sid_buffer;
5083
5084 /* We found a match. */
5085 packet->sender_sid_id = value;
5086
5087 /* If we know the SID, we must get it now. */
5088 sid_buffer = g_hash_table_lookup(sid_id_to_sid_buffer, sid_id_key);
5089 if (sid_buffer)
5090 {
5091 /* We found a match. */
5092 packet->sender_sid = (dof_2009_1_pdu_19_sid)sid_buffer;
5093 }
5094 }
5095 else
5096 {
5097 /* No match, need to add a key. */
5098 key = g_new0(node_key_to_sid_id_key, 1)((node_key_to_sid_id_key *) g_malloc0_n ((1), sizeof (node_key_to_sid_id_key
)))
;
5099 memcpy(key, &lookup_key, sizeof(node_key_to_sid_id_key));
5100
5101 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
5102 g_hash_table_insert(node_key_to_sid_id, key, GUINT_TO_POINTER(dpp_next_sid_id)((gpointer) (gulong) (dpp_next_sid_id)));
5103 packet->sender_sid_id = dpp_next_sid_id++;
5104 }
5105 sid_packet_index_add(packet->sender_sid_id, packet);
5106 }
5107
5108 /* Check if the receiver_sid_id is already assigned, if so we are done. */
5109 if (!packet->receiver_sid_id)
5110 {
5111 /* Build a (non-allocated) key to do the lookup. */
5112 lookup_key.transport_id = api_data->transport_session->transport_id;
5113 lookup_key.transport_node_id = api_data->transport_packet->receiver_id;
5114 lookup_key.dof_id = session->dof_id;
5115 lookup_key.dof_node_id = packet->receiver_id;
5116 lookup_key.dof_session_id = session->session_id;
5117
5118 value = GPOINTER_TO_UINT(g_hash_table_lookup(node_key_to_sid_id, &lookup_key))((guint) (gulong) (g_hash_table_lookup(node_key_to_sid_id, &
lookup_key)))
;
5119 if (value)
5120 {
5121 void *sid_id_key = GUINT_TO_POINTER(value)((gpointer) (gulong) (value));
5122 void *sid_buffer;
5123
5124 /* We found a match. */
5125 packet->receiver_sid_id = value;
5126
5127 /* If we know the SID, we must get it now. */
5128 sid_buffer = g_hash_table_lookup(sid_id_to_sid_buffer, sid_id_key);
5129 if (sid_buffer)
5130 {
5131 /* We found a match. */
5132 packet->receiver_sid = (dof_2009_1_pdu_19_sid)sid_buffer;
5133 }
5134 }
5135 else
5136 {
5137 /* No match, need to add a key. */
5138 key = g_new0(node_key_to_sid_id_key, 1)((node_key_to_sid_id_key *) g_malloc0_n ((1), sizeof (node_key_to_sid_id_key
)))
;
5139 memcpy(key, &lookup_key, sizeof(node_key_to_sid_id_key));
5140
5141 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
5142 g_hash_table_insert(node_key_to_sid_id, key, GUINT_TO_POINTER(dpp_next_sid_id)((gpointer) (gulong) (dpp_next_sid_id)));
5143 packet->receiver_sid_id = dpp_next_sid_id++;
5144 }
5145 if (packet->receiver_sid_id != packet->sender_sid_id)
5146 sid_packet_index_add(packet->receiver_sid_id, packet);
5147 }
5148
5149}
5150
5151/**
5152 * Declare that the sender of the packet is known to have a SID
5153 * that is identified by the specified buffer. There are a few
5154 * cases here:
5155 * 1. The sid of the sender is already assigned. This is a NOP.
5156 * 2. The sid has never been seen. This associates the SID with the sender SID ID.
5157 * 3. The sid has been seen, and matches the SID ID of the sender. This just sets the sid field.
5158 * 4. The sid has been seen, but with a different SID ID than ours. Patch up all the packets.
5159 */
5160static void learn_sender_sid(dof_api_data *api_data, unsigned length, const uint8_t *sid)
5161{
5162 dof_packet_data *packet;
5163 uint8_t lookup_key[256];
5164 uint8_t *key;
5165 void *value;
5166
5167 /* Validate input. */
5168 if (!api_data)
5169 {
5170 /* TODO: Print error. */
5171 return;
5172 }
5173
5174 if (!api_data->packet)
5175 {
5176 /* TODO: Print error. */
5177 return;
5178 }
5179
5180 packet = (dof_packet_data *)api_data->packet;
5181 if (!packet->sender_sid_id)
5182 return;
5183
5184 /* Check for sender SID already known. */
5185 if (packet->sender_sid)
5186 return;
5187
5188 /* The key holds the length in one octet; a longer SID is not learned */
5189 if (length > UINT8_MAX(255))
5190 return;
5191
5192 /* Check for SID already known (has assigned SID ID) */
5193 /* Build a (non-allocated) key to do the lookup. */
5194 lookup_key[0] = length;
5195 memcpy(lookup_key + 1, sid, length);
5196
5197 if (g_hash_table_lookup_extended(sid_buffer_to_sid_id, &lookup_key, (void * *)&key, &value))
5198 {
5199 unsigned sid_id = GPOINTER_TO_UINT(value)((guint) (gulong) (value));
5200
5201 /* We found a match. */
5202 if (packet->sender_sid_id == sid_id)
5203 {
5204 /* It matches our SID ID. Set the sid field. */
5205 packet->sender_sid = key;
5206 return;
5207 }
5208 else
5209 {
5210 /* There is a mis-match between SID and SID ID. Packets that stored
5211 * the provisional id are retargeted to the id this SID already has.
5212 */
5213 retarget_sid_id(packet->sender_sid_id, sid_id);
5214 }
5215
5216 return;
5217 }
5218
5219 /* The SID has never been seen. Associate with the SID ID. */
5220 key = (dof_2009_1_pdu_19_sid)g_malloc0(length + 1);
5221 memcpy(key, lookup_key, length + 1);
5222
5223 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
5224 g_hash_table_insert(sid_buffer_to_sid_id, key, GUINT_TO_POINTER(packet->sender_sid_id)((gpointer) (gulong) (packet->sender_sid_id)));
5225 g_hash_table_insert(sid_id_to_sid_buffer, GUINT_TO_POINTER(packet->sender_sid_id)((gpointer) (gulong) (packet->sender_sid_id)), key);
5226
5227 /* NOTE: We are storing a reference to the SID in the packet data. This memory
5228 * will be freed by the dissector init routine when the SID hash table is destroyed.
5229 * Nothing else should free this SID.
5230 */
5231 packet->sender_sid = (dof_2009_1_pdu_19_sid)key;
5232
5233 /* We have learned the "correct" sid and sid_id, so we can set the sid of
5234 * any packets that have this sid_id (saves hash lookups in the future).
5235 */
5236 {
5237 GSList *l;
5238 GSList *list = NULL((void*)0);
5239
5240 if (sid_id_to_packets)
5241 list = (GSList *)g_hash_table_lookup(sid_id_to_packets, GUINT_TO_POINTER(packet->sender_sid_id)((gpointer) (gulong) (packet->sender_sid_id)));
5242
5243 for (l = list; l; l = l->next)
5244 {
5245 dof_packet_data *ptr = (dof_packet_data *)l->data;
5246
5247 if (ptr->sender_sid_id == packet->sender_sid_id)
5248 ptr->sender_sid = key;
5249
5250 if (ptr->receiver_sid_id == packet->sender_sid_id)
5251 ptr->receiver_sid = key;
5252 }
5253 }
5254}
5255
5256/**
5257 * Learn a SID from an explicit operation. This only defines sids and sid ids.
5258 */
5259static void learn_operation_sid(dof_packet_data *packet, dof_2009_1_pdu_20_opid *opid, unsigned length, const uint8_t *sid)
5260{
5261 uint8_t lookup_key[256];
5262 uint8_t *key;
5263 void *value;
5264
5265 /* Check for sender SID already known. */
5266 if (opid->op_sid)
22
Assuming field 'op_sid' is null
23
Taking false branch
5267 return;
5268
5269 /* The key holds the length in one octet; a longer SID is not learned */
5270 if (length > UINT8_MAX(255))
24
Assuming 'length' is <= UINT8_MAX
25
Taking false branch
5271 return;
5272
5273 /* Check for SID already known (has assigned SID ID) */
5274 /* Build a (non-allocated) key to do the lookup. */
5275 lookup_key[0] = length;
5276 memcpy(lookup_key + 1, sid, length);
5277
5278 if (g_hash_table_lookup_extended(sid_buffer_to_sid_id, &lookup_key, (void * *)&key, &value))
26
Assuming the condition is true
27
Taking true branch
5279 {
5280 unsigned sid_id = GPOINTER_TO_UINT(value)((guint) (gulong) (value));
5281
5282 opid->op_sid_id = sid_id;
5283 opid->op_sid = key;
5284 if (packet
27.1
'packet' is non-null
&& sid_id
27.2
'sid_id' is not equal to field 'sender_sid_id'
!= packet->sender_sid_id && sid_id
27.3
'sid_id' is not equal to field 'receiver_sid_id'
!= packet->receiver_sid_id)
28
Taking true branch
5285 sid_packet_index_add(sid_id, packet);
29
Calling 'sid_packet_index_add'
34
Returning from 'sid_packet_index_add'
5286 return;
5287 }
5288
5289 /* The SID has never been seen. Associate with the SID ID. */
5290 key = (dof_2009_1_pdu_19_sid)g_malloc0(length + 1);
5291 memcpy(key, lookup_key, length + 1);
5292
5293 /* Assign the op_sid_id. */
5294 opid->op_sid_id = dpp_next_sid_id++;
5295 if (packet && opid->op_sid_id != packet->sender_sid_id && opid->op_sid_id != packet->receiver_sid_id)
5296 sid_packet_index_add(opid->op_sid_id, packet);
5297
5298 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
5299 g_hash_table_insert(sid_buffer_to_sid_id, key, GUINT_TO_POINTER(opid->op_sid_id)((gpointer) (gulong) (opid->op_sid_id)));
5300 g_hash_table_insert(sid_id_to_sid_buffer, GUINT_TO_POINTER(opid->op_sid_id)((gpointer) (gulong) (opid->op_sid_id)), key);
5301
5302 /* NOTE: We are storing a reference to the SID in the packet data. This memory
5303 * will be freed by the dissector init routine when the SID hash table is destroyed.
5304 * Nothing else should free this SID.
5305 */
5306 opid->op_sid = (dof_2009_1_pdu_19_sid)key;
5307}
5308
5309static 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)
5310{
5311 uint16_t i;
5312
5313 /* a_len = 1, t = mac_len, q = 4: (t-2)/2 : (q-1) -> 4B */
5314 mac[0] = 0x43 | (((mac_len - 2) / 2) << 3);
5315 memcpy(mac + 1, nonce, 11);
5316 memset(mac + 12, 0, 4);
5317 mac[14] = len >> 8;
5318 mac[15] = len & 0xFF;
5319
5320 gcry_cipher_encrypt(cipher_state, mac, 16, NULL((void*)0), 0);
5321
5322 mac[0] ^= (a_len >> 8);
5323 mac[1] ^= (a_len);
5324 i = 2;
5325
5326 for (int cnt = 0; cnt < a_len; cnt++, i++)
5327 {
5328 if (i % 16 == 0)
5329 gcry_cipher_encrypt(cipher_state, mac, 16, NULL((void*)0), 0);
5330
5331 mac[i % 16] ^= epp[cnt];
5332 }
5333
5334 i = 0;
5335 for (int cnt = 0; cnt < len; cnt++, i++)
5336 {
5337 if (i % 16 == 0)
5338 gcry_cipher_encrypt(cipher_state, mac, 16, NULL((void*)0), 0);
5339
5340 mac[i % 16] ^= data[cnt];
5341 }
5342
5343 gcry_cipher_encrypt(cipher_state, mac, 16, NULL((void*)0), 0);
5344}
5345
5346static gcry_cipher_hd_t ccm_packet_cipher(ccm_session_data *session, ccm_packet_data *pdata)
5347{
5348 if (!pdata || pdata->period == 0)
5349 return session->cipher_data;
5350
5351 if (session->cipher_data_table)
5352 {
5353 ccm_period_key *pk = (ccm_period_key *)g_hash_table_lookup(session->cipher_data_table, GUINT_TO_POINTER(pdata->period)((gpointer) (gulong) (pdata->period)));
5354 if (pk)
5355 return pk->cipher;
5356 }
5357 return NULL((void*)0);
5358}
5359
5360static 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)
5361{
5362 int i;
5363 unsigned char ctr[16];
5364 unsigned char encrypted_ctr[16];
5365 unsigned char mac[16];
5366 unsigned char computed_mac[16];
5367 unsigned int skip;
5368 gcry_cipher_hd_t cipher;
5369
5370 if (data == NULL((void*)0) || len <= 0)
5371 return 0;
5372
5373 /* Check the mac length. Ciphertext shorter than the MAC is rejected before any copy. */
5374 if (session->mac_len < 4 || session->mac_len > 16 || len < session->mac_len)
5375 return 0;
5376
5377 cipher = ccm_packet_cipher(session, pdata);
5378 if (!cipher)
5379 return 0;
5380
5381 /* Determine how many blocks are skipped. */
5382#if 0 /* seems to be dead code... check this! */
5383 skip = a_len + 2;
5384 skip /= 16;
5385 if ((a_len + 2) % 16)
5386 skip += 1;
5387#endif
5388 skip = 0;
5389
5390 /* This is hard-coded for q=4. This can only change with a protocol revision.
5391 Note the value is stored as (q-1). */
5392 ctr[0] = 0x03;
5393 memcpy(ctr + 1, nonce, 11);
5394 ctr[12] = 0;
5395 ctr[13] = 0;
5396 ctr[14] = 0;
5397 ctr[15] = skip; /* Preincremented below. */
5398
5399
5400 for (i = 0; i < len - session->mac_len; i++)
5401 {
5402 if (i % 16 == 0)
5403 {
5404 if (ctr[15] == 255)
5405 ctr[14] += 1;
5406 ctr[15] += 1;
5407 memcpy(encrypted_ctr, ctr, 16);
5408 gcry_cipher_encrypt(cipher, encrypted_ctr, 16, NULL((void*)0), 0);
5409 }
5410
5411 data[i] ^= encrypted_ctr[i % 16];
5412 }
5413
5414 memcpy(mac, data + i, session->mac_len);
5415
5416 ctr[12] = 0;
5417 ctr[13] = 0;
5418 ctr[14] = 0;
5419 ctr[15] = 0;
5420 memcpy(encrypted_ctr, ctr, 16);
5421 gcry_cipher_encrypt(cipher, encrypted_ctr, 16, NULL((void*)0), 0);
5422
5423 for (i = 0; i < session->mac_len; i++)
5424 mac[i] ^= encrypted_ctr[i];
5425
5426 /* Now we have to generate the MAC... */
5427 generateMac(cipher, nonce, epp, a_len, data, (int)(len - session->mac_len), computed_mac, session->mac_len);
5428 if (!memcmp(mac, computed_mac, session->mac_len))
5429 return 1;
5430
5431 /* Failure */
5432 return 0;
5433}
5434
5435/* Master Protocol Layer Handlers */
5436
5437/**
5438 * This dissector is handed a DPP packet of any version. It is responsible for decoding
5439 * the common header fields and then passing off to the specific DPP dissector
5440 */
5441static int dissect_app_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5442{
5443 col_clear(pinfo->cinfo, COL_INFO);
5444
5445 /* Compute the APP control information. This is the version and the flags byte.
5446 * The flags byte is either present, or is based on the version (and can be defaulted).
5447 */
5448 {
5449 uint16_t app;
5450 int app_len;
5451
5452 read_c2(tvb, 0, &app, &app_len);
5453
5454 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "APP(%u)", app);
5455
5456 /* call the next dissector */
5457 if (dissector_try_uint_with_data(app_dissectors, app, tvb, pinfo, tree, true1, data))
5458 {
5459 col_set_fence(pinfo->cinfo, COL_PROTOCOL);
5460 col_set_fence(pinfo->cinfo, COL_INFO);
5461
5462 return tvb_reported_length(tvb);
5463 }
5464 else
5465 {
5466 proto_tree_add_protocol_format(tree, proto_2008_1_app, tvb, 0, app_len,
5467 DOF_APPLICATION_PROTOCOL"DOF Application Protocol" ", Version: %u", app);
5468 }
5469 }
5470
5471 return 0;
5472}
5473
5474/**
5475 * This dissector is handed a DPP packet of any version. It is responsible for decoding
5476 * the common header fields and then passing off to the specific DPP dissector
5477 */
5478static int dof_dissect_dpp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5479{
5480 dof_api_data *api_data = (dof_api_data *)data;
5481 unsigned offset = 0;
5482
5483 DISSECTOR_ASSERT(api_data != NULL)((void) ((api_data != ((void*)0)) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-dof.c"
, 5483, "api_data != ((void*)0)"))))
;
5484
5485 col_clear(pinfo->cinfo, COL_INFO);
5486
5487 /* Compute the DPP control information. This is the version and the flags byte.
5488 * The flags byte is either present, or is based on the version (and can be defaulted).
5489 */
5490 {
5491 uint8_t header = tvb_get_uint8(tvb, offset);
5492 uint8_t dpp_version = header & 0x7F;
5493 uint8_t dpp_flags_included = header & 0x80;
5494 proto_item *hi;
5495 proto_tree * dpp_root,*dpp_tree;
5496
5497 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "DPPv%u", dpp_version);
5498
5499
5500 hi = proto_tree_add_protocol_format(tree, proto_2008_1_dpp, tvb, offset, 0,
5501 DOF_PRESENTATION_PROTOCOL"DOF Presentation Protocol" " Version %u, Flags: %s", dpp_version, dpp_flags_included ? "Included" : "Default");
5502
5503 dpp_root = proto_item_add_subtree(hi, ett_2008_1_dpp);
5504
5505 dpp_tree = proto_tree_add_subtree(dpp_root, tvb, offset, 1, ett_2008_1_dpp_1_header, NULL((void*)0), "Header");
5506
5507
5508 /* Version and Flag bit */
5509 proto_tree_add_item(dpp_tree, hf_2008_1_dpp_1_flag, tvb, offset, 1, ENC_NA0x00000000);
5510 proto_tree_add_item(dpp_tree, hf_2008_1_dpp_1_version, tvb, offset, 1, ENC_NA0x00000000);
5511 offset += 1;
5512
5513 /* This may, in some cases, be the end of the packet. This is only valid in some
5514 * situations, which are checked here.
5515 */
5516 if (offset == tvb_reported_length(tvb))
5517 {
5518 /* TODO: Complete this logic. */
5519
5520 proto_item_set_len(hi, offset);
5521
5522 if (!api_data)
5523 return offset;
5524
5525 if (api_data->transport_session->is_streaming)
5526 {
5527 col_append_str(pinfo->cinfo, COL_INFO, "DNP/DPP Negotiation");
5528
5529 if (pinfo->fd->visited &&
5530 api_data->transport_session->negotiation_required &&
5531 ((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)))
5532 {
5533 /* This is the second pass, so we can check for timeouts. */
5534 expert_add_info(pinfo, hi, &ei_dof_6_timeout);
5535 }
5536
5537 return offset;
5538 }
5539 }
5540
5541 /* call the next dissector */
5542 if (dissector_try_uint_with_data(dof_dpp_dissectors, dpp_version, tvb, pinfo, dpp_root, false0, data))
5543 {
5544 col_set_fence(pinfo->cinfo, COL_PROTOCOL);
5545 col_set_fence(pinfo->cinfo, COL_INFO);
5546
5547 return tvb_reported_length(tvb);
5548 }
5549 }
5550
5551 return 0;
5552}
5553
5554/**
5555 * This dissector is handed a DNP packet of any version. It is responsible for decoding
5556 * the common header fields and then passing off to the specific DNP dissector
5557 */
5558static int dof_dissect_dnp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, dof_api_data *api_data, int offset)
5559{
5560 uint8_t header = tvb_get_uint8(tvb, offset);
5561 uint8_t dnp_version = header & 0x7F;
5562 uint8_t dnp_flags_included = header & 0x80;
5563 proto_item *main_ti;
5564 proto_tree * dnp_root,*dnp_tree;
5565
5566 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "DNPv%u", dnp_version);
5567
5568 main_ti = proto_tree_add_protocol_format(tree, proto_2008_1_dnp, tvb, offset, 0,
5569 DOF_NETWORK_PROTOCOL"DOF Network Protocol" " Version %u, Flags: %s", dnp_version, dnp_flags_included ? "Included" : "Default");
5570
5571 dnp_root = proto_item_add_subtree(main_ti, ett_2008_1_dnp);
5572
5573 dnp_tree = proto_tree_add_subtree(dnp_root, tvb, offset, 1, ett_2008_1_dnp_header, NULL((void*)0), "Header");
5574
5575 /* Version and Flag bit */
5576 proto_tree_add_item(dnp_tree, hf_2008_1_dnp_1_flag, tvb, offset, 1, ENC_NA0x00000000);
5577 proto_tree_add_item(dnp_tree, hf_2008_1_dnp_1_version, tvb, offset, 1, ENC_NA0x00000000);
5578
5579 /* call the next dissector */
5580 if (dissector_try_uint_with_data(dnp_dissectors, dnp_version, tvb, pinfo, dnp_root, false0, api_data))
5581 {
5582 /* Since the transport may have additional packets in this frame, protect our work. */
5583 col_set_fence(pinfo->cinfo, COL_PROTOCOL);
5584 col_set_fence(pinfo->cinfo, COL_INFO);
5585 }
5586 else
5587 {
5588 proto_item_set_end(main_ti, tvb, 1);
5589
5590 /* During negotiation, we can move past DNP even if it is not known. */
5591 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)))
5592 {
5593 offset += dof_dissect_dpp_common(tvb_new_subset_remaining(tvb, offset + 1), pinfo, tree, api_data);
5594 }
5595 }
5596
5597 if (dnp_flags_included && !api_data->transport_session->negotiation_complete_at)
5598 {
5599 api_data->transport_session->negotiation_complete_at = pinfo->fd->num;
5600 api_data->transport_session->negotiation_complete_at_ts = pinfo->abs_ts;
5601 }
5602
5603 return offset;
5604}
5605
5606/**
5607 * This dissector is called for each DPS packet. It assumes that the first layer is
5608 * DNP, but it does not know anything about versioning. Further, it only worries
5609 * about decoding DNP (DNP will decode DPP, and so on).
5610 *
5611 * This routine is given the DPS packet for the first packet, but doesn't know anything
5612 * about DPS sessions. It may understand transport sessions, but these are surprisingly
5613 * worthless for DPS.
5614 */
5615static int dissect_dof_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5616{
5617 dof_api_data *api_data = (dof_api_data *)data;
5618 proto_tree *dof_root;
5619 dof_packet_data *packet;
5620
5621 DISSECTOR_ASSERT(api_data != NULL)((void) ((api_data != ((void*)0)) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-dof.c"
, 5621, "api_data != ((void*)0)"))))
;
5622 DISSECTOR_ASSERT(api_data->transport_session != NULL)((void) ((api_data->transport_session != ((void*)0)) ? (void
)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\""
, "epan/dissectors/packet-dof.c", 5622, "api_data->transport_session != ((void*)0)"
))))
;
5623 DISSECTOR_ASSERT(api_data->transport_packet != NULL)((void) ((api_data->transport_packet != ((void*)0)) ? (void
)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\""
, "epan/dissectors/packet-dof.c", 5623, "api_data->transport_packet != ((void*)0)"
))))
;
5624
5625 packet = (dof_packet_data *)api_data->packet;
5626
5627 /* Create the packet if it doesn't exist. */
5628 if (packet == NULL((void*)0))
5629 {
5630 api_data->packet = packet = create_packet_data(pinfo);
5631 DISSECTOR_ASSERT(packet != NULL)((void) ((packet != ((void*)0)) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-dof.c"
, 5631, "packet != ((void*)0)"))))
;
5632
5633 /* TODO: This is not correct for reversed sessions. */
5634 packet->is_sent_by_initiator = api_data->transport_packet->is_sent_by_client;
5635 }
5636
5637 /* Assign the transport sequence if it does not exist. */
5638 if (api_data->transport_session->transport_session_id == 0)
5639 api_data->transport_session->transport_session_id = globals.next_transport_session++;
5640
5641 /* Compute the DPS information. This is a master holder for general information. */
5642 {
5643 proto_item *ti;
5644
5645 ti = proto_tree_add_protocol_format(tree, proto_2008_1_dof, tvb, 0, tvb_reported_length(tvb), DOF_PROTOCOL_STACK"DOF Protocol Stack");
5646 dof_root = proto_item_add_subtree(ti, ett_2008_1_dof);
5647
5648 /* Add the general packet information. */
5649 {
5650 ti = proto_tree_add_uint(dof_root, hf_2008_1_dof_session_transport, tvb, 0, 0, api_data->transport_session->transport_session_id);
5651 proto_item_set_generated(ti);
5652
5653 ti = proto_tree_add_boolean(dof_root, hf_2008_1_dof_is_2_node, tvb, 0, 0, api_data->transport_session->is_2_node);
5654 proto_item_set_generated(ti);
5655
5656 ti = proto_tree_add_boolean(dof_root, hf_2008_1_dof_is_streaming, tvb, 0, 0, api_data->transport_session->is_streaming);
5657 proto_item_set_generated(ti);
5658
5659 if (api_data->session)
5660 {
5661 ti = proto_tree_add_uint(dof_root, hf_2008_1_dof_session, tvb, 0, 0, api_data->session->session_id);
5662 proto_item_set_generated(ti);
5663 }
5664
5665 if (api_data->secure_session)
5666 {
5667 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);
5668 proto_item_set_generated(ti);
5669 }
5670
5671 ti = proto_tree_add_uint(dof_root, hf_2008_1_dof_frame, tvb, 0, 0, packet->dof_frame);
5672 proto_item_set_generated(ti);
5673
5674 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);
5675 proto_item_set_generated(ti);
5676 }
5677 }
5678
5679 dof_dissect_dnp_common(tvb, pinfo, tree, api_data, 0);
5680
5681 packet->processed = true1;
5682 return tvb_reported_length(tvb);
5683}
5684
5685/**
5686 * This dissector is called for each DPS packet. It assumes that the first layer is
5687 * ENP, but it does not know anything about versioning. Further, it only worries
5688 * about decoding ENP (ENP will decode EPP, and so on).
5689 *
5690 * This routine is given the DPS packet for the first packet, but doesn't know anything
5691 * about DPS sessions. It may understand transport sessions, but these are surprisingly
5692 * worthless for DPS.
5693 */
5694static int dissect_tunnel_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5695{
5696 /* The packet data is the private_data, and must exist. */
5697 tcp_dof_packet_ref *ref = (tcp_dof_packet_ref *)data;
5698 unsigned offset = 0;
5699
5700 /* An Exported PDU can name this dissector without the packet reference */
5701 if (ref == NULL((void*)0))
5702 return 0;
5703
5704 /* Compute the APP control information. This is the version and the length bytes.
5705 * The flags byte is either present, or is based on the version (and can be defaulted).
5706 */
5707 {
5708 uint8_t version = tvb_get_uint8(tvb, offset);
5709 uint8_t opcode;
5710 proto_item *ti;
5711 proto_tree *app_root;
5712
5713 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "TUNv%u", version);
5714
5715 ti = proto_tree_add_protocol_format(tree, proto_2012_1_tunnel, tvb, offset, 0,
5716 "DOF Tunnel Protocol, Version: %u", version);
5717
5718 app_root = proto_item_add_subtree(ti, ett_2012_1_tunnel);
5719 proto_tree_add_item(app_root, hf_2012_1_tunnel_1_version, tvb, offset, 1, ENC_NA0x00000000);
5720 proto_tree_add_item(app_root, hf_2012_1_tunnel_1_length, tvb, offset + 1, 2, ENC_BIG_ENDIAN0x00000000);
5721
5722 opcode = tvb_get_uint8(tvb, offset + 3);
5723 if (opcode == 3)
5724 {
5725 tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset + 5);
5726
5727 dissect_dof_common(next_tvb, pinfo, tree, &ref->api_data);
5728 }
5729 }
5730
5731 return tvb_captured_length(tvb);
5732}
5733
5734static int dissect_tun_app_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
5735{
5736 col_clear(pinfo->cinfo, COL_INFO);
5737
5738 /* Compute the APP control information. This is the version and the flags byte.
5739 * The flags byte is either present, or is based on the version (and can be defaulted).
5740 */
5741 {
5742 uint16_t app;
5743 int app_len;
5744
5745
5746 app = tvb_get_uint8(tvb, 0);
5747 app_len = 1;
5748
5749 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "APP(%u)", app);
5750
5751 /* call the next dissector */
5752 if (dissector_try_uint(dof_tun_app_dissectors, app, tvb, pinfo, tree))
5753 {
5754 col_set_fence(pinfo->cinfo, COL_PROTOCOL);
5755 col_set_fence(pinfo->cinfo, COL_INFO);
5756
5757 return tvb_captured_length(tvb);
5758 }
5759 else
5760 {
5761 proto_tree_add_protocol_format(tree, proto_2012_1_tunnel, tvb, 0, app_len,
5762 DOF_APPLICATION_PROTOCOL"DOF Application Protocol" ", Version: %u", app);
5763 }
5764 }
5765
5766 return 0;
5767}
5768
5769/* Packet and Session Data Creation */
5770
5771static udp_session_data* create_udp_session_data(packet_info *pinfo, conversation_t *conversation _U___attribute__((unused)))
5772{
5773 udp_session_data *packet = wmem_new0(wmem_file_scope(), udp_session_data)((udp_session_data*)wmem_alloc0((wmem_file_scope()), sizeof(udp_session_data
)))
;
5774
5775 /* TODO: Determine if this is valid or not. */
5776 /* WMEM_COPY_ADDRESS( wmem_file_scope(), &packet->server.address, &conversation->key_ptr->addr1 );
5777 packet->server.port = conversation->key_ptr->port1; */
5778 copy_address_wmem(wmem_file_scope(), &packet->server.addr, &pinfo->dst);
5779 packet->server.port = pinfo->destport;
5780
5781 packet->common.transport_id = proto_2008_1_dof_udp;
5782
5783 {
5784 const uint8_t *addr = (const uint8_t *)packet->server.addr.data;
5785 if ((packet->server.addr.type == AT_IPv4) && (addr != NULL((void*)0)) && (addr[0] != 224))
5786 packet->common.is_2_node = true1;
5787 else
5788 packet->common.is_2_node = false0;
5789 }
5790
5791 packet->common.is_streaming = false0;
5792 packet->common.session_start_ts = pinfo->abs_ts;
5793 packet->common.negotiation_required = false0;
5794 packet->common.negotiation_complete_at = 0;
5795
5796 return packet;
5797}
5798
5799static tcp_session_data* create_tcp_session_data(packet_info *pinfo, conversation_t *conversation)
5800{
5801 tcp_session_data *packet = wmem_new0(wmem_file_scope(), tcp_session_data)((tcp_session_data*)wmem_alloc0((wmem_file_scope()), sizeof(tcp_session_data
)))
;
5802
5803 copy_address_wmem(wmem_file_scope(), &packet->client.addr, conversation_key_addr1(conversation->key_ptr));
5804 packet->client.port = conversation_key_port1(conversation->key_ptr);
5805 copy_address_wmem(wmem_file_scope(), &packet->server.addr, conversation_key_addr2(conversation->key_ptr));
5806 packet->server.port = conversation_key_port2(conversation->key_ptr);
5807
5808 packet->not_dps = false0;
5809
5810 packet->common.transport_id = proto_2008_1_dof_tcp;
5811 packet->common.is_2_node = true1;
5812 packet->common.is_streaming = true1;
5813 packet->common.session_start_ts = pinfo->abs_ts;
5814 packet->common.negotiation_required = true1;
5815 packet->common.negotiation_complete_at = 0;
5816
5817 return packet;
5818}
5819
5820static dof_packet_data* create_packet_data(packet_info *pinfo)
5821{
5822 /* Create the packet data. */
5823 dof_packet_data *packet = wmem_new0(wmem_file_scope(), dof_packet_data)((dof_packet_data*)wmem_alloc0((wmem_file_scope()), sizeof(dof_packet_data
)))
;
5824
5825 packet->data_list = wmem_list_new(wmem_file_scope());
5826 packet->frame = pinfo->fd->num;
5827 packet->dof_frame = next_dof_frame++;
5828
5829 /* Add the packet into the list of packets. */
5830 if (!globals.dof_packet_head)
5831 {
5832 globals.dof_packet_head = packet;
5833 globals.dof_packet_tail = packet;
5834 }
5835 else
5836 {
5837 globals.dof_packet_tail->next = packet;
5838 globals.dof_packet_tail = packet;
5839 }
5840
5841 return packet;
5842}
5843
5844/* Dissectors for Transports (UDP/TCP) */
5845
5846/**
5847 * Dissect a UDP packet. The parent protocol is UDP. No assumptions about DPS
5848 * data structures are made on input, but before calling common they must
5849 * be set up.
5850 * This dissector is registered with the UDP protocol on the standard DPS port.
5851 * It will be used for anything that involves that port (source or destination).
5852 */
5853static int dissect_dof_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
5854{
5855 dof_api_data *api_data = (dof_api_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_2008_1_dof_udp, 0);
5856 if (api_data == NULL((void*)0))
5857 {
5858 conversation_t *conversation;
5859 udp_session_data *transport_session;
5860 dof_transport_packet *transport_packet;
5861 /* bool mcast = false; */
5862
5863 /* {
5864 uint8_t* addr = (uint8_t*) pinfo->dst.data;
5865 if ( (pinfo->dst.type == AT_IPv4) && (addr != NULL) && (addr[0] != 224) )
5866 mcast = true;
5867 } */
5868
5869 /* Register the source address as being DPS for the sender UDP port. */
5870 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport, pinfo->destport, NO_ADDR_B0x00010000 | NO_PORT_B0x00020000);
5871 if (!conversation)
5872 {
5873 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport, pinfo->destport, NO_ADDR20x01 | NO_PORT20x02);
5874 conversation_set_dissector(conversation, dof_udp_handle);
5875 }
5876
5877 /* Find or create the conversation for this transport session. For UDP, the transport session is determined entirely by the
5878 * server port. This assumes that the first packet seen is from a client to the server.
5879 */
5880 conversation = find_conversation(pinfo->fd->num, &pinfo->dst, &pinfo->src, CONVERSATION_UDP, pinfo->destport, pinfo->srcport, NO_ADDR_B0x00010000 | NO_PORT_B0x00020000);
5881 if (conversation)
5882 {
5883 /* TODO: Determine if this is valid or not. */
5884 /*if ( conversation->key_ptr->port1 != pinfo->destport || ! addresses_equal( &conversation->key_ptr->addr1, &pinfo->dst ) )
5885 conversation = NULL; */
5886 }
5887
5888 if (!conversation)
5889 conversation = conversation_new(pinfo->fd->num, &pinfo->dst, &pinfo->src, CONVERSATION_UDP, pinfo->destport, pinfo->srcport, NO_ADDR20x01 | NO_PORT20x02 | CONVERSATION_TEMPLATE0x08);
5890
5891 transport_session = (udp_session_data *)conversation_get_proto_data(conversation, proto_2008_1_dof_udp);
5892 if (transport_session == NULL((void*)0))
5893 {
5894 transport_session = create_udp_session_data(pinfo, conversation);
5895 conversation_add_proto_data(conversation, proto_2008_1_dof_udp, transport_session);
5896 }
5897
5898 /* UDP has no framing or retransmission issues, so the dof_api_data is stored directly on the frame. */
5899 api_data = wmem_new0(wmem_file_scope(), dof_api_data)((dof_api_data*)wmem_alloc0((wmem_file_scope()), sizeof(dof_api_data
)))
;
5900 if (api_data == NULL((void*)0))
5901 return 0;
5902
5903 transport_packet = wmem_new0(wmem_file_scope(), dof_transport_packet)((dof_transport_packet*)wmem_alloc0((wmem_file_scope()), sizeof
(dof_transport_packet)))
;
5904 if (transport_packet == NULL((void*)0))
5905 return 0;
5906
5907 transport_packet->is_sent_by_client = true1;
5908 if (addresses_equal(&transport_session->server.addr, &pinfo->src) && (transport_session->server.port == pinfo->srcport))
5909 transport_packet->is_sent_by_client = false0;
5910
5911 transport_packet->sender_id = assign_addr_port_id(pinfo->pool, &pinfo->src, pinfo->srcport);
5912 transport_packet->receiver_id = assign_addr_port_id(pinfo->pool, &pinfo->dst, pinfo->destport);
5913
5914 api_data->transport_session = &transport_session->common;
5915 api_data->transport_packet = transport_packet;
5916 p_add_proto_data(wmem_file_scope(), pinfo, proto_2008_1_dof_udp, 0, api_data);
5917 }
5918
5919 return dissect_dof_common(tvb, pinfo, tree, api_data);
5920}
5921
5922/**
5923 * Determine if the current offset has already been processed.
5924 * This is specific to the TCP dissector.
5925 */
5926static bool_Bool is_retransmission(packet_info *pinfo, tcp_session_data *session, tcp_packet_data *packet, struct tcpinfo *tcpinfo)
5927{
5928 /* TODO: Determine why we get big numbers sometimes... */
5929 /* if ( tcpinfo->seq != 0 && tcpinfo->seq < 1000000) */
5930 {
5931 tcp_ignore_data *id;
5932 uint32_t sequence = tcpinfo->seq;
5933
5934 if (addresses_equal(&pinfo->src, &session->client.addr) && (pinfo->srcport == session->client.port))
5935 {
5936 id = packet->from_client_ignore_list;
5937 }
5938 else
5939 {
5940 id = packet->from_server_ignore_list;
5941 }
5942
5943 while (id != NULL((void*)0) && id->sequence != sequence)
5944 {
5945 id = id->next;
5946 }
5947
5948 if (id == NULL((void*)0))
5949 return false0;
5950
5951 return id->ignore;
5952 }
5953
5954 return false0;
5955}
5956
5957/**
5958 * We have found and processed packets starting at offset, so
5959 * don't allow the same (or previous) packets.
5960 * This only applies to TCP dissector conversations.
5961 */
5962static void remember_offset(packet_info *pinfo, tcp_session_data *session, tcp_packet_data *packet, struct tcpinfo *tcpinfo)
5963{
5964 bool_Bool ignore = false0;
5965
5966 /* TODO: Determine why we get big numbers sometimes... */
5967 /* if ( tcpinfo->seq != 0 && tcpinfo->seq < 1000000) */
5968 {
5969 tcp_ignore_data **last;
5970 tcp_ignore_data *id;
5971 uint32_t sequence;
5972 uint32_t *seqptr = NULL((void*)0);
5973
5974 if (addresses_equal(&pinfo->src, &session->client.addr) && (pinfo->srcport == session->client.port))
5975 {
5976 last = &(packet->from_client_ignore_list);
5977 id = packet->from_client_ignore_list;
5978 sequence = tcpinfo->seq;
5979 seqptr = &session->from_client_seq;
5980
5981 if (LE_SEQ(tcpinfo->seq, session->from_client_seq)((int32_t)((tcpinfo->seq) - (session->from_client_seq))
<= 0)
)
5982 ignore = true1;
5983 }
5984 else
5985 {
5986 last = &(packet->from_server_ignore_list);
5987 id = packet->from_server_ignore_list;
5988 sequence = tcpinfo->seq;
5989 seqptr = &session->from_server_seq;
5990
5991 if (LE_SEQ(tcpinfo->seq, session->from_server_seq)((int32_t)((tcpinfo->seq) - (session->from_server_seq))
<= 0)
)
5992 ignore = true1;
5993 }
5994
5995 while (id != NULL((void*)0) && id->sequence != tcpinfo->seq)
5996 {
5997 last = &(id->next);
5998 id = id->next;
5999 }
6000
6001 *seqptr = sequence;
6002 if (id == NULL((void*)0))
6003 {
6004 *last = wmem_new0(wmem_file_scope(), tcp_ignore_data)((tcp_ignore_data*)wmem_alloc0((wmem_file_scope()), sizeof(tcp_ignore_data
)))
;
6005 id = *last;
6006 id->ignore = ignore;
6007 id->sequence = tcpinfo->seq;
6008 }
6009 }
6010}
6011
6012/**
6013 * This dissector is registered with TCP using the standard port. It uses registered
6014 * protocols to determine framing, and those dissectors will call into the base
6015 * DPS dissector for each packet.
6016 */
6017static int dissect_dof_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6018{
6019 conversation_t *conversation;
6020 tcp_session_data *session;
6021 tcp_packet_data *packet;
6022 struct tcpinfo *tcpinfo = (struct tcpinfo *)data;
6023 uint8_t header;
6024
6025 /* Get the TCP conversation. TCP creates a new conversation for each TCP connection,12
6026 * so we can "mirror" that by attaching our own data to that conversation. If our
6027 * data cannot be found, then it is a new connection (to us).
6028 */
6029 conversation = find_conversation_pinfo(pinfo, 0);
6030 {
6031 /* This should be impossible - the TCP dissector requires this conversation.
6032 * Bail...
6033 */
6034 DISSECTOR_ASSERT(conversation != NULL)((void) ((conversation != ((void*)0)) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-dof.c"
, 6034, "conversation != ((void*)0)"))))
;
6035 }
6036
6037
6038 /* This requires explanation. TCP will call this dissector, and we know
6039 * that the first byte (offset 0 of this tvb) is the first byte of an
6040 * DPS packet. The TCP dissector ensures this.
6041 *
6042 * We do *not* know that this is the only packet, and
6043 * so the dissector that we call below must handle framing. All of
6044 * this state must be stored, and so we store it in a transport
6045 * data structure. DPS packet data is created later and associated
6046 * differently.
6047 *
6048 * Further, this routine MAY be called MULTIPLE times for the SAME
6049 * frame with DIFFERENT sequence numbers. This makes handling
6050 * retransmissions very difficult - we must track each call to this
6051 * routine with its associated offset and ignore flag. However, due
6052 * to the way that Wireshark handles asking for more data we cannot
6053 * mark an offset as "duplicate" until after it has been processed.
6054 */
6055
6056 /* TCP packet data is only associated with TCP frames that hold DPS packets. */
6057 session = (tcp_session_data *)conversation_get_proto_data(conversation, proto_2008_1_dof_tcp);
6058 if (session == NULL((void*)0))
6059 {
6060 session = create_tcp_session_data(pinfo, conversation);
6061 conversation_add_proto_data(conversation, proto_2008_1_dof_tcp, session);
6062 }
6063
6064 if (session->not_dps)
6065 return 0;
6066
6067 packet = (tcp_packet_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_2008_1_dof_tcp, 0);
6068 if (packet == NULL((void*)0))
6069 {
6070 packet = wmem_new0(wmem_file_scope(), tcp_packet_data)((tcp_packet_data*)wmem_alloc0((wmem_file_scope()), sizeof(tcp_packet_data
)))
;
6071 p_add_proto_data(wmem_file_scope(), pinfo, proto_2008_1_dof_tcp, 0, packet);
6072 }
6073
6074 if (is_retransmission(pinfo, session, packet, tcpinfo))
6075 return 0;
6076
6077 /* Loop, checking all the packets in this frame and communicating with the TCP
6078 * desegmenter. The framing dissector entry is used to determine the size
6079 * of the current frame.
6080 */
6081 {
6082 /* Note that we must handle fragmentation on TCP... */
6083 unsigned offset = 0;
6084
6085 while (offset < tvb_reported_length(tvb))
6086 {
6087 int available = tvb_ensure_captured_length_remaining(tvb, offset);
6088 int packet_length;
6089
6090 header = tvb_get_uint8(tvb, offset);
6091
6092 /* If we are negotiating, then we do not need the framing dissector
6093 * as we know the packet length is two. Note that for the first byte
6094 * of a TCP session there are only two cases, both handled here. An error
6095 * of not understanding the first byte will trigger that this is not
6096 * a DPS session.
6097 */
6098 if (((header & 0x80) == 0) && session->common.negotiation_required && ((pinfo->fd->num < session->common.negotiation_complete_at) || (session->common.negotiation_complete_at == 0)))
6099 {
6100 packet_length = 2;
6101 if (header > DNP_MAX_VERSION1)
6102 {
6103 session->not_dps = true1;
6104 return 0;
6105 }
6106 }
6107 else
6108 {
6109 packet_length = dof_dissect_dnp_length(tvb, pinfo, header & 0x7F, &offset);
6110 if (packet_length < 0)
6111 {
6112 session->not_dps = true1;
6113 return offset;
6114 }
6115 }
6116
6117 if (packet_length == 0)
6118 {
6119 pinfo->desegment_offset = offset;
6120 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
6121 return offset + available;
6122 }
6123
6124 if (available < packet_length)
6125 {
6126 pinfo->desegment_offset = offset;
6127 pinfo->desegment_len = packet_length - available;
6128 return offset + available;
6129 }
6130
6131 remember_offset(pinfo, session, packet, tcpinfo);
6132 if (is_retransmission(pinfo, session, packet, tcpinfo))
6133 return 0;
6134
6135 /* We have a packet. We have to store the dof_packet_data in a list, as there may be
6136 * multiple DPS packets in a single Wireshark frame.
6137 */
6138 {
6139 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, packet_length);
6140 tcp_dof_packet_ref *ref;
6141 int raw_offset = tvb_raw_offset(tvb) + offset;
6142 bool_Bool ref_is_new = false0;
6143
6144 /* Get the packet data. This is a list in increasing sequence order. */
6145 if (packet->dof_packets == NULL((void*)0))
6146 {
6147 ref_is_new = true1;
6148 ref = wmem_new0(wmem_file_scope(), tcp_dof_packet_ref)((tcp_dof_packet_ref*)wmem_alloc0((wmem_file_scope()), sizeof
(tcp_dof_packet_ref)))
;
6149 ref->transport_packet.sender_id = assign_addr_port_id(pinfo->pool, &pinfo->src, pinfo->srcport);
6150 ref->transport_packet.receiver_id = assign_addr_port_id(pinfo->pool, &pinfo->dst, pinfo->destport);
6151 packet->dof_packets = ref;
6152 ref->start_offset = raw_offset;
6153 }
6154 else
6155 ref = packet->dof_packets;
6156
6157 /* Find the entry for our offset. */
6158 while (ref->start_offset != raw_offset)
6159 {
6160 if (ref->next)
6161 {
6162 ref = ref->next;
6163 continue;
6164 }
6165
6166 {
6167 tcp_dof_packet_ref *last = ref;
6168
6169 /* This is the default state, NULL and 0. */
6170 ref_is_new = true1;
6171 ref = wmem_new0(wmem_file_scope(), tcp_dof_packet_ref)((tcp_dof_packet_ref*)wmem_alloc0((wmem_file_scope()), sizeof
(tcp_dof_packet_ref)))
;
6172 ref->transport_packet.sender_id = last->transport_packet.sender_id;
6173 ref->transport_packet.receiver_id = last->transport_packet.receiver_id;
6174 ref->start_offset = raw_offset;
6175 last->next = ref;
6176 }
6177 }
6178
6179 if (ref_is_new)
6180 {
6181 dof_transport_packet *tp = &(ref->transport_packet);
6182
6183 tp->is_sent_by_client = false0;
6184 if (addresses_equal(&session->client.addr, &pinfo->src) &&
6185 (session->client.port == pinfo->srcport))
6186 tp->is_sent_by_client = true1;
6187
6188 ref->api_data.transport_session = (dof_transport_session *)&(session->common);
6189 ref->api_data.transport_packet = tp;
6190 }
6191
6192
6193 dissect_dof_common(next_tvb, pinfo, tree, &ref->api_data);
6194 }
6195
6196 offset += packet_length;
6197 }
6198
6199 return offset;
6200 }
6201}
6202
6203#if 0 /* TODO not used yet */
6204/**
6205 * This dissector is registered with the UDP protocol on the standard DPS port.
6206 * It will be used for anything that involves that port (source or destination).
6207 */
6208#if 0
6209static int dissect_tunnel_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
6210{
6211 conversation_t *conversation;
6212 dof_packet_data *packet;
6213
6214 /* Initialize the default transport session structure. */
6215 if (!udp_transport_session)
6216 udp_transport_session = se_alloc0(sizeof(*udp_transport_session));
6217
6218 conversation = find_or_create_conversation(pinfo);
6219
6220 /* Add the packet data. */
6221 packet = p_get_proto_data(wmem_file_scope(), proto_2012_1_tunnel, 0);
6222 if (!packet)
6223 {
6224 packet = wmem_alloc0(wmem_file_scope(), sizeof(dof_packet_data));
6225 packet->frame = pinfo->fd->num;
6226 packet->next = NULL((void*)0);
6227 packet->start_offset = 0;
6228 packet->session_counter = &session_counter;
6229 packet->transport_session = udp_transport_session;
6230 p_add_proto_data(wmem_file_scope(), proto_2012_1_tunnel, 0, packet);
6231 }
6232
6233 pinfo->private_data = packet;
6234 return dissect_tunnel_common(tvb, pinfo, tree);
6235#else
6236static int dissect_tunnel_udp(tvbuff_t *tvb _U___attribute__((unused)), packet_info *pinfo _U___attribute__((unused)), proto_tree *tree _U___attribute__((unused)), void *data _U___attribute__((unused)))
6237{
6238#endif
6239 return 0;
6240}
6241#endif
6242
6243
6244/**
6245 * This dissector is registered with TCP using the standard port. It uses registered
6246 * protocols to determine framing, and those dissectors will call into the base
6247 * DPS dissector for each packet.
6248 */
6249static int dissect_tunnel_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6250{
6251 conversation_t *conversation;
6252 tcp_session_data *session;
6253 tcp_packet_data *packet;
6254 struct tcpinfo *tcpinfo = (struct tcpinfo *)data;
6255
6256 /* Get the TCP conversation. TCP creates a new conversation for each TCP connection,
6257 * so we can "mirror" that by attaching our own data to that conversation. If our
6258 * data cannot be found, then it is a new connection (to us).
6259 */
6260 conversation = find_conversation_pinfo(pinfo, 0);
6261 {
6262 /* This should be impossible - the TCP dissector requires this conversation.
6263 * Bail...
6264 */
6265 DISSECTOR_ASSERT(conversation != NULL)((void) ((conversation != ((void*)0)) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-dof.c"
, 6265, "conversation != ((void*)0)"))))
;
6266 }
6267
6268
6269 /* This requires explanation. TCP will call this dissector, and we know
6270 * that the first byte (offset 0 of this tvb) is the first byte of an
6271 * DPS packet. The TCP dissector ensures this.
6272 *
6273 * We do *not* know that this is the only packet, and
6274 * so the dissector that we call below must handle framing. All of
6275 * this state must be stored, and so we store it in a transport
6276 * data structure. DPS packet data is created later and associated
6277 * differently.
6278 *
6279 * Further, this routine MAY be called MULTIPLE times for the SAME
6280 * frame with DIFFERENT sequence numbers. This makes handling
6281 * retransmissions very difficult - we must track each call to this
6282 * routine with its associated offset and ignore flag. However, due
6283 * to the way that Wireshark handles asking for more data we cannot
6284 * mark an offset as "duplicate" until after it has been processed.
6285 */
6286
6287 /* TCP packet data is only associated with TCP frames that hold DPS packets. */
6288 session = (tcp_session_data *)conversation_get_proto_data(conversation, proto_2012_1_tunnel);
6289 if (session == NULL((void*)0))
6290 {
6291 session = create_tcp_session_data(pinfo, conversation);
6292 conversation_add_proto_data(conversation, proto_2012_1_tunnel, session);
6293 }
6294
6295 packet = (tcp_packet_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_2012_1_tunnel, 0);
6296 if (packet == NULL((void*)0))
6297 {
6298 packet = wmem_new0(wmem_file_scope(), tcp_packet_data)((tcp_packet_data*)wmem_alloc0((wmem_file_scope()), sizeof(tcp_packet_data
)))
;
6299 p_add_proto_data(wmem_file_scope(), pinfo, proto_2012_1_tunnel, 0, packet);
6300 }
6301
6302 if (is_retransmission(pinfo, session, packet, tcpinfo))
6303 return 0;
6304
6305 /* Loop, checking all the packets in this TCP frame.
6306 */
6307 {
6308 /* Note that we must handle fragmentation on TCP... */
6309 unsigned offset = 0;
6310
6311 while (offset < tvb_reported_length(tvb))
6312 {
6313 int available = tvb_reported_length_remaining(tvb, offset);
6314 int packet_length;
6315 int header_length;
6316 int i;
6317
6318 if (available < 3)
6319 {
6320 pinfo->desegment_offset = offset;
6321 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
6322 return offset + available;
6323 }
6324
6325 packet_length = 0;
6326 header_length = 3;
6327
6328 for (i = 0; i < 2; i++)
6329 packet_length = packet_length * 256 + tvb_get_uint8(tvb, offset + 1 + i);
6330
6331 packet_length += header_length;
6332
6333 if (available < packet_length)
6334 {
6335 pinfo->desegment_offset = offset;
6336 pinfo->desegment_len = packet_length - available;
6337 return offset + available;
6338 }
6339
6340 /* We have a packet. We have to store the dof_packet_data in a list, as there may be
6341 * multiple DPS packets in a single Wireshark frame.
6342 */
6343 {
6344 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, packet_length);
6345 tcp_dof_packet_ref *ref;
6346 int raw_offset = tvb_raw_offset(tvb) + offset;
6347 bool_Bool ref_is_new = false0;
6348
6349 /* Get the packet data. This is a list in increasing sequence order. */
6350 if (packet->dof_packets == NULL((void*)0))
6351 {
6352 ref_is_new = true1;
6353 ref = wmem_new0(wmem_file_scope(), tcp_dof_packet_ref)((tcp_dof_packet_ref*)wmem_alloc0((wmem_file_scope()), sizeof
(tcp_dof_packet_ref)))
;
6354 ref->transport_packet.sender_id = assign_addr_port_id(pinfo->pool, &pinfo->src, pinfo->srcport);
6355 ref->transport_packet.receiver_id = assign_addr_port_id(pinfo->pool, &pinfo->dst, pinfo->destport);
6356 packet->dof_packets = ref;
6357 ref->start_offset = raw_offset;
6358 }
6359 else
6360 ref = packet->dof_packets;
6361
6362 /* Find the entry for our offset. */
6363 while (ref->start_offset != raw_offset)
6364 {
6365 if (ref->next)
6366 {
6367 ref = ref->next;
6368 continue;
6369 }
6370
6371 {
6372 tcp_dof_packet_ref *last = ref;
6373
6374 /* This is the default state, NULL and 0. */
6375 ref_is_new = true1;
6376 ref = wmem_new0(wmem_file_scope(), tcp_dof_packet_ref)((tcp_dof_packet_ref*)wmem_alloc0((wmem_file_scope()), sizeof
(tcp_dof_packet_ref)))
;
6377 ref->transport_packet.sender_id = last->transport_packet.sender_id;
6378 ref->transport_packet.receiver_id = last->transport_packet.receiver_id;
6379 ref->start_offset = raw_offset;
6380 last->next = ref;
6381 }
6382 }
6383
6384 if (ref_is_new)
6385 {
6386 dof_transport_packet *tp = &(ref->transport_packet);
6387
6388 tp->is_sent_by_client = false0;
6389 if (addresses_equal(&session->client.addr, &pinfo->src) &&
6390 (session->client.port == pinfo->srcport))
6391 tp->is_sent_by_client = true1;
6392
6393 ref->api_data.transport_session = (dof_transport_session *)&(session->common);
6394 ref->api_data.transport_packet = tp;
6395 }
6396
6397 /* Manage the private data, restoring the existing value. Call the common dissector. */
6398 {
6399 dissect_tunnel_common(next_tvb, pinfo, tree, ref);
6400 }
6401 }
6402
6403 offset += packet_length;
6404 }
6405
6406 return tvb_captured_length(tvb);
6407 }
6408}
6409
6410/* Dissectors */
6411
6412static int dissect_dnp_0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
6413{
6414 unsigned offset = 0;
6415
6416 uint8_t dnp_flags_included = 0;
6417
6418 offset = 0;
6419 col_clear(pinfo->cinfo, COL_INFO);
6420
6421 /* Compute the DNP control information. This is the version and the flags byte.
6422 * The flags byte is either present, or is based on the version (and can be defaulted).
6423 */
6424 {
6425 uint8_t header = tvb_get_uint8(tvb, offset);
6426
6427 dnp_flags_included = (header & 0x80) != 0;
6428
6429 offset += 1;
6430
6431 {
6432 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DNPv0 ");
6433
6434 if (dnp_flags_included)
6435 {
6436 /* TODO: Protocol violation. */
6437 }
6438
6439 if (tvb_reported_length(tvb) == offset)
6440 col_set_str(pinfo->cinfo, COL_INFO, "Query");
6441 else
6442 {
6443 uint8_t first = tvb_get_uint8(tvb, offset);
6444 if (first == 0)
6445 {
6446 /* Query with padding. */
6447 col_set_str(pinfo->cinfo, COL_INFO, "Query");
6448 proto_tree_add_item(tree, hf_2008_1_dnp_0_1_1_padding, tvb, offset, -1, ENC_NA0x00000000);
6449 }
6450 else
6451 {
6452 /* Response. */
6453 col_set_str(pinfo->cinfo, COL_INFO, "Query Response");
6454 while (first)
6455 {
6456 proto_tree_add_item(tree, hf_2008_1_dnp_0_1_1_version, tvb, offset, 1, ENC_NA0x00000000);
6457 offset += 1;
6458 if (offset == tvb_reported_length(tvb))
6459 break;
6460
6461 first = tvb_get_uint8(tvb, offset);
6462 }
6463
6464 if (offset < tvb_reported_length(tvb))
6465 proto_tree_add_item(tree, hf_2008_1_dnp_0_1_1_padding, tvb, offset, -1, ENC_NA0x00000000);
6466 }
6467 }
6468 }
6469 }
6470
6471 col_set_fence(pinfo->cinfo, COL_PROTOCOL);
6472 col_set_fence(pinfo->cinfo, COL_INFO);
6473 return tvb_reported_length(tvb);
6474}
6475
6476/**
6477 * Determine the length of the packet in tvb, starting at an offset that is passed as a
6478 * pointer in private_data.
6479 * Return 0 if the length cannot be determined because there is not enough data in
6480 * the buffer, otherwise return the length of the packet.
6481 */
6482static int determine_packet_length_1(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree _U___attribute__((unused)), void *data)
6483{
6484 /* Note that we must handle fragmentation on TCP... */
6485 int offset = *((int *)data);
6486
6487 {
6488 int available = tvb_ensure_captured_length_remaining(tvb, offset);
6489 uint8_t header, flags;
6490 uint8_t size;
6491 uint8_t i;
6492 int data_len, header_len;
6493
6494 if (available < 2)
6495 return 0;
6496
6497 header = tvb_get_uint8(tvb, offset);
6498 data_len = 0;
6499
6500 if ((header & 0x80) == 0)
6501 {
6502 /* The length is fixed in this case... */
6503 data_len = 0;
6504 header_len = 2;
6505 size = 0;
6506 }
6507 else
6508 {
6509 flags = tvb_get_uint8(tvb, offset + 1);
6510 size = flags & 0x03;
6511 header_len = 2 + size;
6512 }
6513
6514 if (available < header_len)
6515 return 0;
6516
6517 for (i = 0; i < size; i++)
6518 data_len = data_len * 256 + tvb_get_uint8(tvb, offset + 2 + i);
6519
6520 return header_len + data_len;
6521 }
6522}
6523
6524static int dissect_dnp_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6525{
6526 unsigned offset = 0;
6527 dof_api_data *api_data = (dof_api_data *)data;
6528 dof_packet_data *packet;
6529
6530 int8_t dnp_version = -1;
6531 uint8_t dnp_flags_included = 0;
6532 uint8_t dnp_length_length = 0;
6533 uint32_t dnp_flags = 0;
6534
6535 unsigned length = 0;
6536 unsigned encapsulated_length = 0;
6537
6538 int i;
6539
6540 proto_tree *dnp_tree = tree;
6541
6542 if (!api_data)
6543 {
6544 /* TODO: Print error */
6545 return 0;
6546 }
6547
6548 if (!api_data->packet)
6549 {
6550 /* TODO: Print error */
6551 return 0;
6552 }
6553
6554 packet = api_data->packet;
6555
6556 offset = 0;
6557 col_clear(pinfo->cinfo, COL_INFO);
6558
6559 /* Compute the DNP control information. This is the version and the flags byte.
6560 * The flags byte is either present, or is based on the version (and can be defaulted).
6561 */
6562 {
6563 uint8_t header = tvb_get_uint8(tvb, offset);
6564 uint32_t dnp_src_port = 0;
6565 uint32_t dnp_dst_port = 0;
6566
6567 dnp_version = header & 0x7F;
6568 dnp_flags_included = (header & 0x80) != 0;
6569
6570
6571 offset += 1;
6572
6573 {
6574 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DNPv1 ");
6575
6576 if (dnp_flags_included)
6577 {
6578 /* Including flags always terminates negotiation. */
6579 /* packet->negotiated = true; */
6580
6581 proto_item *flags_item;
6582
6583 dnp_flags = tvb_get_uint8(tvb, offset);
6584 flags_item = 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_ENDIAN0x00000000);
6585 if ((dnp_flags & 0xF0) != 0)
6586 expert_add_info(pinfo, flags_item, &ei_dof_10_flags_zero);
6587
6588 offset += 1;
6589 }
6590 else
6591 dnp_flags = DNP_V1_DEFAULT_FLAGS(0);
6592
6593 /* Determine the size of the length field. */
6594 dnp_length_length = dnp_flags & 0x03;
6595 if (dnp_length_length)
6596 proto_tree_add_item(dnp_tree, hf_2009_9_dnp_1_length, tvb, offset, dnp_length_length, ENC_BIG_ENDIAN0x00000000);
6597
6598 /* Read the length. */
6599 length = 0;
6600 for (i = 0; i < dnp_length_length; i++)
6601 length = (length << 8) | tvb_get_uint8(tvb, offset + i);
6602
6603 /* Validate the length. */
6604#if 0
6605 if ( (length == 0) && packet->negotiated && session && ! session->connectionless )
6606 {
6607 expert_add_info( pinfo, NULL((void*)0), &ei_dof_13_length_specified );
6608 }
6609#endif
6610
6611 offset += dnp_length_length;
6612
6613 /* If there isn't a length specified then use the packet size. */
6614 if (dnp_length_length == 0)
6615 length = tvb_reported_length_remaining(tvb, offset);
6616
6617 encapsulated_length = length;
6618
6619 /* Read the srcport */
6620 if (dnp_flags & 0x04)
6621 {
6622 int s_offset = offset;
6623 proto_item *item;
6624 int dnp_src_port_len;
6625
6626 offset = read_c3(tvb, offset, &dnp_src_port, &dnp_src_port_len);
6627 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);
6628 validate_c3(pinfo, item, dnp_src_port, dnp_src_port_len);
6629 if (s_offset < 0 || offset < (unsigned)s_offset || offset - (unsigned)s_offset > encapsulated_length)
6630 {
6631 expert_add_info(pinfo, item, &ei_dof_dnp_length_short);
6632 return offset;
6633 }
6634 encapsulated_length -= offset - (unsigned)s_offset;
6635 }
6636 else
6637 {
6638 proto_item *item = proto_tree_add_uint_format(dnp_tree, hf_2009_9_dnp_1_srcport, tvb, 0, 0, 0, "Source Address: %u", 0);
6639 proto_item_set_generated(item);
6640 }
6641
6642 /* Read the dstport */
6643 if (dnp_flags & 0x08)
6644 {
6645 int s_offset = offset;
6646 int dnp_dst_port_len;
6647 proto_item *item;
6648
6649 offset = read_c3(tvb, offset, &dnp_dst_port, &dnp_dst_port_len);
6650 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);
6651 validate_c3(pinfo, item, dnp_dst_port, dnp_dst_port_len);
6652 if (s_offset < 0 || offset < (unsigned)s_offset || offset - (unsigned)s_offset > encapsulated_length)
6653 {
6654 expert_add_info(pinfo, item, &ei_dof_dnp_length_short);
6655 return offset;
6656 }
6657 encapsulated_length -= offset - (unsigned)s_offset;
6658 }
6659 else
6660 {
6661 proto_item *item = proto_tree_add_uint_format(dnp_tree, hf_2009_9_dnp_1_dstport, tvb, 0, 0, 0, "Destination Address: %u", 0);
6662 proto_item_set_generated(item);
6663 }
6664 }
6665
6666 proto_item_set_end(tree, tvb, offset);
6667
6668 /* Given the transport session and the DPS port information, determine the DPS session. */
6669 if (api_data->session == NULL((void*)0))
6670 {
6671 uint32_t client;
6672 uint32_t server;
6673
6674 if (api_data->transport_packet->is_sent_by_client)
6675 {
6676 client = dnp_src_port;
6677 server = dnp_dst_port;
6678 }
6679 else
6680 {
6681 client = dnp_dst_port;
6682 server = dnp_src_port;
6683 }
6684
6685 api_data->session = dof_ns_session_retrieve(api_data->transport_session->transport_session_id, client, server);
6686 if (api_data->session == NULL((void*)0))
6687 {
6688 dof_session_data *sdata = wmem_new0(wmem_file_scope(), dof_session_data)((dof_session_data*)wmem_alloc0((wmem_file_scope()), sizeof(dof_session_data
)))
;
6689 dof_ns_session_define(api_data->transport_session->transport_session_id, client, server, sdata);
6690 sdata->session_id = globals.next_session++;
6691 sdata->dof_id = dnp_version;
6692 api_data->session = sdata;
6693 }
6694 }
6695
6696 packet->sender_id = dnp_src_port;
6697 packet->receiver_id = dnp_dst_port;
6698
6699 /* Assuming there is more, it must be DPP. */
6700
6701 /* We have a packet. */
6702 {
6703 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, encapsulated_length);
6704 offset += dof_dissect_dpp_common(next_tvb, pinfo, proto_item_get_parent(tree), data);
6705 }
6706 }
6707
6708 col_set_fence(pinfo->cinfo, COL_PROTOCOL);
6709 col_set_fence(pinfo->cinfo, COL_INFO);
6710 return offset;
6711}
6712
6713static int dissect_dpp_0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
6714{
6715 unsigned offset = 0;
6716
6717 uint8_t dpp_flags_included = 0;
6718
6719 offset = 0;
6720 col_clear(pinfo->cinfo, COL_INFO);
6721
6722 /* Compute the DPP control information. This is the version and the flags byte.
6723 * The flags byte is either present, or is based on the version (and can be defaulted).
6724 */
6725 {
6726 uint8_t header = tvb_get_uint8(tvb, offset);
6727
6728 dpp_flags_included = (header & 0x80) != 0;
6729
6730 offset += 1;
6731
6732 {
6733 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DPPv0 ");
6734
6735 if (dpp_flags_included)
6736 {
6737 /* TODO: Protocol violation. */
6738 }
6739
6740 if (tvb_reported_length(tvb) == offset)
6741 col_set_str(pinfo->cinfo, COL_INFO, "Query");
6742 else
6743 {
6744 uint8_t first = tvb_get_uint8(tvb, offset);
6745 /* Response. */
6746 col_set_str(pinfo->cinfo, COL_INFO, "Query Response");
6747 while (first)
6748 {
6749 proto_tree_add_item(tree, hf_2008_1_dpp_0_1_1_version, tvb, offset, 1, ENC_NA0x00000000);
6750 offset += 1;
6751 if (offset == tvb_reported_length(tvb))
6752 break;
6753
6754 first = tvb_get_uint8(tvb, offset);
6755 }
6756 }
6757 }
6758 }
6759
6760 col_set_fence(pinfo->cinfo, COL_PROTOCOL);
6761 col_set_fence(pinfo->cinfo, COL_INFO);
6762 return tvb_reported_length(tvb);
6763}
6764
6765static int dissect_dpp_v2_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6766{
6767 dof_api_data *api_data = (dof_api_data *)data;
6768 dof_packet_data *packet_data;
6769 unsigned offset = 0;
6770 uint8_t opcode;
6771 uint16_t app;
6772 int app_len;
6773 proto_item *ti;
6774 proto_tree *dpps_tree;
6775 proto_tree *opid_tree;
6776
6777 if (api_data == NULL((void*)0))
6778 {
6779 /* TODO: Output error. */
6780 return 0;
6781 }
6782
6783 packet_data = api_data->packet;
6784 if (packet_data == NULL((void*)0))
6785 {
6786 /* TODO: Output error. */
6787 return 0;
6788 }
6789
6790 /* Make entries in Protocol column and Info column on summary display */
6791 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DPPs ");
6792
6793 /* Create the protocol tree. */
6794 offset = 0;
6795 ti = proto_tree_add_item(tree, proto_2009_12_dpp_common, tvb, offset, -1, ENC_NA0x00000000);
6796 dpps_tree = proto_item_add_subtree(ti, ett_2009_12_dpp_common);
6797
6798 /* Add the APPID. */
6799 offset = read_c2(tvb, offset, &app, &app_len);
6800 ti = proto_tree_add_uint(dpps_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
6801 validate_c2(pinfo, ti, app, app_len);
6802
6803
6804 /* Retrieve the opcode. */
6805 opcode = tvb_get_uint8(tvb, offset);
6806 if (!packet_data->is_command)
6807 opcode |= OP_2009_12_RESPONSE_FLAG(0x80);
6808
6809 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, opcode, strings_2009_12_dpp_common_opcodes, "Unknown Opcode (%d)"));
6810
6811 /* Opcode */
6812 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(pinfo->pool, opcode, strings_2009_12_dpp_common_opcodes, "Unknown Opcode (%d)"), opcode & 0x3F);
6813 offset += 1;
6814
6815 switch (opcode)
6816 {
6817 case OP_2009_12_SOURCE_LOST_CMD(1):
6818 case OP_2009_12_SOURCE_FOUND_CMD(8):
6819 case OP_2009_12_RENAME_CMD(2):
6820 packet_data->has_referenced_opid = true1;
6821
6822 /* FALL THROUGH */
6823
6824 case OP_2009_12_CANCEL_ALL_CMD(4):
6825 case OP_2009_12_NODE_DOWN_CMD(0):
6826 case OP_2009_12_QUERY_RSP((0x80)|(6)):
6827 /* SID */
6828 {
6829 proto_tree *oid_tree;
6830 int opid_len;
6831 tvbuff_t *next_tvb;
6832
6833 if (packet_data->has_referenced_opid)
6834 {
6835 opid_tree = proto_tree_add_subtree(dpps_tree, tvb, offset, 0, ett_2009_12_dpp_2_opid, NULL((void*)0), "Operation Identifier");
6836 }
6837 else
6838 {
6839 opid_tree = dpps_tree;
6840 }
6841
6842 oid_tree = proto_tree_add_subtree(opid_tree, tvb, offset, 0, ett_2009_12_dpp_2_opid, NULL((void*)0), "Source Identifier");
6843
6844 next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length(tvb) - offset);
6845 opid_len = call_dissector_only(dof_oid_handle, next_tvb, pinfo, oid_tree, NULL((void*)0));
6846
6847 learn_sender_sid(api_data, opid_len, tvb_get_ptr(next_tvb, 0, opid_len));
6848 if (packet_data->has_referenced_opid)
6849 learn_operation_sid(packet_data, &packet_data->ref_op, opid_len, tvb_get_ptr(next_tvb, 0, opid_len));
6850
6851 offset += opid_len;
6852 }
6853
6854 if (packet_data->has_referenced_opid)
6855 {
6856 uint32_t opcnt;
6857 int opcnt_len;
6858 proto_item *pi;
6859
6860 read_c4(tvb, offset, &opcnt, &opcnt_len);
6861 pi = proto_tree_add_uint_format(opid_tree, hf_2009_12_dpp_2_1_opcnt, tvb, offset, opcnt_len, opcnt, "Operation Count: %u", opcnt);
6862 validate_c4(pinfo, pi, opcnt, opcnt_len);
6863 offset += opcnt_len;
6864
6865 packet_data->ref_op.op_cnt = opcnt;
6866 }
6867
6868 break;
6869 }
6870 return offset;
6871}
6872
6873static int dissect_dpp_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6874{
6875 dof_api_data *api_data = (dof_api_data *)data;
6876 dof_packet_data *packet_data;
6877
6878 proto_item *ti = NULL((void*)0);
6879 proto_item *tf = NULL((void*)0);
6880 proto_item *opid = NULL((void*)0);
6881
6882 int opid_start = -1;
6883 uint8_t dpp_flags_included = 0;
6884 uint32_t dpp_flags = 0;
6885 uint8_t dpp_opid_keytype = 0;
6886
6887 proto_tree *dpp_flags_tree;
6888 proto_tree *opid_tree = NULL((void*)0);
6889
6890
6891 unsigned offset = 0;
6892
6893 proto_tree *dpp_tree = tree;
6894
6895 if (api_data == NULL((void*)0))
1
Assuming 'api_data' is not equal to NULL
2
Taking false branch
6896 {
6897 /* TODO: Output error. */
6898 return 0;
6899 }
6900
6901 packet_data = api_data->packet;
6902 if (packet_data == NULL((void*)0))
3
Assuming 'packet_data' is not equal to NULL
4
Taking false branch
6903 {
6904 /* TODO: Output error. */
6905 return 0;
6906 }
6907
6908 /* We should have everything required for determining the SID ID. */
6909 assign_sid_id(api_data);
6910
6911 offset = 0;
6912 col_clear(pinfo->cinfo, COL_INFO);
6913
6914 /* Compute the DPP control information. This is the version and the flags byte.
6915 * The flags byte is either present, or is based on the version (and can be defaulted).
6916 */
6917 {
6918 uint8_t header = tvb_get_uint8(tvb, offset);
6919 dpp_flags_included = (header & 0x80) != 0;
5
Assuming the condition is true
6920 offset += 1;
6921
6922 {
6923 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DPPv2 ");
6924
6925 ti = proto_tree_add_uint_format(tree, hf_2008_1_dpp_sid_num, tvb,
6926 0, 0, packet_data->sender_sid_id, "SID ID: %d", packet_data->sender_sid_id);
6927 proto_item_set_generated(ti);
6928
6929 if (packet_data->sender_sid)
6
Assuming field 'sender_sid' is null
7
Taking false branch
6930 {
6931 const char *SID = dof_oid_create_standard_string(pinfo->pool, packet_data->sender_sid[0], packet_data->sender_sid + 1, pinfo);
6932 ti = proto_tree_add_bytes_format_value(tree, hf_2008_1_dpp_sid_str, tvb, 0, 0, packet_data->sender_sid, "%s", SID);
6933 proto_item_set_generated(ti);
6934 }
6935
6936 ti = proto_tree_add_uint_format(tree, hf_2008_1_dpp_rid_num, tvb,
6937 0, 0, packet_data->receiver_sid_id, "RID ID: %d", packet_data->receiver_sid_id);
6938 proto_item_set_generated(ti);
6939
6940 if (packet_data->receiver_sid)
8
Assuming field 'receiver_sid' is null
9
Taking false branch
6941 {
6942 const char *SID = dof_oid_create_standard_string(pinfo->pool, packet_data->receiver_sid[0], packet_data->receiver_sid + 1, pinfo);
6943 ti = proto_tree_add_bytes_format_value(tree, hf_2008_1_dpp_rid_str, tvb, 0, 0, packet_data->receiver_sid, "%s", SID);
6944 proto_item_set_generated(ti);
6945 }
6946
6947 if (dpp_flags_included
9.1
'dpp_flags_included' is 1
)
10
Taking true branch
6948 {
6949 dpp_flags = tvb_get_uint8(tvb, offset);
6950 tf = proto_tree_add_uint_format(dpp_tree, hf_2009_12_dpp_2_1_flags, tvb,
6951 offset, 1, dpp_flags, "Flags: 0x%02x", dpp_flags);
6952 if (((dpp_flags & 0x10) != 0) && ((dpp_flags & 0x0F) != 0))
11
Assuming the condition is false
6953 expert_add_info(pinfo, tf, &ei_dpp2_dof_10_flags_zero);
6954 if (((dpp_flags & 0x10) == 0) && ((dpp_flags & 0x09) != 0))
12
Assuming the condition is false
13
Taking false branch
6955 expert_add_info(pinfo, tf, &ei_dpp2_dof_10_flags_zero);
6956
6957 dpp_flags_tree = proto_item_add_subtree(tf, ett_2009_12_dpp_2_1_flags);
6958
6959 if (dpp_flags == DPP_V2_DEFAULT_FLAGS(0))
14
Assuming 'dpp_flags' is not equal to DPP_V2_DEFAULT_FLAGS
15
Taking false branch
6960 expert_add_info(pinfo, dpp_flags_tree, &ei_dpp_default_flags);
6961
6962 proto_tree_add_item(dpp_flags_tree, hf_2009_12_dpp_2_1_flag_security, tvb, offset, 1, ENC_NA0x00000000);
6963 proto_tree_add_item(dpp_flags_tree, hf_2009_12_dpp_2_1_flag_opid, tvb, offset, 1, ENC_NA0x00000000);
6964 proto_tree_add_item(dpp_flags_tree, hf_2009_12_dpp_2_1_flag_cmdrsp, tvb, offset, 1, ENC_NA0x00000000);
6965 if ((dpp_flags & 0x10) == 0)
16
Taking true branch
6966 {
6967 proto_tree_add_item(dpp_flags_tree, hf_2009_12_dpp_2_1_flag_seq, tvb, offset, 1, ENC_NA0x00000000);
6968 proto_tree_add_item(dpp_flags_tree, hf_2009_12_dpp_2_1_flag_retry, tvb, offset, 1, ENC_NA0x00000000);
6969 }
6970
6971 offset += 1;
6972 }
6973 else
6974 dpp_flags = DPP_V2_DEFAULT_FLAGS(0);
6975
6976 packet_data->is_command = (dpp_flags & 0x10) == 0;
6977
6978 /* We are allowed to be complete here if still negotiating. */
6979 /*if ( ! packet->negotiated && (offset == tvb_reported_length(tvb)) )
6980 {
6981 col_set_str( pinfo->cinfo, COL_INFO, "DPS Negotiation" );
6982 return 1;
6983 }*/
6984
6985 dpp_opid_keytype = (dpp_flags & 0x60) >> 5;
6986 switch (dpp_opid_keytype)
17
Control jumps to 'case 3:' at line 7004
6987 {
6988 case 0: /* No OPID */
6989 packet_data->has_opid = false0;
6990 break;
6991
6992 case 1: /* Implied sender. */
6993 packet_data->has_opid = true1;
6994 packet_data->op.op_sid_id = packet_data->sender_sid_id;
6995 packet_data->op.op_sid = packet_data->sender_sid;
6996 break;
6997
6998 case 2: /* Implied receiver. */
6999 packet_data->has_opid = true1;
7000 packet_data->op.op_sid_id = packet_data->receiver_sid_id;
7001 packet_data->op.op_sid = packet_data->receiver_sid;
7002 break;
7003
7004 case 3: /* Explicit. */
7005 packet_data->has_opid = true1;
7006 break;
7007 }
7008
7009 if (dpp_opid_keytype
18.1
'dpp_opid_keytype' is not equal to 0
!= 0)
18
Execution continues on line 7009
19
Taking true branch
7010 {
7011 opid_start = offset;
7012 opid_tree = proto_tree_add_subtree(dpp_tree, tvb, offset, 0, ett_2009_12_dpp_2_opid, NULL((void*)0), "Operation Identifier");
7013 }
7014
7015 switch (dpp_opid_keytype)
20
Control jumps to 'case 3:' at line 7020
7016 {
7017 case 0: /* We have no opid. */
7018 break;
7019
7020 case 3: /* Explicit. */
7021 {
7022 proto_tree *oid_tree;
7023 tvbuff_t *next_tvb;
7024 int opid_len;
7025
7026 oid_tree = proto_tree_add_subtree(opid_tree, tvb, offset, 0, ett_2009_12_dpp_2_opid, NULL((void*)0), "Source Identifier");
7027
7028 next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length(tvb) - offset);
7029 opid_len = call_dissector_only(dof_oid_handle, next_tvb, pinfo, oid_tree, NULL((void*)0));
7030 proto_item_set_len(oid_tree, opid_len);
7031
7032 learn_operation_sid(packet_data, &packet_data->op, opid_len, tvb_get_ptr(next_tvb, 0, opid_len));
21
Calling 'learn_operation_sid'
35
Returning from 'learn_operation_sid'
7033
7034 /* Warn if Explicit SID could be optimized. */
7035 if (packet_data->op.op_sid_id == packet_data->sender_sid_id)
36
Assuming field 'op_sid_id' is not equal to field 'sender_sid_id'
37
Taking false branch
7036 expert_add_info(pinfo, ti, &ei_dpp_explicit_sender_sid_included);
7037 if (packet_data->op.op_sid_id == packet_data->receiver_sid_id)
38
Assuming field 'op_sid_id' is not equal to field 'receiver_sid_id'
39
Taking false branch
7038 expert_add_info(pinfo, ti, &ei_dpp_explicit_receiver_sid_included);
7039
7040 offset += opid_len;
7041 }
7042
7043 /* FALL THROUGH */
7044
7045 case 1: /* Implied sender. */
7046 case 2: /* Implied receiver. */
7047 {
7048 uint32_t opcnt;
7049 int opcnt_len;
7050 proto_item *pi;
7051
7052 /* Display the SID if known. */
7053 if ((dpp_opid_keytype
39.1
'dpp_opid_keytype' is equal to 3
!= 3) && packet_data->op.op_sid)
7054 {
7055 proto_tree *oid_tree;
7056
7057 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]);
7058 oid_tree = proto_tree_add_subtree(opid_tree, tvb, 0, 0, ett_2009_12_dpp_2_opid, NULL((void*)0), "Source Identifier");
7059
7060 call_dissector_only(dof_oid_handle, next_tvb, pinfo, oid_tree, NULL((void*)0));
7061
7062 proto_item_set_generated(ti);
7063 }
7064
7065 read_c4(tvb, offset, &opcnt, &opcnt_len);
7066 pi = proto_tree_add_uint_format(opid_tree, hf_2009_12_dpp_2_1_opcnt, tvb, offset, opcnt_len, opcnt, "Operation Count: %u", opcnt);
7067 validate_c4(pinfo, pi, opcnt, opcnt_len);
7068 offset += opcnt_len;
7069
7070 proto_item_set_len(opid, offset - opid_start);
7071
7072 packet_data->op.op_cnt = opcnt;
7073
7074 /* At this point we have a packet with an operation identifier. We need to
7075 * update the master list of operation identifiers, and do any checking that
7076 * we can in order to validate things.
7077 */
7078 if (packet_data->has_opid && !packet_data->opid_first)
40
Assuming field 'has_opid' is false
7079 {
7080 dof_packet_data *first = (dof_packet_data *)g_hash_table_lookup(dpp_opid_to_packet_data, (const void *) & packet_data->op);
7081 if (first == NULL((void*)0))
7082 {
7083 /* First reference to this operation. */
7084 g_hash_table_insert(dpp_opid_to_packet_data, (void *) & packet_data->op, (void *)packet_data);
7085 packet_data->opid_first = packet_data;
7086 packet_data->opid_last = packet_data;
7087
7088 /* The first opid must be a command. */
7089 }
7090 else
7091 {
7092 /* Operation exists, time to patch things in. */
7093 packet_data->opid_first = first;
7094 first->opid_last->opid_next = packet_data;
7095 first->opid_last = packet_data;
7096
7097 if (!packet_data->is_command)
7098 {
7099 if (!first->opid_first_response)
7100 {
7101 first->opid_first_response = packet_data;
7102 first->opid_last_response = packet_data;
7103 }
7104 else
7105 {
7106 first->opid_last_response->opid_next_response = packet_data;
7107 first->opid_last_response = packet_data;
7108 }
7109 }
7110 }
7111 }
7112
7113
7114 /* Add all the reference information to the tree. */
7115 if (globals.track_operations && tree)
41
Assuming field 'track_operations' is true
42
Assuming 'tree' is non-null
43
Taking true branch
7116 {
7117 proto_tree *ophistory_tree = proto_tree_add_subtree(tree, tvb, 0, 0, ett_2009_12_dpp_2_opid_history, NULL((void*)0), "Operation History");
7118
7119 dof_packet_data *ptr = packet_data->opid_first;
44
'ptr' initialized here
7120
7121 if (ptr)
45
Assuming 'ptr' is null
7122 proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_first_command,
7123 tvb, 0, 0, ptr->frame,
7124 "First Operation: %u",
7125 ptr->frame);
7126
7127 if (ptr->opid_last && ptr->opid_last != ptr)
46
Access to field 'opid_last' results in a dereference of a null pointer (loaded from variable 'ptr')
7128 proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_last_command,
7129 tvb, 0, 0, ptr->opid_last->frame,
7130 "Last Operation: %u",
7131 ptr->opid_last->frame);
7132
7133 if (ptr->opid_first_response)
7134 proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_first_response,
7135 tvb, 0, 0, ptr->opid_first_response->frame,
7136 "First Response: %u",
7137 ptr->opid_first_response->frame);
7138
7139 if (ptr->opid_last_response && ptr->opid_last_response != ptr->opid_first_response)
7140 proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_last_response,
7141 tvb, 0, 0, ptr->opid_last_response->frame,
7142 "Last Response: %u",
7143 ptr->opid_last_response->frame);
7144
7145 /* Determine the window start, then output the number of packets. Output the number of skipped packets before
7146 * and after.
7147 */
7148 {
7149 dof_packet_data *start = packet_data->opid_first;
7150 unsigned diff = 0;
7151 while (ptr)
7152 {
7153 if (ptr == packet_data)
7154 break;
7155
7156 ptr = ptr->opid_next;
7157 diff += 1;
7158
7159 if (diff > globals.track_operations_window)
7160 {
7161 start = start->opid_next;
7162 diff -= 1;
7163 }
7164 }
7165
7166 ptr = start;
7167 diff = 0;
7168
7169 while (ptr)
7170 {
7171 const char *THIS = "";
7172
7173 if (ptr == packet_data)
7174 {
7175 THIS = "this ";
7176 diff = globals.track_operations_window + 1;
7177 }
7178
7179 /* (DPS Frame) [ws WS Frame]: (SID)->(RID): (THIS) (SUMMARY) */
7180 proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_related_frame,
7181 tvb, 0, 0, ptr->frame,
7182 "%u[ws %u]: %u->%u: %s%s",
7183 ptr->dof_frame, ptr->frame,
7184 ptr->sender_sid_id, ptr->receiver_sid_id,
7185 THIS,
7186 ptr->summary ? ptr->summary : "");
7187
7188 ptr = ptr->opid_next;
7189 if (diff && !--diff)
7190 break;
7191 }
7192 }
7193 }
7194 }
7195 break;
7196 }
7197
7198 proto_item_set_len(opid_tree, offset - opid_start);
7199
7200 {
7201 if ((dpp_flags & 0x10) == 0)
7202 {
7203 uint8_t dpp_seq = 0;
7204 uint8_t dpp_retry = 0;
7205 uint16_t dpp_delay = 0;
7206
7207 /* Extract SEQ */
7208 if (dpp_flags & 0x04)
7209 {
7210 dpp_seq = tvb_get_uint8(tvb, offset);
7211 proto_tree_add_uint_format(dpp_tree, hf_2009_12_dpp_2_1_seq, tvb, offset, 1, dpp_seq, "Sequence: %u", dpp_seq);
7212 offset += 1;
7213 }
7214
7215 /* Extract Retry */
7216 if (dpp_flags & 0x02)
7217 {
7218 dpp_retry = tvb_get_uint8(tvb, offset);
7219 proto_tree_add_uint_format(dpp_tree, hf_2009_12_dpp_2_1_retry, tvb, offset, 1, dpp_retry, "Retry: %u", dpp_retry);
7220 offset += 1;
7221 }
7222
7223 /* Extract Delay */
7224 {
7225 dpp_delay = tvb_get_uint8(tvb, offset);
7226 if (dpp_delay > 128)
7227 dpp_delay = 128 + ((dpp_delay - 128) * 32);
7228
7229 proto_tree_add_uint_format(dpp_tree, hf_2009_12_dpp_2_1_delay, tvb, offset, 1, dpp_delay, "Delay: %u seconds", dpp_delay);
7230 offset += 1;
7231 }
7232
7233 packet_data->summary = wmem_strdup_printf(wmem_file_scope(), "command seq %u, retry %u, delay %u", dpp_seq, dpp_retry, dpp_delay);
7234 }
7235 else
7236 packet_data->summary = "response";
7237 }
7238
7239 /* Extract session information. */
7240 if (dpp_flags & 0x80)
7241 {
7242 uint32_t sec_offset = offset;
7243 uint8_t sh_flags;
7244 uint32_t ssid;
7245 proto_tree *security_tree;
7246 proto_tree *sec_flags_tree;
7247 proto_item *item;
7248
7249 security_tree = proto_tree_add_subtree(dpp_tree, tvb, offset, -1, ett_2009_12_dpp_2_3_security, NULL((void*)0), "Security Header");
7250
7251 sh_flags = tvb_get_uint8(tvb, offset);
7252 item = proto_tree_add_uint_format(security_tree, hf_2009_12_dpp_2_3_sec_flags, tvb,
7253 offset, 1, sh_flags, "Flags: 0x%02x", sh_flags);
7254
7255 sec_flags_tree = proto_item_add_subtree(item, ett_2009_12_dpp_2_3_sec_flags);
7256 proto_tree_add_item(sec_flags_tree, hf_2009_12_dpp_2_3_sec_flag_secure, tvb, offset, 1, ENC_NA0x00000000);
7257 proto_tree_add_item(sec_flags_tree, hf_2009_12_dpp_2_3_sec_flag_rdid, tvb, offset, 1, ENC_NA0x00000000);
7258 proto_tree_add_item(sec_flags_tree, hf_2009_12_dpp_2_3_sec_flag_partition, tvb, offset, 1, ENC_NA0x00000000);
7259 proto_tree_add_item(sec_flags_tree, hf_2009_12_dpp_2_3_sec_flag_as, tvb, offset, 1, ENC_NA0x00000000);
7260 proto_tree_add_item(sec_flags_tree, hf_2009_12_dpp_2_3_sec_flag_ssid, tvb, offset, 1, ENC_NA0x00000000);
7261 offset += 1;
7262
7263 ssid = 0;
7264 if (sh_flags & DPP_V2_SEC_FLAG_S(0x01))
7265 {
7266 int s_offset = offset;
7267 int ssid_len;
7268 proto_item *pi;
7269 offset = read_c4(tvb, offset, &ssid, &ssid_len);
7270 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);
7271 validate_c4(pinfo, pi, ssid, ssid_len);
7272 }
7273
7274 /* At this point we know the transport information, DNP port information, and the
7275 * SSID. This means that we can isolate the session that this communication belongs
7276 * to. Note that all uses of an SSID are scoped by the transport.
7277 */
7278 if (sh_flags & DPP_V2_SEC_FLAG_A(0x02))
7279 ssid |= AS_ASSIGNED_SSID0x40000000;
7280
7281 if (api_data->session && !api_data->secure_session)
7282 {
7283 dof_secure_session_data *search = api_data->session->secure_sessions;
7284 while (search)
7285 {
7286 if (ssid == search->ssid)
7287 break;
7288
7289 search = search->next;
7290 }
7291
7292 if (search)
7293 {
7294 api_data->session = search->parent;
7295 api_data->secure_session = search;
7296 }
7297 }
7298
7299 if (sh_flags & DPP_V2_SEC_FLAG_D(0x08))
7300 {
7301 int s_offset = offset;
7302 uint32_t rdid;
7303 int rdid_len;
7304 proto_item *pi;
7305 offset = read_c4(tvb, offset, &rdid, &rdid_len);
7306 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);
7307 validate_c4(pinfo, pi, rdid, rdid_len);
7308
7309 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_10, tvb, pinfo, security_tree,
7310 offset, hf_2009_12_dpp_2_3_sec_remote_partition, ett_2009_12_dpp_2_3_sec_remote_partition, NULL((void*)0));
7311 }
7312
7313 if (sh_flags & DPP_V2_SEC_FLAG_P(0x04))
7314 {
7315 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_10, tvb, pinfo, security_tree,
7316 offset, hf_2009_12_dpp_2_3_sec_partition, ett_2009_12_dpp_2_3_sec_partition, NULL((void*)0));
7317 }
7318
7319 if (sh_flags & DPP_V2_SEC_FLAG_E(0x80))
7320 {
7321 if (!packet_data->security_session_error && !api_data->secure_session)
7322 packet_data->security_session_error = "[Encrypted - No Session Available]";
7323
7324 /* Security has not failed, and we have a security session. */
7325 if (!packet_data->security_session_error)
7326 {
7327 dissector_table_t sec_header = find_dissector_table("dof.secmode");
7328 /* TODO: CCM is hardcoded. We should try all of the sessions, which could mean multiple security modes. */
7329 dissector_handle_t dp = dissector_get_uint_handle(sec_header, 0x6001); /* packet_data->security_session->security_mode); */
7330 if (dp)
7331 {
7332 dof_secmode_api_data sdata;
7333
7334 sdata.context = HEADER;
7335 sdata.security_mode_offset = offset;
7336 sdata.dof_api = api_data;
7337 sdata.secure_session = api_data->secure_session;
7338 sdata.session_key_data = NULL((void*)0);
7339
7340 offset += call_dissector_only(dp, tvb, pinfo, security_tree, &sdata);
7341 }
7342 }
7343
7344 /* If we get here without success, then we can only bail. The
7345 * error is shown in every pass, including the one that found it.
7346 */
7347 if (packet_data->security_session_error)
7348 {
7349 col_set_str(pinfo->cinfo, COL_INFO, packet_data->security_session_error);
7350 proto_item_set_end(tree, tvb, offset);
7351 expert_add_info(pinfo, security_tree, &ei_dpp_no_security_context);
7352 {
7353 tvbuff_t *data_tvb = tvb_new_subset_remaining(tvb, offset);
7354 call_data_dissector(data_tvb, pinfo, tree);
7355 }
7356 proto_item_set_len(security_tree, offset - sec_offset);
7357 return offset;
7358 }
7359
7360 if (!packet_data->decrypted_buffer)
7361 {
7362 proto_item_set_end(tree, tvb, offset);
7363 proto_item_set_len(security_tree, offset - sec_offset);
7364 return offset;
7365 }
7366 }
7367 proto_item_set_len(security_tree, offset - sec_offset);
7368 }
7369
7370 /* The end of the packet must be called in the original tvb or chaos ensues... */
7371 proto_item_set_end(tree, tvb, offset);
7372 }
7373
7374
7375 if (packet_data->decrypted_tvb)
7376 {
7377 tvb = packet_data->decrypted_tvb;
7378 offset = packet_data->decrypted_offset;
7379 }
7380
7381 /* Assuming there is more, it must be DPP. */
7382 /* We have a packet. We must handle the special case of this being *our* application
7383 * protocol (0x7FFF). If it is, then *we* are the dissector...
7384 */
7385 {
7386 uint16_t app;
7387 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length(tvb) - offset);
7388
7389 read_c2(tvb, offset, &app, NULL((void*)0));
7390 if (app == 0x7FFF)
7391 {
7392 offset += dissect_dpp_v2_common(next_tvb, pinfo, proto_item_get_parent(tree), data);
7393 }
7394 else
7395 {
7396 offset += dissect_app_common(next_tvb, pinfo, proto_item_get_parent(tree), data);
7397 }
7398 }
7399 }
7400
7401 col_set_fence(pinfo->cinfo, COL_PROTOCOL);
7402 col_set_fence(pinfo->cinfo, COL_INFO);
7403 return offset;
7404}
7405
7406static int dissect_options(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
7407{
7408 while (offset < (int)tvb_captured_length(tvb))
7409 {
7410 proto_tree *subtree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_2008_1_dsp_12_option, NULL((void*)0), "Option");
7411 tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
7412 int len = dissect_2008_1_dsp_1(next_tvb, pinfo, subtree);
7413 proto_item_set_len(proto_tree_get_parent(subtree), len);
7414 offset += len;
7415 }
7416
7417 return offset;
7418}
7419
7420static int dissect_dsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
7421{
7422 dof_api_data *api_data = (dof_api_data *)data;
7423 dof_packet_data *packet_data;
7424 unsigned offset = 0;
7425 uint8_t opcode;
7426 uint16_t app;
7427 int app_len;
7428 proto_item *ti;
7429 proto_tree *dsp_tree;
7430 proto_tree *options_tree;
7431
7432 if (api_data == NULL((void*)0))
7433 {
7434 /* TODO: Output error. */
7435 return 0;
7436 }
7437
7438 packet_data = api_data->packet;
7439 if (packet_data == NULL((void*)0))
7440 {
7441 /* TODO: Output error. */
7442 return 0;
7443 }
7444
7445 /* Make entries in Protocol column and Info column on summary display */
7446 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DSPv2 ");
7447
7448 /* Create the protocol tree. */
7449 offset = 0;
7450 ti = proto_tree_add_item(tree, proto_2008_1_dsp, tvb, offset, -1, ENC_NA0x00000000);
7451 dsp_tree = proto_item_add_subtree(ti, ett_2008_1_dsp_12);
7452
7453 /* Add the APPID. */
7454 offset = read_c2(tvb, offset, &app, &app_len);
7455 ti = proto_tree_add_uint(dsp_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
7456 validate_c2(pinfo, ti, app, app_len);
7457
7458#if 0
7459 if (!packet->is_streaming)
7460 {
7461 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DSPv2 ");
7462
7463 if (tvb_captured_length(tvb) == offset)
7464 col_set_str(pinfo->cinfo, COL_INFO, "Query");
7465 else
7466 {
7467 col_set_str(pinfo->cinfo, COL_INFO, "Query Response");
7468 while (offset < tvb_captured_length(tvb))
7469 {
7470 uint16_t app;
7471 int start = offset;
7472 offset = read_c2(tvb, offset, &app, NULL((void*)0));
7473 proto_tree_add_uint(dsp_tree, hf_2008_1_app_version, tvb, start, offset - start, app);
7474 }
7475 }
7476
7477 return offset;
7478 }
7479#endif
7480
7481 if (offset == tvb_captured_length(tvb))
7482 {
7483 col_append_str(pinfo->cinfo, COL_INFO, "DSP [nop]");
7484 expert_add_info(pinfo, dsp_tree, &ei_implicit_no_op);
7485
7486 return offset;
7487 }
7488
7489 /* Determine the ESP opcode. */
7490 opcode = tvb_get_uint8(tvb, offset);
7491
7492 if (!packet_data->is_command)
7493 opcode |= OP_2008_1_RSP(0x80);
7494
7495 proto_tree_add_uint_format(dsp_tree, hf_2008_1_dsp_12_opcode, tvb, offset, 1, opcode, "Opcode: %s (%u)", val_to_str(pinfo->pool, opcode, strings_2008_1_dsp_opcodes, "Unknown Opcode (%d)"), opcode & 0x7F);
7496 offset += 1;
7497 col_append_sep_str(pinfo->cinfo, COL_INFO, "/", val_to_str(pinfo->pool, opcode, strings_2008_1_dsp_opcodes, "Unknown Opcode (%d)"));
7498
7499 switch (opcode)
7500 {
7501 case OP_2008_1_OPEN_CMD6: /* 2008.1 DSP.14.1 */
7502 break;
7503
7504 case OP_2008_1_OPEN_RSP((0x80)|6): /* 2008.1 DSP.14.2 */
7505 case OP_2008_1_OPEN_SECURE_RSP((0x80)|7): /* 2008.1 DSP.14.3 */
7506 {
7507 while (offset < tvb_captured_length(tvb))
7508 {
7509 uint16_t ap;
7510 int length;
7511 proto_item *pi;
7512 int start = offset;
7513 offset = read_c2(tvb, offset, &ap, &length);
7514 pi = proto_tree_add_uint(dsp_tree, hf_2008_1_app_version, tvb, start, offset - start, ap);
7515 validate_c2(pinfo, pi, ap, length);
7516 }
7517 }
7518 break;
7519
7520 case OP_2008_1_QUERY_CMD0:
7521 break;
7522
7523 case OP_2008_1_QUERY_RSP((0x80)|0):
7524 break;
7525
7526 case OP_2008_1_CONFIG_ACK((0x80)|2):
7527 break;
7528
7529 case OP_2008_1_CONFIG_REQ1:
7530 /* This will start a session if not existing... */
7531 /* FALL THROUGH */
7532
7533 case OP_2008_1_CONFIG_NAK((0x80)|3):
7534 {
7535 int length = tvb_captured_length(tvb) - offset;
7536
7537 options_tree = proto_tree_add_subtree_format(dsp_tree, tvb, offset, length, ett_2008_1_dsp_12_options, NULL((void*)0),
7538 "DSP Options: (%d byte%s)", length, plurality(length, "", "s")((length) == 1 ? ("") : ("s")));
7539 offset = dissect_options(tvb, offset, pinfo, options_tree, NULL((void*)0));
7540 }
7541 break;
7542
7543 case OP_2008_1_CONFIG_REJ((0x80)|4):
7544 /* TODO: Handle reject. */
7545 break;
7546
7547 case OP_2008_1_TERMINATE_CMD5:
7548 case OP_2008_1_TERMINATE_RSP((0x80)|5):
7549 /* Nothing */
7550 break;
7551 }
7552
7553 return offset;
7554}
7555
7556static int dissect_ccm_dsp(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree, void *data _U___attribute__((unused)))
7557{
7558 /* We are handed a buffer that starts with an option and our protocol id. Any options follow that. */
7559 unsigned offset = 0;
7560 proto_item *parent = proto_tree_get_parent(tree);
7561 uint8_t len, strength_count, i;
7562 proto_item *ti;
7563 proto_tree *ccm_tree;
7564
7565 /* Append description to the parent. */
7566 proto_item_append_text(parent, " (CCM)");
7567
7568 /* Compute the version and flags, masking off other bits. */
7569 offset += 3; /* Skip the type and protocol. */
7570 len = tvb_get_uint8(tvb, offset++);
7571
7572 ti = proto_tree_add_item(tree, hf_ccm_dsp_option, tvb, offset, len, ENC_NA0x00000000);
7573 ccm_tree = proto_item_add_subtree(ti, ett_ccm_dsp_option);
7574
7575 proto_tree_add_item_ret_uint8(ccm_tree, hf_ccm_dsp_strength_count, tvb, offset++, 1, ENC_NA0x00000000, &strength_count);
7576
7577 for (i = 0; i < strength_count; i++)
7578 proto_tree_add_item(ccm_tree, hf_ccm_dsp_strength, tvb, offset++, 1, ENC_NA0x00000000);
7579
7580 proto_tree_add_item(ccm_tree, hf_ccm_dsp_e_flag, tvb, offset, 1, ENC_NA0x00000000);
7581 proto_tree_add_item(ccm_tree, hf_ccm_dsp_m_flag, tvb, offset, 1, ENC_NA0x00000000);
7582 proto_tree_add_item(ccm_tree, hf_ccm_dsp_tmax, tvb, offset, 1, ENC_NA0x00000000);
7583 proto_tree_add_item(ccm_tree, hf_ccm_dsp_tmin, tvb, offset, 1, ENC_NA0x00000000);
7584
7585 offset += 1;
7586 return offset;
7587}
7588
7589/**
7590 * This is the main entry point for the CCM dissector. It is always called from an DPS
7591 * dissector, and is always passed the dof_secmode_data structure.
7592 */
7593static int dissect_ccm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
7594{
7595 dof_secmode_api_data *secmode_api_data;
7596 dof_session_key_exchange_data *key_data;
7597
7598 secmode_api_data = (dof_secmode_api_data *)data;
7599 if (secmode_api_data == NULL((void*)0))
7600 {
7601 return 0;
7602 }
7603
7604 key_data = secmode_api_data->session_key_data;
7605
7606 /* Based on the context of the request, handle the work. */
7607 switch (secmode_api_data->context)
7608 {
7609 case INITIALIZE:
7610 /* Parse off the initialization fields, and if necessary create the security mode state
7611 * that is being initialized. This is passed the DPS data, DPS session data, and Key Exchange Data.
7612 */
7613 {
7614 ccm_session_data *ccm_data = (ccm_session_data *)key_data->security_mode_key_data;
7615 unsigned offset = 0;
7616 uint8_t header;
7617 uint16_t length;
7618
7619 if (!ccm_data)
7620 {
7621 /* We need to parse the initialization data. */
7622 ccm_data = wmem_new0(wmem_file_scope(), ccm_session_data)((ccm_session_data*)wmem_alloc0((wmem_file_scope()), sizeof(ccm_session_data
)))
;
7623 if (!ccm_data)
7624 return 0;
7625 wmem_register_callback(wmem_file_scope(), dof_sessions_destroy_cb, ccm_data);
7626
7627 key_data->security_mode_key_data = ccm_data;
7628
7629 if (!key_data->security_mode_data || key_data->security_mode_data_length < 3)
7630 return 0;
7631
7632 /* TODO: Not sure that these are all right. */
7633 ccm_data->protocol_id = DOF_PROTOCOL_CCM24577;
7634 ccm_data->cipher = key_data->security_mode_data[1];
7635 ccm_data->encrypted = key_data->security_mode_data[key_data->security_mode_data_length - 1] & 0x80;
7636 ccm_data->mac_len = (key_data->security_mode_data[key_data->security_mode_data_length - 1] & 0x07) * 2 + 2;
7637 ccm_data->client_datagram_number = 0;
7638 ccm_data->server_datagram_number = 0;
7639
7640 switch (ccm_data->protocol_id)
7641 {
7642 case DOF_PROTOCOL_CCM24577:
7643 if (gcry_cipher_open(&ccm_data->cipher_data, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0)) {
7644 return 0;
7645 }
7646 break;
7647
7648 default:
7649 return 0;
7650 }
7651 }
7652
7653 /* A NULL buffer is used when the key is installed before any CCM header
7654 * exists (TEP accept). Treat it like a 2-node session: key the handle
7655 * already opened above and do not read the tvbuff.
7656 */
7657 if (tvb == NULL((void*)0) || secmode_api_data->dof_api->transport_session->is_2_node)
7658 {
7659 if (!ccm_data->cipher_data || !key_data->session_key)
7660 return 0;
7661
7662 switch (ccm_data->protocol_id)
7663 {
7664 case DOF_PROTOCOL_CCM24577:
7665 if (gcry_cipher_setkey(ccm_data->cipher_data, key_data->session_key, 32)) {
7666 gcry_cipher_close(ccm_data->cipher_data);
7667 ccm_data->cipher_data = NULL((void*)0);
7668 return 0;
7669 }
7670 break;
7671
7672 default:
7673 return 0;
7674 }
7675
7676 /* This mode has a fixed size, so we can return here without parsing further. */
7677 return 2;
7678 }
7679
7680 offset = read_c2(tvb, offset, &length, NULL((void*)0));
7681 /* TODO validate C2 */
7682 header = tvb_get_uint8(tvb, offset);
7683 offset += 1;
7684
7685 /* Determine the period, and store the key. */
7686 {
7687 uint8_t period = (header & 0x70) >> 4;
7688 uint32_t lookup;
7689 ccm_period_key *existing = NULL((void*)0);
7690 ccm_period_key *ekey;
7691
7692 if (!key_data->session_key)
7693 return 0;
7694
7695 if (ccm_data->cipher_data_table == NULL((void*)0))
7696 ccm_data->cipher_data_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL((void*)0), dof_cipher_data_destroy);
7697
7698 lookup = ccm_data->periods[period];
7699 if (lookup)
7700 existing = (ccm_period_key *)g_hash_table_lookup(ccm_data->cipher_data_table, GUINT_TO_POINTER(lookup)((gpointer) (gulong) (lookup)));
7701
7702 if (!existing || memcmp(key_data->session_key, existing->key, sizeof(existing->key)) != 0)
7703 {
7704 ekey = ccm_period_key_new(key_data->session_key);
7705 if (!ekey)
7706 return 0;
7707
7708 ccm_data->period += 1;
7709 ccm_data->periods[period] = ccm_data->period;
7710 g_hash_table_insert(ccm_data->cipher_data_table, GUINT_TO_POINTER(ccm_data->period)((gpointer) (gulong) (ccm_data->period)), ekey);
7711 }
7712 }
7713
7714 return offset + length - 1;
7715 }
7716
7717 case HEADER:
7718 {
7719 ccm_session_data *session;
7720 dof_transport_session *transport_session = (dof_transport_session *)secmode_api_data->dof_api->transport_session;
7721 dof_secure_session_data *secure_session = secmode_api_data->secure_session;
7722 dof_session_key_exchange_data *security_data = NULL((void*)0);
7723 dof_packet_data *dof_packet = secmode_api_data->dof_api->packet;
7724 uint8_t ccm_flags;
7725 uint32_t nid;
7726 uint16_t slot = 0;
7727 uint32_t pn = 0;
7728 bool_Bool pn_present = false0;
7729 uint32_t tnid;
7730 uint32_t nnid;
7731 proto_tree *ccm_flags_tree;
7732 proto_tree *header_tree;
7733 proto_item * item,*header;
7734 ccm_packet_data *pdata;
7735 unsigned offset = 0;
7736
7737 if (!dof_packet->security_session)
7738 {
7739 if (transport_session->is_streaming)
7740 {
7741 /* Find the first security data that is applicable - they are in order of packet sequence. */
7742 security_data = secure_session->session_security_data;
7743 while (security_data)
7744 {
7745 if (dof_packet->is_sent_by_initiator && (dof_packet->dof_frame > security_data->i_valid))
7746 break;
7747
7748 if (!dof_packet->is_sent_by_initiator && (dof_packet->dof_frame > security_data->r_valid))
7749 break;
7750
7751 security_data = security_data->next;
7752 }
7753
7754 if (security_data)
7755 dof_packet->security_session = security_data;
7756 else
7757 {
7758 dof_packet->security_session_error = "[Encrypted - No Session Available]";
7759 return offset;
7760 }
7761 }
7762 else
7763 {
7764 dof_packet->security_session = secure_session->session_security_data;
7765 security_data = dof_packet->security_session;
7766 }
7767 }
7768 else
7769 {
7770 security_data = dof_packet->security_session;
7771 }
7772
7773 if (!security_data || !security_data->session_key || !security_data->security_mode_key_data)
7774 {
7775 dof_packet->security_session_error = "[Encrypted - No Session Available]";
7776 return offset;
7777 }
7778
7779 session = (ccm_session_data *)security_data->security_mode_key_data;
7780 offset = secmode_api_data->security_mode_offset;
7781
7782 /* Add a master header for this protocol. */
7783 header = proto_tree_add_protocol_format(tree, proto_ccm, tvb, offset, 0,
7784 "CCM Security Mode, Version: 1");
7785 header_tree = proto_item_add_subtree(header, ett_header);
7786 tree = header_tree;
7787
7788 ccm_flags = tvb_get_uint8(tvb, offset);
7789 item = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_flags, tvb,
7790 offset, 1, ccm_flags, "Flags: 0x%02x", ccm_flags);
7791
7792 ccm_flags_tree = proto_item_add_subtree(item, ett_epp_v1_ccm_flags);
7793 proto_tree_add_item(ccm_flags_tree, hf_epp_v1_ccm_flags_manager, tvb, offset, 1, ENC_NA0x00000000);
7794 proto_tree_add_item(ccm_flags_tree, hf_epp_v1_ccm_flags_period, tvb, offset, 1, ENC_NA0x00000000);
7795 proto_tree_add_item(ccm_flags_tree, hf_epp_v1_ccm_flags_target, tvb, offset, 1, ENC_NA0x00000000);
7796 proto_tree_add_item(ccm_flags_tree, hf_epp_v1_ccm_flags_next_nid, tvb, offset, 1, ENC_NA0x00000000);
7797 proto_tree_add_item(ccm_flags_tree, hf_epp_v1_ccm_flags_packet, tvb, offset, 1, ENC_NA0x00000000);
7798 offset += 1;
7799
7800 if (ccm_flags & 0x01)
7801 pn_present = true1;
7802
7803 pdata = (ccm_packet_data *)dof_packet->security_packet;
7804 if (!pdata)
7805 {
7806 pdata = wmem_new0(wmem_file_scope(), ccm_packet_data)((ccm_packet_data*)wmem_alloc0((wmem_file_scope()), sizeof(ccm_packet_data
)))
;
7807 if (pdata)
7808 {
7809 dof_packet->security_packet = pdata;
7810
7811 if (transport_session->is_2_node)
7812 {
7813 if (dof_packet->is_sent_by_initiator)
7814 {
7815 pdata->nid = 0;
7816 if (pn_present == false0)
7817 pdata->dn = ++session->client_datagram_number;
7818 else
7819 pdata->dn = pn;
7820 }
7821 else
7822 {
7823 pdata->nid = 1;
7824 if (pn_present == 0)
7825 pdata->dn = ++session->server_datagram_number;
7826 else
7827 pdata->dn = pn;
7828 }
7829 }
7830 else
7831 {
7832 uint8_t packet_period = (ccm_flags & 0x70) >> 4;
7833 pdata->period = session->periods[packet_period];
7834 }
7835 }
7836 }
7837
7838 if (!pdata)
7839 return offset - secmode_api_data->security_mode_offset;
7840
7841 if (!secure_session->is_2_node)
7842 {
7843 int nid_len;
7844 proto_item *pi;
7845 read_c4(tvb, offset, &nid, &nid_len);
7846 /* TODO: Do this right, as offset from BNID. */
7847 nid /= 2;
7848 pdata->nid = nid;
7849 pi = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_nid, tvb, offset, nid_len, nid, "Node ID: %u", nid);
7850 validate_c4(pinfo, pi, nid, nid_len);
7851 offset += nid_len;
7852 }
7853 else
7854 {
7855 item = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_nid, tvb, 0, 0, pdata->nid, "Node ID: %u", pdata->nid);
7856 proto_item_set_generated(item);
7857 }
7858
7859 if (!secure_session->is_2_node)
7860 {
7861 int slot_len;
7862 proto_item *pi;
7863 read_c2(tvb, offset, &slot, &slot_len);
7864 pi = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_slot, tvb, offset, slot_len, slot, "Slot: %hu", slot);
7865 validate_c2(pinfo, pi, slot, slot_len);
7866 offset += slot_len;
7867 }
7868 else
7869 {
7870 item = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_slot, tvb, 0, 0, 0, "Slot: %u", 0);
7871 proto_item_set_generated(item);
7872 }
7873
7874 if (ccm_flags & 0x01)
7875 {
7876 int pn_len;
7877 proto_item *pi;
7878 read_c4(tvb, offset, &pn, &pn_len);
7879 pi = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_pn, tvb, offset, pn_len, pn, "Packet Number: %u", pn);
7880 validate_c4(pinfo, pi, pn, pn_len);
7881 pdata->dn = pn;
7882 offset += pn_len;
7883 }
7884 else
7885 {
7886 item = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_pn, tvb, 0, 0, pdata->dn, "Packet Number: %u", pdata->dn);
7887 proto_item_set_generated(item);
7888 }
7889
7890 if (ccm_flags & 0x08)
7891 {
7892 int tnid_len;
7893 proto_item *pi;
7894 read_c4(tvb, offset, &tnid, &tnid_len);
7895 pi = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_tnid, tvb, offset, tnid_len, tnid, "Target Node ID: %u", tnid);
7896 validate_c4(pinfo, pi, tnid, tnid_len);
7897 offset += tnid_len;
7898 }
7899
7900 if (ccm_flags & 0x02)
7901 {
7902 int nnid_len;
7903 proto_item *pi;
7904 read_c4(tvb, offset, &nnid, &nnid_len);
7905 pi = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_nnid, tvb, offset, nnid_len, nnid, "Next Node ID: %u", nnid);
7906 validate_c4(pinfo, pi, nnid, nnid_len);
7907 offset += nnid_len;
7908 }
7909
7910 proto_item_set_len(header, offset - secmode_api_data->security_mode_offset);
7911
7912 if (dof_packet->decrypted_buffer_error)
7913 {
7914 col_set_str(pinfo->cinfo, COL_INFO, dof_packet->decrypted_buffer_error);
7915 expert_add_info(pinfo, tree, &ei_decode_failure);
7916 return offset - secmode_api_data->security_mode_offset;
7917 }
7918
7919 /* We have reached the encryption boundary. At this point the rest of the packet
7920 * is encrypted, and we may or may not be able to decrypt it.
7921 *
7922 * If we can decrypt it (which for now means that it uses a Session Key of [0]
7923 * the we switch to decoding the decrypted PDU. Otherwise we create an entry
7924 * for the encrypted bytes and move on...
7925 */
7926
7927 {
7928 unsigned a_len = offset;
7929 const uint8_t *epp_buf = tvb_get_ptr(tvb, 0, offset);
7930 unsigned e_len = tvb_captured_length_remaining(tvb, offset);
7931 uint8_t *buf = (uint8_t *)tvb_memdup(pinfo->pool, tvb, offset, e_len);
7932 tvbuff_t *app;
7933
7934 /* The default nonce is a function of whether or not this is the server
7935 * or the client and the packet count. The packet count either comes from
7936 * the PDU or is a function of the previous value (of the sending node).
7937 */
7938 uint8_t nonce[11] = { 0 };
7939
7940 nonce[0] = (pdata->nid) >> 24;
7941 nonce[1] = (pdata->nid) >> 16;
7942 nonce[2] = (pdata->nid) >> 8;
7943 nonce[3] = (uint8_t)(pdata->nid);
7944 nonce[4] = slot >> 8;
7945 nonce[5] = (uint8_t)slot;
7946 nonce[7] = (pdata->dn) >> 24;
7947 nonce[8] = (pdata->dn) >> 16;
7948 nonce[9] = (pdata->dn) >> 8;
7949 nonce[10] = (uint8_t)(pdata->dn);
7950
7951 /* Now the hard part. We need to determine the current packet number.
7952 * This is a function of the sending node, the previous state and the
7953 * current PDU.
7954 */
7955
7956 app = NULL((void*)0);
7957
7958 proto_item_set_end(tree, tvb, offset);
7959 if (e_len < session->mac_len)
7960 {
7961 dof_packet->decrypted_buffer_error = "[Encrypted packet - decryption failure]";
7962 }
7963 else if (!session->encrypted)
7964 {
7965 /* There is still a MAC involved, and even though we don't need a new
7966 * buffer we need to adjust the length of the existing buffer.
7967 * The MAC is not checked. Keep a copy of the (clear) payload as the
7968 * secured buffer, so that it is dissected and seen as secured.
7969 */
7970 unsigned plain_len = e_len - session->mac_len;
7971
7972 app = tvb_new_subset_length(tvb, offset, plain_len);
7973 if (!dof_packet->decrypted_buffer && plain_len > 0)
7974 dof_packet->decrypted_buffer = (uint8_t *)tvb_memdup(wmem_file_scope(), app, 0, plain_len);
7975 dof_packet->decrypted_tvb = app;
7976 dof_packet->decrypted_offset = 0;
7977 }
7978 else
7979 {
7980 unsigned plain_len = e_len - session->mac_len;
7981
7982 if (dof_packet->decrypted_buffer)
7983 {
7984 /* No need to decrypt, but still need to create buffer. */
7985 app = tvb_new_real_data((const uint8_t *)dof_packet->decrypted_buffer, plain_len, plain_len);
7986 tvb_set_child_real_data_tvbuff(tvb, app);
7987 add_new_data_source(pinfo, app, "Decrypted DOF");
7988 dof_packet->decrypted_tvb = app;
7989 dof_packet->decrypted_offset = 0;
7990 }
7991 else
7992 {
7993 if (decrypt(session, pdata, nonce, epp_buf, a_len, buf, e_len))
7994 {
7995 /* store decrypted buffer in file scope for reuse in next pass */
7996 uint8_t *cache = (uint8_t *)wmem_alloc0(wmem_file_scope(), plain_len);
7997 memcpy(cache, buf, plain_len);
7998 app = tvb_new_real_data(cache, plain_len, plain_len);
7999 tvb_set_child_real_data_tvbuff(tvb, app);
8000 add_new_data_source(pinfo, app, "Decrypted DOF");
8001 dof_packet->decrypted_buffer = cache;
8002 dof_packet->decrypted_offset = 0;
8003 dof_packet->decrypted_tvb = app;
8004 }
8005 else
8006 {
8007 /* Failure to decrypt or validate the MAC.
8008 * The packet is secure, so there is nothing we can do!
8009 */
8010 dof_packet->decrypted_buffer_error = "[Encrypted packet - decryption failure]";
8011 }
8012 }
8013 }
8014
8015 /* Show a failure found just now as the later passes do (above). */
8016 if (dof_packet->decrypted_buffer_error)
8017 {
8018 col_set_str(pinfo->cinfo, COL_INFO, dof_packet->decrypted_buffer_error);
8019 expert_add_info(pinfo, tree, &ei_decode_failure);
8020 }
8021 }
8022
8023 return offset - secmode_api_data->security_mode_offset;
8024 }
8025 break;
8026
8027 case TRAILER:
8028 /* TODO check this case */
8029 break;
8030
8031 }
8032
8033 return 0;
8034}
8035
8036static int dissect_ccm_app(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
8037{
8038 unsigned offset = 0;
8039 uint8_t opcode = 0;
8040 uint16_t app;
8041 int app_len;
8042
8043 proto_item *ti;
8044 proto_tree *ccm_tree;
8045
8046 /* Make entries in Protocol column and Info column on summary display */
8047 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CCM ");
8048
8049 /* Create the protocol tree. */
8050 offset = 0;
8051 ti = proto_tree_add_item(tree, proto_ccm_app, tvb, offset, -1, ENC_NA0x00000000);
8052 ccm_tree = proto_item_add_subtree(ti, ett_ccm);
8053
8054 /* Add the APPID. */
8055 offset = read_c2(tvb, offset, &app, &app_len);
8056 ti = proto_tree_add_uint(ccm_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
8057 validate_c2(pinfo, ti, app, app_len);
8058
8059 /* Retrieve the opcode. */
8060 opcode = tvb_get_uint8(tvb, offset);
8061
8062 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, opcode, ccm_opcode_strings, "Unknown Opcode (%d)"));
8063
8064 if (tree)
8065 {
8066 /* Opcode */
8067 proto_tree_add_item(ccm_tree, hf_ccm_opcode, tvb, offset, 1, ENC_NA0x00000000);
8068#if 0 /* this needs completion */
8069 offset += 1;
8070
8071 switch (opcode)
8072 {
8073 case CCM_PDU_PROBE(0):
8074 {
8075 }
8076 break;
8077
8078 }
8079#endif
8080 }
8081
8082 return 1;
8083}
8084
8085#if 0 /* TODO not used yet */
8086static int dissect_ccm_validate(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree, void *data)
8087{
8088 dof_api_data *api_data = (dof_api_data *)data;
8089 dof_packet_data *packet;
8090 ccm_session_data *session;
8091 int offset;
8092 uint8_t ccm_flags;
8093 uint32_t nid;
8094 uint16_t slot;
8095 uint32_t pn;
8096 uint32_t tnid;
8097
8098 if (api_data == NULL((void*)0))
8099 {
8100 fprintf(stderrstderr, "api_data is NULL.");
8101 return 0;
8102 }
8103
8104 packet = api_data->packet;
8105 if (packet == NULL((void*)0))
8106 {
8107 fprintf(stderrstderr, "api_data->packet is NULL.");
8108 return 0;
8109 }
8110
8111 if (!packet->security_session)
8112 {
8113 fprintf(stderrstderr, "packet->security_session is NULL");
8114 return 0;
8115 }
8116
8117 if (packet->security_session->security_mode != DOF_PROTOCOL_CCM24577)
8118 {
8119 fprintf(stderrstderr, "packet->security_session->security_mode != DOF_PROTOCOL_CCM");
8120 return 0;
8121 }
8122
8123 session = (ccm_session_data *)packet->security_session->security_mode_key_data;
8124
8125 /* The buffer we have been passed includes the entire EPP frame. The packet
8126 * structure gives us the offset to our header.
8127 */
8128 offset = 0;
8129
8130 ccm_flags = tvb_get_uint8(tvb, offset);
8131 offset += 1;
8132
8133 /* TODO validate the C2 and C4 fields below? */
8134 if (ccm_flags & 0x04)
8135 offset = read_c4(tvb, offset, &nid, NULL((void*)0));
8136
8137 if (ccm_flags & 0x02)
8138 offset = read_c2(tvb, offset, &slot, NULL((void*)0));
8139
8140 if (ccm_flags & 0x01)
8141 offset = read_c4(tvb, offset, &pn, NULL((void*)0));
8142
8143 if (ccm_flags & 0x08)
8144 offset = read_c4(tvb, offset, &tnid, NULL((void*)0));
8145
8146
8147 /* We have reached the encryption boundary. At this point the rest of the packet
8148 * is encrypted, and we may or may not be able to decrypt it.
8149 *
8150 * If we can decrypt it (which for now means that it uses a Session Key of [0]
8151 * the we switch to decoding the decrypted PDU. Otherwise we create an entry
8152 * for the encrypted bytes and move on...
8153 */
8154
8155 {
8156 unsigned a_len = offset;
8157 const uint8_t *epp_buf = tvb_get_ptr(tvb, 0, offset);
8158 unsigned e_len = tvb_captured_length_remaining(tvb, offset);
8159 uint16_t e_off;
8160 uint8_t *buf = (uint8_t *)g_malloc(e_len);
8161
8162 /* The default nonce is a function of whether or not this is the server
8163 * or the client and the packet count. The packet count either comes from
8164 * the PDU or is a function of the previous value (of the sending node).
8165 */
8166 uint8_t nonce[] = { 0x00, 0x00, 0x00, 0x01,
8167 0x00, 0x00,
8168 0x00,
8169 0x00, 0x00, 0x00, 0x00 };
8170
8171 nonce[0] = nid >> 24;
8172 nonce[1] = nid >> 16;
8173 nonce[2] = nid >> 8;
8174 nonce[3] = (uint8_t)nid;
8175 nonce[4] = slot >> 8;
8176 nonce[5] = (uint8_t)slot;
8177 nonce[7] = pn >> 24;
8178 nonce[8] = pn >> 16;
8179 nonce[9] = pn >> 8;
8180 nonce[10] = (uint8_t)pn;
8181
8182 /* Now the hard part. We need to determine the current packet number.
8183 * This is a function of the sending node, the previous state and the
8184 * current PDU.
8185 */
8186 for (e_off = 0; e_off < e_len; e_off++)
8187 buf[e_off] = tvb_get_uint8(tvb, offset + e_off);
8188
8189 /* TODO: This is hardcoded for a 4-byte MAC */
8190
8191 proto_item_set_end(tree, tvb, offset);
8192 if (decrypt(session, (ccm_packet_data *)packet->security_packet, nonce, epp_buf, a_len, buf, e_len))
8193 {
8194 g_free(buf)(__builtin_object_size ((buf), 0) != ((size_t) - 1)) ? g_free_sized
(buf, __builtin_object_size ((buf), 0)) : (g_free) (buf)
;
8195 return 1;
8196 }
8197 else
8198 {
8199 /* Failure to decrypt or validate the MAC.
8200 * The packet is secure, so there is nothing we can do!
8201 */
8202 g_free(buf)(__builtin_object_size ((buf), 0) != ((size_t) - 1)) ? g_free_sized
(buf, __builtin_object_size ((buf), 0)) : (g_free) (buf)
;
8203 return 1;
8204 }
8205 }
8206}
8207#endif
8208
8209static int dissect_oap_dsp(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree, void *data _U___attribute__((unused)))
8210{
8211 /* We are handed a buffer that starts with our protocol id. Any options follow that. */
8212 unsigned offset = 0;
8213
8214 /* We don't care except for the treeview. */
8215 if (!tree)
8216 return 0;
8217
8218 /* Compute the version and flags, masking off other bits. */
8219 offset += 4; /* Skip the type and protocol. */
8220
8221 proto_tree_add_item(tree, hf_oap_1_dsp_option, tvb, 0, -1, ENC_NA0x00000000);
8222 return offset;
8223}
8224
8225static int dissect_oap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
8226{
8227 dof_api_data *api_data = (dof_api_data *)data;
8228 dof_packet_data *packet_data;
8229
8230 unsigned offset = 0;
8231 uint8_t opcode = 0;
8232 uint8_t flags = 0;
8233 uint16_t item_id = 0;
8234 uint16_t app;
8235 int app_len;
8236
8237 oap_1_packet_data *oap_packet = NULL((void*)0);
8238
8239 proto_item *ti;
8240 proto_tree *oap_tree;
8241
8242 if (api_data == NULL((void*)0))
8243 {
8244 return 0;
8245 }
8246
8247 packet_data = api_data->packet;
8248 if (packet_data == NULL((void*)0))
8249 {
8250 return 0;
8251 }
8252
8253
8254 /* Make entries in Protocol column and Info column on summary display */
8255 col_set_str(pinfo->cinfo, COL_PROTOCOL, "OAPv1 ");
8256
8257 /* Create the protocol tree. */
8258 offset = 0;
8259 ti = proto_tree_add_item(tree, proto_oap_1, tvb, offset, -1, ENC_NA0x00000000);
8260 oap_tree = proto_item_add_subtree(ti, ett_oap_1);
8261
8262 /* Add the APPID. */
8263 offset = read_c2(tvb, offset, &app, &app_len);
8264 ti = proto_tree_add_uint(oap_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
8265 validate_c2(pinfo, ti, app, app_len);
8266
8267 if ((unsigned)app_len == tvb_captured_length(tvb))
8268 {
8269 col_append_str(pinfo->cinfo, COL_INFO, "OAP [nop]");
8270 expert_add_info(pinfo, oap_tree, &ei_implicit_no_op);
8271
8272 return app_len;
8273 }
8274
8275 oap_packet = (oap_1_packet_data *)dof_packet_get_proto_data(packet_data, proto_oap_1);
8276 if (!oap_packet)
8277 {
8278 oap_packet = wmem_new0(wmem_file_scope(), oap_1_packet_data)((oap_1_packet_data*)wmem_alloc0((wmem_file_scope()), sizeof(
oap_1_packet_data)))
;
8279 dof_packet_add_proto_data(packet_data, proto_oap_1, oap_packet);
8280 }
8281
8282 /* Compute the version and flags, masking off other bits. */
8283 opcode = tvb_get_uint8(tvb, offset) & 0x1F;
8284 if (!packet_data->is_command)
8285 opcode |= OAP_1_RESPONSE(0x80);
8286
8287 flags = tvb_get_uint8(tvb, offset) & 0xE0;
8288
8289 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, opcode, oap_opcode_strings, "Unknown Opcode (%d)"));
8290
8291
8292 /* Opcode */
8293 {
8294 uint8_t mask = 0x10;
8295 char str[20];
8296 uint8_t no_of_bits = 5;
8297 uint8_t i;
8298 uint8_t bit = 3;
8299 (void) g_strlcpy(str, "...", 20);
8300
8301 /* read the bits for the int */
8302 for (i = 0; i < no_of_bits; i++)
8303 {
8304 if (bit && (!(bit % 4)))
8305 (void) g_strlcat(str, " ", 20);
8306
8307 bit++;
8308
8309 if (opcode & mask)
8310 (void) g_strlcat(str, "1", 20);
8311 else
8312 (void) g_strlcat(str, "0", 20);
8313
8314 mask = mask >> 1;
8315 }
8316
8317 proto_tree_add_uint_format(oap_tree, hf_oap_1_opcode, tvb, offset, 1, opcode & 0x1F, "%s = Opcode: %s (%u)", str, val_to_str(pinfo->pool, opcode, oap_opcode_strings, "Unknown Opcode (%d)"), opcode & 0x1F);
8318 }
8319
8320
8321 /* Flags, based on opcode.
8322 * Each opcode needs to define the flags, however, the fall into major categories...
8323 */
8324 switch (opcode)
8325 {
8326 /* Both alias and a flag that equals command control. */
8327 case OAP_1_CMD_ACTIVATE28:
8328 case OAP_1_CMD_CONNECT4:
8329 case OAP_1_CMD_FULL_CONNECT3:
8330 case OAP_1_CMD_GET10:
8331 case OAP_1_CMD_INVOKE12:
8332 case OAP_1_CMD_REGISTER25:
8333 case OAP_1_CMD_SET20:
8334 case OAP_1_CMD_SUBSCRIBE24:
8335 case OAP_1_CMD_WATCH30:
8336 proto_tree_add_item(oap_tree, hf_oap_1_alias_size, tvb, offset, 1, ENC_NA0x00000000);
8337 proto_tree_add_item(oap_tree, hf_oap_1_flags, tvb, offset, 1, ENC_NA0x00000000);
8338 if (flags & 0x20)
8339 {
8340 offset += 1;
8341 offset = oap_1_tree_add_cmdcontrol(pinfo, oap_tree, tvb, offset);
8342 }
8343 else
8344 offset += 1;
8345
8346 break;
8347
8348 /* No alias, but flags for command control. */
8349 case OAP_1_CMD_ADVERTISE5:
8350 /* TODO: Expert info on top two bits.*/
8351 proto_tree_add_item(oap_tree, hf_oap_1_flags, tvb, offset, 1, ENC_NA0x00000000);
8352 if (flags & 0x20)
8353 {
8354 offset += 1;
8355 offset = oap_1_tree_add_cmdcontrol(pinfo, oap_tree, tvb, offset);
8356 }
8357 else
8358 offset += 1;
8359
8360 break;
8361
8362 /* No alias, but flag for provider. */
8363 case OAP_1_RSP_GET(10|(0x80)):
8364 case OAP_1_RSP_INVOKE(12|(0x80)):
8365 case OAP_1_RSP_REGISTER(25|(0x80)):
8366 case OAP_1_RSP_SET(20|(0x80)):
8367 case OAP_1_RSP_SUBSCRIBE(24|(0x80)):
8368 /* TODO: Expert info on top two bits.*/
8369 proto_tree_add_item(oap_tree, hf_oap_1_flags, tvb, offset, 1, ENC_NA0x00000000);
8370 if (flags & 0x20)
8371 {
8372 offset += 1;
8373 offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, oap_tree,
8374 offset, hf_oap_1_providerid, ett_oap_1_1_providerid, NULL((void*)0));
8375 }
8376 else
8377 offset += 1;
8378 if ((opcode == OAP_1_RSP_GET(10|(0x80))) || (opcode == OAP_1_RSP_INVOKE(12|(0x80))))
8379 {
8380 /* The value list can be empty */
8381 if (tvb_reported_length_remaining(tvb, offset) > 0)
8382 {
8383 proto_tree_add_item(oap_tree, hf_oap_1_value_list, tvb, offset, -1, ENC_NA0x00000000);
8384 offset += tvb_reported_length_remaining(tvb, offset);
8385 }
8386 }
8387
8388 break;
8389
8390 /* Alias, but no flags. */
8391 case OAP_1_CMD_CHANGE2:
8392 case OAP_1_CMD_OPEN14:
8393 case OAP_1_CMD_PROVIDE16:
8394 case OAP_1_CMD_SIGNAL22:
8395 proto_tree_add_item(oap_tree, hf_oap_1_alias_size, tvb, offset, 1, ENC_NA0x00000000);
8396 offset += 1;
8397 break;
8398
8399 /* Special flags. */
8400 case OAP_1_RSP_EXCEPTION(9|(0x80)):
8401 proto_tree_add_item(oap_tree, hf_oap_1_exception_internal_flag, tvb, offset, 1, ENC_NA0x00000000);
8402 proto_tree_add_item(oap_tree, hf_oap_1_exception_final_flag, tvb, offset, 1, ENC_NA0x00000000);
8403 proto_tree_add_item(oap_tree, hf_oap_1_exception_provider_flag, tvb, offset, 1, ENC_NA0x00000000);
8404 offset += 1;
8405 break;
8406
8407 /* No flags. */
8408 case OAP_1_CMD_DEFINE6:
8409 case OAP_1_RSP_DEFINE(6|(0x80)):
8410 case OAP_1_RSP_OPEN(14|(0x80)):
8411 /* TODO: Non-zero not allowed.*/
8412 offset += 1;
8413 break;
8414
8415 default:
8416 /* TODO: Illegal opcode.*/
8417 return offset;
8418 }
8419
8420 /* Parse off arguments based on opcodes. */
8421 switch (opcode)
8422 {
8423 case OAP_1_CMD_SUBSCRIBE24:
8424 {
8425 uint8_t alias_len = (flags & 0xC0) >> 6;
8426 if (alias_len == 3)
8427 alias_len = 4;
8428
8429 /* The item identifier comes first, but it is compressed. */
8430 {
8431 int item_id_len;
8432 proto_item *pi;
8433
8434 read_c2(tvb, offset, &item_id, &item_id_len);
8435 pi = proto_tree_add_uint_format(oap_tree, hf_oap_1_itemid, tvb, offset, item_id_len, item_id, "Item ID: %u", item_id);
8436 validate_c2(pinfo, pi, item_id, item_id_len);
8437 offset += item_id_len;
8438 }
8439
8440 if (alias_len > 0)
8441 {
8442 if (api_data->session == NULL((void*)0))
8443 {
8444 expert_add_info(pinfo, ti, &ei_oap_no_session);
8445 return offset;
8446 }
8447 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true1);
8448 }
8449 else
8450 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8451
8452 /* Read the minimum delta. */
8453 {
8454 int delta_len;
8455 uint16_t delta;
8456 proto_item *pi;
8457
8458 read_c2(tvb, offset, &delta, &delta_len);
8459 pi = proto_tree_add_uint_format(oap_tree, hf_oap_1_subscription_delta, tvb, offset, delta_len, delta, "Minimum Delta: %u", delta);
8460 validate_c2(pinfo, pi, delta, delta_len);
8461 offset += delta_len;
8462 }
8463 }
8464 break;
8465
8466 case OAP_1_CMD_REGISTER25:
8467 {
8468 uint8_t alias_len = (flags & 0xC0) >> 6;
8469 if (alias_len == 3)
8470 alias_len = 4;
8471
8472 /* The item identifier comes first, but it is compressed. */
8473 {
8474 int item_id_len;
8475 proto_item *pi;
8476
8477 read_c2(tvb, offset, &item_id, &item_id_len);
8478 pi = proto_tree_add_uint_format(oap_tree, hf_oap_1_itemid, tvb, offset, item_id_len, item_id, "Item ID: %u", item_id);
8479 validate_c2(pinfo, pi, item_id, item_id_len);
8480 offset += item_id_len;
8481 }
8482
8483 if (alias_len > 0)
8484 {
8485 if (api_data->session == NULL((void*)0))
8486 {
8487 expert_add_info(pinfo, ti, &ei_oap_no_session);
8488 return offset;
8489 }
8490 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true1);
8491 }
8492 else
8493 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8494 }
8495 break;
8496
8497 case OAP_1_RSP_REGISTER(25|(0x80)):
8498 {
8499 if (flags & 0x20)
8500 {
8501 /* offset = add_oid( tvb, offset, NULL, oap_tree ); */
8502 }
8503
8504 /* Sequence is next. */
8505 proto_tree_add_item(oap_tree, hf_oap_1_update_sequence, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
8506 offset += 2;
8507 }
8508 break;
8509
8510 case OAP_1_CMD_WATCH30:
8511 case OAP_1_CMD_ACTIVATE28:
8512 case OAP_1_CMD_CONNECT4:
8513 case OAP_1_CMD_FULL_CONNECT3:
8514 {
8515 uint8_t alias_len = (flags & 0xC0) >> 6;
8516 if (alias_len == 3)
8517 alias_len = 4;
8518
8519 if (alias_len > 0)
8520 {
8521 if (api_data->session == NULL((void*)0))
8522 {
8523 expert_add_info(pinfo, ti, &ei_oap_no_session);
8524 return offset;
8525 }
8526 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true1);
8527 }
8528 else
8529 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8530 }
8531 break;
8532
8533 case OAP_1_CMD_ADVERTISE5:
8534 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8535 break;
8536
8537 case OAP_1_CMD_GET10:
8538 case OAP_1_CMD_INVOKE12:
8539 case OAP_1_CMD_SET20:
8540 {
8541 uint8_t alias_len = (flags & 0xC0) >> 6;
8542 if (alias_len == 3)
8543 alias_len = 4;
8544
8545 /* The item identifier comes first, but it is compressed. */
8546 {
8547 int item_id_len;
8548 proto_item *pi;
8549
8550 read_c2(tvb, offset, &item_id, &item_id_len);
8551 pi = proto_tree_add_uint_format(oap_tree, hf_oap_1_itemid, tvb, offset, item_id_len, item_id, "Item ID: %u", item_id);
8552 validate_c2(pinfo, pi, item_id, item_id_len);
8553 offset += item_id_len;
8554 }
8555
8556 if (alias_len > 0)
8557 {
8558 if (api_data->session == NULL((void*)0))
8559 {
8560 expert_add_info(pinfo, ti, &ei_oap_no_session);
8561 return offset;
8562 }
8563 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true1);
8564 }
8565 else
8566 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8567
8568 if ((opcode == OAP_1_CMD_SET20) || (opcode == OAP_1_CMD_INVOKE12))
8569 {
8570 /* The value list can be empty */
8571 if (tvb_reported_length_remaining(tvb, offset) > 0)
8572 {
8573 proto_tree_add_item(oap_tree, hf_oap_1_value_list, tvb, offset, -1, ENC_NA0x00000000);
8574 offset += tvb_reported_length_remaining(tvb, offset);
8575 }
8576 }
8577 }
8578 break;
8579
8580 case OAP_1_CMD_OPEN14:
8581 {
8582 uint8_t alias_len = (flags & 0xC0) >> 6;
8583 if (alias_len == 3)
8584 alias_len = 4;
8585
8586 if (alias_len > 0)
8587 {
8588 if (api_data->session == NULL((void*)0))
8589 {
8590 expert_add_info(pinfo, ti, &ei_oap_no_session);
8591 return offset;
8592 }
8593 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true1);
8594 }
8595 else
8596 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8597
8598 offset = oap_1_tree_add_interface(oap_tree, tvb, offset);
8599
8600 offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, oap_tree,
8601 offset, hf_oap_1_objectid, ett_oap_1_objectid, NULL((void*)0));
8602 }
8603 break;
8604
8605 case OAP_1_CMD_PROVIDE16:
8606 {
8607 uint8_t alias_length = flags >> 6;
8608 int alias_offset;
8609 int iid_offset;
8610 int oid_offset;
8611
8612 if (alias_length == 3)
8613 alias_length = 4;
8614
8615 alias_offset = offset;
8616 if (alias_length == 0)
8617 {
8618 expert_add_info_format(pinfo, ti, &ei_malformed, "alias_length == 0");
8619 return offset;
8620 }
8621 if (api_data->session == NULL((void*)0))
8622 {
8623 expert_add_info(pinfo, ti, &ei_oap_no_session);
8624 return offset;
8625 }
8626 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_length, false0);
8627
8628 iid_offset = offset;
8629 offset = oap_1_tree_add_interface(oap_tree, tvb, offset);
8630
8631 oid_offset = offset;
8632 offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, oap_tree,
8633 offset, hf_oap_1_objectid, ett_oap_1_objectid, NULL((void*)0));
8634
8635 if (!packet_data->processed)
8636 {
8637 uint32_t alias;
8638 oap_1_binding *binding = wmem_new0(wmem_file_scope(), oap_1_binding)((oap_1_binding*)wmem_alloc0((wmem_file_scope()), sizeof(oap_1_binding
)))
;
8639 int i;
8640
8641 alias = 0;
8642 for (i = 0; i < alias_length; i++)
8643 alias = (alias << 8) | tvb_get_uint8(tvb, alias_offset + i);
8644
8645 binding->iid_length = oid_offset - iid_offset;
8646 binding->iid = (uint8_t *)wmem_alloc0(wmem_file_scope(), binding->iid_length);
8647 tvb_memcpy(tvb, binding->iid, iid_offset, binding->iid_length);
8648
8649 binding->oid_length = offset - oid_offset;
8650 binding->oid = (uint8_t *)wmem_alloc0(wmem_file_scope(), binding->oid_length);
8651 tvb_memcpy(tvb, binding->oid, oid_offset, binding->oid_length);
8652
8653 binding->frame = pinfo->fd->num;
8654 oap_1_define_alias(api_data, alias, binding);
8655 }
8656 }
8657 break;
8658
8659 case OAP_1_CMD_CHANGE2:
8660 case OAP_1_CMD_SIGNAL22:
8661 {
8662 uint8_t alias_len = (flags & 0xC0) >> 6;
8663 if (alias_len == 3)
8664 alias_len = 4;
8665
8666 /* The item identifier comes first, but it is compressed. */
8667 {
8668 int item_id_len;
8669 proto_item *pi;
8670
8671 read_c2(tvb, offset, &item_id, &item_id_len);
8672 pi = proto_tree_add_uint_format(oap_tree, hf_oap_1_itemid, tvb, offset, item_id_len, item_id, "Item ID: %u", item_id);
8673 validate_c2(pinfo, pi, item_id, item_id_len);
8674 offset += item_id_len;
8675 }
8676
8677 if (alias_len > 0)
8678 {
8679 if (api_data->session == NULL((void*)0))
8680 {
8681 expert_add_info(pinfo, ti, &ei_oap_no_session);
8682 return offset;
8683 }
8684 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true1);
8685 }
8686 else
8687 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8688
8689 /* Sequence is next. */
8690 proto_tree_add_item(oap_tree, hf_oap_1_update_sequence, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
8691 offset += 2;
8692
8693 /* The value list can be empty */
8694 if (tvb_reported_length_remaining(tvb, offset) > 0)
8695 {
8696 proto_tree_add_item(oap_tree, hf_oap_1_value_list, tvb, offset, -1, ENC_NA0x00000000);
8697 offset += tvb_reported_length_remaining(tvb, offset);
8698 }
8699 }
8700 break;
8701
8702 case OAP_1_RSP_EXCEPTION(9|(0x80)):
8703 {
8704 if (flags & 0x20)
8705 {
8706 /* offset = add_oid( tvb, offset, NULL, oap_tree );*/
8707 }
8708
8709 /* The response code, compressed. */
8710 {
8711 int rsp_len;
8712 uint16_t rsp;
8713
8714 /* TODO: Validate*/
8715 read_c2(tvb, offset, &rsp, &rsp_len);
8716 /* TODO: Add to tree with error codes. */
8717 offset += rsp_len;
8718 }
8719 /* The value list can be empty */
8720 if (tvb_reported_length_remaining(tvb, offset) > 0)
8721 {
8722 proto_tree_add_item(oap_tree, hf_oap_1_value_list, tvb, offset, -1, ENC_NA0x00000000);
8723 offset += tvb_reported_length_remaining(tvb, offset);
8724 }
8725 }
8726 break;
8727
8728 default:
8729 /* TODO: Bad opcode!*/
8730 break;
8731 }
8732
8733 return offset;
8734}
8735
8736static int dissect_sgmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
8737{
8738 dof_api_data *api_data = (dof_api_data *)data;
8739 dof_packet_data *packet_data;
8740 unsigned offset = 0;
8741 uint8_t opcode;
8742 uint16_t app;
8743 int app_len;
8744 proto_item *ti;
8745 proto_tree *sgmp_tree;
8746
8747 if (api_data == NULL((void*)0))
8748 {
8749 /* TODO: Output error. */
8750 return 0;
8751 }
8752
8753 packet_data = api_data->packet;
8754 if (packet_data == NULL((void*)0))
8755 {
8756 /* TODO: Output error. */
8757 return 0;
8758 }
8759
8760 /* Make entries in Protocol column and Info column on summary display */
8761 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SGMPv1 ");
8762
8763 /* Create the protocol tree. */
8764 offset = 0;
8765 ti = proto_tree_add_item(tree, proto_sgmp, tvb, offset, -1, ENC_NA0x00000000);
8766 sgmp_tree = proto_item_add_subtree(ti, ett_sgmp);
8767
8768 /* Add the APPID. */
8769 offset = read_c2(tvb, offset, &app, &app_len);
8770 ti = proto_tree_add_uint(sgmp_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
8771 validate_c2(pinfo, ti, app, app_len);
8772
8773 if (offset == tvb_captured_length(tvb))
8774 {
8775 col_append_str(pinfo->cinfo, COL_INFO, "SGMP [nop]");
8776 expert_add_info(pinfo, sgmp_tree, &ei_implicit_no_op);
8777
8778 return offset;
8779 }
8780
8781
8782 /* Retrieve the opcode. */
8783 opcode = tvb_get_uint8(tvb, offset);
8784 if (!packet_data->is_command)
8785 opcode |= SGMP_RESPONSE(0x80);
8786
8787 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, opcode, sgmp_opcode_strings, "Unknown Opcode (%d)"));
8788
8789 /* Opcode */
8790 proto_tree_add_item(sgmp_tree, hf_opcode, tvb, offset, 1, ENC_NA0x00000000);
8791 offset += 1;
8792
8793 switch (opcode)
8794 {
8795 case SGMP_CMD_EPOCH_CHANGED(1):
8796 {
8797 /* TMIN - 2 bytes */
8798 {
8799 proto_tree_add_item(sgmp_tree, hf_sgmp_tmin, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
8800 offset += 2;
8801 }
8802
8803 /* EPOCH - 2 bytes */
8804 {
8805 proto_tree_add_item(sgmp_tree, hf_sgmp_epoch, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
8806 offset += 2;
8807 }
8808 }
8809 break;
8810
8811 case SGMP_CMD_HEARTBEAT(0):
8812 {
8813 int start_offset;
8814
8815 /* Latest SGMP Version - Type.1 */
8816 {
8817 uint16_t version;
8818 int length;
8819 proto_item *pi;
8820
8821 start_offset = offset;
8822 offset = read_c2(tvb, offset, &version, &length);
8823 pi = proto_tree_add_uint(sgmp_tree, hf_latest_version, tvb, start_offset, offset - start_offset, version);
8824 validate_c2(pinfo, pi, version, length);
8825 }
8826
8827 /* Desire - 1 byte */
8828 {
8829 proto_tree_add_item(sgmp_tree, hf_desire, tvb, offset, 1, ENC_NA0x00000000);
8830 offset += 1;
8831 }
8832
8833 /* Tie Breaker - 4 bytes */
8834 {
8835 proto_tree_add_item(sgmp_tree, hf_tie_breaker, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
8836 offset += 4;
8837 }
8838 }
8839 break;
8840
8841 case SGMP_CMD_REKEY(2):
8842 case SGMP_CMD_REKEY_EPOCH(5):
8843 case SGMP_CMD_REKEY_MERGE(7):
8844 {
8845#if 0 /*TODO check this */
8846 int start_offset;
8847 tvbuff_t *initial_state;
8848#endif
8849 uint8_t key[32];
8850
8851 /* Delay - one byte */
8852 if (opcode != SGMP_CMD_REKEY_MERGE(7))
8853 {
8854 proto_tree_add_item(sgmp_tree, hf_delay, tvb, offset, 1, ENC_NA0x00000000);
8855 offset += 1;
8856 }
8857
8858 /* Initial State - Security.9 (not REKEY_MERGE) */
8859 {
8860 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_9, tvb, pinfo, sgmp_tree,
8861 offset, hf_initial_state, ett_initial_state, NULL((void*)0));
8862#if 0 /*TODO check this */
8863 initial_state = tvb_new_subset_length(tvb, start_offset, offset - start_offset);
8864#endif
8865 }
8866
8867 /* Epoch - 2 bytes (only REKEY_EPOCH) */
8868 if (opcode == SGMP_CMD_REKEY_EPOCH(5))
8869 {
8870 proto_tree_add_item(sgmp_tree, hf_sgmp_epoch, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
8871 offset += 2;
8872 }
8873
8874 /* Kgm - 32 bytes */
8875 {
8876 proto_tree_add_item(sgmp_tree, hf_key, tvb, offset, 32, ENC_NA0x00000000);
8877 tvb_memcpy(tvb, key, offset, 32);
8878 offset += 32;
8879 }
8880
8881 /* Handle the initialization block. */
8882 if (!packet_data->processed && api_data->session)
8883 {
8884 /*dof_session_data* session = (dof_session_data*)api_data->session;*/
8885
8886 /* Look up the field-dissector table, and determine if it is registered. */
8887 dissector_table_t field_dissector = find_dissector_table("dof.secmode");
8888 if (field_dissector != NULL((void*)0))
8889 {
8890#if 0
8891 dissector_handle_t field_handle = dissector_get_port_handle(field_dissector, packet_data->security_mode);
8892 if (field_handle != NULL((void*)0))
8893 {
8894 void *saved_private = pinfo->private_data;
8895 dof_secmode_api_data setup_data;
8896 int block_length;
8897
8898 setup_data.version = DOF_API_VERSION;
8899 setup_data.context = INITIALIZE;
8900 setup_data.dof_api = api_data;
8901 setup_data.secure_session = rekey_data->security_session;
8902 /* TODO FIX THIS setup_data.session_key = session_key; */
8903 pinfo->private_data = &setup_data;
8904 block_length = call_dissector_only(field_handle, NULL((void*)0), pinfo, NULL((void*)0));
8905 pinfo->private_data = saved_private;
8906 }
8907#endif
8908 }
8909 }
8910 }
8911 break;
8912
8913 case SGMP_CMD_REQUEST_GROUP(3):
8914 {
8915 uint8_t *domain_buf = NULL((void*)0);
8916 unsigned domain_length = 0;
8917 int start_offset;
8918 unsigned I_offset = offset;
8919 sgmp_packet_data *sgmp_data = NULL((void*)0);
8920 uint16_t epoch;
8921
8922 /* START OF I BLOCK */
8923 /* Domain - Security.7 */
8924 {
8925 start_offset = offset;
8926 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, sgmp_tree,
8927 offset, hf_sgmp_domain, ett_sgmp_domain, NULL((void*)0));
8928 if (!packet_data->processed)
8929 {
8930 domain_length = dof_consumed_length(offset, start_offset);
8931 domain_buf = (uint8_t *)wmem_alloc0(pinfo->pool, domain_length);
8932 tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
8933 }
8934 }
8935
8936 /* Epoch - 2 bytes */
8937 {
8938 proto_tree_add_item_ret_uint16(sgmp_tree, hf_sgmp_epoch, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000, &epoch);
8939 offset += 2;
8940 }
8941
8942 /* Initiator Block - SGMP.6.3 */
8943 {
8944 /* SGMP Key Request - Security.4 */
8945 {
8946 dof_2008_16_security_4 response;
8947 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_4, tvb, pinfo, sgmp_tree,
8948 offset, hf_initiator_block, ett_initiator_block, &response);
8949 if (!packet_data->processed)
8950 {
8951 tvbuff_t *identity = response.identity;
8952 unsigned identity_length = tvb_reported_length(identity);
8953 uint8_t *identity_buf = (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length);
8954
8955 /* Get the buffer. */
8956 tvb_memcpy(identity, identity_buf, 0, identity_length);
8957
8958 {
8959 sgmp_data = wmem_new0(wmem_file_scope(), sgmp_packet_data)((sgmp_packet_data*)wmem_alloc0((wmem_file_scope()), sizeof(sgmp_packet_data
)))
;
8960 dof_packet_add_proto_data(packet_data, proto_sgmp, sgmp_data);
8961
8962 sgmp_data->domain_length = domain_length;
8963 sgmp_data->domain = (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length);
8964 memcpy(sgmp_data->domain, domain_buf, domain_length);
8965
8966 sgmp_data->group_length = identity_length;
8967 sgmp_data->group = (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length);
8968 memcpy(sgmp_data->group, identity_buf, identity_length);
8969
8970 sgmp_data->epoch = epoch;
8971 sgmp_data->request_session = api_data->session;
8972 }
8973 }
8974 }
8975 }
8976
8977 /* Security Scope - Security.10 */
8978 {
8979 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_10, tvb, pinfo, sgmp_tree,
8980 offset, hf_sgmp_security_scope, ett_sgmp_security_scope, NULL((void*)0));
8981 }
8982
8983 /* END OF I BLOCK */
8984 if (sgmp_data && !sgmp_data->I)
8985 {
8986 sgmp_data->I_length = dof_consumed_length(offset, I_offset);
8987 sgmp_data->I = (uint8_t *)wmem_alloc0(wmem_file_scope(), sgmp_data->I_length);
8988 tvb_memcpy(tvb, sgmp_data->I, I_offset, sgmp_data->I_length);
8989 }
8990 }
8991 break;
8992
8993 case SGMP_RSP_REQUEST_GROUP((3)|(0x80)):
8994 {
8995 int start_offset;
8996#if 0 /*TODO check this */
8997 unsigned A_offset;
8998 tvbuff_t *initial_state;
8999 unsigned A_end;
9000#endif
9001
9002 /* START OF A BLOCK */
9003 /* Initial State - SGMP.6.2.1 */
9004 {
9005 /* A_offset = offset;*/
9006
9007 /* Initial State - Security.9 */
9008 {
9009 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_9, tvb, pinfo, sgmp_tree,
9010 offset, hf_initial_state, ett_initial_state, NULL((void*)0));
9011#if 0 /*TODO check this */
9012 initial_state = tvb_new_subset_length(tvb, start_offset, offset - start_offset);
9013#endif
9014 }
9015
9016 /* Latest SGMP Version - Type.1 */
9017 {
9018 uint16_t version;
9019 int length;
9020 proto_item *pi;
9021
9022 start_offset = offset;
9023 offset = read_c2(tvb, offset, &version, &length);
9024 pi = proto_tree_add_uint(sgmp_tree, hf_latest_version, tvb, start_offset, offset - start_offset, version);
9025 validate_c2(pinfo, pi, version, length);
9026 }
9027
9028 /* Desire - 1 byte */
9029 {
9030 proto_tree_add_item(sgmp_tree, hf_desire, tvb, offset, 1, ENC_NA0x00000000);
9031 offset += 1;
9032 }
9033 }
9034
9035 /* END OF A BLOCK */
9036 /* A block data handled in first part of the next block. */
9037#if 0 /*TODO check this */
9038 A_end = offset;
9039#endif
9040
9041 /* Ticket - Security.5 */
9042 {
9043 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, sgmp_tree,
9044 offset, hf_ticket, ett_ticket, NULL((void*)0));
9045 }
9046
9047 /* Try to match up the information learned here with any groups that exist.
9048 * Note that we do not know the SSID, and so we can only match based on the
9049 * domain and group identifier. We will learn the SSID based on a successful
9050 * match to a secure session.
9051 */
9052 if (packet_data->opid_first && !api_data->secure_session)
9053 {
9054#if 0
9055 sgmp_packet_data* cmd_data = (sgmp_packet_data*)dof_packet_get_proto_data(packet_data->opid_first, proto_sgmp);
9056 extern struct BlockCipher BlockCipher_AES_256;
9057 struct BlockCipher* cipher = &BlockCipher_AES_256;
9058 uint8_t* ekey = (uint8_t*)ep_alloc(cipher->keyStateSize);
9059
9060 if (cmd_data && !cmd_data->A)
9061 {
9062 cmd_data->A_length = A_end - A_offset;
9063 cmd_data->A = (uint8_t*)wmem_alloc0(wmem_file_scope(), cmd_data->A_length);
9064 tvb_memcpy(tvb, cmd_data->A, A_offset, cmd_data->A_length);
9065 }
9066
9067 /* Search through the appropriate keks to find a match. */
9068 {
9069 dof_learned_group_data* group = globals.learned_group_data;
9070 struct list;
9071 struct list
9072 { dof_learned_group_data *group;
9073 struct list *next; };
9074 struct list *to_try = NULL((void*)0);
9075 uint8_t confirmation[32];
9076 uint8_t* discovered_kek = NULL((void*)0);
9077 dof_learned_group_auth_data *auth = NULL((void*)0);
9078
9079 tvb_memcpy(tvb, confirmation, start_offset, 32);
9080
9081 while (group)
9082 {
9083 if ((cmd_data->domain_length == group->domain_length) &&
9084 (memcmp(cmd_data->domain, group->domain, group->domain_length) == 0) &&
9085 (cmd_data->group_length == group->group_length) &&
9086 (memcmp(cmd_data->group, group->group, group->group_length) == 0))
9087 {
9088 struct list *n = (struct list *) ep_alloc0(sizeof(struct list));
9089 n->group = group;
9090 n->next = to_try;
9091 to_try = n;
9092 }
9093
9094 group = group->next;
9095 }
9096
9097 /* At this point we may be able to learn the session key. */
9098 while (to_try && !discovered_kek)
9099 {
9100 group = to_try->group;
9101
9102 auth = group->keys;
9103
9104 while (auth && !discovered_kek)
9105 {
9106 uint8_t mac[32];
9107 uint8_t key[32];
9108 int j;
9109
9110 /* It only makes sense to check matching epochs. */
9111 if (auth->epoch == cmd_data->epoch)
9112 {
9113 tvb_memcpy(tvb, mac, start_offset, 32);
9114 tvb_memcpy(tvb, key, start_offset + 32, 32);
9115
9116 if (cipher != NULL((void*)0))
9117 {
9118 cipher->GenerateKeyState(ekey, auth->kek);
9119 cipher->Encrypt(ekey, mac);
9120 cipher->Encrypt(ekey, mac + 16);
9121 }
9122
9123 for (j = 0; j < 32; j++)
9124 key[j] ^= mac[j];
9125
9126 if (sgmp_validate_session_key(cmd_data, confirmation, auth->kek, key))
9127 {
9128 discovered_kek = (uint8_t*)se_alloc0(32);
9129 memcpy(discovered_kek, key, 32);
9130 break;
9131 }
9132 }
9133
9134 auth = auth->next;
9135 }
9136
9137 to_try = to_try->next;
9138 }
9139
9140 /* Determine if there is already a secure session for this information. If there is, then
9141 * EPP will find it to decode any packets. If there is not, then we must create a secure
9142 * session and initialize it so that future packets can be decoded.
9143 * NOTE: None of the actual decoding is done here, because this packet is not encrypted
9144 * in the session that it defines.
9145 * NOTE: SGMP secure sessions are always attached to the DPS session, which is always
9146 * associated with the transport session (server address).
9147 */
9148 if (discovered_kek)
9149 {
9150 dissector_table_t field_dissector;
9151 dissector_handle_t field_handle;
9152 dof_session_key_exchange_data *key_exchange = NULL((void*)0);
9153
9154 dof_secure_session_data *dof_secure_session = cmd_data->request_session->secure_sessions;
9155 while (dof_secure_session)
9156 {
9157 if ((dof_secure_session->ssid == group->ssid) &&
9158 (dof_secure_session->domain_length == group->domain_length) &&
9159 (memcmp(dof_secure_session->domain, group->domain, group->domain_length) == 0))
9160 break;
9161
9162 dof_secure_session = dof_secure_session->next;
9163 }
9164
9165 if (!dof_secure_session)
9166 {
9167 dof_session_data *dof_session = wmem_alloc0(wmem_file_scope(), sizeof(dof_session_data));
9168 dof_session->session_id = globals.next_session++;
9169 dof_session->dof_id = api_data->session->dof_id;
9170
9171 dof_secure_session = wmem_alloc0(wmem_file_scope(), sizeof(dof_secure_session_data));
9172 dof_secure_session->ssid = group->ssid;
9173 dof_secure_session->domain_length = group->domain_length;
9174 dof_secure_session->domain = group->domain;
9175 dof_secure_session->original_session_id = cmd_data->request_session->session_id;
9176 dof_secure_session->parent = dof_session;
9177 dof_secure_session->is_2_node = false0;
9178 dof_secure_session->next = cmd_data->request_session->secure_sessions;
9179 cmd_data->request_session->secure_sessions = dof_secure_session;
9180 }
9181
9182 /* This packet represents a new key exchange, and so a new key exchange data
9183 * structure needs to be created.
9184 */
9185 {
9186 key_exchange = wmem_alloc0(wmem_file_scope(), sizeof(dof_session_key_exchange_data));
9187 if (!key_exchange)
9188 return offset;
9189
9190 key_exchange->i_valid = packet_data->opid_first->dof_frame;
9191 key_exchange->r_valid = packet_data->dof_frame;
9192 key_exchange->security_mode = auth->security_mode;
9193 key_exchange->security_mode_data = auth->mode;
9194 key_exchange->security_mode_data_length = auth->mode_length;
9195 key_exchange->session_key = discovered_kek;
9196
9197 /* Insert the new key information at the front of the list. */
9198 if (!dof_secure_session->session_security_data_last)
9199 dof_secure_session->session_security_data = key_exchange;
9200 else
9201 dof_secure_session->session_security_data_last->next = key_exchange;
9202
9203 dof_secure_session->session_security_data_last = key_exchange;
9204 }
9205
9206 /* Look up the field-dissector table, and determine if it is registered. */
9207 field_dissector = find_dissector_table("dps.secmode");
9208 if (field_dissector != NULL((void*)0))
9209 {
9210 field_handle = dissector_get_uint_handle(field_dissector, auth->security_mode);
9211 if (field_handle != NULL((void*)0))
9212 {
9213 dof_secmode_api_data setup_data;
9214 int block_length;
9215 tvbuff_t *ntvb = tvb_new_subset_remaining(tvb, A_offset);
9216
9217 setup_data.context = INITIALIZE;
9218 setup_data.security_mode_offset = 0;
9219 setup_data.dof_api = api_data;
9220 setup_data.secure_session = dof_secure_session;
9221 setup_data.session_key_data = key_exchange;
9222 block_length = call_dissector_only(field_handle, ntvb, pinfo, tree, &setup_data);
9223 }
9224 }
9225 }
9226 }
9227#endif
9228 }
9229 }
9230 break;
9231
9232 default:
9233 break;
9234 }
9235
9236 return offset;
9237}
9238
9239static bool_Bool validate_session_key(tep_rekey_data *rekey, unsigned S_length, uint8_t *S, uint8_t *confirmation, uint8_t *key)
9240{
9241 uint8_t pad[16];
9242 gcry_mac_hd_t hmac;
9243 gcry_error_t result;
9244
9245 if (rekey->i_nonce_length > sizeof(pad) || rekey->r_nonce_length > sizeof(pad))
9246 return false0;
9247 if ((S_length > 0 && S == NULL((void*)0)) || (rekey->r_identity_length > 0 && rekey->r_identity == NULL((void*)0)))
9248 return false0;
9249
9250 memset(pad, 0, sizeof(pad));
9251 result = gcry_mac_open(&hmac, GCRY_MAC_HMAC_SHA256, 0, NULL((void*)0));
9252 if (result != 0)
9253 return false0;
9254
9255 gcry_mac_setkey(hmac, key, 32);
9256 gcry_mac_write(hmac, pad, 16 - rekey->i_nonce_length);
9257 if (rekey->i_nonce_length > 0)
9258 gcry_mac_write(hmac, rekey->i_nonce, rekey->i_nonce_length);
9259 gcry_mac_write(hmac, pad, 16 - rekey->r_nonce_length);
9260 if (rekey->r_nonce_length > 0)
9261 gcry_mac_write(hmac, rekey->r_nonce, rekey->r_nonce_length);
9262 if (S_length > 0)
9263 gcry_mac_write(hmac, S, S_length);
9264 if (rekey->r_identity_length > 0)
9265 gcry_mac_write(hmac, rekey->r_identity, rekey->r_identity_length);
9266 result = gcry_mac_verify(hmac, confirmation, 32);
9267 gcry_mac_close(hmac);
9268 return result == 0;
9269}
9270
9271static int dissect_tep_dsp(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree, void *data _U___attribute__((unused)))
9272{
9273 /* We are handed a buffer that starts with our protocol id. Any options follow that. */
9274 unsigned offset = 0;
9275
9276 /* We don't care except for the treeview. */
9277 if (!tree)
9278 return 0;
9279
9280 /* Compute the version and flags, masking off other bits. */
9281 offset += 4; /* Skip the type and protocol. */
9282
9283 proto_tree_add_item(tree, hf_dsp_option, tvb, 0, -1, ENC_NA0x00000000);
9284 return offset;
9285}
9286
9287static int dissect_2008_4_tep_2_2_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t *ssid, void *data)
9288{
9289 unsigned offset = 0;
9290 proto_item *ti;
9291 dof_api_data *api_data = (dof_api_data *)data;
9292 dof_packet_data *packet_data;
9293
9294 if (api_data == NULL((void*)0))
9295 {
9296 /* TODO: Output error. */
9297 return 0;
9298 }
9299
9300 packet_data = api_data->packet;
9301 if (packet_data == NULL((void*)0))
9302 {
9303 /* TODO: Output error. */
9304 return 0;
9305 }
9306
9307 /* State Identifier - Only if Unsecured */
9308 if (packet_data->decrypted_buffer == NULL((void*)0))
9309 {
9310 proto_item *pi;
9311 int ssid_len;
9312 int start = offset;
9313 offset = read_c4(tvb, offset, ssid, &ssid_len);
9314 pi = proto_tree_add_uint(tree, hf_tep_2_2_1_state_identifier, tvb, start, offset - start, *ssid);
9315 validate_c4(pinfo, pi, *ssid, ssid_len);
9316 }
9317
9318 /* Initial State */
9319 {
9320 int block_length;
9321 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
9322 ti = proto_tree_add_item(tree, hf_tep_2_2_1_initial_state, tvb, offset, 0, ENC_NA0x00000000);
9323 ti = proto_item_add_subtree(ti, ett_tep_2_2_1_initial_state);
9324 block_length = dof_dissect_pdu(dissect_2008_16_security_9, start, pinfo, ti, NULL((void*)0));
9325 proto_item_set_len(ti, block_length);
9326 offset += block_length;
9327 }
9328
9329 return offset;
9330}
9331
9332/**
9333 * This is the main entry point for the CCM dissector.
9334 * TEP operations create security periods.
9335 * They can also create sessions when used with "None" sessions.
9336 * In any case, these PDUs need to pass information between
9337 * them.
9338 * They also must maintain state for each rekey request, some of
9339 * which modify the session key, some of which create new
9340 * sessions, and others that determine new session information
9341 * like permission sets.
9342 *
9343 * In order to store information appropriately, the following structures are
9344 * used:
9345 * 1. api_data (dof_api_data*) source for all other state.
9346 * 2. packet (dof_packet_data*) dps packet information.
9347 * 3. rekey_data (tep_rekey_data*) tep information for rekey/accept/confirm.
9348 */
9349static int dissect_tep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
9350{
9351 dof_api_data *api_data = (dof_api_data *)data;
9352 dof_packet_data *packet;
9353 tep_rekey_data *rekey_data;
9354
9355 unsigned offset = 0;
9356 uint8_t operation;
9357 uint16_t app;
9358 int app_len;
9359 proto_item *ti;
9360 proto_tree *tep_tree, *operation_tree;
9361
9362 if (api_data == NULL((void*)0))
9363 {
9364 /* TODO: Output error. */
9365 return 0;
9366 }
9367
9368 packet = api_data->packet;
9369 if (packet == NULL((void*)0))
9370 {
9371 /* TODO: Output error. */
9372 return 0;
9373 }
9374
9375 /* Make entries in Protocol column and Info column on summary display */
9376 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TEPv1 ");
9377
9378 /* Create the protocol tree. */
9379 offset = 0;
9380 ti = proto_tree_add_item(tree, proto_tep, tvb, offset, -1, ENC_NA0x00000000);
9381 tep_tree = proto_item_add_subtree(ti, ett_tep);
9382
9383 /* Add the APPID. */
9384 offset = read_c2(tvb, offset, &app, &app_len);
9385 ti = proto_tree_add_uint(tep_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
9386 validate_c2(pinfo,ti, app, app_len);
9387
9388 /* Check for empty packet. */
9389 if (offset == tvb_captured_length(tvb))
9390 {
9391 col_append_str(pinfo->cinfo, COL_INFO, "TEP [nop]");
9392 expert_add_info(pinfo, tep_tree, &ei_implicit_no_op);
9393
9394 return offset;
9395 }
9396
9397 /* Retrieve the opcode. */
9398 operation = tvb_get_uint8(tvb, offset);
9399 if (!packet->is_command)
9400 operation |= TEP_OPCODE_RSP(0x80);
9401
9402 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, operation, tep_opcode_strings, "Unknown Opcode (%d)"));
9403
9404 ti = proto_tree_add_uint_format(tep_tree, hf_tep_operation, tvb, offset, 1, operation, "Operation: %s (%u)", val_to_str(pinfo->pool, operation, tep_opcode_strings, "Unknown Opcode (%d)"), operation);
9405
9406 operation_tree = proto_item_add_subtree(ti, ett_tep_operation);
9407 ti = proto_tree_add_boolean(operation_tree, hf_tep_operation_type, tvb, offset, 0, operation);
9408 proto_item_set_generated(ti);
9409
9410 /* The flags are reserved except for OPCODE=1 & COMMAND */
9411 if ((operation & 0x8F) == 0x01)
9412 {
9413 proto_tree_add_item(operation_tree, hf_tep_c, tvb, offset, 1, ENC_NA0x00000000);
9414 proto_tree_add_item(operation_tree, hf_tep_k, tvb, offset, 1, ENC_NA0x00000000);
9415 }
9416
9417 proto_tree_add_item(operation_tree, hf_tep_opcode, tvb, offset, 1, ENC_NA0x00000000);
9418 offset += 1;
9419
9420 switch (operation)
9421 {
9422 case TEP_PDU_REQUEST_KEY((0x10)|(1)):
9423 /* The K bit must be set, so there is a domain ONLY IF NOT SECURED. */
9424
9425 /* Remember the current request. */
9426 rekey_data = (tep_rekey_data *)packet->opid_data;
9427 if (!rekey_data)
9428 {
9429 packet->opid_data = rekey_data = wmem_new0(wmem_file_scope(), tep_rekey_data)((tep_rekey_data*)wmem_alloc0((wmem_file_scope()), sizeof(tep_rekey_data
)))
;
9430 }
9431
9432 if (!rekey_data->key_data)
9433 rekey_data->key_data = wmem_new0(wmem_file_scope(), dof_session_key_exchange_data)((dof_session_key_exchange_data*)wmem_alloc0((wmem_file_scope
()), sizeof(dof_session_key_exchange_data)))
;
9434 rekey_data->is_rekey = true1;
9435
9436 /* The K bit must be set, so there is a domain ONLY IF NOT SECURED. */
9437 if (packet->decrypted_buffer == NULL((void*)0))
9438 {
9439 int start_offset = offset;
9440
9441 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, tep_tree,
9442 offset, hf_tep_2_1_domain, ett_tep_2_1_domain, NULL((void*)0));
9443
9444 if (!rekey_data->domain)
9445 {
9446 rekey_data->domain_length = dof_consumed_length(offset, start_offset);
9447 rekey_data->domain = (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data->domain_length);
9448
9449 /* Get the buffer. */
9450 tvb_memcpy(tvb, rekey_data->domain, start_offset, rekey_data->domain_length);
9451 }
9452 }
9453 else
9454 {
9455 /* The domain is not present, but this is a secure packet and so the domain can be obtained
9456 * through the session.
9457 */
9458 if (!rekey_data->domain)
9459 {
9460 rekey_data->domain_length = api_data->secure_session->domain_length;
9461 rekey_data->domain = api_data->secure_session->domain;
9462 }
9463 }
9464
9465 /* FALL THROUGH */
9466
9467 case TEP_PDU_REQUEST(1):
9468
9469 /* Remember the current request. */
9470 rekey_data = (tep_rekey_data *)packet->opid_data;
9471 if (!rekey_data)
9472 {
9473 if (api_data->secure_session == NULL((void*)0))
9474 {
9475 /* TODO: Output error. */
9476 return 0;
9477 }
9478 packet->opid_data = rekey_data = wmem_new0(wmem_file_scope(), tep_rekey_data)((tep_rekey_data*)wmem_alloc0((wmem_file_scope()), sizeof(tep_rekey_data
)))
;
9479 rekey_data->domain_length = api_data->secure_session->domain_length;
9480 rekey_data->domain = api_data->secure_session->domain;
9481 }
9482
9483 /* The C bit must be clear, so there is an Initiator Block. */
9484 {
9485 dof_2008_16_security_6_1 response;
9486 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_1, tvb, pinfo, tep_tree,
9487 offset, hf_tep_2_1_initiator_block, ett_tep_2_1_initiator_block, &response);
9488 if (!packet->processed)
9489 {
9490 tvbuff_t *inonce = response.i_nonce;
9491 tvbuff_t *iidentity = response.i_identity;
9492
9493 rekey_data->i_nonce_length = tvb_reported_length(inonce);
9494 rekey_data->i_nonce = (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data->i_nonce_length);
9495 tvb_memcpy(inonce, rekey_data->i_nonce, 0, rekey_data->i_nonce_length);
9496
9497 rekey_data->i_identity_length = tvb_reported_length(iidentity);
9498 rekey_data->i_identity = (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data->i_identity_length);
9499 tvb_memcpy(iidentity, rekey_data->i_identity, 0, rekey_data->i_identity_length);
9500
9501 rekey_data->security_mode = response.security_mode;
9502 rekey_data->security_mode_data_length = response.security_mode_data_length;
9503 rekey_data->security_mode_data = response.security_mode_data;
9504 }
9505 }
9506 break;
9507
9508 case TEP_PDU_ACCEPT((0x80)|(1)):
9509 {
9510 uint32_t ssid = 0;
9511 uint8_t *S = NULL((void*)0);
9512 unsigned S_length = 0;
9513 uint8_t confirmation[32];
9514 typedef struct identity_key
9515 {
9516 uint8_t *session_key;
9517 struct identity_key *next;
9518 } identity_key;
9519 identity_key *identity_key_list = NULL((void*)0);
9520 dof_secure_session_data *dof_secure_session = NULL((void*)0);
9521
9522 if (!packet->opid_first)
9523 {
9524 /* TODO: Print error */
9525 return 0;
9526 }
9527
9528 rekey_data = (tep_rekey_data *)packet->opid_first->opid_data;
9529 if (!rekey_data)
9530 return tvb_captured_length(tvb);
9531
9532 /* Initiator Ticket */
9533 {
9534 int start_offset;
9535 uint8_t ticket[64];
9536
9537 start_offset = offset;
9538 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, tep_tree,
9539 offset, hf_tep_2_2_initiator_ticket, ett_tep_2_2_initiator_ticket, NULL((void*)0));
9540
9541 if (!packet->processed)
9542 {
9543 int i;
9544
9545 /* Produce a (possibly empty) list of potential keys based on our
9546 * initiator secrets based on identity. These will be validated
9547 * later on.
9548 */
9549 for (i = 0; i < globals.global_security->identity_data_count; i++)
9550 {
9551 dof_identity_data *identity = globals.global_security->identity_data + i;
9552 gcry_cipher_hd_t rijndael_handle;
9553 int j;
9554
9555 if (identity->domain_length != rekey_data->domain_length)
9556 continue;
9557 if (memcmp(identity->domain, rekey_data->domain, identity->domain_length) != 0)
9558 continue;
9559 if (identity->identity_length != rekey_data->i_identity_length)
9560 continue;
9561 if (memcmp(identity->identity, rekey_data->i_identity, identity->identity_length) != 0)
9562 continue;
9563
9564 tvb_memcpy(tvb, ticket, start_offset, 64);
9565
9566 if (!gcry_cipher_open(&rijndael_handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0)) {
9567 if (!gcry_cipher_setkey(rijndael_handle, identity->secret, 32)) {
9568 gcry_cipher_encrypt(rijndael_handle, ticket, 16, NULL((void*)0), 0);
9569 gcry_cipher_encrypt(rijndael_handle, ticket + 16, 16, NULL((void*)0), 0);
9570 }
9571 gcry_cipher_close(rijndael_handle);
9572 }
9573
9574 for (j = 0; j < 32; j++)
9575 ticket[j + 32] = ticket[j + 32] ^ ticket[j];
9576
9577 /* Add the key to the list - ep memory. */
9578 {
9579 identity_key *key = (identity_key *)wmem_alloc0(wmem_file_scope(), sizeof(*key));
9580 key->session_key = (uint8_t *)wmem_alloc0(wmem_file_scope(), 32);
9581 memcpy(key->session_key, ticket + 32, 32);
9582 key->next = identity_key_list;
9583 identity_key_list = key;
9584 }
9585 }
9586 }
9587 }
9588
9589 /* Ticket Confirmation */
9590 {
9591 if (!packet->processed)
9592 tvb_memcpy(tvb, confirmation, offset, sizeof(confirmation));
9593 proto_tree_add_item(tep_tree, hf_tep_2_2_ticket_confirmation, tvb, offset, 32, ENC_NA0x00000000);
9594 offset += 32;
9595 }
9596
9597 /* Responder Initialization - present based on whether the command was a rekey */
9598 {
9599
9600 if (rekey_data->is_rekey)
9601 {
9602 int block_length;
9603 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
9604 ti = proto_tree_add_item(tep_tree, hf_tep_2_2_responder_initialization, tvb, offset, 0, ENC_NA0x00000000);
9605 ti = proto_item_add_subtree(ti, ett_tep_2_2_responder_initialization);
9606 block_length = dissect_2008_4_tep_2_2_1(start, pinfo, ti, &ssid, data);
9607 proto_item_set_len(ti, block_length);
9608 offset += block_length;
9609
9610 if (!packet->processed)
9611 {
9612 if (block_length > 0)
9613 {
9614 S_length = (unsigned)block_length;
9615 S = (uint8_t *)wmem_alloc0(wmem_file_scope(), S_length);
9616 tvb_memcpy(start, S, 0, S_length);
9617 }
9618 }
9619
9620 /* TEP can create new sessions when not used inside an existing secure
9621 * session. Each session can use an SSID, present in TEP.2.2.1.
9622 * Note that in this case there may be no existing session, and so
9623 * we need to "backpedal" and create one.
9624 */
9625 if (packet->decrypted_buffer == NULL((void*)0) && !packet->processed)
9626 {
9627#if 0
9628 if (api_data->session)
9629 tep_session = (tep_session_data*)dof_session_get_proto_data((dof_session_data*)api_data->session, proto_tep);
9630 if (!tep_session && api_data->session)
9631 {
9632 tep_session = (tep_session_data*)se_alloc0(sizeof(*tep_session));
9633 dof_session_add_proto_data((dof_session_data*)api_data->session, proto_tep, tep_session);
9634 }
9635
9636 tep_session->pending_rekey = cmd;
9637 tep_session->pending_confirm = packet;
9638#endif
9639 }
9640 }
9641 }
9642
9643 /* Responder Block */
9644 {
9645 dof_2008_16_security_6_2 response;
9646 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_2, tvb, pinfo, tep_tree,
9647 offset, hf_tep_2_2_responder_block, ett_tep_2_2_responder_block, &response);
9648 if (!packet->processed)
9649 {
9650 tvbuff_t *rnonce = response.r_nonce;
9651 tvbuff_t *ridentity = response.r_identity;
9652
9653 rekey_data->r_nonce_length = tvb_reported_length(rnonce);
9654 rekey_data->r_nonce = (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data->r_nonce_length);
9655 tvb_memcpy(rnonce, rekey_data->r_nonce, 0, rekey_data->r_nonce_length);
9656
9657 rekey_data->r_identity_length = tvb_reported_length(ridentity);
9658 rekey_data->r_identity = (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data->r_identity_length);
9659 tvb_memcpy(ridentity, rekey_data->r_identity, 0, rekey_data->r_identity_length);
9660 }
9661 }
9662
9663 /* Authentication Initialization */
9664 {
9665 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_3, tvb, pinfo, tep_tree,
9666 offset, hf_tep_2_2_authenticator_initialization, ett_tep_2_2_authenticator_initialization, NULL((void*)0));
9667 }
9668
9669
9670 /* The request was accepted, and so a new secure session exists. We define the session,
9671 * add it to the list of secure sessions for the unsecure session, and EPP will do the
9672 * rest.
9673 */
9674 if (packet->decrypted_buffer == NULL((void*)0))
9675 {
9676 /* This triggers the creation of the corresponding secure DPS session if it is not already
9677 * created. This allows information to be stored in that session even though no packets
9678 * have used it yet. There is a problem, however, because at this point we do not know
9679 * the SSID that (may) be associated with this session.
9680 */
9681 {
9682 dof_session_data *dof_session = api_data->session;
9683
9684 dof_secure_session = dof_session->secure_sessions;
9685 while (dof_secure_session != NULL((void*)0))
9686 {
9687 /* Determine matching session. The session list already is scoped by transport and DPS
9688 * session, so the only thing remaining is the domain and secure session ID.
9689 */
9690 if ((dof_secure_session->ssid == ssid) &&
9691 (dof_secure_session->domain_length == rekey_data->domain_length) &&
9692 (memcmp(dof_secure_session->domain, rekey_data->domain, rekey_data->domain_length) == 0))
9693 break;
9694
9695 dof_secure_session = dof_secure_session->next;
9696 }
9697
9698 if (!dof_secure_session)
9699 {
9700 dof_session = wmem_new0(wmem_file_scope(), dof_session_data)((dof_session_data*)wmem_alloc0((wmem_file_scope()), sizeof(dof_session_data
)))
;
9701 dof_session->session_id = globals.next_session++;
9702 dof_session->dof_id = api_data->session->dof_id;
9703
9704 dof_secure_session = wmem_new0(wmem_file_scope(), dof_secure_session_data)((dof_secure_session_data*)wmem_alloc0((wmem_file_scope()), sizeof
(dof_secure_session_data)))
;
9705 dof_secure_session->ssid = ssid;
9706 dof_secure_session->domain_length = rekey_data->domain_length;
9707 dof_secure_session->domain = rekey_data->domain;
9708 dof_secure_session->original_session_id = api_data->session->session_id;
9709 dof_secure_session->parent = dof_session;
9710 dof_secure_session->is_2_node = true1;
9711 dof_secure_session->next = api_data->session->secure_sessions;
9712 api_data->session->secure_sessions = dof_secure_session;
9713
9714 if (!dof_secure_session->session_security_data_last)
9715 dof_secure_session->session_security_data = rekey_data->key_data;
9716 else
9717 dof_secure_session->session_security_data_last->next = rekey_data->key_data;
9718
9719 dof_secure_session->session_security_data_last = rekey_data->key_data;
9720 }
9721 }
9722 }
9723
9724 /* This PDU indicates the beginning of security for the responder. The next PDU
9725 * sent will be encrypted with these settings. This means that we must determine
9726 * the security settings and set them in the session.
9727 */
9728 if (!packet->processed && rekey_data->is_rekey)
9729 {
9730 int i;
9731 uint8_t *session_key = NULL((void*)0);
9732
9733 /* We have everything that we need. Determine the session secret if we can. */
9734
9735 /* Check any keys determined above by initiator identity. */
9736 while (session_key == NULL((void*)0) && identity_key_list)
9737 {
9738 if (validate_session_key(rekey_data, S_length, S, confirmation, identity_key_list->session_key))
9739 {
9740 session_key = (uint8_t *)wmem_alloc0(wmem_file_scope(), 32);
9741 memcpy(session_key, identity_key_list->session_key, 32);
9742 }
9743
9744 identity_key_list = identity_key_list->next;
9745 }
9746
9747 /* For each key in the global configuration, see if we can validate the confirmation. */
9748 for (i = 0; session_key == NULL((void*)0) && i < globals.global_security->session_key_count; i++)
9749 {
9750 if (validate_session_key(rekey_data, S_length, S, confirmation, globals.global_security->session_key[i].session_key))
9751 session_key = globals.global_security->session_key[i].session_key;
9752 }
9753
9754
9755 /* Whether or not this can be decrypted, the security mode information
9756 * should be kept with the session.
9757 */
9758 {
9759 rekey_data->key_data->r_valid = packet->dof_frame;
9760 rekey_data->key_data->i_valid = UINT32_MAX(4294967295U);
9761 rekey_data->key_data->session_key = session_key;
9762 rekey_data->key_data->security_mode = rekey_data->security_mode;
9763 rekey_data->key_data->security_mode_data_length = rekey_data->security_mode_data_length;
9764 rekey_data->key_data->security_mode_data = rekey_data->security_mode_data;
9765
9766 if (session_key && dof_secure_session)
9767 {
9768 /* Look up the field-dissector table, and determine if it is registered. */
9769 dissector_table_t field_dissector = find_dissector_table("dof.secmode");
9770 if (field_dissector != NULL((void*)0))
9771 {
9772 dissector_handle_t field_handle = dissector_get_uint_handle(field_dissector, rekey_data->key_data->security_mode);
9773 if (field_handle != NULL((void*)0))
9774 {
9775 dof_secmode_api_data setup_data;
9776
9777 setup_data.context = INITIALIZE;
9778 setup_data.security_mode_offset = 0;
9779 setup_data.dof_api = api_data;
9780 setup_data.secure_session = dof_secure_session;
9781 setup_data.session_key_data = rekey_data->key_data;
9782
9783 call_dissector_only(field_handle, NULL((void*)0), pinfo, NULL((void*)0), &setup_data);
9784 }
9785 }
9786 }
9787 }
9788 }
9789
9790 /* Add a field to show the session key that has been learned (in this
9791 * pass or an earlier one).
9792 */
9793 if (rekey_data->key_data && rekey_data->key_data->session_key && tep_tree)
9794 {
9795 ti = proto_tree_add_bytes_with_length(tree, hf_tep_session_key, tvb, 0, 0, rekey_data->key_data->session_key, 32);
9796 proto_item_set_generated(ti);
9797 }
9798 }
9799 break;
9800
9801 case TEP_PDU_CONFIRM((0x20)|(1)):
9802 {
9803 /* C is set, K is clear. */
9804 /* Ticket Confirmation */
9805 proto_tree_add_item(tep_tree, hf_tep_2_1_ticket_confirmation, tvb, offset, 32, ENC_NA0x00000000);
9806 offset += 32;
9807
9808 if (!packet->processed && api_data->session && packet->opid_first && packet->opid_first->opid_data)
9809 {
9810 dof_session_key_exchange_data *sk_data;
9811
9812 rekey_data = (tep_rekey_data *)packet->opid_first->opid_data;
9813 sk_data = rekey_data->key_data;
9814
9815 /* TODO: Error if not found or if already set. */
9816 if (sk_data)
9817 sk_data->i_valid = packet->dof_frame;
9818 }
9819 }
9820 break;
9821
9822 case TEP_PDU_END_SESSION(5):
9823 case TEP_PDU_SESSION_ENDING(6):
9824 break;
9825
9826 case TEP_PDU_REJECT((0x80)|0):
9827 {
9828 /* Error Code */
9829 proto_tree_add_item(tep_tree, hf_tep_reject_code, tvb, offset, 1, ENC_NA0x00000000);
9830 offset += 1;
9831
9832 /* Error Description */
9833 if (tvb_captured_length(tvb) > offset)
9834 proto_tree_add_item(tep_tree, hf_tep_reject_data, tvb, offset, -1, ENC_NA0x00000000);
9835 }
9836 break;
9837
9838 default:
9839 break;
9840 }
9841 return offset;
9842}
9843
9844static int dissect_trp_dsp(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree, void *data _U___attribute__((unused)))
9845{
9846 /* We are handed a buffer that starts with our protocol id. Any options follow that. */
9847 unsigned offset = 0;
9848
9849 /* We don't care except for the treeview. */
9850 if (!tree)
9851 return 0;
9852
9853 /* Compute the version and flags, masking off other bits. */
9854 offset += 4; /* Skip the type and protocol. */
9855
9856 proto_tree_add_item(tree, hf_trp_dsp_option, tvb, 0, -1, ENC_NA0x00000000);
9857 return offset;
9858}
9859
9860static int dissect_trp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
9861{
9862 dof_api_data *api_data = (dof_api_data *)data;
9863 dof_packet_data *packet_data;
9864 unsigned offset = 0;
9865 uint8_t opcode;
9866 uint16_t app;
9867 int app_len;
9868 proto_item *ti;
9869 proto_tree *trp_tree;
9870 trp_packet_data *trp_data;
9871
9872 /* Make entries in Protocol column and Info column on summary display */
9873 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TRP ");
9874
9875 /* Create the protocol tree. */
9876 offset = 0;
9877 ti = proto_tree_add_item(tree, proto_trp, tvb, offset, -1, ENC_NA0x00000000);
9878 trp_tree = proto_item_add_subtree(ti, ett_trp);
9879
9880 /* Add the APPID. */
9881 offset = read_c2(tvb, offset, &app, &app_len);
9882 ti = proto_tree_add_uint(trp_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
9883 validate_c2(pinfo, ti, app, app_len);
9884
9885 if (api_data == NULL((void*)0))
9886 {
9887 expert_add_info_format(pinfo, ti, &ei_malformed, "api_data == NULL");
9888 return offset;
9889 }
9890
9891 packet_data = api_data->packet;
9892 if (packet_data == NULL((void*)0))
9893 {
9894 expert_add_info_format(pinfo, ti, &ei_malformed, "api_data == NULL");
9895 return offset;
9896 }
9897
9898 trp_data = (trp_packet_data *)dof_packet_get_proto_data(packet_data, proto_trp);
9899
9900 if (offset == tvb_captured_length(tvb))
9901 {
9902 col_append_str(pinfo->cinfo, COL_INFO, "TRP [nop]");
9903 expert_add_info(pinfo, trp_tree, &ei_implicit_no_op);
9904
9905 return offset;
9906 }
9907
9908 /* Retrieve the opcode. */
9909 opcode = tvb_get_uint8(tvb, offset);
9910 if (!packet_data->is_command)
9911 opcode |= TRP_RESPONSE(0x80);
9912
9913 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, opcode, trp_opcode_strings, "Unknown Opcode (%d)"));
9914
9915 /* Opcode */
9916 ti = proto_tree_add_uint_format(trp_tree, hf_trp_opcode, tvb, offset, 1, opcode & 0x7F, "Opcode: %s (%u)", val_to_str(pinfo->pool, opcode, trp_opcode_strings, "Unknown Opcode (%d)"), opcode & 0x7F);
9917 offset += 1;
9918
9919 switch (opcode)
9920 {
9921 case TRP_RSP_REJECT((0x80)|0):
9922 {
9923 /* Error Code */
9924 proto_tree_add_item(trp_tree, hf_trp_errorcode, tvb, offset, 1, ENC_NA0x00000000);
9925 offset += 1;
9926 }
9927 break;
9928
9929 case TRP_CMD_REQUEST_KEK(1):
9930 {
9931 uint8_t *domain_buf = NULL((void*)0);
9932 unsigned domain_length = 0;
9933 int start_offset;
9934
9935 /* Domain - Security.7 */
9936 start_offset = offset;
9937 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree, offset, hf_domain, ett_domain, NULL((void*)0));
9938 if (!packet_data->processed)
9939 {
9940 domain_length = dof_consumed_length(offset, start_offset);
9941 domain_buf = (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length);
9942 tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
9943 }
9944
9945 /* Initiator Block - TRP.4.1.1 */
9946 {
9947 dof_2008_16_security_4 response;
9948 trp_packet_data *trp_pkt_data = NULL((void*)0);
9949
9950 start_offset = offset;
9951
9952 /* Initiator Key Request - Security.4 */
9953 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_4, tvb, pinfo, trp_tree,
9954 offset, hf_initiator_request, ett_initiator_request, &response);
9955 if (!packet_data->processed)
9956 {
9957 tvbuff_t *identity = response.identity;
9958 unsigned identity_length = tvb_reported_length(identity);
9959 uint8_t *identity_buf = (uint8_t *)wmem_alloc0(pinfo->pool, identity_length);
9960 int i;
9961
9962 /* Get the buffer. */
9963 tvb_memcpy(identity, identity_buf, 0, identity_length);
9964
9965 /* Check to see if there is a matching identity. */
9966 for (i = 0; i < globals.global_security->identity_data_count; i++)
9967 {
9968 dof_identity_data *gidentity = globals.global_security->identity_data + i;
9969
9970 if (domain_length != gidentity->domain_length ||
9971 memcmp(domain_buf, gidentity->domain, domain_length) != 0)
9972 continue;
9973
9974 if (identity_length == gidentity->identity_length &&
9975 memcmp(identity_buf, gidentity->identity, identity_length) == 0)
9976 {
9977 trp_pkt_data = wmem_new0(wmem_file_scope(), trp_packet_data)((trp_packet_data*)wmem_alloc0((wmem_file_scope()), sizeof(trp_packet_data
)))
;
9978 dof_packet_add_proto_data(packet_data, proto_trp, trp_pkt_data);
9979
9980 trp_pkt_data->domain_length = domain_length;
9981 trp_pkt_data->domain = (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length);
9982 memcpy(trp_pkt_data->domain, domain_buf, domain_length);
9983
9984 trp_pkt_data->identity_length = identity_length;
9985 trp_pkt_data->identity = (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length);
9986 memcpy(trp_pkt_data->identity, identity_buf, identity_length);
9987
9988 trp_pkt_data->secret = gidentity->secret;
9989 }
9990 }
9991 }
9992
9993 /* The initiator is in the identity table (found now or in an
9994 * earlier pass).
9995 */
9996 if (trp_pkt_data || (trp_data && trp_data->identity_length))
9997 expert_add_info(pinfo, ti, &ei_trp_initiator_id_known);
9998
9999 /* Group Identifier - Security.8 */
10000 {
10001 int gid_start = offset;
10002 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_8, tvb, pinfo, trp_tree,
10003 offset, hf_group_identifier, ett_group_identifier, NULL((void*)0));
10004
10005 if (trp_pkt_data)
10006 {
10007 trp_pkt_data->group_length = dof_consumed_length(offset, gid_start);
10008 trp_pkt_data->group = (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pkt_data->group_length);
10009 tvb_memcpy(tvb, trp_pkt_data->group, gid_start, trp_pkt_data->group_length);
10010 }
10011 }
10012
10013 if (trp_pkt_data)
10014 {
10015 /* We need to store the entire block_I for later use. */
10016 trp_pkt_data->block_I_length = dof_consumed_length(offset, start_offset);
10017 trp_pkt_data->block_I = (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pkt_data->block_I_length);
10018 tvb_memcpy(tvb, trp_pkt_data->block_I, start_offset, trp_pkt_data->block_I_length);
10019 }
10020 }
10021 }
10022 break;
10023
10024 case TRP_RSP_REQUEST_KEK((0x80)|(1)):
10025 {
10026 int start_offset;
10027 uint32_t ssid;
10028 uint8_t *mode;
10029 unsigned mode_length;
10030 uint8_t *block_A;
10031 unsigned block_A_length;
10032
10033 if (trp_data && trp_data->kek_known)
10034 {
10035 expert_add_info(pinfo, ti, &ei_trp_kek_discovered);
10036 }
10037
10038 /* Initiator Ticket - Security.5 */
10039 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, trp_tree,
10040 offset, hf_initiator_ticket, ett_initiator_ticket, NULL((void*)0));
10041
10042 /* Initialization Block - TRP.4.2.1 */
10043 /* A BLOCK */
10044 {
10045 start_offset = offset;
10046
10047 /* THB */
10048 {
10049 proto_tree_add_item(trp_tree, hf_thb, tvb, offset, 1, ENC_NA0x00000000);
10050 offset += 1;
10051 }
10052
10053 /* TMIN */
10054 {
10055 proto_tree_add_item(trp_tree, hf_tmin, tvb, offset, 1, ENC_NA0x00000000);
10056 offset += 1;
10057 }
10058
10059 /* TMAX */
10060 {
10061 proto_tree_add_item(trp_tree, hf_tmax, tvb, offset, 1, ENC_NA0x00000000);
10062 offset += 1;
10063 }
10064
10065 /* Epoch */
10066 {
10067 proto_tree_add_item(trp_tree, hf_trp_epoch, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
10068 offset += 2;
10069 }
10070
10071 /* SIDg - Type.4 */
10072 {
10073 offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, trp_tree,
10074 offset, hf_sidg, ett_sidg, NULL((void*)0));
10075 }
10076
10077 /* Initiator Node Security Scope - Security.10 */
10078 {
10079 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_10, tvb, pinfo, trp_tree,
10080 offset, hf_security_scope, ett_security_scope, NULL((void*)0));
10081 }
10082
10083 /* Security Mode - Security.13 */
10084 {
10085 int mode_start = offset;
10086 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_13, tvb, pinfo, trp_tree,
10087 offset, hf_security_mode, ett_security_mode, NULL((void*)0));
10088 if (!packet_data->processed)
10089 {
10090 mode_length = dof_consumed_length(offset, mode_start);
10091 mode = (uint8_t *)wmem_alloc0(pinfo->pool, mode_length);
10092 tvb_memcpy(tvb, mode, mode_start, mode_length);
10093 }
10094 }
10095
10096 /* State Identifier - Type.3 */
10097 {
10098 int s_offset = offset;
10099 int ssid_len;
10100 proto_item *pi;
10101 offset = read_c4(tvb, offset, &ssid, &ssid_len);
10102 ssid |= AS_ASSIGNED_SSID0x40000000; /* TRP SSID are *always* assigned by the AS. */
10103 pi = proto_tree_add_uint_format(trp_tree, hf_ssid, tvb, s_offset, offset - s_offset, ssid, "SSID: %u", ssid);
10104 validate_c4(pinfo, pi, ssid, ssid_len);
10105 }
10106
10107 /* PG - Security.2 */
10108 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_2, tvb, pinfo, trp_tree,
10109 offset, hf_responder_pg, ett_responder_pg, NULL((void*)0));
10110
10111 /* Group Validation - Security.11 */
10112 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_11, tvb, pinfo, trp_tree,
10113 offset, hf_responder_validation, ett_responder_validation, NULL((void*)0));
10114
10115 /* Initiator Validation - Security.11 */
10116 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_11, tvb, pinfo, trp_tree,
10117 offset, hf_initiator_validation, ett_initiator_validation, NULL((void*)0));
10118
10119 block_A_length = dof_consumed_length(offset, start_offset);
10120 block_A = (uint8_t *)wmem_alloc0(pinfo->pool, block_A_length);
10121 tvb_memcpy(tvb, block_A, start_offset, block_A_length);
10122 }
10123
10124 /* Determine the KEK, if possible. This requires that either the initiator node's secret
10125 * is known or that the group has been configured. In either case this requires knowledge
10126 * from the matching command, including the domain, identity, and group information.
10127 */
10128 if (packet_data->opid_first && !packet_data->processed)
10129 {
10130#if 0
10131 trp_packet_data* cmd_data = (trp_packet_data*)dof_packet_get_proto_data(packet_data->opid_first, proto_trp);
10132 uint8_t mac[32];
10133 extern struct BlockCipher BlockCipher_AES_256;
10134 struct BlockCipher* cipher = &BlockCipher_AES_256;
10135 uint8_t* ekey = (uint8_t*)ep_alloc(cipher->keyStateSize);
10136
10137 int i;
10138
10139 if (cmd_data)
10140 {
10141 uint8_t kek[32];
10142
10143 tvb_memcpy(tvb, mac, mac_offset, 32);
10144 tvb_memcpy(tvb, kek, mac_offset + 32, 32);
10145
10146 if (cipher != NULL((void*)0))
10147 {
10148 cipher->GenerateKeyState(ekey, cmd_data->secret);
10149 cipher->Encrypt(ekey, mac);
10150 cipher->Encrypt(ekey, mac + 16);
10151 }
10152
10153 for (i = 0; i < 32; i++)
10154 kek[i] ^= mac[i];
10155
10156 {
10157 OALSecureHMACContext ctx;
10158 OALSecureHMACDigest digest;
10159
10160 OALSecureHMAC_Start(&ctx, cmd_data->secret);
10161 OALSecureHMAC_Digest(&ctx, cmd_data->domain_length, cmd_data->domain);
10162 OALSecureHMAC_Digest(&ctx, cmd_data->block_I_length, cmd_data->block_I);
10163 OALSecureHMAC_Digest(&ctx, block_A_length, block_A);
10164 OALSecureHMAC_Digest(&ctx, 32, kek);
10165 OALSecureHMAC_Finish(&ctx, digest);
10166
10167 tvb_memcpy(tvb, mac, mac_offset, 32);
10168 if (memcmp(mac, digest, 32) == 0)
10169 {
10170 dof_learned_group_data* group = globals.learned_group_data;
10171 dof_learned_group_auth_data *auth = NULL((void*)0);
10172
10173 /* The KEK has been discovered, flag this for output on the PDU. */
10174 if (!trp_data)
10175 {
10176 trp_data = wmem_alloc0(wmem_file_scope(), sizeof(trp_packet_data));
10177 dof_packet_add_proto_data(packet_data, proto_trp, trp_data);
10178 }
10179
10180 trp_data->kek_known = true1;
10181
10182 while (group)
10183 {
10184 if ((cmd_data->domain_length == group->domain_length) &&
10185 (memcmp(cmd_data->domain, group->domain, group->domain_length) == 0) &&
10186 (cmd_data->group_length == group->group_length) &&
10187 (memcmp(cmd_data->group, group->group, group->group_length) == 0) &&
10188 (ssid == group->ssid))
10189 break;
10190
10191 group = group->next;
10192 }
10193
10194 if (group == NULL((void*)0))
10195 {
10196 group = wmem_alloc0(wmem_file_scope, sizeof(dof_learned_group_data));
10197 group->domain_length = cmd_data->domain_length;
10198 group->domain = cmd_data->domain;
10199 group->group_length = cmd_data->group_length;
10200 group->group = cmd_data->group;
10201 group->ssid = ssid;
10202 group->next = globals.learned_group_data;
10203 globals.learned_group_data = group;
10204 }
10205
10206 auth = group->keys;
10207
10208 while (auth)
10209 {
10210 if (epoch == auth->epoch)
10211 break;
10212
10213 auth = auth->next;
10214 }
10215
10216 if (auth == NULL((void*)0))
10217 {
10218 auth = wmem_alloc0(wmem_file_scope(), sizeof(dof_learned_group_auth_data));
10219 auth->epoch = epoch;
10220 auth->next = group->keys;
10221 group->keys = auth;
10222
10223 auth->kek = (uint8_t*)wmem_alloc0(wmem_file_scope(), 32);
10224 memcpy(auth->kek, kek, 32);
10225
10226 auth->mode_length = mode_length;
10227 auth->mode = (uint8_t*)wmem_alloc0(wmem_file_scope(), mode_length);
10228 memcpy(auth->mode, mode, mode_length);
10229
10230 auth->security_mode = (mode[1] * 256) | mode[2];
10231 auth->parent = group;
10232 }
10233 }
10234 }
10235 }
10236#endif
10237 }
10238 }
10239 break;
10240
10241 case TRP_CMD_REQUEST_RANDOM(2):
10242 {
10243 uint8_t *domain_buf = NULL((void*)0);
10244 unsigned domain_length = 0;
10245 int start_offset;
10246
10247 /* Domain - Security.7 */
10248 start_offset = offset;
10249 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree,
10250 offset, hf_domain, ett_domain, NULL((void*)0));
10251 if (!packet_data->processed)
10252 {
10253 domain_length = dof_consumed_length(offset, start_offset);
10254 domain_buf = (uint8_t *)wmem_alloc0(pinfo->pool, domain_length);
10255 tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
10256 }
10257
10258 /* Initiator Block - TRP.6.1.1 */
10259 {
10260 dof_2008_16_security_4 response;
10261 trp_packet_data *trp_pkt_data = NULL((void*)0);
10262
10263 start_offset = offset;
10264
10265 /* Initiator Key Request - Security.4 */
10266 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_4, tvb, pinfo, trp_tree,
10267 offset, hf_initiator_request, ett_initiator_request, &response);
10268 if (!packet_data->processed)
10269 {
10270 tvbuff_t *identity = response.identity;
10271 unsigned identity_length = tvb_reported_length(identity);
10272 uint8_t *identity_buf = (uint8_t *)wmem_alloc0(pinfo->pool, identity_length);
10273 int i;
10274
10275 /* Get the buffer. */
10276 tvb_memcpy(identity, identity_buf, 0, identity_length);
10277
10278 /* Check to see if there is a matching identity. */
10279 for (i = 0; i < globals.global_security->identity_data_count; i++)
10280 {
10281 dof_identity_data *gidentity = globals.global_security->identity_data + i;
10282
10283 if (domain_length != gidentity->domain_length ||
10284 memcmp(domain_buf, gidentity->domain, domain_length) != 0)
10285 continue;
10286
10287 if (identity_length == gidentity->identity_length &&
10288 memcmp(identity_buf, gidentity->identity, identity_length) == 0)
10289 {
10290 trp_pkt_data = wmem_new0(wmem_file_scope(), trp_packet_data)((trp_packet_data*)wmem_alloc0((wmem_file_scope()), sizeof(trp_packet_data
)))
;
10291 dof_packet_add_proto_data(packet_data, proto_trp, trp_pkt_data);
10292
10293 trp_pkt_data->domain_length = domain_length;
10294 trp_pkt_data->domain = (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length);
10295 memcpy(trp_pkt_data->domain, domain_buf, domain_length);
10296
10297 trp_pkt_data->identity_length = identity_length;
10298 trp_pkt_data->identity = (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length);
10299 memcpy(trp_pkt_data->identity, identity_buf, identity_length);
10300
10301 trp_pkt_data->secret = gidentity->secret;
10302 }
10303 }
10304 }
10305
10306 /* The initiator is in the identity table (found now or in an
10307 * earlier pass).
10308 */
10309 if (trp_pkt_data || (trp_data && trp_data->identity_length))
10310 expert_add_info(pinfo, ti, &ei_trp_initiator_id_known);
10311
10312 if (trp_pkt_data)
10313 {
10314 /* We need to store the entire block_I for later use. */
10315 trp_pkt_data->block_I_length = dof_consumed_length(offset, start_offset);
10316 trp_pkt_data->block_I = (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pkt_data->block_I_length);
10317 tvb_memcpy(tvb, trp_pkt_data->block_I, start_offset, trp_pkt_data->block_I_length);
10318 }
10319 }
10320 }
10321 break;
10322
10323 case TRP_RSP_REQUEST_RANDOM((0x80)|(2)):
10324 {
10325 /* Initiator Ticket - Security.5 */
10326 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, trp_tree,
10327 offset, hf_initiator_ticket, ett_initiator_ticket, NULL((void*)0));
10328 }
10329 break;
10330
10331 case TRP_CMD_REQUEST_SECURITY_SCOPES(4):
10332 {
10333 uint8_t *domain_buf = NULL((void*)0);
10334 unsigned domain_length = 0;
10335 int start_offset;
10336
10337 /* Domain - Security.7 */
10338 start_offset = offset;
10339 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree,
10340 offset, hf_domain, ett_domain, NULL((void*)0));
10341 if (!packet_data->processed)
10342 {
10343 domain_length = dof_consumed_length(offset, start_offset);
10344 domain_buf = (uint8_t *)wmem_alloc0(pinfo->pool, domain_length);
10345 tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
10346 }
10347
10348 /* Initiator Block - TRP.5.1.1 */
10349 {
10350 dof_2008_16_security_4 response;
10351 trp_packet_data *trp_pk_data = NULL((void*)0);
10352
10353 start_offset = offset;
10354
10355 /* Initiator Duration Request */
10356 proto_tree_add_item(trp_tree, hf_trp_duration, tvb, offset, 1, ENC_NA0x00000000);
10357 offset += 1;
10358
10359 /* Initiator Key Request - Security.4 */
10360 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_4, tvb, pinfo, trp_tree,
10361 offset, hf_initiator_request, ett_initiator_request, &response);
10362 if (!packet_data->processed)
10363 {
10364 tvbuff_t *identity = response.identity;
10365 unsigned identity_length = tvb_reported_length(identity);
10366 uint8_t *identity_buf = (uint8_t *)wmem_alloc0(pinfo->pool, identity_length);
10367 int i;
10368
10369 /* Get the buffer. */
10370 tvb_memcpy(identity, identity_buf, 0, identity_length);
10371
10372 /* Check to see if there is a matching identity. */
10373 for (i = 0; i < globals.global_security->identity_data_count; i++)
10374 {
10375 dof_identity_data *gidentity = globals.global_security->identity_data + i;
10376
10377 if (domain_length != gidentity->domain_length ||
10378 memcmp(domain_buf, gidentity->domain, domain_length) != 0)
10379 continue;
10380
10381 if (identity_length == gidentity->identity_length &&
10382 memcmp(identity_buf, gidentity->identity, identity_length) == 0)
10383 {
10384 trp_pk_data = wmem_new0(wmem_file_scope(), trp_packet_data)((trp_packet_data*)wmem_alloc0((wmem_file_scope()), sizeof(trp_packet_data
)))
;
10385 dof_packet_add_proto_data(packet_data, proto_trp, trp_pk_data);
10386
10387 trp_pk_data->domain_length = domain_length;
10388 trp_pk_data->domain = (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length);
10389 memcpy(trp_pk_data->domain, domain_buf, domain_length);
10390
10391 trp_pk_data->identity_length = identity_length;
10392 trp_pk_data->identity = (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length);
10393 memcpy(trp_pk_data->identity, identity_buf, identity_length);
10394
10395 trp_pk_data->secret = gidentity->secret;
10396 }
10397 }
10398 }
10399
10400 /* The initiator is in the identity table (found now or in an
10401 * earlier pass).
10402 */
10403 if (trp_pk_data || (trp_data && trp_data->identity_length))
10404 expert_add_info(pinfo, ti, &ei_trp_initiator_id_known);
10405
10406 /* Node - Security.8 */
10407 {
10408 int gid_start = offset;
10409 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_8, tvb, pinfo, trp_tree,
10410 offset, hf_node_identifier, ett_node_identifier, NULL((void*)0));
10411
10412 if (trp_pk_data)
10413 {
10414 trp_pk_data->group_length = dof_consumed_length(offset, gid_start);
10415 trp_pk_data->group = (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pk_data->group_length);
10416 tvb_memcpy(tvb, trp_pk_data->group, gid_start, trp_pk_data->group_length);
10417 }
10418 }
10419
10420 if (trp_pk_data)
10421 {
10422 /* We need to store the entire block_I for later use. */
10423 trp_pk_data->block_I_length = dof_consumed_length(offset, start_offset);
10424 trp_pk_data->block_I = (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pk_data->block_I_length);
10425 tvb_memcpy(tvb, trp_pk_data->block_I, start_offset, trp_pk_data->block_I_length);
10426 }
10427 }
10428 }
10429 break;
10430
10431 case TRP_RSP_REQUEST_SECURITY_SCOPES((0x80)|(4)):
10432 {
10433 int start_offset;
10434 uint8_t *block_A;
10435 unsigned block_A_length;
10436
10437 /* Initiator Ticket - Security.5 */
10438 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, trp_tree,
10439 offset, hf_initiator_ticket, ett_initiator_ticket, NULL((void*)0));
10440
10441 /* Initialization Block - TRP.5.2.1 */
10442 /* A BLOCK */
10443 {
10444 start_offset = offset;
10445
10446 /* Initiator Duration Request */
10447 proto_tree_add_item(trp_tree, hf_trp_duration, tvb, offset, 1, ENC_NA0x00000000);
10448 offset += 1;
10449
10450 /* Initiator Node Security Scope - Security.10 */
10451 {
10452 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_10, tvb, pinfo, trp_tree,
10453 offset, hf_security_scope, ett_security_scope, NULL((void*)0));
10454 }
10455
10456 /* Validation - Security.11 */
10457 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_11, tvb, pinfo, trp_tree,
10458 offset, hf_initiator_validation, ett_initiator_validation, NULL((void*)0));
10459
10460 block_A_length = dof_consumed_length(offset, start_offset);
10461 block_A = (uint8_t *)wmem_alloc0(pinfo->pool, block_A_length);
10462 tvb_memcpy(tvb, block_A, start_offset, block_A_length);
10463 }
10464 }
10465 break;
10466
10467 case TRP_CMD_RESOLVE_CREDENTIAL(6):
10468 {
10469 uint8_t *domain_buf = NULL((void*)0);
10470 unsigned domain_length = 0;
10471 int start_offset;
10472
10473 /* Domain - Security.7 */
10474 start_offset = offset;
10475 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree,
10476 offset, hf_domain, ett_domain, NULL((void*)0));
10477 if (!packet_data->processed)
10478 {
10479 domain_length = dof_consumed_length(offset, start_offset);
10480 domain_buf = (uint8_t *)wmem_alloc0(pinfo->pool, domain_length);
10481 tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
10482 }
10483
10484 /* Identity Resolution - Security.3.2 */
10485 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_3_2, tvb, pinfo, trp_tree,
10486 offset, hf_identity_resolution, ett_identity_resolution, NULL((void*)0));
10487 }
10488 break;
10489
10490 case TRP_RSP_RESOLVE_CREDENTIAL((0x80)|(6)):
10491 {
10492 /* Identity Resolution - Security.3.2 */
10493 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_3_2, tvb, pinfo, trp_tree,
10494 offset, hf_identity_resolution, ett_identity_resolution, NULL((void*)0));
10495 }
10496 break;
10497
10498 case TRP_CMD_REQUEST_SESSION(3):
10499 {
10500 uint8_t *domain_buf = NULL((void*)0);
10501 unsigned domain_length = 0;
10502 int start_offset;
10503
10504 if (trp_data && trp_data->identity_length)
10505 {
10506 expert_add_info(pinfo, ti, &ei_trp_initiator_id_known);
10507 }
10508
10509 /* Domain - Security.7 */
10510 start_offset = offset;
10511 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree,
10512 offset, hf_domain, ett_domain, NULL((void*)0));
10513 if (!packet_data->processed)
10514 {
10515 domain_length = dof_consumed_length(offset, start_offset);
10516 domain_buf = (uint8_t *)wmem_alloc0(pinfo->pool, domain_length);
10517 tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
10518 }
10519
10520 /* Responder Block - Security.6.2 */
10521 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_2, tvb, pinfo, trp_tree,
10522 offset, hf_responder_request, ett_responder_request, NULL((void*)0));
10523
10524 /* Initiator Block - Security.6.1 */
10525 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_1, tvb, pinfo, trp_tree,
10526 offset, hf_initiator_request, ett_initiator_request, NULL((void*)0));
10527 }
10528 break;
10529
10530 case TRP_RSP_REQUEST_SESSION((0x80)|(3)):
10531 {
10532 int start_offset;
10533 uint8_t *block_A;
10534 unsigned block_A_length;
10535
10536 /* Responder Ticket - Security.5 */
10537 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, trp_tree,
10538 offset, hf_responder_ticket, ett_responder_ticket, NULL((void*)0));
10539
10540 /* Initiator Ticket - Security.5 */
10541 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, trp_tree,
10542 offset, hf_initiator_ticket, ett_initiator_ticket, NULL((void*)0));
10543
10544
10545 /* Initialization Block - Security.6.3 */
10546 /* A BLOCK */
10547 {
10548 start_offset = offset;
10549
10550 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_3, tvb, pinfo, trp_tree,
10551 offset, hf_authentication_block, ett_authentication_block, NULL((void*)0));
10552
10553 block_A_length = dof_consumed_length(offset, start_offset);
10554 block_A = (uint8_t *)wmem_alloc0(pinfo->pool, block_A_length);
10555 tvb_memcpy(tvb, block_A, start_offset, block_A_length);
10556 }
10557 }
10558 break;
10559
10560 case TRP_CMD_VALIDATE_CREDENTIAL(9):
10561 {
10562 tvbuff_t *data_tvb;
10563
10564 /* Domain - Security.7 */
10565 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree,
10566 offset, hf_domain, ett_domain, NULL((void*)0));
10567
10568 offset = dof_dissect_pdu_as_field(dissect_2008_16_security_3_1, tvb, pinfo, trp_tree,
10569 offset, hf_identity_resolution, ett_identity_resolution, NULL((void*)0));
10570 data_tvb = tvb_new_subset_remaining(tvb, offset);
10571 call_data_dissector(data_tvb, pinfo, trp_tree);
10572 }
10573 break;
10574
10575 case TRP_RSP_VALIDATE_CREDENTIAL((0x80)|(9)):
10576 {
10577 tvbuff_t *data_tvb = tvb_new_subset_remaining(tvb, offset);
10578 call_data_dissector(data_tvb, pinfo, trp_tree);
10579 }
10580 break;
10581 }
10582
10583 return offset;
10584}
10585
10586/* Initialize Core Tunnel Functionality */
10587static void dof_tun_register(void)
10588{
10589 static hf_register_info hf[] =
10590 {
10591 { &hf_2012_1_tunnel_1_version,
10592 { "Version", "dof.2012_1.tunnel_1.version", FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
10593 },
10594 { &hf_2012_1_tunnel_1_length,
10595 { "Length", "dof.2012_1.tunnel_1.length", FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
10596 },
10597 };
10598
10599 static int *ett[] = {
10600 &ett_2012_1_tunnel,
10601 };
10602
10603 proto_2012_1_tunnel = proto_register_protocol(TUNNEL_PROTOCOL_STACK"DOF Tunnel Protocol Stack", "DTPS", "dtps");
10604 proto_register_field_array(proto_2012_1_tunnel, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
10605 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
10606
10607 register_dissector_with_description("dof.tunnel", TUNNEL_PROTOCOL_STACK"DOF Tunnel Protocol Stack", dissect_tunnel_common, proto_2012_1_tunnel);
10608 dof_tun_app_dissectors = register_dissector_table("dof.tunnel.app", "DOF Tunnel Version", proto_2012_1_tunnel, FT_UINT8, BASE_DEC);
10609}
10610
10611static void dof_tun_reset(void)
10612{
10613}
10614
10615static void dof_tun_cleanup(void)
10616{
10617}
10618
10619/* The registration hand-off routine */
10620static void dof_tun_handoff(void)
10621{
10622 static dissector_handle_t tcp_handle;
10623
10624 register_dissector_with_description("dof.app", TUNNEL_APPLICATION_PROTOCOL"DOF Tunnel Protocol", dissect_tun_app_common, proto_2008_1_app);
10625
10626 tcp_handle = create_dissector_handle(dissect_tunnel_tcp, proto_2012_1_tunnel);
10627
10628 dissector_add_uint_with_preference("tcp.port", DOF_TUN_NON_SEC_TCP_PORT8567, tcp_handle);
10629}
10630
10631/* Main DOF Registration Support */
10632
10633static void dof_reset(void)
10634{
10635 globals.next_session = 1;
10636 globals.next_transport_session = 1;
10637 globals.dof_packet_head = globals.dof_packet_tail = NULL((void*)0);
10638 globals.global_security = &global_security;
10639 globals.learned_group_data = NULL((void*)0);
10640 globals.decrypt_all_packets = decrypt_all_packets;
10641 globals.track_operations = track_operations;
10642 globals.track_operations_window = track_operations_window;
10643
10644 init_addr_port_tables();
10645
10646 /* Reset the packet counter. */
10647 next_dof_frame = 1;
10648
10649 /* Load the template values for different groups. */
10650 {
10651 secmode_field_t *list = secmode_list;
10652 unsigned i;
10653
10654 global_security.group_data = g_new0(dof_group_data, num_secmode_list)((dof_group_data *) g_malloc0_n ((num_secmode_list), sizeof (
dof_group_data)))
;
10655 global_security.group_data_count = num_secmode_list;
10656 for (i = 0; i < num_secmode_list; i++)
10657 {
10658 unsigned kek_len;
10659 dof_group_data *group_data = global_security.group_data + i;
10660 uint32_t size;
10661
10662 /* Hex digits or an OID string, as for the identity secrets. */
10663 if (VALIDHEX(list[i].domain[0])( ((list[i].domain[0]) >= '0' && (list[i].domain[0
]) <= '9') || ((list[i].domain[0]) >= 'A' && (list
[i].domain[0]) <= 'F') || ((list[i].domain[0]) >= 'a' &&
(list[i].domain[0]) <= 'f') )
)
10664 {
10665 parse_hex_string(list[i].domain, &(group_data->domain), &(group_data->domain_length));
10666 }
10667 else
10668 {
10669 size = (uint32_t)strlen(list[i].domain);
10670 dof_oid_new_standard_string(list[i].domain, &size, &(group_data->domain));
10671 group_data->domain_length = size;
10672 }
10673
10674 if (VALIDHEX(list[i].identity[0])( ((list[i].identity[0]) >= '0' && (list[i].identity
[0]) <= '9') || ((list[i].identity[0]) >= 'A' &&
(list[i].identity[0]) <= 'F') || ((list[i].identity[0]) >=
'a' && (list[i].identity[0]) <= 'f') )
)
10675 {
10676 parse_hex_string(list[i].identity, &(group_data->identity), &(group_data->identity_length));
10677 }
10678 else
10679 {
10680 size = (uint32_t)strlen(list[i].identity);
10681 dof_oid_new_standard_string(list[i].identity, &size, &(group_data->identity));
10682 group_data->identity_length = size;
10683 }
10684 parse_hex_string(list[i].kek, &(group_data->kek), &kek_len);
10685 }
10686 }
10687
10688 /* Load the template values for different secrets. */
10689 {
10690 seckey_field_t *list = seckey_list;
10691 unsigned i;
10692
10693 /* Clear existing. */
10694 for (i = 0; i < global_security.session_key_count; i++)
10695 {
10696 dof_session_key_data *session_data = &global_security.session_key[i];
10697 g_free(session_data->session_key)(__builtin_object_size ((session_data->session_key), 0) !=
((size_t) - 1)) ? g_free_sized (session_data->session_key
, __builtin_object_size ((session_data->session_key), 0)) :
(g_free) (session_data->session_key)
;
10698 }
10699
10700 g_free(global_security.session_key)(__builtin_object_size ((global_security.session_key), 0) != (
(size_t) - 1)) ? g_free_sized (global_security.session_key, __builtin_object_size
((global_security.session_key), 0)) : (g_free) (global_security
.session_key)
;
10701 global_security.session_key = NULL((void*)0);
10702 global_security.session_key_count = 0;
10703
10704 global_security.session_key = g_new0(dof_session_key_data, num_seckey_list)((dof_session_key_data *) g_malloc0_n ((num_seckey_list), sizeof
(dof_session_key_data)))
;
10705 global_security.session_key_count = num_seckey_list;
10706 for (i = 0; i < num_seckey_list; i++)
10707 {
10708 unsigned key_len;
10709 dof_session_key_data *session_data = global_security.session_key + i;
10710 parse_hex_string(list[i].key, &(session_data->session_key), &key_len);
10711 }
10712 }
10713
10714 /* Load the template values for different identities. */
10715 {
10716 identsecret_field_t *list = identsecret_list;
10717 unsigned i;
10718
10719 /* Clear existing. */
10720 for (i = 0; i < global_security.identity_data_count; i++)
10721 {
10722 dof_identity_data *identity_data = &global_security.identity_data[i];
10723 g_free(identity_data->domain)(__builtin_object_size ((identity_data->domain), 0) != ((size_t
) - 1)) ? g_free_sized (identity_data->domain, __builtin_object_size
((identity_data->domain), 0)) : (g_free) (identity_data->
domain)
;
10724 g_free(identity_data->identity)(__builtin_object_size ((identity_data->identity), 0) != (
(size_t) - 1)) ? g_free_sized (identity_data->identity, __builtin_object_size
((identity_data->identity), 0)) : (g_free) (identity_data
->identity)
;
10725 g_free(identity_data->secret)(__builtin_object_size ((identity_data->secret), 0) != ((size_t
) - 1)) ? g_free_sized (identity_data->secret, __builtin_object_size
((identity_data->secret), 0)) : (g_free) (identity_data->
secret)
;
10726 }
10727
10728 g_free(global_security.identity_data)(__builtin_object_size ((global_security.identity_data), 0) !=
((size_t) - 1)) ? g_free_sized (global_security.identity_data
, __builtin_object_size ((global_security.identity_data), 0))
: (g_free) (global_security.identity_data)
;
10729 global_security.identity_data = NULL((void*)0);
10730 global_security.identity_data_count = 0;
10731
10732 global_security.identity_data = g_new0(dof_identity_data, num_identsecret_list)((dof_identity_data *) g_malloc0_n ((num_identsecret_list), sizeof
(dof_identity_data)))
;
10733 global_security.identity_data_count = num_identsecret_list;
10734 for (i = 0; i < num_identsecret_list; i++)
10735 {
10736 unsigned key_len;
10737 uint32_t size;
10738
10739 dof_identity_data *identity_data = global_security.identity_data + i;
10740 if (VALIDHEX(list[i].domain[0])( ((list[i].domain[0]) >= '0' && (list[i].domain[0
]) <= '9') || ((list[i].domain[0]) >= 'A' && (list
[i].domain[0]) <= 'F') || ((list[i].domain[0]) >= 'a' &&
(list[i].domain[0]) <= 'f') )
)
10741 {
10742 parse_hex_string(list[i].domain, &(identity_data->domain), &(identity_data->domain_length));
10743 }
10744 else
10745 {
10746 size = (uint32_t)strlen(list[i].domain);
10747 dof_oid_new_standard_string(list[i].domain, &size, &(identity_data->domain));
10748 identity_data->domain_length = size;
10749 }
10750
10751 if (VALIDHEX(list[i].identity[0])( ((list[i].identity[0]) >= '0' && (list[i].identity
[0]) <= '9') || ((list[i].identity[0]) >= 'A' &&
(list[i].identity[0]) <= 'F') || ((list[i].identity[0]) >=
'a' && (list[i].identity[0]) <= 'f') )
)
10752 {
10753 parse_hex_string(list[i].identity, &(identity_data->identity), &(identity_data->identity_length));
10754 }
10755 else
10756 {
10757 size = (uint32_t)strlen(list[i].identity);
10758 dof_oid_new_standard_string(list[i].identity, &size, &(identity_data->identity));
10759 identity_data->identity_length = size;
10760 }
10761
10762 parse_hex_string(list[i].secret, &(identity_data->secret), &key_len);
10763 }
10764 }
10765}
10766
10767static void dof_cleanup(void)
10768{
10769 unsigned i;
10770
10771 /* Clear existing. */
10772 for (i = 0; i < global_security.group_data_count; i++)
10773 {
10774 dof_group_data *group_data = &global_security.group_data[i];
10775 g_free(group_data->domain)(__builtin_object_size ((group_data->domain), 0) != ((size_t
) - 1)) ? g_free_sized (group_data->domain, __builtin_object_size
((group_data->domain), 0)) : (g_free) (group_data->domain
)
;
10776 g_free(group_data->identity)(__builtin_object_size ((group_data->identity), 0) != ((size_t
) - 1)) ? g_free_sized (group_data->identity, __builtin_object_size
((group_data->identity), 0)) : (g_free) (group_data->identity
)
;
10777 g_free(group_data->kek)(__builtin_object_size ((group_data->kek), 0) != ((size_t)
- 1)) ? g_free_sized (group_data->kek, __builtin_object_size
((group_data->kek), 0)) : (g_free) (group_data->kek)
;
10778 }
10779
10780 g_free(global_security.group_data)(__builtin_object_size ((global_security.group_data), 0) != (
(size_t) - 1)) ? g_free_sized (global_security.group_data, __builtin_object_size
((global_security.group_data), 0)) : (g_free) (global_security
.group_data)
;
10781 global_security.group_data = NULL((void*)0);
10782 global_security.group_data_count = 0;
10783
10784}
10785
10786/**
10787 * Initialize Core DPS Functionality
10788 */
10789static void dof_register(void)
10790{
10791 static hf_register_info hf[] =
10792 {
10793 { &hf_security_1_permission_type,
10794 { "Permission Type", "dof.2008.16.security.1.desired-duration", FT_UINT16, BASE_DEC, VALS(dof_2008_16_permission_type)((0 ? (const struct _value_string*)0 : ((dof_2008_16_permission_type
))))
, 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10795
10796 { &hf_security_1_length,
10797 { "Length", "dof.2008.16.security.1.length", FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10798
10799 { &hf_security_1_data,
10800 { "Data", "dof.2008.16.security.1.data", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10801
10802 /* Security.2 */
10803 { &hf_security_2_count,
10804 { "Count", "dof.2008.16.security.2.count", FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10805
10806 { &hf_security_2_permission,
10807 { "Permission", "dof.2008.16.security.2.permission", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10808
10809 /* Security.3.1 */
10810 { &hf_security_3_1_credential_type,
10811 { "Credential Type", "dof.2008.16.security.3.1.credential_type", FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10812
10813 { &hf_security_3_1_stage,
10814 { "Stage", "dof.2008.16.security.3.1.stage", FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10815
10816 { &hf_security_3_1_security_node_identifier,
10817 { "Security Node Identifier", "dof.2008.16.security.3.1.security_node_identifier", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10818
10819 /* Security 3.2 */
10820 { &hf_security_3_2_credential_type,
10821 { "Credential Type", "dof.2008.16.security.3.2.credential_type", FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10822
10823 { &hf_security_3_2_stage,
10824 { "Stage", "dof.2008.16.security.3.2.stage", FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10825
10826 { &hf_security_3_2_length,
10827 { "Length", "dof.2008.16.security.3.2.length", FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10828
10829 { &hf_security_3_2_public_data,
10830 { "Public Data", "dof.2008.16.security.3.2.public_data", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10831
10832 /* Security.4 */
10833 { &hf_security_4_l,
10834 { "L", "dof.2008.16.security.4.l", FT_UINT8, BASE_DEC, NULL((void*)0), 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10835
10836 { &hf_security_4_f,
10837 { "F", "dof.2008.16.security.4.f", FT_UINT8, BASE_DEC, NULL((void*)0), 0x40, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10838
10839 { &hf_security_4_ln,
10840 { "Ln", "dof.2008.16.security.4.ln", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0F, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10841
10842 { &hf_security_4_identity,
10843 { "Identity", "dof.2008.16.security.4.identity", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10844
10845 { &hf_security_4_nonce,
10846 { "Nonce", "dof.2008.16.security.4.nonce", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10847
10848 { &hf_security_4_permission_set,
10849 { "Permission Set", "dof.2008.16.security.4.permission_set", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10850
10851 /* Security.5 */
10852 { &hf_security_5_mac,
10853 { "MAC", "dof.2008.16.security.5.mac", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10854
10855 { &hf_security_5_key,
10856 { "KEY", "dof.2008.16.security.5.key", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10857
10858 /* Security.6.1 */
10859 { &hf_security_6_1_desired_duration,
10860 { "Desired Duration", "dof.2008.16.security.6.1.desired_duration", FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10861
10862 { &hf_security_6_1_desired_security_mode,
10863 { "Desired Security Mode", "dof.2008.16.security.6.1.desired_security_mode", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10864
10865 { &hf_security_6_1_initiator_request,
10866 { "Initiator Request", "dof.2008.16.security.6.1.initiator_request", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10867
10868 /* Security.6.2 */
10869 { &hf_security_6_2_responder_request,
10870 { "Responder Request", "dof.2008.16.security.6.2.responder_request", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10871
10872 /* Security.6.3 */
10873 { &hf_security_6_3_granted_duration,
10874 { "Granted Duration", "dof.2008.16.security.6.3.granted_duration", FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10875
10876 { &hf_security_6_3_session_security_scope,
10877 { "Session Security Scope", "dof.2008.16.security.6.3.session_security_scope", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10878
10879 { &hf_security_6_3_initiator_validation,
10880 { "Initiator Validation", "dof.2008.16.security.6.3.initiator_validation", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10881
10882 { &hf_security_6_3_responder_validation,
10883 { "Responder Validation", "dof.2008.16.security.6.3.responder_validation", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10884
10885 /* Security.9 */
10886 { &hf_security_9_length,
10887 { "Length", "dof.2008.16.security.9.length", FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10888
10889 { &hf_security_9_initial_state,
10890 { "Initial State", "dof.2008.16.security.9.initial_state", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10891
10892 /* Security.10 */
10893 { &hf_security_10_count,
10894 { "Count", "dof.2008.16.security.10.count", FT_UINT8, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10895
10896 { &hf_security_10_permission_group_identifier,
10897 { "Permission Group Identifier", "dof.2008.16.security.10.permission_group_identifier", FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10898
10899 /* Security.11 */
10900 { &hf_security_11_count,
10901 { "Count", "dof.2008.16.security.11.count", FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10902
10903 { &hf_security_11_permission_security_scope,
10904 { "Permission Security Scope", "dof.2008.16.security.11.permission_security_scope", FT_NONE, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10905
10906 /* Security.12 */
10907 { &hf_security_12_m,
10908 { "M", "dof.2008.16.security.12.m", FT_UINT8, BASE_DEC, VALS(dof_2008_16_security_12_m)((0 ? (const struct _value_string*)0 : ((dof_2008_16_security_12_m
))))
, 0xC0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10909
10910 { &hf_security_12_count,
10911 { "Count", "dof.2008.16.security.12.count", FT_UINT8, BASE_DEC, NULL((void*)0), 0x3F, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10912
10913 { &hf_security_12_permission_group_identifier,
10914 { "Permission Group Identifier", "dof.2008.16.security.12.permission_group_identifier", FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
10915
10916 { &hf_2008_1_dof_session_transport,
10917 { "Transport Session", "dof.transport_session", FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
10918 },
10919 { &hf_2008_1_dof_session,
10920 { "DPS Session", "dof.session", FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
10921 },
10922 { &hf_2008_1_dof_frame,
10923 { "DPS Frame", "dof.frame", FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
10924 },
10925 { &hf_2008_1_dof_is_2_node,
10926 { "DPS Is 2 Node", "dof.is_2_node", FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
10927 },
10928 { &hf_2008_1_dof_is_streaming,
10929 { "DPS Is Streaming", "dof.is_streaming", FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
10930 },
10931 { &hf_2008_1_dof_is_from_client,
10932 { "DPS Is From Client", "dof.is_from_client", FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
10933 }
10934 };
10935
10936 static int *ett[] = {
10937 /* Security.2 */
10938 &ett_security_2_permission,
10939 &ett_security_3_1_security_node_identifier,
10940
10941 /* Security.11 */
10942 &ett_security_11_permission_security_scope,
10943
10944 &ett_security_6_1_desired_security_mode,
10945 &ett_security_6_1_initiator_request,
10946
10947 &ett_security_6_2_responder_request,
10948 &ett_security_6_3_session_security_scope,
10949 &ett_security_6_3_initiator_validation,
10950 &ett_security_6_3_responder_validation,
10951
10952 &ett_security_4_identity,
10953 &ett_security_4_permission_set,
10954
10955 &ett_2008_1_dof,
10956 };
10957
10958 static ei_register_info ei[] =
10959 {
10960#if 0
10961 { &ei_undecoded, { "dof.undecoded", PI_UNDECODED0x05000000, PI_WARN0x00600000, "DOF: Some protocol octets were not decoded", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
10962#endif
10963 { &ei_malformed, { "dof.malformed", PI_MALFORMED0x07000000, PI_ERROR0x00800000, "Malformed:", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
10964 { &ei_implicit_no_op, { "dof.implicit_no_op", PI_PROTOCOL0x09000000, PI_COMMENT0x00100000, "Implicit No-op", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
10965 { &ei_c2_c3_c4_format, { "dof.c2_c3_c4_format", PI_MALFORMED0x07000000, PI_WARN0x00600000, "DOF: Cx IE format", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
10966 { &ei_security_3_1_invalid_stage, { "dof.security.3.1.invalid_stage", PI_MALFORMED0x07000000, PI_ERROR0x00800000, "DPS: Security.3.1: Stage invalid.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
10967 { &ei_security_4_invalid_bit, { "dof.security.4.invalid_bit", PI_MALFORMED0x07000000, PI_WARN0x00600000, "DPS: Security.4: Reserved bit set.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
10968 { &ei_security_13_out_of_range, { "dof.security.13.out_of_range", PI_MALFORMED0x07000000, PI_ERROR0x00800000, "DPS: Security.13: Attribute Data out of range.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
10969 };
10970
10971 /* Security mode of operation templates. */
10972 static uat_field_t secmode_uat_fields[] = {
10973 UAT_FLD_CSTRING(secmode_list, domain, "Domain", "The domain, coded as hex digits of PDU Security.7."){"domain", "Domain", PT_TXTMOD_STRING,{uat_fld_chk_str,secmode_list_domain_set_cb
,secmode_list_domain_tostr_cb},{0,0,0},0,"The domain, coded as hex digits of PDU Security.7."
,((void*)0)}
,
10974 UAT_FLD_CSTRING(secmode_list, identity, "Group ID", "The group identifier, coded as hex digits of PDU Security.8."){"identity", "Group ID", PT_TXTMOD_STRING,{uat_fld_chk_str,secmode_list_identity_set_cb
,secmode_list_identity_tostr_cb},{0,0,0},0,"The group identifier, coded as hex digits of PDU Security.8."
,((void*)0)}
,
10975 UAT_FLD_CSTRING(secmode_list, kek, "KEK", "The KEK, coded as hex digits representing the KEK (256-bit)."){"kek", "KEK", PT_TXTMOD_STRING,{uat_fld_chk_str,secmode_list_kek_set_cb
,secmode_list_kek_tostr_cb},{0,0,0},0,"The KEK, coded as hex digits representing the KEK (256-bit)."
,((void*)0)}
,
10976 UAT_END_FIELDS{((void*)0),((void*)0),PT_TXTMOD_NONE,{0,0,0},{0,0,0},0,0,((void
*)0)}
10977 };
10978
10979 /* Security keys. */
10980 static uat_field_t seckey_uat_fields[] = {
10981 UAT_FLD_CSTRING(seckey_list, key, "Session Key", "The session key to try to use, coded as hex digits representing the key (256-bit)."){"key", "Session Key", PT_TXTMOD_STRING,{uat_fld_chk_str,seckey_list_key_set_cb
,seckey_list_key_tostr_cb},{0,0,0},0,"The session key to try to use, coded as hex digits representing the key (256-bit)."
,((void*)0)}
,
10982 UAT_END_FIELDS{((void*)0),((void*)0),PT_TXTMOD_NONE,{0,0,0},{0,0,0},0,0,((void
*)0)}
10983 };
10984
10985 /* Identity secrets. */
10986 static uat_field_t identsecret_uat_fields[] = {
10987 UAT_FLD_CSTRING(identsecret_list, domain, "Domain", "The domain, coded as hex digits of PDU Security.7."){"domain", "Domain", PT_TXTMOD_STRING,{uat_fld_chk_str,identsecret_list_domain_set_cb
,identsecret_list_domain_tostr_cb},{0,0,0},0,"The domain, coded as hex digits of PDU Security.7."
,((void*)0)}
,
10988 UAT_FLD_CSTRING(identsecret_list, identity, "Identity", "The group identifier, coded as hex digits of PDU Security.8."){"identity", "Identity", PT_TXTMOD_STRING,{uat_fld_chk_str,identsecret_list_identity_set_cb
,identsecret_list_identity_tostr_cb},{0,0,0},0,"The group identifier, coded as hex digits of PDU Security.8."
,((void*)0)}
,
10989 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)."){"secret", "Secret", PT_TXTMOD_STRING,{ identsecret_chk_cb ,identsecret_list_secret_set_cb
,identsecret_list_secret_tostr_cb},{0,0,0},0,"The resolved secret for a given identity, coded as hex digits representing the secret (256-bit)."
,((void*)0)}
,
10990 UAT_END_FIELDS{((void*)0),((void*)0),PT_TXTMOD_NONE,{0,0,0},{0,0,0},0,0,((void
*)0)}
10991 };
10992
10993 module_t *dof_module;
10994 uat_t *secmode_uat;
10995 uat_t *seckey_uat;
10996 uat_t *identsecret_uat;
10997 expert_module_t *expert_security;
10998
10999 dsp_option_dissectors = register_dissector_table("dof.dsp.options", "DSP Protocol Options", proto_2008_1_dsp, FT_UINT32, BASE_DEC);
11000 dof_sec_dissectors = register_dissector_table("dof.secmode", "DOF Security Mode of Operation", proto_2008_1_dof, FT_UINT16, BASE_DEC);
11001 register_dissector_table("dof.2008.1", "DOF Common PDU", proto_2008_1_dof, FT_STRING, BASE_DEC);
11002
11003 proto_2008_1_dof = proto_register_protocol(DOF_PROTOCOL_STACK"DOF Protocol Stack", "DOF", "dof");
11004
11005 proto_2008_1_dof_tcp = proto_register_protocol(DOF_PROTOCOL_STACK"DOF Protocol Stack"" TCP", "DOF-TCP", "dof-tcp");
11006 proto_2008_1_dof_udp = proto_register_protocol(DOF_PROTOCOL_STACK"DOF Protocol Stack"" UDP", "DOF-UDP", "dof-udp");
11007
11008 proto_register_field_array(proto_2008_1_dof, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11009 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
11010
11011 expert_security = expert_register_protocol(proto_2008_1_dof);
11012 expert_register_field_array(expert_security, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
11013
11014 dof_module = prefs_register_protocol(proto_2008_1_dof, dof_reset);
11015 secmode_uat = uat_new("DPS Security Mode Templates",
11016 sizeof(secmode_field_t),
11017 "custom_dof_secmode_list",
11018 true1,
11019 &secmode_list,
11020 &num_secmode_list,
11021 (UAT_AFFECTS_DISSECTION0x00000001 | UAT_AFFECTS_FIELDS0x00000002),
11022 NULL((void*)0),
11023 secmode_list_copy_cb,
11024 secmode_list_update_cb,
11025 secmode_list_free_cb,
11026 secmode_list_post_update_cb,
11027 NULL((void*)0),
11028 secmode_uat_fields
11029 );
11030
11031 seckey_uat = uat_new("DPS Session Keys",
11032 sizeof(seckey_field_t),
11033 "custom_dof_seckey_list",
11034 true1,
11035 &seckey_list,
11036 &num_seckey_list,
11037 (UAT_AFFECTS_DISSECTION0x00000001 | UAT_AFFECTS_FIELDS0x00000002),
11038 NULL((void*)0),
11039 seckey_list_copy_cb,
11040 seckey_list_update_cb,
11041 seckey_list_free_cb,
11042 seckey_list_post_update_cb,
11043 NULL((void*)0),
11044 seckey_uat_fields
11045 );
11046
11047 identsecret_uat = uat_new("DPS Identity Secrets",
11048 sizeof(identsecret_field_t),
11049 "custom_dof_identsecret_list",
11050 true1,
11051 &identsecret_list,
11052 &num_identsecret_list,
11053 (UAT_AFFECTS_DISSECTION0x00000001 | UAT_AFFECTS_FIELDS0x00000002),
11054 NULL((void*)0),
11055 identsecret_list_copy_cb,
11056 identsecret_list_update_cb,
11057 identsecret_list_free_cb,
11058 identsecret_list_post_update_cb,
11059 NULL((void*)0),
11060 identsecret_uat_fields
11061 );
11062
11063 prefs_register_bool_preference(dof_module, "custom_dof_decrypt_all",
11064 "Attempt to decrypt all packets",
11065 "Specifies that decryption should be attempted on all packets, even if the session initialization wasn't captured.",
11066 &decrypt_all_packets);
11067
11068 prefs_register_bool_preference(dof_module, "custom_dof_track_operations",
11069 "Track DPS operations",
11070 "Specifies that operations should be tracked across multiple packets, providing summary lists. This takes time and memory.",
11071 &track_operations);
11072
11073 prefs_register_uint_preference(dof_module, "custom_dof_track_operations_window",
11074 "Track DPS window",
11075 "Limits the number of operations shown before and after the current operations",
11076 10, &track_operations_window);
11077
11078 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.");
11079
11080 prefs_register_uat_preference(dof_module, "custom_dof_secmode_list", "DPS Security Mode Templates",
11081 "A table of security modes and initialization data that will be tried if no security mode is found.",
11082 secmode_uat);
11083
11084 prefs_register_uat_preference(dof_module, "custom_dof_seckey_list", "DPS Session Keys",
11085 "A table of session keys to attempt if none is known.",
11086 seckey_uat);
11087
11088 prefs_register_uat_preference(dof_module, "custom_dof_identsecret_list", "DPS Identity Secrets",
11089 "A table of secrets for different identities.",
11090 identsecret_uat);
11091}
11092
11093static void dof_handoff(void)
11094{
11095 static dissector_handle_t tcp_handle;
11096
11097 dof_oid_handle = register_dissector_with_description("dof.oid", DOF_OBJECT_IDENTIFIER"DOF Object Identifier", dissect_2009_11_type_4, oid_proto);
11098
11099 tcp_handle = create_dissector_handle(dissect_dof_tcp, proto_2008_1_dof);
11100 dof_udp_handle = create_dissector_handle(dissect_dof_udp, proto_2008_1_dof);
11101
11102 dissector_add_uint_with_preference("tcp.port", DOF_P2P_NEG_SEC_TCP_PORT3567, tcp_handle);
11103 dissector_add_uint_range_with_preference("udp.port", DOF_NEG_SEC_UDP_PORT_RANGE"3567,5567", dof_udp_handle);
11104}
11105
11106/* OID Registration Support */
11107
11108static void oid_reset(void)
11109{
11110}
11111
11112static void oid_cleanup(void)
11113{
11114}
11115
11116/* Initialize OID */
11117static void oid_register(void)
11118{
11119 static hf_register_info hf[] = {
11120 { &hf_oid_class,
11121 { "Class", "dof.oid.class", FT_UINT32, BASE_DEC, NULL((void*)0), 0, "DPS Object Identifier Class", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11122 },
11123 { &hf_oid_header,
11124 { "Header", "dof.oid.header", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11125 },
11126 { &hf_oid_attribute,
11127 { "Attribute", "dof.oid.attribute", FT_UINT8, BASE_DEC, NULL((void*)0), 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11128 },
11129 { &hf_oid_length,
11130 { "Length", "dof.oid.length", FT_UINT8, BASE_DEC, NULL((void*)0), 0x3F, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11131 },
11132 { &hf_oid_data,
11133 { "Data", "dof.oid.data", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11134 },
11135 { &hf_oid_all_attribute_data,
11136 { "Attribute Data", "dof.oid.attribute-data", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11137 },
11138 { &hf_oid_attribute_header,
11139 { "Header", "dof.attribute.header", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11140 },
11141 { &hf_oid_attribute_attribute,
11142 { "Attribute", "dof.attribute.attribute", FT_UINT8, BASE_DEC, NULL((void*)0), 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11143 },
11144 { &hf_oid_attribute_id,
11145 { "ID", "dof.attribute.id", FT_UINT8, BASE_DEC, NULL((void*)0), 0x7F, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11146 },
11147 { &hf_oid_attribute_length,
11148 { "Length", "dof.attribute.length", FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11149 },
11150 { &hf_oid_attribute_data,
11151 { "Data", "dof.attribute.data", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11152 },
11153 { &hf_oid_attribute_oid,
11154 { "OID", "dof.attribute.oid", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11155 },
11156 };
11157
11158 static int *ett[] = {
11159 &ett_oid,
11160 &ett_oid_header,
11161 &ett_oid_attribute,
11162 &ett_oid_attribute_header,
11163 &ett_oid_attribute_oid,
11164 };
11165
11166 static ei_register_info ei[] =
11167 {
11168 { &ei_type_4_header_zero, { "dof.oid.header_zero", PI_MALFORMED0x07000000, PI_ERROR0x00800000, "DOF Violation: Type.4: Header bit mandated 0.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11169 };
11170
11171 if (oid_proto == -1)
11172 {
11173 expert_module_t *expert_oid;
11174
11175 oid_proto = proto_register_protocol(DOF_OBJECT_IDENTIFIER"DOF Object Identifier", "DPS.OID", "dof.oid");
11176 proto_register_field_array(oid_proto, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11177 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
11178 expert_oid = expert_register_protocol(oid_proto);
11179 expert_register_field_array(expert_oid, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
11180 }
11181}
11182
11183static void oid_handoff(void)
11184{
11185}
11186
11187/* DNP Registration Support */
11188
11189static unsigned dof_ns_session_key_hash_fn(const void *key)
11190{
11191 const dof_ns_session_key *session_key = (const dof_ns_session_key *)key;
11192 unsigned result = 0;
11193
11194 result += g_int_hash(&session_key->transport_session_id);
11195 result += g_int_hash(&session_key->client);
11196 result += g_int_hash(&session_key->server);
11197
11198 return result;
11199}
11200
11201static gboolean dof_ns_session_key_equal_fn(const void *key1, const void *key2)
11202{
11203 const dof_ns_session_key *session_key_ptr1 = (const dof_ns_session_key *)key1;
11204 const dof_ns_session_key *session_key_ptr2 = (const dof_ns_session_key *)key2;
11205
11206 if (session_key_ptr1->transport_session_id != session_key_ptr2->transport_session_id)
11207 return FALSE(0);
11208
11209 if (session_key_ptr1->client != session_key_ptr2->client)
11210 return FALSE(0);
11211
11212 if (session_key_ptr1->server != session_key_ptr2->server)
11213 return FALSE(0);
11214
11215 return TRUE(!(0));
11216}
11217
11218static void dof_dnp_reset(void)
11219{
11220 dof_ns_session_lookup = g_hash_table_new_full(dof_ns_session_key_hash_fn, dof_ns_session_key_equal_fn, g_free, NULL((void*)0));
11221}
11222
11223static void dof_dnp_cleanup(void)
11224{
11225 g_hash_table_destroy(dof_ns_session_lookup);
11226 dof_ns_session_lookup = NULL((void*)0);
11227}
11228
11229static void dof_register_dnp_0(void)
11230{
11231 static hf_register_info hf[] =
11232 {
11233 { &hf_2008_1_dnp_0_1_1_padding,
11234 { "Padding", "dof.dnp.v0.padding", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11235 },
11236 { &hf_2008_1_dnp_0_1_1_version,
11237 { "Version", "dof.dnp.v0.version", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11238 },
11239 };
11240
11241 if (proto_2008_1_dnp_0 <= 0)
11242 {
11243 proto_2008_1_dnp_0 = proto_register_protocol(DOF_NETWORK_PROTOCOL"DOF Network Protocol" " V0", "DPS.DNP.V0", "dof.dnp.v0");
11244
11245 proto_register_field_array(proto_2008_1_dnp_0, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11246 }
11247}
11248
11249/**
11250 * The registration hand-off routine
11251 */
11252static void dof_reg_handoff_dnp_0(void)
11253{
11254 dissector_handle_t dnp_handle;
11255 dnp_handle = create_dissector_handle(dissect_dnp_0, proto_2008_1_dnp_0);
11256
11257 dissector_add_uint("dof.dnp", 0, dnp_handle);
11258}
11259
11260static void dof_register_dnp_1(void)
11261{
11262 expert_module_t *expert_dnp;
11263
11264 static hf_register_info hf[] =
11265 {
11266 { &hf_2009_9_dnp_1_flags,
11267 { "Flags", "dof.2009_9.dnp_1.flags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11268 },
11269 { &hf_2009_9_dnp_1_flag_length,
11270 { "Length Size", "dof.2009_9.dnp_1.flags.lengthsize", FT_UINT8, BASE_DEC, NULL((void*)0), 0x03, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11271 },
11272 { &hf_2009_9_dnp_1_flag_srcport,
11273 { "Source Port", "dof.2009_9.dnp_1.flags.srcport", FT_UINT8, BASE_DEC, NULL((void*)0), 0x04, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11274 },
11275 { &hf_2009_9_dnp_1_flag_dstport,
11276 { "Destination Port", "dof.2009_9.dnp_1.flags.dstport", FT_UINT8, BASE_DEC, NULL((void*)0), 0x08, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11277 },
11278
11279 { &hf_2009_9_dnp_1_length,
11280 { "Length", "dof.2009_9.dnp_1.length", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11281 },
11282 { &hf_2009_9_dnp_1_srcport,
11283 { "Source Port", "dof.2009_9.dnp_1.srcport", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11284 },
11285 { &hf_2009_9_dnp_1_dstport,
11286 { "Destination Port", "dof.2009_9.dnp_1.dstport", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11287 },
11288 };
11289
11290 static int *ett[] =
11291 {
11292 &ett_2009_9_dnp_1_flags,
11293 };
11294
11295 static ei_register_info ei[] =
11296 {
11297 { &ei_dof_10_flags_zero, { "dof.dnp.v1.flags_zero", PI_UNDECODED0x05000000, PI_ERROR0x00800000, "DPS-10: Reserved flag bits must be zero.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11298 { &ei_dof_dnp_length_short, { "dof.dnp.v1.length_short", PI_MALFORMED0x07000000, PI_ERROR0x00800000, "DNP length is shorter than the address fields", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11299#if 0
11300 { &ei_dof_13_length_specified, { "dof.dnp.v1.length_specified", PI_UNDECODED0x05000000, PI_ERROR0x00800000, "DPS-13: Length must be specified on a connection.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11301#endif
11302 };
11303
11304 if (proto_2009_9_dnp_1 <= 0)
11305 {
11306 proto_2009_9_dnp_1 = proto_register_protocol(DOF_NETWORK_PROTOCOL"DOF Network Protocol" " V1", "DOF.DNP.V1", "dof.dnp.v1");
11307
11308 proto_register_field_array(proto_2009_9_dnp_1, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11309 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
11310
11311 expert_dnp = expert_register_protocol(proto_2009_9_dnp_1);
11312 expert_register_field_array(expert_dnp, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
11313 }
11314}
11315
11316/**
11317 * The registration hand-off routine
11318 */
11319static void dof_reg_handoff_dnp_1(void)
11320{
11321 dissector_handle_t dnp_handle, dnp_frame_handle;
11322 dnp_handle = create_dissector_handle(dissect_dnp_1, proto_2009_9_dnp_1);
11323 dnp_frame_handle = create_dissector_handle(determine_packet_length_1, proto_2009_9_dnp_1);
11324
11325 dissector_add_uint("dof.dnp", 1, dnp_handle);
11326 dissector_add_uint("dof.dnp.frame", 1, dnp_frame_handle);
11327}
11328
11329static void dof_dnp_handoff(void)
11330{
11331 dof_reg_handoff_dnp_0();
11332 dof_reg_handoff_dnp_1();
11333}
11334
11335/**
11336 * Initialize Core DNP Functionality
11337 */
11338static void dof_dnp_register(void)
11339{
11340 static hf_register_info hf[] =
11341 {
11342 { &hf_2008_1_dnp_1_flag,
11343 { "Flag", "dof.2008_1.dnp_1.flag", FT_BOOLEAN, 8, TFS(&tfs_present_not_present)((0 ? (const struct true_false_string*)0 : ((&tfs_present_not_present
))))
, 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11344 },
11345 { &hf_2008_1_dnp_1_version,
11346 { "Version", "dof.2008_1.dnp_1.version", FT_UINT8, BASE_DEC, NULL((void*)0), 0x7F, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11347 },
11348 };
11349
11350 static int *ett[] =
11351 {
11352 &ett_2008_1_dnp,
11353 &ett_2008_1_dnp_header,
11354 };
11355
11356 proto_2008_1_dnp = proto_register_protocol(DOF_NETWORK_PROTOCOL"DOF Network Protocol", "DPS.DNP", "dof.dnp");
11357
11358 proto_register_field_array(proto_2008_1_dnp, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11359 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
11360 dnp_dissectors = register_dissector_table("dof.dnp", "DOF DNP Version", proto_2008_1_dnp, FT_UINT8, BASE_DEC);
11361 dnp_framing_dissectors = register_dissector_table("dof.dnp.frame", "DOF DNP Framing", proto_2008_1_dnp, FT_UINT8, BASE_DEC);
11362
11363 dof_register_dnp_0();
11364 dof_register_dnp_1();
11365}
11366
11367/* DPP Registration Support */
11368
11369/**
11370 * This routine is called each time the system is reset (file load, capture)
11371 * and so it should take care of freeing any of our persistent stuff.
11372 */
11373static void dof_dpp_reset(void)
11374{
11375 dpp_reset_opid_support();
11376 dpp_reset_sid_support();
11377}
11378
11379static void dof_dpp_cleanup(void)
11380{
11381}
11382
11383static void dof_register_dpp_0(void)
11384{
11385 static hf_register_info hf[] =
11386 {
11387 { &hf_2008_1_dpp_0_1_1_version,
11388 { "Version", "dof.dpp.v0.version", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11389 },
11390 };
11391
11392 if (proto_2008_1_dpp_0 <= 0)
11393 {
11394 proto_2008_1_dpp_0 = proto_register_protocol(DOF_PRESENTATION_PROTOCOL"DOF Presentation Protocol" " V0", "DPS.DPP.V0", "dof.dpp.v0");
11395
11396 proto_register_field_array(proto_2008_1_dpp_0, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11397 }
11398}
11399
11400/**
11401 * The registration hand-off routine
11402 */
11403static void dof_reg_handoff_dpp_0(void)
11404{
11405 dissector_handle_t dpp_handle;
11406 dpp_handle = create_dissector_handle(dissect_dpp_0, proto_2008_1_dpp_0);
11407
11408 dissector_add_uint("dof.dpp", 0, dpp_handle);
11409}
11410
11411static void dof_register_dpp_2(void)
11412{
11413 expert_module_t *expert_dpp;
11414
11415 static hf_register_info hf[] =
11416 {
11417 { &hf_2009_12_dpp_2_1_flags,
11418 { "Flags", "dof.dpp.v2.flags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11419 },
11420 { &hf_2009_12_dpp_2_1_flag_security,
11421 { "Secure", "dof.dpp.v2.flags.security", FT_BOOLEAN, 8, NULL((void*)0), 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11422 },
11423 { &hf_2009_12_dpp_2_1_flag_opid,
11424 { "Operation ID Type", "dof.dpp.v2.flags.opidtype", FT_UINT8, BASE_DEC, VALS(strings_2009_12_dpp_opid_types)((0 ? (const struct _value_string*)0 : ((strings_2009_12_dpp_opid_types
))))
, 0x60, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11425 { &hf_2009_12_dpp_2_1_flag_cmdrsp,
11426 { "Command/Response", "dof.dpp.v2.flags.cmdrsp", FT_BOOLEAN, 8, TFS(&tfs_response_command)((0 ? (const struct true_false_string*)0 : ((&tfs_response_command
))))
, 0x10, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11427 { &hf_2009_12_dpp_2_1_flag_seq,
11428 { "Sequence", "dof.dpp.v2.flags.sequence", FT_BOOLEAN, 8, TFS(&tfs_present_not_present)((0 ? (const struct true_false_string*)0 : ((&tfs_present_not_present
))))
, 0x04, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11429 { &hf_2009_12_dpp_2_1_flag_retry,
11430 { "Retry", "dof.dpp.v2.flags.retry", FT_BOOLEAN, 8, TFS(&tfs_present_not_present)((0 ? (const struct true_false_string*)0 : ((&tfs_present_not_present
))))
, 0x02, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11431
11432 { &hf_2009_12_dpp_2_3_sec_flags,
11433 { "Flags", "dof.dpp.v2.security.flags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11434 { &hf_2009_12_dpp_2_3_sec_flag_secure,
11435 { "Security Mode Header", "dof.dpp.v2.security.flags.securitymodeheader", FT_UINT8, BASE_DEC, NULL((void*)0), 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11436 { &hf_2009_12_dpp_2_3_sec_flag_rdid,
11437 { "Remote Domain ID", "dof.dpp.v2.security.flags.rdid", FT_UINT8, BASE_DEC, NULL((void*)0), 0x08, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11438 { &hf_2009_12_dpp_2_3_sec_flag_partition,
11439 { "Partition Present", "dof.dpp.v2.security.flags.partition", FT_UINT8, BASE_DEC, NULL((void*)0), 0x04, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11440 { &hf_2009_12_dpp_2_3_sec_flag_ssid,
11441 { "SSID Present", "dof.dpp.v2.security.flags.ssid", FT_UINT8, BASE_DEC, NULL((void*)0), 0x01, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11442 { &hf_2009_12_dpp_2_3_sec_flag_as,
11443 { "AS Present", "dof.dpp.v2.security.flags.as", FT_UINT8, BASE_DEC, NULL((void*)0), 0x02, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11444 { &hf_2009_12_dpp_2_3_sec_ssid,
11445 { "Security State Identifier", "dof.dpp.v2.security.ssid", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11446 { &hf_2009_12_dpp_2_3_sec_rdid,
11447 { "Remote Domain Identifier", "dof.dpp.v2.security.rdid", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11448 { &hf_2009_12_dpp_2_3_sec_remote_partition,
11449 { "Remote Security Scope", "dof.dpp.v2.security.remote-scope", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11450 { &hf_2009_12_dpp_2_3_sec_partition,
11451 { "Security Scope", "dof.dpp.v2.security.scope", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11452
11453 { &hf_2009_12_dpp_2_1_opcnt,
11454 { "Operation Count", "dof.dpp.v2.opcnt", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11455 { &hf_2009_12_dpp_2_1_seq,
11456 { "Sequence", "dof.dpp.v2.sequence", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11457 { &hf_2009_12_dpp_2_1_retry,
11458 { "Retry", "dof.dpp.v2.retry", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11459 { &hf_2009_12_dpp_2_1_delay,
11460 { "Delay", "dof.dpp.v2.delay", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11461 };
11462
11463 static hf_register_info shf[] =
11464 {
11465 { &hf_2009_12_dpp_2_14_opcode,
11466 { "Opcode", "dof.dpp.v2s.opcode", FT_UINT8, BASE_DEC, VALS(strings_2009_12_dpp_common_opcodes)((0 ? (const struct _value_string*)0 : ((strings_2009_12_dpp_common_opcodes
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11467 };
11468
11469 static int *ett[] =
11470 {
11471 &ett_2009_12_dpp_2_1_flags,
11472 &ett_2009_12_dpp_2_opid,
11473 &ett_2009_12_dpp_2_opid_history,
11474 &ett_2009_12_dpp_2_3_security,
11475 &ett_2009_12_dpp_2_3_sec_flags,
11476 &ett_2009_12_dpp_2_3_sec_remote_partition,
11477 &ett_2009_12_dpp_2_3_sec_partition,
11478 };
11479
11480 static ei_register_info ei[] =
11481 {
11482 { &ei_dpp2_dof_10_flags_zero, { "dof.dpp.v2.flags_zero", PI_UNDECODED0x05000000, PI_ERROR0x00800000, "DPPv2: Reserved flag bits must be zero.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11483 { &ei_dpp_default_flags, { "dof.dpp.v2.flags_included", PI_COMMENTS_GROUP0x0b000000, PI_NOTE0x00400000, "Default flag value is included explicitly.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11484 { &ei_dpp_explicit_sender_sid_included, { "dof.dpp.v2.sender_sid_included", PI_PROTOCOL0x09000000, PI_NOTE0x00400000, "Explicit SID could be optimized, same as sender.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11485 { &ei_dpp_explicit_receiver_sid_included, { "dof.dpp.v2.receiver_sid_included", PI_PROTOCOL0x09000000, PI_NOTE0x00400000, "Explicit SID could be optimized, same as receiver.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11486 { &ei_dpp_no_security_context, { "dof.dpp.v2.no_context", PI_UNDECODED0x05000000, PI_WARN0x00600000, "No security context to enable packet decryption.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11487 };
11488
11489 static int *sett[] =
11490 {
11491 &ett_2009_12_dpp_common,
11492 };
11493
11494 if (proto_2009_12_dpp <= 0)
11495 {
11496 proto_2009_12_dpp = proto_register_protocol(DOF_PRESENTATION_PROTOCOL"DOF Presentation Protocol" " V2", "DPS.DPP.V2", "dof.dpp.v2");
11497 proto_register_field_array(proto_2009_12_dpp, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11498 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
11499 }
11500
11501 if (proto_2009_12_dpp_common <= 0)
11502 {
11503 proto_2009_12_dpp_common = proto_register_protocol(DOF_PRESENTATION_PROTOCOL"DOF Presentation Protocol" " V2 Support", "DPS.DPP.V2S", "dof.dpp.v2s");
11504
11505 proto_register_field_array(proto_2009_12_dpp, shf, array_length(shf)(sizeof (shf) / sizeof (shf)[0]));
11506 proto_register_subtree_array(sett, array_length(sett)(sizeof (sett) / sizeof (sett)[0]));
11507
11508 expert_dpp = expert_register_protocol(proto_2009_12_dpp);
11509 expert_register_field_array(expert_dpp, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
11510 }
11511}
11512
11513/**
11514 * The registration hand-off routine
11515 */
11516static void dof_reg_handoff_dpp_2(void)
11517{
11518 dissector_handle_t dpp_handle;
11519 dpp_handle = create_dissector_handle(dissect_dpp_2, proto_2009_12_dpp);
11520 dissector_add_uint("dof.dpp", 2, dpp_handle);
11521}
11522
11523/**
11524 * Initialize Core DPP Functionality
11525 */
11526static void dof_dpp_register(void)
11527{
11528 static hf_register_info hf[] =
11529 {
11530 { &hf_2008_1_dpp_sid_num,
11531 { "SID ID", "dof.dpp.v2.sid-id", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11532 },
11533 { &hf_2008_1_dpp_sid_str,
11534 { "SID", "dof.dpp.v2.sid", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11535 },
11536 { &hf_2008_1_dpp_rid_num,
11537 { "RID ID", "dof.dpp.v2.rid-id", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11538 },
11539 { &hf_2008_1_dpp_rid_str,
11540 { "RID", "dof.dpp.v2.rid", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11541 },
11542 { &hf_2008_1_dpp_first_command,
11543 { "First Operation", "dof.dpp.v2.first-operation", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11544 { &hf_2008_1_dpp_last_command,
11545 { "Last Operation", "dof.dpp.v2.last-operation", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11546 { &hf_2008_1_dpp_first_response,
11547 { "First Response", "dof.dpp.v2.first-response", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11548 { &hf_2008_1_dpp_last_response,
11549 { "Last Response", "dof.dpp.v2.last-response", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11550 { &hf_2008_1_dpp_related_frame,
11551 { "Related Frame", "dof.dpp.v2.related-frame", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11552 { &hf_2008_1_dpp_1_flag,
11553 { "Flags", "dof.dpp.flag", FT_BOOLEAN, 8, TFS(&tfs_present_not_present)((0 ? (const struct true_false_string*)0 : ((&tfs_present_not_present
))))
, 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11554 },
11555 { &hf_2008_1_dpp_1_version,
11556 { "Version", "dof.dpp.version", FT_UINT8, BASE_DEC, NULL((void*)0), 0x7F, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11557 },
11558 };
11559
11560 static int *ett[] =
11561 {
11562 &ett_2008_1_dpp,
11563 &ett_2008_1_dpp_1_header,
11564 };
11565
11566 static ei_register_info ei[] =
11567 {
11568 { &ei_dof_6_timeout, { "dof.dpp.timeout", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "DOF Violation: DPS.6: Negotiation not complete within 10 seconds.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11569 };
11570
11571 if (proto_2008_1_dpp <= 0)
11572 {
11573 expert_module_t *expert_dpp;
11574
11575 proto_2008_1_dpp = proto_register_protocol(DOF_PRESENTATION_PROTOCOL"DOF Presentation Protocol", "DPS.DPP", "dof.dpp");
11576
11577 proto_register_field_array(proto_2008_1_dpp, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11578 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
11579 dof_dpp_dissectors = register_dissector_table("dof.dpp", "DOF DPP Version", proto_2008_1_dpp, FT_UINT8, BASE_DEC);
11580
11581 expert_dpp = expert_register_protocol(proto_2008_1_dpp);
11582 expert_register_field_array(expert_dpp, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
11583 }
11584
11585 dof_register_dpp_0();
11586 dof_register_dpp_2();
11587}
11588
11589static void dof_dpp_handoff(void)
11590{
11591 dof_reg_handoff_dpp_0();
11592 dof_reg_handoff_dpp_2();
11593}
11594
11595/* General Application Registration Support */
11596
11597static void app_reset(void)
11598{
11599}
11600
11601static void app_cleanup(void)
11602{
11603}
11604
11605/**
11606 * Initialize Core DPP Functionality
11607 */
11608static void app_register(void)
11609{
11610 if (proto_2008_1_app <= 0)
11611 {
11612 proto_2008_1_app = proto_register_protocol(DOF_APPLICATION_PROTOCOL"DOF Application Protocol", "DPS.APP", "dof.app");
11613 app_dissectors = register_dissector_table("dof.app", "DOF APP Version", proto_2008_1_app, FT_UINT16, BASE_DEC);
11614 }
11615}
11616
11617static void app_handoff(void)
11618{
11619}
11620
11621/* DSP Registration Support */
11622
11623static void dof_dsp_reset(void)
11624{
11625}
11626
11627static void dof_dsp_cleanup(void)
11628{
11629}
11630
11631static void dof_register_dsp_0(void)
11632{
11633 static hf_register_info hf[] =
11634 {
11635 { &hf_2008_1_app_version,
11636 { "APPID", "dof.app.v0.appid", FT_UINT16, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
11637 },
11638
11639 { &hf_2008_1_dsp_12_opcode,
11640 { "Opcode", "dof.dsp.opcode", FT_UINT8, BASE_DEC, VALS(strings_2008_1_dsp_opcodes)((0 ? (const struct _value_string*)0 : ((strings_2008_1_dsp_opcodes
))))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11641
11642 { &hf_2008_1_dsp_attribute_code,
11643 { "Attribute Code", "dof.dsp.avp.attribute-code", FT_UINT8, BASE_DEC, VALS(strings_2008_1_dsp_attribute_codes)((0 ? (const struct _value_string*)0 : ((strings_2008_1_dsp_attribute_codes
))))
, 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11644
11645 { &hf_2008_1_dsp_attribute_data,
11646 { "Attribute Data", "dof.dsp.avp.attribute-data", FT_UINT16, BASE_HEX, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11647
11648 { &hf_2008_1_dsp_value_length,
11649 { "Value Length", "dof.dsp.avp.value-length", FT_UINT8, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11650
11651 { &hf_2008_1_dsp_value_data,
11652 { "Value Data", "dof.dsp.avp.value-data", FT_BYTES, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11653 };
11654
11655 static int *ett[] =
11656 {
11657 &ett_2008_1_dsp_12,
11658 &ett_2008_1_dsp_12_options,
11659 &ett_2008_1_dsp_12_option,
11660 };
11661
11662 proto_2008_1_dsp = proto_register_protocol("DOF Session Protocol", "DOF.ESP", "dof.esp");
11663
11664 proto_register_field_array(proto_2008_1_dsp, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11665 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
11666}
11667
11668/**
11669 * The registration hand-off routine
11670 */
11671static void dof_reg_handoff_dsp_0(void)
11672{
11673 dissector_handle_t dsp_handle = create_dissector_handle(dissect_dsp, proto_2008_1_dsp);
11674 dissector_add_uint("dof.app", 0, dsp_handle);
11675}
11676
11677static void dof_dsp_register(void)
11678{
11679 dof_register_dsp_0();
11680}
11681
11682static void dof_dsp_handoff(void)
11683{
11684 dof_reg_handoff_dsp_0();
11685}
11686
11687/* CCM Registration Support */
11688
11689static void dof_ccm_reset(void)
11690{
11691}
11692
11693static void dof_ccm_cleanup(void)
11694{
11695}
11696
11697static void dof_register_ccm_24577(void)
11698{
11699 expert_module_t *expert_ccm;
11700
11701 static hf_register_info hfdsp[] =
11702 {
11703 { &hf_ccm_dsp_option,
11704 { "CCM Security Mode", "dof.ccm.dsp_opt", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11705 { &hf_ccm_dsp_strength_count,
11706 { "CCM Strength Count", "dof.ccm.strength-count", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11707 { &hf_ccm_dsp_strength,
11708 { "CCM Strength", "dof.ccm.strength", FT_UINT8, BASE_DEC, VALS(ccm_strengths)((0 ? (const struct _value_string*)0 : ((ccm_strengths)))), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11709 { &hf_ccm_dsp_e_flag,
11710 { "CCM Minimum Encrypt", "dof.ccm.encrypt.min", FT_BOOLEAN, 8, TFS(&tfs_encrypt_do_not_encrypt)((0 ? (const struct true_false_string*)0 : ((&tfs_encrypt_do_not_encrypt
))))
, 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11711 { &hf_ccm_dsp_m_flag,
11712 { "CCM Maximum Encrypt", "dof.ccm.encrypt.max", FT_BOOLEAN, 8, TFS(&tfs_encrypt_do_not_encrypt)((0 ? (const struct true_false_string*)0 : ((&tfs_encrypt_do_not_encrypt
))))
, 0x40, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11713 { &hf_ccm_dsp_tmax,
11714 { "CCM Maximum MAC", "dof.ccm.mac.max", FT_UINT8, BASE_DEC, NULL((void*)0), 0x38, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11715 { &hf_ccm_dsp_tmin,
11716 { "CCM Minimum MAC", "dof.ccm.mac.min", FT_UINT8, BASE_DEC, NULL((void*)0), 0x07, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11717 };
11718
11719 static hf_register_info hf[] =
11720 {
11721 { &hf_ccm_opcode,
11722 { "Opcode", "dof.ccm.opcode", FT_UINT8, BASE_DEC, VALS(ccm_opcode_strings)((0 ? (const struct _value_string*)0 : ((ccm_opcode_strings))
))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11723 };
11724
11725 static int *ett[] =
11726 {
11727 &ett_ccm_dsp_option,
11728 &ett_ccm_dsp,
11729 &ett_ccm,
11730 };
11731
11732 static hf_register_info hfheader[] =
11733 {
11734 { &hf_epp_v1_ccm_flags,
11735 { "Flags", "dof.epp.v1.ccm.flags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11736 { &hf_epp_v1_ccm_flags_manager,
11737 { "Manager", "dof.epp.v1.ccm.flags.manager", FT_UINT8, BASE_DEC, NULL((void*)0), 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11738 { &hf_epp_v1_ccm_flags_period,
11739 { "Period", "dof.epp.v1.ccm.flags.period", FT_UINT8, BASE_DEC, NULL((void*)0), 0x70, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11740 { &hf_epp_v1_ccm_flags_target,
11741 { "Target", "dof.epp.v1.ccm.flags.target", FT_UINT8, BASE_DEC, NULL((void*)0), 0x08, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11742 { &hf_epp_v1_ccm_flags_next_nid,
11743 { "Next Node Identifier", "dof.epp.v1.ccm.flags.next-nid", FT_UINT8, BASE_DEC, NULL((void*)0), 0x02, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11744 { &hf_epp_v1_ccm_flags_packet,
11745 { "Packet", "dof.epp.v1.ccm.flags.packet", FT_UINT8, BASE_DEC, NULL((void*)0), 0x01, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11746 { &hf_epp_v1_ccm_nid,
11747 { "Node ID", "dof.epp.v1.ccm.nodeid", FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11748 { &hf_epp_v1_ccm_slot,
11749 { "Slot", "dof.epp.v1.ccm.slot", FT_UINT16, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11750 { &hf_epp_v1_ccm_pn,
11751 { "Packet", "dof.epp.v1.ccm.packet", FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11752 { &hf_epp_v1_ccm_tnid,
11753 { "Target Node ID", "dof.epp.v1.ccm.target", FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11754 { &hf_epp_v1_ccm_nnid,
11755 { "Next Node ID", "dof.epp.v1.ccm.nnid", FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11756 };
11757
11758 static int *ettheader[] =
11759 {
11760 &ett_epp_v1_ccm_flags,
11761 &ett_header,
11762 };
11763
11764 static ei_register_info ei[] =
11765 {
11766 { &ei_decode_failure, { "dof.ccm.decode_failure", PI_UNDECODED0x05000000, PI_WARN0x00600000, "Failure to decrypt packet.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11767 };
11768
11769 /* No Configuration options to register? */
11770
11771 proto_ccm_app = proto_register_protocol("DOF CCM Security Mode App", "DOF.CCM.APP", "dof.ccm.app");
11772 proto_ccm = proto_register_protocol("DOF CCM Security Mode of Operation", "DOF.CCM", "dof.ccm");
11773 proto_ccm_dsp = proto_register_protocol("DOF CCM Security Mode DSP Options", "DOF.CCM.DSP", "dof.ccm.dsp");
11774
11775 proto_register_field_array(proto_ccm_app, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11776 proto_register_field_array(proto_ccm_dsp, hfdsp, array_length(hfdsp)(sizeof (hfdsp) / sizeof (hfdsp)[0]));
11777 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
11778
11779 proto_register_field_array(proto_ccm, hfheader, array_length(hfheader)(sizeof (hfheader) / sizeof (hfheader)[0]));
11780 proto_register_subtree_array(ettheader, array_length(ettheader)(sizeof (ettheader) / sizeof (ettheader)[0]));
11781
11782 expert_ccm = expert_register_protocol(proto_ccm);
11783 expert_register_field_array(expert_ccm, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
11784}
11785
11786/**
11787 * The registration hand-off routine
11788 */
11789static void dof_reg_handoff_ccm_24577(void)
11790{
11791 static dissector_handle_t ccm_app_handle;
11792 static dissector_handle_t dsp_handle;
11793 static dissector_handle_t ccm_handle;
11794
11795 ccm_app_handle = create_dissector_handle(dissect_ccm_app, proto_ccm_app);
11796 dsp_handle = create_dissector_handle(dissect_ccm_dsp, proto_ccm_dsp);
11797 ccm_handle = create_dissector_handle(dissect_ccm, proto_ccm);
11798
11799 dissector_add_uint("dof.app", DOF_PROTOCOL_CCM24577, ccm_app_handle);
11800 dissector_add_uint("dof.dsp.options", DSP_CCM_FAMILY0x020000 | DOF_PROTOCOL_CCM24577, dsp_handle);
11801 dissector_add_uint("dof.secmode", DOF_PROTOCOL_CCM24577, ccm_handle);
11802}
11803
11804static void dof_ccm_register(void)
11805{
11806 dof_register_ccm_24577();
11807}
11808
11809static void dof_ccm_handoff(void)
11810{
11811 dof_reg_handoff_ccm_24577();
11812}
11813
11814/* OAP Registration Support */
11815
11816static void dof_oap_reset(void)
11817{
11818 /* Keys and values are not owned by the table. Drop the previous table on each file load. */
11819 if (oap_1_alias_to_binding)
11820 g_hash_table_destroy(oap_1_alias_to_binding);
11821 oap_1_alias_to_binding = g_hash_table_new_full(oap_1_alias_hash_func, oap_1_alias_equal_func, NULL((void*)0), NULL((void*)0));
11822}
11823
11824static void dof_oap_cleanup(void)
11825{
11826 g_hash_table_destroy(oap_1_alias_to_binding);
11827 oap_1_alias_to_binding = NULL((void*)0);
11828}
11829
11830static void dof_register_oap_1(void)
11831{
11832 expert_module_t *expert_oap;
11833
11834 static hf_register_info hfdsp[] =
11835 {
11836 { &hf_oap_1_dsp_option,
11837 { "Object Access Protocol", "dof.oap.dsp_opt", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11838 };
11839
11840 static hf_register_info hf[] =
11841 {
11842 { &hf_oap_1_opcode,
11843 { "Opcode", "dof.oap.opcode", FT_UINT8, BASE_DEC, VALS(oap_opcode_strings)((0 ? (const struct _value_string*)0 : ((oap_opcode_strings))
))
, 0x1F, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11844
11845 { &hf_oap_1_alias_size,
11846 { "Alias Length", "dof.oap.aliaslen", FT_UINT8, BASE_DEC, NULL((void*)0), 0xC0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11847
11848 { &hf_oap_1_flags,
11849 { "Flags", "dof.oap.flags", FT_UINT8, BASE_DEC, NULL((void*)0), 0x20, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11850
11851 { &hf_oap_1_exception_internal_flag,
11852 { "Internal Exception", "dof.oap.exception.internal", FT_UINT8, BASE_DEC, NULL((void*)0), 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11853
11854 { &hf_oap_1_exception_final_flag,
11855 { "Final Exception", "dof.oap.exception.final", FT_UINT8, BASE_DEC, NULL((void*)0), 0x40, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11856
11857 { &hf_oap_1_exception_provider_flag,
11858 { "Exception Provider", "dof.oap.exception.provider", FT_UINT8, BASE_DEC, NULL((void*)0), 0x20, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11859
11860 { &hf_oap_1_cmdcontrol,
11861 { "Command Control", "dof.oap.cmdcontrol", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11862
11863 { &hf_oap_1_cmdcontrol_cache_flag,
11864 { "Cache Delay Flag", "dof.oap.cmdcontrol.flag.cache", FT_UINT8, BASE_HEX, NULL((void*)0), 0x40, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11865
11866 { &hf_oap_1_cmdcontrol_cache,
11867 { "Cache Delay", "dof.oap.cmdcontrol.cache", FT_UINT8, BASE_HEX, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11868
11869 { &hf_oap_1_cmdcontrol_verbosity_flag,
11870 { "Verbosity Flag", "dof.oap.cmdcontrol.flag.verbosity", FT_UINT8, BASE_HEX, NULL((void*)0), 0x30, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11871
11872 { &hf_oap_1_cmdcontrol_noexecute_flag,
11873 { "No Execute Flag", "dof.oap.cmdcontrol.flag.noexecute", FT_UINT8, BASE_HEX, NULL((void*)0), 0x08, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11874
11875 { &hf_oap_1_cmdcontrol_ack_flag,
11876 { "Ack List Flag", "dof.oap.cmdcontrol.flag.ack", FT_UINT8, BASE_HEX, NULL((void*)0), 0x04, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11877
11878 { &hf_oap_1_cmdcontrol_ackcnt,
11879 { "Ack List Count", "dof.oap.cmdcontrol.ackcnt", FT_UINT8, BASE_HEX, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11880
11881 { &hf_oap_1_cmdcontrol_ack,
11882 { "Ack", "dof.oap.cmdcontrol.ack", FT_BYTES, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11883
11884 { &hf_oap_1_cmdcontrol_delay_flag,
11885 { "Execution Delay Flag", "dof.oap.cmdcontrol.flag.delay", FT_UINT8, BASE_HEX, NULL((void*)0), 0x02, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11886
11887 { &hf_oap_1_cmdcontrol_heuristic_flag,
11888 { "Heuristic Flag", "dof.oap.cmdcontrol.flag.heuristic", FT_UINT8, BASE_HEX, NULL((void*)0), 0x01, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11889
11890 { &hf_oap_1_cmdcontrol_heuristic,
11891 { "Heuristic", "dof.oap.cmdcontrol.heuristic", FT_UINT8, BASE_HEX, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11892
11893 { &hf_oap_1_providerid,
11894 { "Provider ID", "dof.oap.provider-id", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11895
11896 { &hf_oap_1_objectid,
11897 { "Object ID", "dof.oap.object-id", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11898
11899 { &hf_oap_1_interfaceid,
11900 { "Interface ID", "dof.oap.interface-id", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11901
11902 { &hf_oap_1_itemid,
11903 { "Item ID", "dof.oap.item-id", FT_UINT16, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11904
11905#if 0 /* not used yet */
11906 { &hf_oap_1_distance,
11907 { "Distance", "dof.oap.distance", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11908#endif
11909
11910 { &hf_oap_1_alias,
11911 { "Alias", "dof.oap.alias", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11912
11913 { &hf_oap_1_alias_frame,
11914 { "Alias Frame", "dof.oap.alias-frame", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11915
11916#if 0 /* not used yet */
11917 { &hf_oap_1_opinfo_start_frame,
11918 { "Command Frame", "dof.oap.command-frame", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11919
11920 { &hf_oap_1_opinfo_end_frame,
11921 { "Response Frame", "dof.oap.response-frame", FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11922
11923 { &hf_oap_1_opinfo_timeout,
11924 { "Operation Timeout", "dof.oap.opid.timeout", FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11925#endif
11926
11927 { &hf_oap_1_subscription_delta,
11928 { "Minimum Delta", "dof.oap.subscription.min-delta", FT_UINT16, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11929
11930 { &hf_oap_1_update_sequence,
11931 { "Sequence", "dof.oap.sequence", FT_UINT16, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11932
11933 { &hf_oap_1_value_list,
11934 { "OAP Value List", "dof.oap.value_list", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
11935 };
11936
11937 static int *ett[] =
11938 {
11939 &ett_oap_1_dsp,
11940 &ett_oap_1_dsp_options,
11941 &ett_oap_1,
11942 &ett_oap_1_opinfo,
11943 &ett_oap_1_cmdcontrol,
11944 &ett_oap_1_cmdcontrol_flags,
11945 &ett_oap_1_cmdcontrol_ack,
11946 &ett_oap_1_alias,
11947 &ett_oap_1_objectid,
11948 &ett_oap_1_1_providerid,
11949 };
11950
11951 static ei_register_info ei[] =
11952 {
11953 { &ei_oap_no_session, { "dof.oap.no_session", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "Session not found", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
11954 };
11955
11956 proto_oap_1 = proto_register_protocol("DOF Object Access Protocol", "DOF.OAP", "dof.oap");
11957 proto_oap_1_dsp = proto_register_protocol("DOF Object Access Protocol DSP Options", "DOF.OAP.DSP", "dof.oap.dsp");
11958
11959 proto_register_field_array(proto_oap_1, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
11960 proto_register_field_array(proto_oap_1_dsp, hfdsp, array_length(hfdsp)(sizeof (hfdsp) / sizeof (hfdsp)[0]));
11961 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
11962
11963 expert_oap = expert_register_protocol(proto_oap_1);
11964 expert_register_field_array(expert_oap, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
11965}
11966
11967/**
11968 * The registration hand-off routine
11969 */
11970static void dof_reg_handoff_oap_1(void)
11971{
11972 dissector_handle_t oap_handle = create_dissector_handle(dissect_oap, proto_oap_1);
11973 dissector_handle_t dsp_handle = create_dissector_handle(dissect_oap_dsp, proto_oap_1_dsp);
11974
11975 dissector_add_uint("dof.app", DOF_PROTOCOL_OAP_11, oap_handle);
11976 dissector_add_uint("dof.dsp.options", DSP_OAP_FAMILY0x010000 | DOF_PROTOCOL_OAP_11, dsp_handle);
11977}
11978
11979static void dof_oap_register(void)
11980{
11981 dof_register_oap_1();
11982}
11983
11984static void dof_oap_handoff(void)
11985{
11986 dof_reg_handoff_oap_1();
11987}
11988
11989/* SGMP Registration Support */
11990
11991static void dof_register_sgmp_130(void);
11992static void dof_reg_handoff_sgmp_130(void);
11993
11994static void dof_sgmp_reset(void)
11995{
11996}
11997
11998static void dof_sgmp_cleanup(void)
11999{
12000}
12001
12002static void dof_register_sgmp_130(void)
12003{
12004 static hf_register_info hf[] =
12005 {
12006 { &hf_opcode,
12007 { "Opcode", "dof.sgmp.v1.opcode", FT_UINT8, BASE_DEC, VALS(sgmp_opcode_strings)((0 ? (const struct _value_string*)0 : ((sgmp_opcode_strings)
)))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12008
12009 { &hf_sgmp_domain,
12010 { "Domain", "dof.sgmp.v1.domain", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12011
12012 { &hf_sgmp_epoch,
12013 { "Epoch", "dof.sgmp.v1.epoch", FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12014
12015 { &hf_initiator_block,
12016 { "Initiator Block", "dof.sgmp.v1.initiator-block", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12017
12018 { &hf_sgmp_security_scope,
12019 { "Security Scope", "dof.sgmp.v1.security-scope", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12020
12021 { &hf_initial_state,
12022 { "Initial State", "dof.sgmp.v1.initial-state", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12023
12024 { &hf_latest_version,
12025 { "Latest SGMP Version", "dof.sgmp.v1.latest-sgmp-version", FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12026
12027 { &hf_desire,
12028 { "Desire", "dof.sgmp.v1.desire", FT_UINT8, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12029
12030 { &hf_ticket,
12031 { "Ticket", "dof.sgmp.v1.ticket", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12032
12033 { &hf_sgmp_tmin,
12034 { "TMIN", "dof.sgmp.v1.tmin", FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12035
12036 { &hf_tie_breaker,
12037 { "Tie Breaker", "dof.sgmp.v1.tie-breaker", FT_UINT32, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12038
12039 { &hf_delay,
12040 { "Delay", "dof.sgmp.v1.delay", FT_UINT8, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12041
12042 { &hf_key,
12043 { "Key", "dof.sgmp.v1.key", FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12044 };
12045
12046 static int *ett[] =
12047 {
12048 &ett_sgmp,
12049 &ett_sgmp_domain,
12050 &ett_initiator_block,
12051 &ett_sgmp_security_scope,
12052 &ett_initial_state,
12053 &ett_ticket,
12054 };
12055
12056 proto_sgmp = proto_register_protocol("DOF Secure Group Management Protocol", "DOF.SGMP", "dof.sgmp");
12057
12058 proto_register_field_array(proto_sgmp, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
12059 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
12060}
12061
12062/**
12063 * The registration hand-off routine
12064 */
12065static void dof_reg_handoff_sgmp_130(void)
12066{
12067 dissector_handle_t sgmp_handle = create_dissector_handle(dissect_sgmp, proto_sgmp);
12068
12069 dissector_add_uint("dof.app", DOF_PROTOCOL_SGMP130, sgmp_handle);
12070}
12071
12072static void dof_sgmp_register(void)
12073{
12074 dof_register_sgmp_130();
12075}
12076
12077static void dof_sgmp_handoff(void)
12078{
12079 dof_reg_handoff_sgmp_130();
12080}
12081
12082/* TEP Registration Support */
12083
12084static void dof_tep_reset(void)
12085{
12086}
12087
12088static void dof_tep_cleanup(void)
12089{
12090}
12091
12092static void dof_register_tep_128(void)
12093{
12094 static hf_register_info hfdsp[] =
12095 {
12096 { &hf_dsp_option,
12097 { "Ticket Exchange Protocol Version 1", "dof.tep1.dsp_opt", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12098 };
12099
12100 static hf_register_info hf[] =
12101 {
12102 { &hf_tep_operation,
12103 { "Operation", "dof.tep1.operation", FT_UINT8, BASE_DEC, VALS(tep_opcode_strings)((0 ? (const struct _value_string*)0 : ((tep_opcode_strings))
))
, 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12104
12105 { &hf_tep_operation_type,
12106 { "Operation Type", "dof.tep1.operation_type", FT_BOOLEAN, 8, TFS(&tep_optype_vals)((0 ? (const struct true_false_string*)0 : ((&tep_optype_vals
))))
, TEP_OPCODE_RSP(0x80), NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12107
12108 { &hf_tep_opcode,
12109 { "Opcode", "dof.tep1.opcode", FT_UINT8, BASE_DEC, VALS(tep_opcode_strings)((0 ? (const struct _value_string*)0 : ((tep_opcode_strings))
))
, 0x0F, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12110
12111 { &hf_tep_k,
12112 { "K", "dof.tep1.k", FT_UINT8, BASE_DEC, NULL((void*)0), 0x10, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12113
12114 { &hf_tep_c,
12115 { "C", "dof.tep1.c", FT_UINT8, BASE_DEC, NULL((void*)0), 0x20, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12116
12117 { &hf_tep_reject_code,
12118 { "Code", "dof.tep1.reject.code", FT_UINT8, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12119
12120 { &hf_tep_reject_data,
12121 { "Data", "dof.tep1.reject.data", FT_BYTES, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12122
12123 /* TEP.2.1 */
12124 { &hf_tep_2_1_domain,
12125 { "Domain", "dof.2008.4.tep1.2.1.domain", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12126
12127 { &hf_tep_2_1_initiator_block,
12128 { "Initiator Block", "dof.2008.4.tep1.2.1.initiator_block", FT_NONE, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12129
12130 { &hf_tep_2_1_ticket_confirmation,
12131 { "Ticket Confirmation", "dof.2008.4.tep1.2.1.ticket_confirmation", FT_BYTES, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12132
12133 /* TEP.2.2 */
12134 { &hf_tep_2_2_initiator_ticket,
12135 { "Initiator Ticket", "dof.2008.4.tep1.2.2.initiator_ticket", FT_NONE, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12136
12137 { &hf_tep_2_2_ticket_confirmation,
12138 { "Ticket Confirmation", "dof.2008.4.tep1.2.2.ticket_confirmation", FT_BYTES, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12139
12140 { &hf_tep_2_2_responder_initialization,
12141 { "Responder Initialization", "dof.2008.4.tep1.2.2.responder_initialization", FT_NONE, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12142
12143 { &hf_tep_2_2_responder_block,
12144 { "Responder Block", "dof.2008.4.tep1.2.2.responder_block", FT_NONE, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12145
12146 { &hf_tep_2_2_authenticator_initialization,
12147 { "Authenticator Initialization", "dof.2008.4.tep1.2.2.authenticator_initialization", FT_NONE, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12148
12149 /* TEP.2.2.1 */
12150 { &hf_tep_2_2_1_state_identifier,
12151 { "State Identifier", "dof.2008.4.tep1.2.2.1.state_identifier", FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12152
12153 { &hf_tep_2_2_1_initial_state,
12154 { "Initial State", "dof.2008.4.tep1.2.2.1.initial_state", FT_NONE, BASE_NONE, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12155
12156 { &hf_tep_session_key,
12157 { "Session Key", "dof.session_key", FT_BYTES, SEP_COLON, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12158 };
12159
12160 static int *ett[] =
12161 {
12162 &ett_tep_dsp,
12163 &ett_tep_dsp_options,
12164 &ett_tep,
12165 &ett_tep_operation,
12166
12167 &ett_tep_2_1_domain,
12168 &ett_tep_2_1_initiator_block,
12169
12170 &ett_tep_2_2_initiator_ticket,
12171 &ett_tep_2_2_responder_initialization,
12172 &ett_tep_2_2_responder_block,
12173 &ett_tep_2_2_authenticator_initialization,
12174
12175 &ett_tep_2_2_1_initial_state,
12176 };
12177
12178 /* module_t *tep_module;*/
12179
12180 /* No Configuration options to register? */
12181
12182 proto_tep = proto_register_protocol("DOF Ticket Exchange Protocol Version 1", "DOF.TEP1", "dof.tep1");
12183
12184 proto_tep_dsp = proto_register_protocol("DOF Ticket Exchange Protocol DSP Options", "DOF.TEP1.DSP", "dof.tep1.dsp");
12185
12186 proto_register_field_array(proto_tep, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
12187 proto_register_field_array(proto_tep_dsp, hfdsp, array_length(hfdsp)(sizeof (hfdsp) / sizeof (hfdsp)[0]));
12188 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
12189
12190 /* tep_module = prefs_register_protocol( proto_tep, NULL );*/
12191}
12192
12193/**
12194 * The registration hand-off routine
12195 */
12196static void dof_reg_handoff_tep_128(void)
12197{
12198 dissector_handle_t tep_handle = create_dissector_handle(dissect_tep, proto_tep);
12199 dissector_handle_t dsp_handle = create_dissector_handle(dissect_tep_dsp, proto_tep_dsp);
12200
12201 dissector_add_uint("dof.app", DOF_PROTOCOL_TEP128, tep_handle);
12202 dissector_add_uint("dof.dsp.options", DSP_TEP_FAMILY0x000000 | DOF_PROTOCOL_TEP128, dsp_handle);
12203}
12204
12205static void dof_tep_register(void)
12206{
12207 dof_register_tep_128();
12208}
12209
12210static void dof_tep_handoff(void)
12211{
12212 dof_reg_handoff_tep_128();
12213}
12214
12215/* TRP Registration Support */
12216
12217static void dof_trp_reset(void)
12218{
12219}
12220
12221static void dof_trp_cleanup(void)
12222{
12223}
12224
12225static void dof_register_trp_129(void)
12226{
12227 expert_module_t *expert_trp;
12228
12229 static hf_register_info hfdsp[] =
12230 {
12231 { &hf_trp_dsp_option,
12232 { "Ticket Request Protocol", "dof.trp.dsp_opt", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12233 };
12234
12235 static hf_register_info hf[] =
12236 {
12237 { &hf_trp_opcode,
12238 { "Opcode", "dof.trp.opcode", FT_UINT8, BASE_DEC, VALS(trp_opcode_strings)((0 ? (const struct _value_string*)0 : ((trp_opcode_strings))
))
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12239
12240 { &hf_domain,
12241 { "Domain", "dof.trp.domain", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12242
12243 { &hf_identity_resolution,
12244 { "Identity Resolution", "dof.trp.identity_resolution", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12245
12246 { &hf_initiator_request,
12247 { "Initiator Request", "dof.trp.initiator_request", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12248
12249 { &hf_responder_request,
12250 { "Responder Request", "dof.trp.responder_request", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12251
12252 { &hf_initiator_ticket,
12253 { "Initiator Ticket", "dof.trp.initiator_ticket", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12254
12255 { &hf_responder_ticket,
12256 { "Responder Ticket", "dof.trp.responder_ticket", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12257
12258 { &hf_authentication_block,
12259 { "Authentication Block", "dof.trp.authentication_block", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12260
12261 { &hf_group_identifier,
12262 { "Group Identifier", "dof.trp.group_identifier", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12263
12264 { &hf_node_identifier,
12265 { "Node Identifier", "dof.trp.node_identifier", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12266
12267 { &hf_thb,
12268 { "Thb", "dof.trp.thb", FT_UINT8, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12269
12270 { &hf_tmin,
12271 { "Tmin", "dof.trp.tmin", FT_UINT8, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12272
12273 { &hf_tmax,
12274 { "Tmax", "dof.trp.tmax", FT_UINT8, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12275
12276 { &hf_trp_epoch,
12277 { "Epoch", "dof.trp.epoch", FT_UINT16, BASE_DEC, NULL((void*)0), 0x00, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12278
12279 { &hf_sidg,
12280 { "SIDg", "dof.trp.sid_g", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12281
12282 { &hf_security_scope,
12283 { "Security Scope", "dof.trp.security_scope", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12284
12285 { &hf_security_mode,
12286 { "Security Mode", "dof.trp.security_mode", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12287
12288 { &hf_ssid,
12289 { "SSID", "dof.trp.ssid", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12290
12291#if 0 /* not used yet */
12292 { &hf_initiator_pg,
12293 { "Initiator Permissions", "dof.trp.initiator_pg", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12294#endif
12295
12296 { &hf_initiator_validation,
12297 { "Initiator Validation", "dof.trp.initiator_validation", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12298
12299 { &hf_responder_pg,
12300 { "Responder Permissions", "dof.trp.responder_pg", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12301
12302 { &hf_responder_validation,
12303 { "Responder Validation", "dof.trp.responder_validation", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12304
12305 { &hf_trp_errorcode,
12306 { "Error Code", "dof.trp.errorcode", FT_UINT8, BASE_DEC, VALS(trp_error_strings)((0 ? (const struct _value_string*)0 : ((trp_error_strings)))
)
, 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12307
12308 { &hf_trp_duration,
12309 { "Duration", "dof.trp.duration", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12310
12311#if 0 /* not used yet */
12312 { &hf_trp_rnonce,
12313 { "Requestor Nonce", "dof.trp.rnonce", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12314
12315 { &hf_trp_pnonce,
12316 { "Provider Nonce", "dof.trp.pnonce", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12317
12318 { &hf_trp_reqid,
12319 { "Requestor ID", "dof.trp.reqid", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12320
12321 { &hf_trp_provid,
12322 { "Provider ID", "dof.trp.provid", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12323
12324 { &hf_trp_perm_count,
12325 { "Permission Count", "dof.trp.perm.count", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12326
12327 { &hf_trp_perm_type,
12328 { "Permission Type", "dof.trp.perm.type", FT_UINT16, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12329
12330 { &hf_trp_perm_rflags,
12331 { "Requestor SRP Flags", "dof.trp.rflags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12332
12333 { &hf_trp_perm_rcache,
12334 { "Requestor SRP Cache", "dof.trp.rcache", FT_BOOLEAN, 8, NULL((void*)0), 0x2, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12335
12336 { &hf_trp_perm_rsrp,
12337 { "Requestor SRP", "dof.trp.rsrp", FT_BOOLEAN, 8, NULL((void*)0), 0x1, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12338
12339 { &hf_trp_perm_rsrp_a,
12340 { "Requestor SRP A", "dof.trp.rsrp.a", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12341
12342 { &hf_trp_perm_rsrp_u,
12343 { "Requestor SRP u", "dof.trp.rsrp.u", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12344
12345 { &hf_trp_perm_pflags,
12346 { "Provider SRP Flags", "dof.trp.pflags", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12347
12348 { &hf_trp_perm_pcache,
12349 { "Provider SRP Cache", "dof.trp.pcache", FT_BOOLEAN, 8, NULL((void*)0), 0x2, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12350
12351 { &hf_trp_perm_psrp,
12352 { "Provider SRP", "dof.trp.psrp", FT_BOOLEAN, 8, NULL((void*)0), 0x1, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12353
12354 { &hf_trp_perm_psrp_a,
12355 { "Provider SRP A", "dof.trp.psrp.a", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12356
12357 { &hf_trp_perm_psrp_u,
12358 { "Provider SRP u", "dof.trp.psrp.u", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12359
12360 { &hf_trp_perm_psrp_b,
12361 { "Provider SRP B", "dof.trp.psrp.b", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12362
12363 { &hf_trp_perm_psrp_s,
12364 { "Provider SRP S", "dof.trp.psrp.s", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12365
12366 { &hf_trp_confirmation,
12367 { "Confirmation", "dof.trp.confirmation", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12368
12369 { &hf_trp_perm_pke,
12370 { "Provider Key Expression", "dof.trp.pke", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12371
12372 { &hf_trp_perm_pka,
12373 { "Provider Key Authenticator", "dof.trp.pka", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
12374#endif
12375 };
12376
12377 static int *ett[] =
12378 {
12379 &ett_trp_dsp,
12380 &ett_trp,
12381 &ett_domain,
12382 &ett_identity_resolution,
12383 &ett_initiator_request,
12384 &ett_initiator_ticket,
12385 &ett_responder_request,
12386 &ett_responder_ticket,
12387 &ett_authentication_block,
12388 &ett_group_identifier,
12389 &ett_node_identifier,
12390 &ett_sidg,
12391 &ett_security_scope,
12392 &ett_security_mode,
12393 &ett_initiator_pg,
12394 &ett_initiator_validation,
12395 &ett_responder_pg,
12396 &ett_responder_validation,
12397 &ett_trp_permset,
12398 &ett_srp_flags,
12399 &ett_trp_ticket,
12400 };
12401
12402 static ei_register_info ei[] =
12403 {
12404 { &ei_trp_initiator_id_known, { "dof.trp.initiator_id_known", PI_PROTOCOL0x09000000, PI_COMMENT0x00100000, "Initiator identity known", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
12405 { &ei_trp_kek_discovered, { "dof.trp.kek_discovered", PI_PROTOCOL0x09000000, PI_COMMENT0x00100000, "KEK discovered", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
} },
12406 };
12407
12408 /* No Configuration options to register? */
12409
12410 proto_trp = proto_register_protocol("DOF Ticket Request Protocol", "DOF.TRP", "dof.trp");
12411
12412 proto_trp_dsp = proto_register_protocol("DOF Ticket Request Protocol DSP Options", "DOF.TRP.DSP", "dof.trp.dsp");
12413
12414 proto_register_field_array(proto_trp, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
12415 proto_register_field_array(proto_trp_dsp, hfdsp, array_length(hfdsp)(sizeof (hfdsp) / sizeof (hfdsp)[0]));
12416 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
12417 expert_trp = expert_register_protocol(proto_trp);
12418 expert_register_field_array(expert_trp, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
12419}
12420
12421/**
12422 * The registration hand-off routine
12423 */
12424static void dof_reg_handoff_trp_129(void)
12425{
12426 dissector_handle_t trp_handle = create_dissector_handle(dissect_trp, proto_trp);
12427 dissector_handle_t dsp_handle = create_dissector_handle(dissect_trp_dsp, proto_trp_dsp);
12428
12429 dissector_add_uint("dof.app", DOF_PROTOCOL_TRP129, trp_handle);
12430 dissector_add_uint("dof.dsp.options", DSP_TRP_FAMILY0x030000 | DOF_PROTOCOL_TRP129, dsp_handle);
12431}
12432
12433static void dof_trp_register(void)
12434{
12435 dof_register_trp_129();
12436}
12437
12438static void dof_trp_handoff(void)
12439{
12440 dof_reg_handoff_trp_129();
12441}
12442
12443/* Wireshark Dissector Registration Proper */
12444
12445/**
12446 * This is called only during reset (file load, reload, etc.).
12447 */
12448static void dof_reset_routine(void)
12449{
12450 dof_tun_reset();
12451 dof_reset();
12452 oid_reset();
12453 dof_dnp_reset();
12454 dof_dpp_reset();
12455 app_reset();
12456 dof_dsp_reset();
12457 dof_ccm_reset();
12458 dof_oap_reset();
12459 dof_sgmp_reset();
12460 dof_tep_reset();
12461 dof_trp_reset();
12462}
12463
12464static void dof_cleanup_routine(void)
12465{
12466 dof_tun_cleanup();
12467 dof_cleanup();
12468 oid_cleanup();
12469 dof_dnp_cleanup();
12470 dof_dpp_cleanup();
12471 app_cleanup();
12472 dof_dsp_cleanup();
12473 dof_ccm_cleanup();
12474 dof_oap_cleanup();
12475 dof_sgmp_cleanup();
12476 dof_tep_cleanup();
12477 dof_trp_cleanup();
12478}
12479
12480static void
12481dof_shutdown_routine(void)
12482{
12483 unsigned i;
12484
12485 for (i = 0; i < global_security.identity_data_count; i++) {
12486 g_free(global_security.identity_data[i].identity)(__builtin_object_size ((global_security.identity_data[i].identity
), 0) != ((size_t) - 1)) ? g_free_sized (global_security.identity_data
[i].identity, __builtin_object_size ((global_security.identity_data
[i].identity), 0)) : (g_free) (global_security.identity_data[
i].identity)
;
12487 g_free(global_security.identity_data[i].domain)(__builtin_object_size ((global_security.identity_data[i].domain
), 0) != ((size_t) - 1)) ? g_free_sized (global_security.identity_data
[i].domain, __builtin_object_size ((global_security.identity_data
[i].domain), 0)) : (g_free) (global_security.identity_data[i]
.domain)
;
12488 g_free(global_security.identity_data[i].secret)(__builtin_object_size ((global_security.identity_data[i].secret
), 0) != ((size_t) - 1)) ? g_free_sized (global_security.identity_data
[i].secret, __builtin_object_size ((global_security.identity_data
[i].secret), 0)) : (g_free) (global_security.identity_data[i]
.secret)
;
12489 }
12490 g_free(global_security.identity_data)(__builtin_object_size ((global_security.identity_data), 0) !=
((size_t) - 1)) ? g_free_sized (global_security.identity_data
, __builtin_object_size ((global_security.identity_data), 0))
: (g_free) (global_security.identity_data)
;
12491
12492 for (i = 0; i < global_security.group_data_count; i++) {
12493 g_free(global_security.group_data[i].domain)(__builtin_object_size ((global_security.group_data[i].domain
), 0) != ((size_t) - 1)) ? g_free_sized (global_security.group_data
[i].domain, __builtin_object_size ((global_security.group_data
[i].domain), 0)) : (g_free) (global_security.group_data[i].domain
)
;
12494 g_free(global_security.group_data[i].identity)(__builtin_object_size ((global_security.group_data[i].identity
), 0) != ((size_t) - 1)) ? g_free_sized (global_security.group_data
[i].identity, __builtin_object_size ((global_security.group_data
[i].identity), 0)) : (g_free) (global_security.group_data[i].
identity)
;
12495 g_free(global_security.group_data[i].kek)(__builtin_object_size ((global_security.group_data[i].kek), 0
) != ((size_t) - 1)) ? g_free_sized (global_security.group_data
[i].kek, __builtin_object_size ((global_security.group_data[i
].kek), 0)) : (g_free) (global_security.group_data[i].kek)
;
12496 }
12497
12498 if (addr_port_to_id)
12499 g_hash_table_destroy(addr_port_to_id);
12500 if (dpp_opid_to_packet_data)
12501 g_hash_table_destroy(dpp_opid_to_packet_data);
12502 if (node_key_to_sid_id)
12503 g_hash_table_destroy(node_key_to_sid_id);
12504 if (sid_buffer_to_sid_id)
12505 g_hash_table_destroy(sid_buffer_to_sid_id);
12506 if (sid_id_to_sid_buffer)
12507 g_hash_table_destroy(sid_id_to_sid_buffer);
12508 if (sid_id_to_packets)
12509 {
12510 g_hash_table_destroy(sid_id_to_packets);
12511 sid_id_to_packets = NULL((void*)0);
12512 }
12513}
12514
12515/**
12516 * This is the first entry point into the dissector, called on program launch.
12517 */
12518void proto_register_dof(void)
12519{
12520 dof_tun_register();
12521 dof_register();
12522 oid_register();
12523 dof_dnp_register();
12524 dof_dpp_register();
12525 app_register();
12526 dof_dsp_register();
12527 dof_ccm_register();
12528 dof_oap_register();
12529 dof_sgmp_register();
12530 dof_tep_register();
12531 dof_trp_register();
12532
12533 register_init_routine(&dof_reset_routine);
12534 register_cleanup_routine(&dof_cleanup_routine);
12535 register_shutdown_routine(&dof_shutdown_routine);
12536}
12537
12538/**
12539 * This routine is called after initialization and whenever the preferences are changed.
12540 */
12541void proto_reg_handoff_dof(void)
12542{
12543 dof_tun_handoff();
12544 dof_handoff();
12545 oid_handoff();
12546 dof_dnp_handoff();
12547 dof_dpp_handoff();
12548 app_handoff();
12549 dof_dsp_handoff();
12550 dof_ccm_handoff();
12551 dof_oap_handoff();
12552 dof_sgmp_handoff();
12553 dof_tep_handoff();
12554 dof_trp_handoff();
12555}
12556
12557/**
12558 * Protocol-specific data attached to a conversation_t structure - protocol
12559 * index and opaque pointer.
12560 */
12561typedef struct _dof_proto_data {
12562 int proto;
12563 void *proto_data;
12564} dof_proto_data;
12565
12566static int p_compare(const void *a, const void *b)
12567{
12568 const dof_proto_data *ap = (const dof_proto_data *)a;
12569 const dof_proto_data *bp = (const dof_proto_data *)b;
12570
12571 if (ap->proto > bp->proto)
12572 return 1;
12573 else if (ap->proto == bp->proto)
12574 return 0;
12575 else
12576 return -1;
12577}
12578
12579#if 0 /* TODO not used yet */
12580static void dof_session_add_proto_data(wmem_allocator_t* allocator, dof_session_data *session, int proto, void *proto_data)
12581{
12582 dof_proto_data *p1 = wmem_new0(allocator, dof_proto_data)((dof_proto_data*)wmem_alloc0((allocator), sizeof(dof_proto_data
)))
;
12583
12584 p1->proto = proto;
12585 p1->proto_data = proto_data;
12586
12587 /* Add it to the list of items for this conversation. */
12588
12589 session->data_list = g_slist_insert_sorted(session->data_list, (void * *)p1, p_compare);
12590}
12591
12592static void *dof_session_get_proto_data(dof_session_data *session, int proto)
12593{
12594 dof_proto_data temp, *p1;
12595 GSList *item;
12596
12597 temp.proto = proto;
12598 temp.proto_data = NULL((void*)0);
12599
12600 item = g_slist_find_custom(session->data_list, (void * *)&temp,
12601 p_compare);
12602
12603 if (item != NULL((void*)0))
12604 {
12605 p1 = (dof_proto_data *)item->data;
12606 return p1->proto_data;
12607 }
12608
12609 return NULL((void*)0);
12610}
12611
12612static void dof_session_delete_proto_data(dof_session_data *session, int proto)
12613{
12614 dof_proto_data temp;
12615 GSList *item;
12616
12617 temp.proto = proto;
12618 temp.proto_data = NULL((void*)0);
12619
12620 item = g_slist_find_custom(session->data_list, (void * *)&temp,
12621 p_compare);
12622
12623 while (item)
12624 {
12625 session->data_list = g_slist_remove(session->data_list, item->data);
12626 item = item->next;
12627 }
12628}
12629#endif
12630
12631static void dof_packet_add_proto_data(dof_packet_data *packet, int proto, void *proto_data)
12632{
12633 dof_proto_data *p1 = wmem_new0(wmem_file_scope(), dof_proto_data)((dof_proto_data*)wmem_alloc0((wmem_file_scope()), sizeof(dof_proto_data
)))
;
12634
12635 p1->proto = proto;
12636 p1->proto_data = proto_data;
12637
12638 /* Add it to the list of items for this conversation. */
12639
12640 wmem_list_insert_sorted(packet->data_list, (void * *)p1, p_compare);
12641}
12642
12643static void *dof_packet_get_proto_data(dof_packet_data *packet, int proto)
12644{
12645 dof_proto_data temp, *p1;
12646 wmem_list_frame_t *item;
12647
12648 temp.proto = proto;
12649 temp.proto_data = NULL((void*)0);
12650
12651 item = wmem_list_find_custom(packet->data_list, (void * *)&temp,
12652 p_compare);
12653
12654 if (item != NULL((void*)0))
12655 {
12656 p1 = (dof_proto_data *)wmem_list_frame_data(item);
12657 return p1->proto_data;
12658 }
12659
12660 return NULL((void*)0);
12661}
12662
12663static 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)
12664{
12665 int block_length;
12666 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
12667 proto_tree *my_tree;
12668 proto_item *ti = proto_tree_add_item(tree, item, tvb, offset, -1, ENC_NA0x00000000);
12669 my_tree = proto_item_add_subtree(ti, ett);
12670 block_length = dof_dissect_pdu(dissector, start, pinfo, my_tree, result);
12671 return offset + block_length;
12672}
12673
12674static int dof_dissect_pdu(dissector_t dissector, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *result)
12675{
12676 int len = dissector(tvb, pinfo, tree, result);
12677 proto_item_set_len(proto_tree_get_parent(tree), len);
12678
12679 return len;
12680}
12681
12682static int dof_dissect_dnp_length(tvbuff_t *tvb, packet_info *pinfo, uint8_t version, unsigned *offset)
12683{
12684 dissector_handle_t dp;
12685
12686 dp = dissector_get_uint_handle(dnp_framing_dissectors, version);
12687 if (!dp)
12688 return -1;
12689
12690 return call_dissector_only(dp, tvb, pinfo, NULL((void*)0), offset);
12691}
12692
12693/*
12694 * Editor modelines - https://www.wireshark.org/tools/modelines.html
12695 *
12696 * Local variables:
12697 * c-basic-offset: 4
12698 * tab-width: 8
12699 * indent-tabs-mode: nil
12700 * End:
12701 *
12702 * vi: set shiftwidth=4 tabstop=8 expandtab:
12703 * :indentSize=4:tabSize=8:noTabs=true:
12704 */