Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-dof.c
Line
Count
Source
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
 */
218
typedef 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
 */
227
typedef 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
 */
240
typedef 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 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 is_streaming;  /* Inverse is 'is_datagram'. */
280
281
    /**
282
     * Cardinality of transport session.
283
     */
284
    bool is_2_node; /* Inverse is 'is_n_node'. */
285
} dof_transport_session;
286
287
typedef struct _dof_transport_packet
288
{
289
    /**
290
     * Source of packet (if known, default is server).
291
     */
292
    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
 */
309
typedef 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
 */
355
typedef 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
 */
363
typedef struct _dof_group_data
364
{
365
    uint8_t *domain;
366
    uint8_t domain_length;
367
    uint8_t *identity;
368
    uint8_t identity_length;
369
    uint8_t *kek;
370
} dof_group_data;
371
372
/**
373
 * This structure contains security keys for non-group identities.
374
 */
375
typedef struct _dof_identity_data
376
{
377
    uint8_t *domain;
378
    uint8_t domain_length;
379
    uint8_t *identity;
380
    uint8_t identity_length;
381
    uint8_t *secret;
382
} dof_identity_data;
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
 */
391
typedef 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
 */
413
struct _dof_learned_group_data;
414
typedef 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
 */
428
typedef struct _dof_learned_group_data
429
{
430
    uint8_t domain_length;
431
    uint8_t *domain;
432
    uint8_t 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
 */
453
struct _dof_session_data;
454
typedef 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
    uint8_t 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 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
 */
505
typedef 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
535
typedef struct _dof_2008_16_security_3_1
536
{
537
    tvbuff_t *identity;
538
} dof_2008_16_security_3_1;
539
540
typedef struct _dof_2008_16_security_4
541
{
542
    tvbuff_t *identity;
543
    tvbuff_t *nonce;
544
} dof_2008_16_security_4;
545
546
typedef 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
555
typedef 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
 */
566
typedef struct _ws_node
567
{
568
    address addr;
569
    uint32_t port;
570
} ws_node;
571
572
typedef 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
 */
589
typedef 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 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 is_command;    /* Inverse is 'is_response'. */
638
    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 has_opid;
658
    dof_2009_1_pdu_20_opid op;
659
    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
 */
692
typedef 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 decrypt_all_packets;
701
    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
 */
710
typedef 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
 */
746
typedef enum _dof_secmode_context
747
{
748
    INITIALIZE,
749
    HEADER,
750
    TRAILER
751
} dof_secmode_context;
752
753
/* Seasonal, initialized to zero. */
754
typedef 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. */
792
void proto_register_dof(void);
793
void proto_reg_handoff_dof(void);
794
795
/* Dissector routines. */
796
static int dissect_2008_1_dsp_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
797
static int dissect_2008_16_security_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
798
static int dissect_2008_16_security_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
799
static int dissect_2008_16_security_3_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
800
static int dissect_2008_16_security_3_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
801
static int dissect_2008_16_security_4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
802
static int dissect_2008_16_security_5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
803
static int dissect_2008_16_security_6_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
804
static int dissect_2008_16_security_6_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
805
static int dissect_2008_16_security_6_3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
806
static int dissect_2008_16_security_7(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
807
static int dissect_2008_16_security_8(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
808
static int dissect_2008_16_security_9(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
809
static int dissect_2008_16_security_10(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
810
static int dissect_2008_16_security_11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
811
static int dissect_2008_16_security_12(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
812
static int dissect_2008_16_security_13(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
813
static int dissect_2009_11_type_4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
814
static int dissect_2009_11_type_5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
815
816
static const char* dof_oid_create_standard_string(wmem_allocator_t* allocator, uint32_t bufferSize, const uint8_t *pOIDBuffer, packet_info *pinfo);
817
static const char* dof_iid_create_standard_string(wmem_allocator_t* allocator, uint32_t bufferSize, const uint8_t *pIIDBuffer);
818
static uint8_t dof_oid_create_internal(const char *oid, uint32_t *size, uint8_t *buffer);
819
static void dof_oid_new_standard_string(const char *data, uint32_t *rsize, uint8_t **oid);
820
static int read_c4(tvbuff_t *tvb, int offset, uint32_t *v, int *len);
821
static void validate_c4(packet_info *pinfo, proto_item *pi, uint32_t, int len);
822
static int read_c3(tvbuff_t *tvb, int offset, uint32_t *v, int *len);
823
static void validate_c3(packet_info *pinfo, proto_item *pi, uint32_t, int len);
824
static int read_c2(tvbuff_t *tvb, int offset, uint16_t *v, int *len);
825
static void validate_c2(packet_info *pinfo, proto_item *pi, uint16_t, int len);
826
827
static int dof_dissect_pdu(dissector_t dissector, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *result);
828
static int dof_dissect_pdu_as_field(dissector_t dissector, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, int item, int ett, void *result);
829
830
#if 0 /* TODO not used yet */
831
static void dof_session_add_proto_data(dof_session_data *session, int proto, void *proto_data);
832
static void* dof_session_get_proto_data(dof_session_data *session, int proto);
833
static void dof_session_delete_proto_data(dof_session_data *session, int proto);
834
#endif
835
836
static void dof_packet_add_proto_data(dof_packet_data *packet, int proto, void *proto_data);
837
static void* dof_packet_get_proto_data(dof_packet_data *packet, int proto);
838
839
/* DOF PROTOCOL STACK */
840
417
#define 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
15
#define DOF_NEG_SEC_UDP_PORT_RANGE  "3567,5567" /* P2P + Multicast */
858
15
#define DOF_P2P_NEG_SEC_TCP_PORT    3567
859
/* Reserved UDP port                3568*/
860
#define DOF_TUN_SEC_TCP_PORT        3568
861
#define DOF_P2P_SEC_TCP_PORT        5567
862
/* Reserved UDP port                8567*/
863
15
#define DOF_TUN_NON_SEC_TCP_PORT    8567
864
865
/* This is needed to register multicast sessions with the UDP handler. */
866
static dissector_handle_t dof_udp_handle;
867
868
static int proto_2008_1_dof;
869
static int proto_2008_1_dof_tcp;
870
static int proto_2008_1_dof_udp;
871
872
static int hf_2008_1_dof_session;
873
static int hf_2008_1_dof_is_2_node;
874
static int hf_2008_1_dof_is_streaming;
875
static int hf_2008_1_dof_is_from_client;
876
static int hf_2008_1_dof_frame;
877
static int hf_2008_1_dof_session_transport;
878
879
static int ett_2008_1_dof;
880
881
/* DOF Tunnel Protocol */
882
883
/* UDP Registrations */
884
30
#define TUNNEL_PROTOCOL_STACK "DOF Tunnel Protocol Stack"
885
15
#define TUNNEL_APPLICATION_PROTOCOL "DOF Tunnel Protocol"
886
887
static dissector_table_t dof_tun_app_dissectors;
888
889
/***** TUNNEL *****/
890
static int proto_2012_1_tunnel;
891
892
static int ett_2012_1_tunnel;
893
894
static int hf_2012_1_tunnel_1_version;
895
static int hf_2012_1_tunnel_1_length;
896
897
/* DOF NETWORK PROTOCOL */
898
1
#define DNP_MAX_VERSION 1
899
417
#define DOF_NETWORK_PROTOCOL "DOF Network Protocol"
900
901
static dissector_table_t dnp_dissectors;
902
static dissector_table_t dnp_framing_dissectors;
903
904
static int proto_2008_1_dnp;
905
906
static int hf_2008_1_dnp_1_version;
907
static int hf_2008_1_dnp_1_flag;
908
909
static int ett_2008_1_dnp;
910
static int ett_2008_1_dnp_header;
911
912
/* DNP V0 */
913
static int proto_2008_1_dnp_0;
914
915
static int hf_2008_1_dnp_0_1_1_padding;
916
static int hf_2008_1_dnp_0_1_1_version;
917
918
/* DNP V1 */
919
341
#define DNP_V1_DEFAULT_FLAGS    (0)
920
static int proto_2009_9_dnp_1;
921
922
static int hf_2009_9_dnp_1_flags;
923
static int hf_2009_9_dnp_1_flag_length;
924
static int hf_2009_9_dnp_1_length;
925
static int hf_2009_9_dnp_1_flag_srcport;
926
static int hf_2009_9_dnp_1_srcport;
927
static int hf_2009_9_dnp_1_flag_dstport;
928
static int hf_2009_9_dnp_1_dstport;
929
930
static int ett_2009_9_dnp_1_flags;
931
932
static int * const bitmask_2009_9_dnp_1_flags[] = {
933
    &hf_2009_9_dnp_1_flag_length,
934
    &hf_2009_9_dnp_1_flag_srcport,
935
    &hf_2009_9_dnp_1_flag_dstport,
936
    NULL
937
};
938
939
/* DOF PRESENTATION PROTOCOL */
940
415
#define DOF_PRESENTATION_PROTOCOL "DOF Presentation Protocol"
941
942
static dissector_table_t dof_dpp_dissectors;
943
944
static int proto_2008_1_dpp;
945
946
static int hf_2008_1_dpp_sid_num;
947
static int hf_2008_1_dpp_rid_num;
948
static int hf_2008_1_dpp_sid_str;
949
static int hf_2008_1_dpp_rid_str;
950
static int hf_2008_1_dpp_first_command;
951
static int hf_2008_1_dpp_last_command;
952
static int hf_2008_1_dpp_first_response;
953
static int hf_2008_1_dpp_last_response;
954
static int hf_2008_1_dpp_related_frame;
955
static int hf_2008_1_dpp_1_version;
956
static int hf_2008_1_dpp_1_flag;
957
958
static int ett_2008_1_dpp;
959
static int ett_2008_1_dpp_1_header;
960
961
/* DPP V0 */
962
static int proto_2008_1_dpp_0;
963
964
static int hf_2008_1_dpp_0_1_1_version;
965
966
/* DPP V1 - RESERVED, NOT SUPPORTED */
967
968
/* DPP V2 */
969
340
#define DPP_V2_DEFAULT_FLAGS    (0)
970
30
#define DPP_V2_SEC_FLAG_E (0x80)
971
30
#define DPP_V2_SEC_FLAG_D (0x08)
972
30
#define DPP_V2_SEC_FLAG_P (0x04)
973
30
#define DPP_V2_SEC_FLAG_A (0x02)
974
30
#define DPP_V2_SEC_FLAG_S (0x01)
975
976
static int proto_2009_12_dpp;
977
static int proto_2009_12_dpp_common;
978
979
/* TODO: The complete on final and final flags are not covered. */
980
static int hf_2009_12_dpp_2_1_flags;
981
static int hf_2009_12_dpp_2_1_flag_security;
982
static int hf_2009_12_dpp_2_1_flag_opid;
983
static int hf_2009_12_dpp_2_1_flag_seq;
984
static int hf_2009_12_dpp_2_1_flag_retry;
985
static int hf_2009_12_dpp_2_1_flag_cmdrsp;
986
static int hf_2009_12_dpp_2_3_sec_flags;
987
static int hf_2009_12_dpp_2_3_sec_flag_secure;
988
static int hf_2009_12_dpp_2_3_sec_flag_rdid;
989
static int hf_2009_12_dpp_2_3_sec_flag_partition;
990
static int hf_2009_12_dpp_2_3_sec_flag_ssid;
991
static int hf_2009_12_dpp_2_3_sec_flag_as;
992
static int hf_2009_12_dpp_2_3_sec_ssid;
993
static int hf_2009_12_dpp_2_3_sec_rdid;
994
static int hf_2009_12_dpp_2_3_sec_remote_partition;
995
static int hf_2009_12_dpp_2_3_sec_partition;
996
static int hf_2009_12_dpp_2_1_opcnt;
997
static int hf_2009_12_dpp_2_1_seq;
998
static int hf_2009_12_dpp_2_1_retry;
999
static int hf_2009_12_dpp_2_1_delay;
1000
static int hf_2009_12_dpp_2_14_opcode;
1001
1002
static int ett_2009_12_dpp_2_1_flags;
1003
static int ett_2009_12_dpp_2_3_security;
1004
static int ett_2009_12_dpp_2_3_sec_flags;
1005
static int ett_2009_12_dpp_2_3_sec_remote_partition;
1006
static int ett_2009_12_dpp_2_3_sec_partition;
1007
static int ett_2009_12_dpp_2_opid;
1008
static int ett_2009_12_dpp_2_opid_history;
1009
1010
static int ett_2009_12_dpp_common;
1011
1012
static const value_string strings_2009_12_dpp_opid_types[] = {
1013
    { 0, "Not Present" },
1014
    { 1, "SID [Sender]" },
1015
    { 2, "SID [Receiver]" },
1016
    { 3, "SID [Explicit]" },
1017
    { 0, NULL }
1018
};
1019
1020
13
#define OP_2009_12_RESPONSE_FLAG      (0x80)
1021
12
#define OP_2009_12_NODE_DOWN_CMD      (0)
1022
#define OP_2009_12_NODE_DOWN_RSP      (OP_2009_12_RESPONSE_FLAG|OP_2009_12_NODE_DOWN_CMD)
1023
5
#define OP_2009_12_SOURCE_LOST_CMD    (1)
1024
#define OP_2009_12_SOURCE_LOST_RSP    (OP_2009_12_RESPONSE_FLAG|OP_2009_12_SOURCE_LOST_CMD)
1025
10
#define OP_2009_12_RENAME_CMD         (2)
1026
#define OP_2009_12_RENAME_RSP         (OP_2009_12_RESPONSE_FLAG|OP_2009_12_RENAME_CMD)
1027
#define OP_2009_12_PING_CMD           (3)
1028
#define OP_2009_12_PING_RSP           (OP_2009_12_RESPONSE_FLAG|OP_2009_12_PING_CMD)
1029
10
#define OP_2009_12_CANCEL_ALL_CMD     (4)
1030
#define OP_2009_12_CANCEL_ALL_RSP     (OP_2009_12_RESPONSE_FLAG|OP_2009_12_CANCEL_ALL_CMD)
1031
#define OP_2009_12_HEARTBEAT_CMD      (5)
1032
#define OP_2009_12_HEARTBEAT_RSP      (OP_2009_12_RESPONSE_FLAG|OP_2009_12_HEARTBEAT_CMD)
1033
12
#define OP_2009_12_QUERY_CMD          (6)
1034
12
#define OP_2009_12_QUERY_RSP          (OP_2009_12_RESPONSE_FLAG|OP_2009_12_QUERY_CMD)
1035
5
#define OP_2009_12_SOURCE_FOUND_CMD   (8)
1036
#define OP_2009_12_SOURCE_FOUND_RSP   (OP_2009_12_RESPONSE_FLAG|OP_2009_12_SOURCE_FOUND_CMD)
1037
1038
static const value_string strings_2009_12_dpp_common_opcodes[] = {
1039
    { OP_2009_12_NODE_DOWN_CMD, "DPP Node Down" },
1040
    { OP_2009_12_NODE_DOWN_RSP, "DPP Node Down Response (Illegal)" },
1041
    { OP_2009_12_SOURCE_LOST_CMD, "DPP Source Lost" },
1042
    { OP_2009_12_SOURCE_LOST_RSP, "DPP Source Lost Response (Illegal)" },
1043
    { OP_2009_12_SOURCE_FOUND_CMD, "DPP Source Found" },
1044
    { OP_2009_12_SOURCE_FOUND_RSP, "DPP Source Found Response (Illegal)" },
1045
    { OP_2009_12_RENAME_CMD, "DPP Rename" },
1046
    { OP_2009_12_RENAME_RSP, "DPP Rename Response (Illegal)" },
1047
    { OP_2009_12_PING_CMD, "DPP Ping" },
1048
    { OP_2009_12_PING_RSP, "DPP Ping Response" },
1049
    { OP_2009_12_HEARTBEAT_CMD, "DPP Heartbeat" },
1050
    { OP_2009_12_HEARTBEAT_RSP, "DPP Heartbeat Response (Illegal)" },
1051
    { OP_2009_12_QUERY_CMD, "DPP Query" },
1052
    { OP_2009_12_QUERY_RSP, "DPP Query Response" },
1053
    { OP_2009_12_CANCEL_ALL_CMD, "DPP Cancel All" },
1054
    { OP_2009_12_CANCEL_ALL_RSP, "DPP Cancel All Response (Illegal)" },
1055
    { 0, NULL }
1056
};
1057
1058
/* DOF APPLICATION PROTOCOL */
1059
239
#define DOF_APPLICATION_PROTOCOL "DOF Application Protocol"
1060
1061
static dissector_table_t app_dissectors;
1062
1063
static int proto_2008_1_app;
1064
1065
static 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. */
1069
static dissector_table_t dsp_option_dissectors;
1070
1071
static int hf_2008_1_dsp_12_opcode;
1072
static int hf_2008_1_dsp_attribute_code;
1073
static int hf_2008_1_dsp_attribute_data;
1074
static int hf_2008_1_dsp_value_length;
1075
static int hf_2008_1_dsp_value_data;
1076
1077
static const value_string strings_2008_1_dsp_attribute_codes[] = {
1078
    { 0, "TEP Family" },
1079
    { 1, "OAP Family" },
1080
    { 2, "CCM Family" },
1081
    { 3, "TRP Family" },
1082
    { 255, "General" },
1083
    { 0, NULL }
1084
};
1085
1086
#define DOF_PROTOCOL_DSP 0
1087
15
#define DSP_OAP_FAMILY 0x010000
1088
1089
static int proto_2008_1_dsp;
1090
1091
37
#define OP_2008_1_RSP                   (0x80)
1092
4
#define OP_2008_1_QUERY_CMD             0
1093
2
#define OP_2008_1_QUERY_RSP             (OP_2008_1_RSP|OP_2008_1_QUERY_CMD)
1094
15
#define OP_2008_1_CONFIG_REQ            1
1095
0
#define OP_2008_1_CONFIG_ACK            (OP_2008_1_RSP|2)
1096
17
#define OP_2008_1_CONFIG_NAK            (OP_2008_1_RSP|3)
1097
0
#define OP_2008_1_CONFIG_REJ            (OP_2008_1_RSP|4)
1098
0
#define OP_2008_1_TERMINATE_CMD         5
1099
0
#define OP_2008_1_TERMINATE_RSP         (OP_2008_1_RSP|OP_2008_1_TERMINATE_CMD)
1100
1
#define OP_2008_1_OPEN_CMD              6
1101
1
#define OP_2008_1_OPEN_RSP              (OP_2008_1_RSP|OP_2008_1_OPEN_CMD)
1102
6
#define OP_2008_1_OPEN_SECURE_RSP       (OP_2008_1_RSP|7)
1103
1104
static const value_string strings_2008_1_dsp_opcodes[] = {
1105
    { OP_2008_1_QUERY_CMD, "DSP Query" },
1106
    { OP_2008_1_QUERY_RSP, "DSP Query Response" },
1107
    { OP_2008_1_CONFIG_REQ, "DSP Request" },
1108
    { OP_2008_1_CONFIG_ACK, "DSP ACK Response" },
1109
    { OP_2008_1_CONFIG_NAK, "DSP NAK Response" },
1110
    { OP_2008_1_CONFIG_REJ, "DSP REJ Response" },
1111
    { OP_2008_1_TERMINATE_CMD, "DSP Terminate/Close Request" },
1112
    { OP_2008_1_TERMINATE_RSP, "DSP Terminate/Close Response" },
1113
    { OP_2008_1_OPEN_CMD, "DSP Open" },
1114
    { OP_2008_1_OPEN_RSP, "DSP Open Response" },
1115
    { OP_2008_1_OPEN_SECURE_RSP, "DSP Open Secure Response" },
1116
    { 0, NULL }
1117
};
1118
1119
#define DSP_AVP_AUTHENTICATION          0
1120
#define DSP_AVP_APPLICATION             1
1121
1122
#if 0 /* not used yet */
1123
static const value_string strings_2008_1_dsp_attributes[] = {
1124
    { DSP_AVP_AUTHENTICATION, "Authentication Protocol" },
1125
    { DSP_AVP_APPLICATION, "Application Protocol" },
1126
    { 0, NULL }
1127
};
1128
1129
static const value_string strings_2008_1_dsp_values[] = {
1130
    { 1, "DOF Object Access Protocol (version 1)" },
1131
    { 3, "DOF Ticket Exchange Protocol (version 1)" },
1132
    { 0, NULL }
1133
};
1134
#endif
1135
1136
static int ett_2008_1_dsp_12;
1137
static int ett_2008_1_dsp_12_options;
1138
static int ett_2008_1_dsp_12_option;
1139
1140
/* DAP V1 (OAP - OBJECT ACCESS PROTOCOL V1) */
1141
/* This is the defined protocol id for OAP. */
1142
30
#define DOF_PROTOCOL_OAP_1 1
1143
/* There are two "protocols", one hooks into DSP and the other to DOF. */
1144
static int proto_oap_1;
1145
static int proto_oap_1_dsp;
1146
1147
/* OAP DSP protocol items. */
1148
static int hf_oap_1_dsp_option;
1149
1150
/* OAP protocol items. */
1151
static int hf_oap_1_opcode;
1152
1153
static int hf_oap_1_alias_size;
1154
static int hf_oap_1_flags;
1155
static int hf_oap_1_exception_internal_flag;
1156
static int hf_oap_1_exception_final_flag;
1157
static int hf_oap_1_exception_provider_flag;
1158
static int hf_oap_1_cmdcontrol;
1159
static int hf_oap_1_cmdcontrol_cache_flag;
1160
static int hf_oap_1_cmdcontrol_verbosity_flag;
1161
static int hf_oap_1_cmdcontrol_noexecute_flag;
1162
static int hf_oap_1_cmdcontrol_ack_flag;
1163
static int hf_oap_1_cmdcontrol_delay_flag;
1164
static int hf_oap_1_cmdcontrol_heuristic_flag;
1165
static int hf_oap_1_cmdcontrol_heuristic;
1166
static int hf_oap_1_cmdcontrol_cache;
1167
static int hf_oap_1_cmdcontrol_ackcnt;
1168
static int hf_oap_1_cmdcontrol_ack;
1169
1170
#if 0 /* not used yet */
1171
static int hf_oap_1_opinfo_start_frame;
1172
static int hf_oap_1_opinfo_end_frame;
1173
static int hf_oap_1_opinfo_timeout;
1174
#endif
1175
1176
static int hf_oap_1_providerid;
1177
static int ett_oap_1_1_providerid;
1178
1179
static int hf_oap_1_objectid;
1180
static int ett_oap_1_objectid;
1181
1182
static int hf_oap_1_interfaceid;
1183
static int hf_oap_1_itemid;
1184
1185
#if 0 /* not used yet */
1186
static int hf_oap_1_distance;
1187
#endif
1188
1189
static int hf_oap_1_alias;
1190
static int hf_oap_1_alias_frame;
1191
1192
static int hf_oap_1_subscription_delta;
1193
static int hf_oap_1_update_sequence;
1194
static int hf_oap_1_value_list;
1195
1196
static int ett_oap_1_dsp;
1197
static int ett_oap_1_dsp_options;
1198
1199
static int ett_oap_1;
1200
static int ett_oap_1_opinfo;
1201
static int ett_oap_1_cmdcontrol;
1202
static int ett_oap_1_cmdcontrol_flags;
1203
static int ett_oap_1_cmdcontrol_ack;
1204
static int ett_oap_1_alias;
1205
1206
static int * const bitmask_oap_1_cmdcontrol_flags[] = {
1207
    &hf_oap_1_cmdcontrol_cache_flag,
1208
    &hf_oap_1_cmdcontrol_verbosity_flag,
1209
    &hf_oap_1_cmdcontrol_noexecute_flag,
1210
    &hf_oap_1_cmdcontrol_ack_flag,
1211
    &hf_oap_1_cmdcontrol_delay_flag,
1212
    &hf_oap_1_cmdcontrol_heuristic_flag,
1213
    NULL
1214
};
1215
1216
static expert_field ei_oap_no_session;
1217
1218
static GHashTable *oap_1_alias_to_binding;
1219
1220
5
#define OAP_1_RESPONSE                    (0x80)
1221
2
#define OAP_1_CMD_ACTIVATE                28
1222
#define OAP_1_RSP_ACTIVATE                (OAP_1_CMD_ACTIVATE|OAP_1_RESPONSE)
1223
2
#define OAP_1_CMD_ADVERTISE               5
1224
#define OAP_1_RSP_ADVERTISE               (OAP_1_CMD_ADVERTISE|OAP_1_RESPONSE)
1225
34
#define OAP_1_CMD_CHANGE                  2
1226
#define OAP_1_RSP_CHANGE                  (OAP_1_CMD_CHANGE|OAP_1_RESPONSE)
1227
7
#define OAP_1_CMD_CONNECT                 4
1228
#define OAP_1_RSP_CONNECT                 (OAP_1_CMD_CONNECT|OAP_1_RESPONSE)
1229
2
#define OAP_1_CMD_DEFINE                  6
1230
1
#define OAP_1_RSP_DEFINE                  (OAP_1_CMD_DEFINE|OAP_1_RESPONSE)
1231
0
#define OAP_1_CMD_EXCEPTION               9
1232
0
#define OAP_1_RSP_EXCEPTION               (OAP_1_CMD_EXCEPTION|OAP_1_RESPONSE)
1233
8
#define OAP_1_CMD_FULL_CONNECT            3
1234
#define OAP_1_RSP_FULL_CONNECT            (OAP_1_CMD_FULL_CONNECT|OAP_1_RESPONSE)
1235
55
#define OAP_1_CMD_GET                     10
1236
0
#define OAP_1_RSP_GET                     (OAP_1_CMD_GET|OAP_1_RESPONSE)
1237
99
#define OAP_1_CMD_INVOKE                  12
1238
0
#define OAP_1_RSP_INVOKE                  (OAP_1_CMD_INVOKE|OAP_1_RESPONSE)
1239
20
#define OAP_1_CMD_OPEN                    14
1240
1
#define OAP_1_RSP_OPEN                    (OAP_1_CMD_OPEN|OAP_1_RESPONSE)
1241
20
#define OAP_1_CMD_PROVIDE                 16
1242
#define OAP_1_RSP_PROVIDE                 (OAP_1_CMD_PROVIDE|OAP_1_RESPONSE)
1243
78
#define OAP_1_CMD_REGISTER                25
1244
0
#define OAP_1_RSP_REGISTER                (OAP_1_CMD_REGISTER|OAP_1_RESPONSE)
1245
109
#define OAP_1_CMD_SET                     20
1246
0
#define OAP_1_RSP_SET                     (OAP_1_CMD_SET|OAP_1_RESPONSE)
1247
38
#define OAP_1_CMD_SIGNAL                  22
1248
#define OAP_1_RSP_SIGNAL                  (OAP_1_CMD_SIGNAL|OAP_1_RESPONSE)
1249
81
#define OAP_1_CMD_SUBSCRIBE               24
1250
0
#define OAP_1_RSP_SUBSCRIBE               (OAP_1_CMD_SUBSCRIBE|OAP_1_RESPONSE)
1251
81
#define OAP_1_CMD_WATCH                   30
1252
#define OAP_1_RSP_WATCH                   (OAP_1_CMD_WATCH|OAP_1_RESPONSE)
1253
1254
static const value_string oap_opcode_strings[] = {
1255
    { OAP_1_CMD_ACTIVATE, "OAP Activate" },
1256
    { OAP_1_RSP_ACTIVATE, "OAP Activate Response (Illegal)" },
1257
    { OAP_1_CMD_ADVERTISE, "OAP Advertise" },
1258
    { OAP_1_RSP_ADVERTISE, "OAP Advertise Response (Illegal)" },
1259
    { OAP_1_CMD_CHANGE, "OAP Change" },
1260
    { OAP_1_RSP_CHANGE, "OAP Change Response (Illegal)" },
1261
    { OAP_1_CMD_CONNECT, "OAP Connect" },
1262
    { OAP_1_RSP_CONNECT, "OAP Connect Response (Illegal)" },
1263
    { OAP_1_CMD_DEFINE, "OAP Define" },
1264
    { OAP_1_RSP_DEFINE, "OAP Define Response" },
1265
    { OAP_1_CMD_EXCEPTION, "OAP Exception (Illegal)" },
1266
    { OAP_1_RSP_EXCEPTION, "OAP Exception Response" },
1267
    { OAP_1_CMD_FULL_CONNECT, "OAP Full Connect" },
1268
    { OAP_1_RSP_FULL_CONNECT, "OAP Full Connect Response (Illegal)" },
1269
    { OAP_1_CMD_GET, "OAP Get" },
1270
    { OAP_1_RSP_GET, "OAP Get Response" },
1271
    { OAP_1_CMD_INVOKE, "OAP Invoke" },
1272
    { OAP_1_RSP_INVOKE, "OAP Invoke Response" },
1273
    { OAP_1_CMD_OPEN, "OAP Open" },
1274
    { OAP_1_RSP_OPEN, "OAP Open Response" },
1275
    { OAP_1_CMD_PROVIDE, "OAP Provide" },
1276
    { OAP_1_RSP_PROVIDE, "OAP Provide Response (Illegal)" },
1277
    { OAP_1_CMD_REGISTER, "OAP Register" },
1278
    { OAP_1_RSP_REGISTER, "OAP Register Response" },
1279
    { OAP_1_CMD_SET, "OAP Set" },
1280
    { OAP_1_RSP_SET, "OAP Set Response" },
1281
    { OAP_1_CMD_SIGNAL, "OAP Signal" },
1282
    { OAP_1_RSP_SIGNAL, "OAP Signal Response (Illegal)" },
1283
    { OAP_1_CMD_SUBSCRIBE, "OAP Subscribe" },
1284
    { OAP_1_RSP_SUBSCRIBE, "OAP Subscribe Response" },
1285
    { OAP_1_CMD_WATCH, "OAP Watch" },
1286
    { OAP_1_RSP_WATCH, "OAP Watch Response (Illegal)" },
1287
1288
    { 0, NULL }
1289
};
1290
1291
typedef struct _alias_key
1292
{
1293
    uint32_t session;
1294
    uint32_t sender;
1295
    uint32_t alias;
1296
} oap_1_alias_key;
1297
1298
static unsigned oap_1_alias_hash_func(const void *ptr)
1299
4
{
1300
4
    const oap_1_alias_key *key = (const oap_1_alias_key *)ptr;
1301
4
    return g_int_hash(&key->session) + g_int_hash(&key->sender) + g_int_hash(&key->alias);
1302
4
}
1303
1304
static int oap_1_alias_equal_func(const void *ptr1, const void *ptr2)
1305
0
{
1306
0
    const oap_1_alias_key *key1 = (const oap_1_alias_key *)ptr1;
1307
0
    const oap_1_alias_key *key2 = (const oap_1_alias_key *)ptr2;
1308
1309
0
    if (key1->session != key2->session)
1310
0
        return 0;
1311
1312
0
    if (key1->sender != key2->sender)
1313
0
        return 0;
1314
1315
0
    if (key1->alias != key2->alias)
1316
0
        return 0;
1317
1318
0
    return 1;
1319
0
}
1320
1321
typedef 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
1330
typedef struct oap_1_binding_list
1331
{
1332
    oap_1_binding *binding;
1333
    struct oap_1_binding_list *next;
1334
} oap_1_binding_list;
1335
1336
typedef struct
1337
{
1338
    oap_1_binding *resolved_alias;
1339
} oap_1_packet_data;
1340
1341
static oap_1_binding* oap_1_resolve_alias(oap_1_alias_key *key);
1342
1343
static int oap_1_tree_add_alias(dof_api_data *api_data, oap_1_packet_data *oap_packet _U_, dof_packet_data *packet, proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, uint8_t alias_length, uint8_t resolve)
1344
5
{
1345
5
    dof_session_data *session = api_data->session;
1346
5
    proto_item *ti;
1347
5
    proto_tree *options_tree;
1348
1349
5
    if (alias_length == 0)
1350
    /* TODO: Output error. */
1351
0
        return offset;
1352
1353
5
    if (session == NULL)
1354
    /* TODO: Output error. */
1355
0
        return offset;
1356
1357
5
    ti = proto_tree_add_item(tree, hf_oap_1_alias, tvb, offset, alias_length, ENC_BIG_ENDIAN);
1358
1359
5
    if (resolve)
1360
4
    {
1361
4
        oap_1_binding *binding = NULL;
1362
4
        oap_1_alias_key key;
1363
4
        int i;
1364
4
        uint32_t alias;
1365
1366
4
        alias = 0;
1367
12
        for (i = 0; i < alias_length; i++)
1368
8
            alias = (alias << 8) | tvb_get_uint8(tvb, offset + i);
1369
1370
4
        key.session = session->session_id;
1371
4
        key.sender = packet->sender_id;
1372
4
        key.alias = alias;
1373
4
        binding = oap_1_resolve_alias(&key);
1374
1375
4
        if (binding)
1376
0
        {
1377
0
            options_tree = proto_item_add_subtree(ti, ett_oap_1_alias);
1378
1379
            /* Decode the Interface */
1380
0
            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));
1381
0
            proto_item_set_generated(ti);
1382
1383
            /* Decode the Object ID */
1384
0
            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));
1385
0
            proto_item_set_generated(ti);
1386
1387
0
            proto_tree_add_uint_format(options_tree, hf_oap_1_alias_frame,
1388
0
                                       tvb, 0, 0, binding->frame,
1389
0
                                       "This alias is defined in frame %u",
1390
0
                                       binding->frame);
1391
0
        }
1392
4
    }
1393
1394
5
    return offset + alias_length;
1395
5
}
1396
1397
static int oap_1_tree_add_interface(proto_tree *tree, tvbuff_t *tvb, int offset)
1398
31
{
1399
31
    uint8_t registry;
1400
31
    uint8_t len;
1401
1402
31
    registry = tvb_get_uint8(tvb, offset);
1403
31
    len = registry & 0x03;
1404
    /* XXX - The DOF specifications indicate "len [bits] equal to 0 is invalid"
1405
     * Why is a length of 16 bytes used in that case, and why is it handled
1406
     * differently in InterfaceID_ToString? */
1407
31
    if (len == 0)
1408
20
        len = 16;
1409
11
    else
1410
11
        len = 1 << (len - 1);
1411
1412
31
    proto_tree_add_item(tree, hf_oap_1_interfaceid, tvb, offset, 1 + len, ENC_NA);
1413
31
    return offset + 1 + len;
1414
31
}
1415
1416
static int oap_1_tree_add_binding(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int offset)
1417
30
{
1418
  /*  uint8_t cl; */
1419
1420
30
    offset = oap_1_tree_add_interface(tree, tvb, offset);
1421
1422
#if 0 /* this seems to be dead code - check! */
1423
    cl = tvb_get_uint8(tvb, offset);
1424
    if (cl & 0x80)
1425
        len = tvb_get_uint8(tvb, offset + 2);
1426
    else
1427
        len = tvb_get_uint8(tvb, offset + 1);
1428
#endif
1429
1430
30
    offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, tree,
1431
30
                                      offset, hf_oap_1_objectid, ett_oap_1_objectid, NULL);
1432
30
    return offset;
1433
30
}
1434
1435
static int oap_1_tree_add_cmdcontrol(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset)
1436
80
{
1437
80
    proto_item *ti;
1438
80
    proto_tree *opinfo_tree;
1439
80
    uint8_t flags;
1440
1441
80
    flags = tvb_get_uint8(tvb, offset);
1442
1443
80
    ti = proto_tree_add_bitmask(tree, tvb, offset, hf_oap_1_cmdcontrol, ett_oap_1_cmdcontrol_flags, bitmask_oap_1_cmdcontrol_flags, ENC_NA);
1444
80
    opinfo_tree = proto_item_add_subtree(ti, ett_oap_1_cmdcontrol);
1445
1446
80
    proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_cache_flag, tvb, offset, 1, ENC_NA);
1447
80
    proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_verbosity_flag, tvb, offset, 1, ENC_NA);
1448
80
    proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_noexecute_flag, tvb, offset, 1, ENC_NA);
1449
80
    proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_ack_flag, tvb, offset, 1, ENC_NA);
1450
80
    proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_delay_flag, tvb, offset, 1, ENC_NA);
1451
80
    proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_heuristic_flag, tvb, offset, 1, ENC_NA);
1452
1453
80
    offset += 1;
1454
1455
80
    if (flags & 0x01)
1456
50
    {
1457
        /* Heuristic */
1458
50
        int heur_len;
1459
50
        uint16_t heur;
1460
50
        proto_item *pi;
1461
1462
50
        read_c2(tvb, offset, &heur, &heur_len);
1463
50
        pi = proto_tree_add_uint_format(opinfo_tree, hf_oap_1_cmdcontrol_heuristic, tvb, offset, heur_len, heur, "Heuristic Value: %hu", heur);
1464
50
        validate_c2(pinfo, pi, heur, heur_len);
1465
50
        offset += heur_len;
1466
50
    }
1467
1468
80
    if (flags & 0x04)
1469
72
    {
1470
        /* Ack List */
1471
72
        uint8_t ackcnt;
1472
72
        uint8_t i;
1473
1474
72
        proto_tree_add_item_ret_uint8(opinfo_tree, hf_oap_1_cmdcontrol_ackcnt, tvb, offset, 1, ENC_NA, &ackcnt);
1475
72
        offset += 1;
1476
1477
1.30k
        for (i = 0; i < ackcnt; i++)
1478
1.22k
        {
1479
1.22k
            offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, opinfo_tree,
1480
1.22k
                                              offset, hf_oap_1_cmdcontrol_ack, ett_oap_1_cmdcontrol_ack, NULL);
1481
1.22k
        }
1482
72
    }
1483
1484
80
    if (flags & 0x40)
1485
3
    {
1486
        /* Cache Delay */
1487
3
        int cache_len;
1488
3
        uint16_t cache;
1489
3
        proto_item *pi;
1490
1491
3
        read_c2(tvb, offset, &cache, &cache_len);
1492
3
        pi = proto_tree_add_uint_format(opinfo_tree, hf_oap_1_cmdcontrol_cache, tvb, offset, cache_len, cache, "Cache Delay: %hu", cache);
1493
3
        validate_c2(pinfo, pi, cache, cache_len);
1494
3
        offset += cache_len;
1495
3
    }
1496
1497
80
    return offset;
1498
80
}
1499
1500
/**
1501
 * Define an alias. This routine is called for each Provide operation that includes an alias assignment.
1502
 * It is also called for retries of Provide operations.
1503
 * The alias is defined for the duration of the Provide. This means that if the operation is cancelled
1504
 * then the alias should no longer be valid.
1505
 * The alias is associated with an oap_session, an dof_node, and the alias itself. Aliases
1506
 * may be reused as long as the previous use has expired, and so the list is stored in reverse
1507
 * order.
1508
 *
1509
 * NOTE: The alias is passed as a structure pointer, and must be reallocated if it is stored in
1510
 * the hash.
1511
 */
1512
static void oap_1_define_alias(dof_api_data *api_data, uint32_t alias, oap_1_binding *binding)
1513
0
{
1514
    /* The definer of an alias is the sender, in the session. */
1515
0
    dof_session_data *session = api_data->session;
1516
0
    dof_packet_data *packet = (dof_packet_data *)api_data->packet;
1517
0
    uint32_t session_id;
1518
0
    uint32_t sender_id;
1519
0
    oap_1_alias_key key;
1520
1521
0
    if (!session)
1522
0
        return;
1523
1524
0
    session_id = session->session_id;
1525
0
    sender_id = packet->sender_id;
1526
1527
0
    if (!binding)
1528
0
        return;
1529
1530
0
    key.session = session_id;
1531
0
    key.sender = sender_id;
1532
0
    key.alias = alias;
1533
1534
    /* If there isn't an entry for the alias, then we need to create one.
1535
    * The first entry will be the binding we are defining.
1536
    */
1537
0
    if (!g_hash_table_lookup(oap_1_alias_to_binding, &key))
1538
0
    {
1539
0
        oap_1_alias_key *alias_ptr = wmem_new0(wmem_file_scope(), oap_1_alias_key);
1540
0
        memcpy(alias_ptr, &key, sizeof(oap_1_alias_key));
1541
0
        g_hash_table_insert(oap_1_alias_to_binding, alias_ptr, binding);
1542
0
    }
1543
0
}
1544
1545
/**
1546
 * Given an oap_alias, resolve it to an oap_1_binding. This assumes that the destination of the
1547
 * packet is the one that defined the alias.
1548
 */
1549
static oap_1_binding* oap_1_resolve_alias(oap_1_alias_key *key)
1550
4
{
1551
    /* The first lookup is inside the session based on defining node. */
1552
4
    return (oap_1_binding *)g_hash_table_lookup(oap_1_alias_to_binding, key);
1553
4
}
1554
1555
/* DAP V128 (TEP - TICKET EXCHANGE PROTOCOL V1) */
1556
30
#define DOF_PROTOCOL_TEP 128
1557
15
#define DSP_TEP_FAMILY 0x000000
1558
static int proto_tep;
1559
static int proto_tep_dsp;
1560
1561
static int hf_dsp_option;
1562
1563
static int ett_tep_operation;
1564
static int hf_tep_operation;
1565
static int hf_tep_operation_type;
1566
static int hf_tep_opcode;
1567
static int hf_tep_k;
1568
static int hf_tep_c;
1569
static int hf_tep_reject_code;
1570
static int hf_tep_reject_data;
1571
1572
static const true_false_string tep_optype_vals = { "DPP Response", "DPP Command" };
1573
1574
/* TEP.2.1 */
1575
static int ett_tep_2_1_domain;
1576
static int hf_tep_2_1_domain;
1577
static int ett_tep_2_1_initiator_block;
1578
static int hf_tep_2_1_initiator_block;
1579
static int hf_tep_2_1_ticket_confirmation;
1580
1581
/* TEP.2.2 */
1582
static int ett_tep_2_2_initiator_ticket;
1583
static int hf_tep_2_2_initiator_ticket;
1584
static int hf_tep_2_2_ticket_confirmation;
1585
static int ett_tep_2_2_responder_initialization;
1586
static int hf_tep_2_2_responder_initialization;
1587
static int ett_tep_2_2_responder_block;
1588
static int hf_tep_2_2_responder_block;
1589
static int ett_tep_2_2_authenticator_initialization;
1590
static int hf_tep_2_2_authenticator_initialization;
1591
1592
/* TEP.2.2.1 */
1593
static int hf_tep_2_2_1_state_identifier;
1594
static int ett_tep_2_2_1_initial_state;
1595
static int hf_tep_2_2_1_initial_state;
1596
1597
static int hf_tep_session_key;
1598
1599
static int ett_tep_dsp;
1600
static int ett_tep_dsp_options;
1601
static int ett_tep;
1602
1603
#if 0 /* not used yet */
1604
static const value_string tep_filter_existing[] = {
1605
    { 1, "Include Existing Matches" },
1606
    { 0, "Exclude Existing Matches" },
1607
    { 0, NULL }
1608
};
1609
#endif
1610
1611
17
#define TEP_OPCODE_RSP                                                  (0x80)
1612
0
#define TEP_OPCODE_C                                                    (0x20)
1613
0
#define TEP_OPCODE_K                                                    (0x10)
1614
0
#define TEP_PDU_REJECT                                                  (TEP_OPCODE_RSP|0)
1615
1
#define TEP_PDU_REQUEST                                                 (1)
1616
0
#define TEP_PDU_END_SESSION                                             (5)
1617
0
#define TEP_PDU_SESSION_ENDING                                  (6)
1618
1619
0
#define TEP_PDU_REQUEST_KEY                                             (TEP_OPCODE_K|TEP_PDU_REQUEST)
1620
0
#define TEP_PDU_CONFIRM                                                 (TEP_OPCODE_C|TEP_PDU_REQUEST)
1621
1
#define TEP_PDU_ACCEPT                                                  (TEP_OPCODE_RSP|TEP_PDU_REQUEST)
1622
#define TEP_PDU_CONFIRM_ACK                                             (TEP_OPCODE_RSP|TEP_OPCODE_C|TEP_PDU_REQUEST)
1623
1624
static const value_string tep_opcode_strings[] = {
1625
    { TEP_PDU_REJECT, "TEP Reject" },
1626
    { TEP_PDU_REQUEST, "TEP Request" },
1627
    { TEP_PDU_END_SESSION, "TEP End Session" },
1628
    { TEP_PDU_SESSION_ENDING, "TEP Session Ending" },
1629
1630
    { TEP_PDU_REQUEST_KEY, "TEP Rekey" },
1631
    { TEP_PDU_CONFIRM, "TEP Confirm" },
1632
    { TEP_PDU_ACCEPT, "TEP Accept" },
1633
    { TEP_PDU_CONFIRM_ACK, "TEP Confirm Ack" },
1634
1635
    { 0, NULL }
1636
};
1637
1638
#if 0 /* not use yet */
1639
static const value_string tep_error_strings[] = {
1640
    { 1, "Parse Error" },
1641
    { 2, "Access Denied" },
1642
    { 3, "Duration Not Supported" },
1643
    { 4, "Authentication Failed" },
1644
    { 0, NULL }
1645
};
1646
#endif
1647
1648
/* Initialized to zero. */
1649
typedef struct tep_rekey_data
1650
{
1651
    /* Stored from the K bit of the Request PDU. */
1652
    bool is_rekey;
1653
1654
    /* Stored from the key request for non-secure rekeys. Otherwise 0 and NULL. */
1655
    uint8_t domain_length;
1656
    uint8_t *domain;
1657
1658
    /* Stored from the identity of the Request PDU. Seasonal. */
1659
    uint8_t *i_identity;
1660
    uint8_t i_identity_length;
1661
1662
    /* Stored from the nonce of the Request PDU. Seasonal. */
1663
    uint8_t *i_nonce;
1664
    uint8_t i_nonce_length;
1665
1666
    /* Stored from the identity of the Request response PDU. Seasonal. */
1667
    uint8_t *r_identity;
1668
    uint8_t r_identity_length;
1669
1670
    /* Stored from the nonce of the Request response PDU. Seasonal. */
1671
    uint8_t *r_nonce;
1672
    uint8_t r_nonce_length;
1673
1674
    uint16_t security_mode;
1675
    uint32_t security_mode_data_length;
1676
    uint8_t *security_mode_data;
1677
1678
    /* Security session data for this rekey, if is_rekey is true. */
1679
    dof_session_key_exchange_data *key_data;
1680
} tep_rekey_data;
1681
1682
/* DAP V129 (TRP - TICKET REQUEST PROTOCOL V2) */
1683
30
#define DOF_PROTOCOL_TRP 129
1684
15
#define DSP_TRP_FAMILY 0x030000
1685
typedef struct _trp_packet_data
1686
{
1687
    uint8_t *domain;
1688
    uint8_t domain_length;
1689
    uint8_t *identity;
1690
    uint8_t identity_length;
1691
    uint8_t *group;
1692
    uint8_t group_length;
1693
    uint8_t *block_I;
1694
    uint16_t block_I_length;
1695
    uint8_t *secret;
1696
    bool kek_known;
1697
} trp_packet_data;
1698
1699
1700
static int proto_trp;
1701
static int proto_trp_dsp;
1702
1703
static int hf_trp_dsp_option;
1704
1705
static int hf_trp_opcode;
1706
static int hf_domain;
1707
static int hf_identity_resolution;
1708
static int hf_initiator_request;
1709
static int hf_responder_request;
1710
static int hf_initiator_ticket;
1711
static int hf_responder_ticket;
1712
static int hf_authentication_block;
1713
static int hf_group_identifier;
1714
static int hf_node_identifier;
1715
static int hf_thb;
1716
static int hf_tmin;
1717
static int hf_tmax;
1718
static int hf_trp_epoch;
1719
static int hf_sidg;
1720
static int hf_security_scope;
1721
static int hf_security_mode;
1722
static int hf_ssid;
1723
#if 0 /* not used yet */
1724
static int hf_initiator_pg;
1725
#endif
1726
static int hf_initiator_validation;
1727
static int hf_responder_pg;
1728
static int hf_responder_validation;
1729
1730
static int hf_trp_errorcode;
1731
static int hf_trp_duration;
1732
#if 0 /* not used yet */
1733
static int hf_trp_rnonce;
1734
static int hf_trp_pnonce;
1735
static int hf_trp_reqid;
1736
static int hf_trp_provid;
1737
static int hf_trp_perm_count;
1738
static int hf_trp_perm_type;
1739
static int hf_trp_perm_rcache;
1740
static int hf_trp_perm_rsrp;
1741
static int hf_trp_perm_rsrp_a;
1742
static int hf_trp_perm_rsrp_u;
1743
static int hf_trp_perm_rflags;
1744
static int hf_trp_perm_pcache;
1745
static int hf_trp_perm_psrp;
1746
static int hf_trp_perm_psrp_a;
1747
static int hf_trp_perm_psrp_u;
1748
static int hf_trp_perm_psrp_b;
1749
static int hf_trp_perm_psrp_s;
1750
static int hf_trp_perm_pflags;
1751
static int hf_trp_confirmation;
1752
static int hf_trp_perm_pke;
1753
static int hf_trp_perm_pka;
1754
#endif
1755
1756
static int ett_trp_dsp;
1757
static int ett_trp;
1758
static int ett_domain;
1759
static int ett_identity_resolution;
1760
static int ett_initiator_request;
1761
static int ett_initiator_ticket;
1762
static int ett_responder_request;
1763
static int ett_responder_ticket;
1764
static int ett_authentication_block;
1765
static int ett_group_identifier;
1766
static int ett_node_identifier;
1767
static int ett_sidg;
1768
static int ett_security_scope;
1769
static int ett_security_mode;
1770
static int ett_initiator_pg;
1771
static int ett_initiator_validation;
1772
static int ett_responder_pg;
1773
static int ett_responder_validation;
1774
1775
1776
static int ett_trp_permset;
1777
static int ett_srp_flags;
1778
static int ett_trp_ticket;
1779
1780
static expert_field ei_trp_initiator_id_known;
1781
static expert_field ei_trp_kek_discovered;
1782
1783
171
#define TRP_RESPONSE                    (0x80)
1784
1785
1
#define TRP_RSP_REJECT                                                  (TRP_RESPONSE|0)
1786
94
#define TRP_CMD_REQUEST_KEK                                             (1)
1787
93
#define TRP_RSP_REQUEST_KEK                                             (TRP_RESPONSE|TRP_CMD_REQUEST_KEK)
1788
2
#define TRP_CMD_REQUEST_RANDOM                                  (2)
1789
1
#define TRP_RSP_REQUEST_RANDOM                                  (TRP_RESPONSE|TRP_CMD_REQUEST_RANDOM)
1790
1
#define TRP_CMD_REQUEST_SESSION                                 (3)
1791
0
#define TRP_RSP_REQUEST_SESSION                                 (TRP_RESPONSE|TRP_CMD_REQUEST_SESSION)
1792
29
#define TRP_CMD_REQUEST_SECURITY_SCOPES                 (4)
1793
15
#define TRP_RSP_REQUEST_SECURITY_SCOPES                 (TRP_RESPONSE|TRP_CMD_REQUEST_SECURITY_SCOPES)
1794
0
#define TRP_CMD_RESOLVE_CREDENTIAL                              (6)
1795
0
#define TRP_RSP_RESOLVE_CREDENTIAL                              (TRP_RESPONSE|TRP_CMD_RESOLVE_CREDENTIAL)
1796
#define TRP_CMD_REQUEST_LOCAL_DOMAIN                    (7)
1797
#define TRP_RSP_REQUEST_LOCAL_DOMAIN                    (TRP_RESPONSE|TRP_CMD_REQUEST_LOCAL_DOMAIN)
1798
#define TRP_CMD_REQUEST_REMOTE_DOMAIN                   (8)
1799
#define TRP_RSP_REQUEST_REMOTE_DOMAIN                   (TRP_RESPONSE|TRP_CMD_REQUEST_REMOTE_DOMAIN)
1800
#define TRP_RSP_REQUEST_DISCOVERED_REMOTE_DOMAIN        (TRP_RESPONSE|0x0A)
1801
0
#define TRP_CMD_VALIDATE_CREDENTIAL                             (9)
1802
0
#define TRP_RSP_VALIDATE_CREDENTIAL                             (TRP_RESPONSE|TRP_CMD_VALIDATE_CREDENTIAL)
1803
1804
static const value_string trp_opcode_strings[] = {
1805
    { TRP_RSP_REJECT, "Reject" },
1806
1807
    { TRP_CMD_REQUEST_KEK, "TRP Request KEK" },
1808
    { TRP_RSP_REQUEST_KEK, "TRP Request KEK Response" },
1809
1810
    { TRP_CMD_REQUEST_RANDOM, "TRP Request Random" },
1811
    { TRP_RSP_REQUEST_RANDOM, "TRP Request Random Response" },
1812
1813
    { TRP_CMD_REQUEST_SESSION, "TRP Request Session" },
1814
    { TRP_RSP_REQUEST_SESSION, "TRP Request Session Response" },
1815
1816
    { TRP_CMD_REQUEST_SECURITY_SCOPES, "TRP Request Security Scopes" },
1817
    { TRP_RSP_REQUEST_SECURITY_SCOPES, "TRP Request Security Scopes Response" },
1818
1819
    { TRP_CMD_RESOLVE_CREDENTIAL, "TRP Resolve Credential" },
1820
    { TRP_RSP_RESOLVE_CREDENTIAL, "TRP Resolve Credential Response" },
1821
1822
    { TRP_CMD_REQUEST_LOCAL_DOMAIN, "TRP Request Local Domain" },
1823
    { TRP_RSP_REQUEST_LOCAL_DOMAIN, "TRP Request Local Domain Response" },
1824
1825
    { TRP_CMD_REQUEST_REMOTE_DOMAIN, "TRP Request Remote Domain" },
1826
    { TRP_RSP_REQUEST_REMOTE_DOMAIN, "TRP Request Remote Domain Response" },
1827
    { TRP_RSP_REQUEST_DISCOVERED_REMOTE_DOMAIN, "TRP Request Discovered Remote Domain Response" },
1828
1829
    { TRP_CMD_VALIDATE_CREDENTIAL, "TRP Validate Credential" },
1830
    { TRP_RSP_VALIDATE_CREDENTIAL, "TRP Validate Credential Response" },
1831
1832
    { 0, NULL }
1833
};
1834
1835
static const value_string trp_error_strings[] = {
1836
    { 1, "Parse Error" },
1837
    { 2, "Access Denied" },
1838
    { 3, "Unknown Initiator" },
1839
    { 4, "Unknown Responder" },
1840
    { 5, "Unknown Domain" },
1841
    { 6, "High Load" },
1842
    { 7, "Bad Mode" },
1843
    { 8, "Incompatible Security Identifiers" },
1844
    { 127, "Internal Error" },
1845
1846
    { 0, NULL }
1847
};
1848
1849
/* DAP V130 (SGMP - SECURE GROUP MANAGEMENT PROTOCOL V1) */
1850
15
#define DOF_PROTOCOL_SGMP       130
1851
typedef struct _sgmp_packet_data
1852
{
1853
    uint8_t domain_length;
1854
    uint8_t *domain;
1855
1856
    uint8_t group_length;
1857
    uint8_t *group;
1858
1859
    uint16_t epoch;
1860
    uint8_t *kek;
1861
1862
    unsigned I_length;
1863
    uint8_t *I;
1864
    unsigned A_length;
1865
    uint8_t *A;
1866
1867
    dof_session_data *request_session;
1868
} sgmp_packet_data;
1869
1870
static int proto_sgmp;
1871
1872
static int hf_opcode;
1873
static int hf_sgmp_domain;
1874
static int hf_sgmp_epoch;
1875
static int hf_initiator_block;
1876
static int hf_sgmp_security_scope;
1877
static int hf_initial_state;
1878
static int hf_latest_version;
1879
static int hf_desire;
1880
static int hf_ticket;
1881
static int hf_sgmp_tmin;
1882
static int hf_tie_breaker;
1883
static int hf_delay;
1884
static int hf_key;
1885
1886
static int ett_sgmp;
1887
static int ett_sgmp_domain;
1888
static int ett_initiator_block;
1889
static int ett_sgmp_security_scope;
1890
static int ett_initial_state;
1891
static int ett_ticket;
1892
1893
0
#define SGMP_RESPONSE                                   (0x80)
1894
1
#define SGMP_CMD_HEARTBEAT                              (0)
1895
#define SGMP_RSP_HEARTBEAT                              (SGMP_CMD_HEARTBEAT|SGMP_RESPONSE)
1896
1
#define SGMP_CMD_EPOCH_CHANGED                  (1)
1897
#define SGMP_RSP_EPOCH_CHANGED                  (SGMP_CMD_EPOCH_CHANGED|SGMP_RESPONSE)
1898
0
#define SGMP_CMD_REKEY                                  (2)
1899
#define SGMP_RSP_REKEY                                  (SGMP_CMD_REKEY|SGMP_RESPONSE)
1900
0
#define SGMP_CMD_REQUEST_GROUP                  (3)
1901
0
#define SGMP_RSP_REQUEST_GROUP                  (SGMP_CMD_REQUEST_GROUP|SGMP_RESPONSE)
1902
1
#define SGMP_CMD_REKEY_EPOCH                    (5)
1903
#define SGMP_RSP_REKEY_EPOCH                    (SGMP_CMD_REKEY_EPOCH|SGMP_RESPONSE)
1904
2
#define SGMP_CMD_REKEY_MERGE                    (7)
1905
#define SGMP_RSP_REKEY_MERGE                    (SGMP_CMD_REKEY_MERGE|SGMP_RESPONSE)
1906
1907
static const value_string sgmp_opcode_strings[] = {
1908
    { SGMP_CMD_HEARTBEAT, "SGMP Heartbeat" },
1909
    { SGMP_RSP_HEARTBEAT, "SGMP Heartbeat Response (Illegal)" },
1910
    { SGMP_CMD_EPOCH_CHANGED, "SGMP Epoch Changed" },
1911
    { SGMP_RSP_EPOCH_CHANGED, "SGMP Epoch Changed Response (Illegal)" },
1912
    { SGMP_CMD_REKEY, "SGMP Rekey" },
1913
    { SGMP_RSP_REKEY, "SGMP Rekey Response (Illegal)" },
1914
    { SGMP_CMD_REQUEST_GROUP, "SGMP Request Group" },
1915
    { SGMP_RSP_REQUEST_GROUP, "SGMP Request Group Response" },
1916
    { SGMP_CMD_REKEY_EPOCH, "SGMP Rekey Epoch" },
1917
    { SGMP_RSP_REKEY_EPOCH, "SGMP Rekey Epoch Response (Illegal)" },
1918
    { SGMP_CMD_REKEY_MERGE, "SGMP Rekey Merge" },
1919
    { SGMP_RSP_REKEY_MERGE, "SGMP Rekey Merge Response (Illegal)" },
1920
1921
    { 0, NULL }
1922
};
1923
1924
1925
#if 0 /* TODO not used yet */
1926
static bool sgmp_validate_session_key(sgmp_packet_data *cmd_data, uint8_t *confirmation, uint8_t *kek, uint8_t *key)
1927
{
1928
    gcry_mac_hd_t hmac;
1929
    gcry_error_t result;
1930
1931
    result = gcry_mac_open(&hmac, GCRY_MAC_HMAC_SHA256, 0, NULL);
1932
    if (result != 0)
1933
        return false;
1934
1935
    gcry_mac_setkey(hmac, kek, 32);
1936
    gcry_mac_write(hmac, cmd_data->I, cmd_data->I_length);
1937
    gcry_mac_write(hmac, cmd_data->A, cmd_data->A_length);
1938
    gcry_mac_write(hmac, key, 32);
1939
    result = gcry_mac_verify(hmac, confirmation, sizeof(confirmation));
1940
    return result == 0;
1941
}
1942
#endif
1943
1944
/* DOF SECURITY PROTOCOL */
1945
#define DOF_SECURITY_PROTOCOL "DOF Security Protocol"
1946
static dissector_table_t dof_sec_dissectors;
1947
113
#define AS_ASSIGNED_SSID 0x40000000
1948
1949
/* DOFSEC Vxxxx (CCM - COUNTER WITH CBC-MAC PROTOCOL V1) */
1950
45
#define DOF_PROTOCOL_CCM 24577
1951
15
#define DSP_CCM_FAMILY 0x020000
1952
1953
static int proto_ccm_app;
1954
static int proto_ccm;
1955
static int proto_ccm_dsp;
1956
1957
static int hf_ccm_dsp_option;
1958
static int hf_ccm_dsp_strength_count;
1959
static int hf_ccm_dsp_strength;
1960
static int hf_ccm_dsp_e_flag;
1961
static int hf_ccm_dsp_m_flag;
1962
static int hf_ccm_dsp_tmax;
1963
static int hf_ccm_dsp_tmin;
1964
1965
static const value_string ccm_strengths[] = {
1966
    { 1, "256-bit" },
1967
    { 2, "192-bit" },
1968
    { 3, "128-bit" },
1969
    { 0, NULL }
1970
};
1971
static int hf_ccm_opcode;
1972
1973
static int hf_epp_v1_ccm_flags;
1974
static int hf_epp_v1_ccm_flags_manager;
1975
static int hf_epp_v1_ccm_flags_period;
1976
static int hf_epp_v1_ccm_flags_target;
1977
static int hf_epp_v1_ccm_flags_next_nid;
1978
static int hf_epp_v1_ccm_flags_packet;
1979
static int hf_epp_v1_ccm_tnid;
1980
static int hf_epp_v1_ccm_nnid;
1981
static int hf_epp_v1_ccm_nid;
1982
static int hf_epp_v1_ccm_slot;
1983
static int hf_epp_v1_ccm_pn;
1984
1985
static int ett_header;
1986
static int ett_epp_v1_ccm_flags;
1987
1988
static int ett_ccm_dsp_option;
1989
static int ett_ccm_dsp;
1990
static int ett_ccm;
1991
1992
static expert_field ei_decode_failure;
1993
1994
typedef struct _ccm_session_data
1995
{
1996
    unsigned protocol_id;
1997
    gcry_cipher_hd_t cipher_data;
1998
    GHashTable *cipher_data_table;
1999
    /* Starts at 1, incrementing for each new key. */
2000
    uint32_t period;
2001
    /* Mapping from wire period to absolute periods. */
2002
    uint8_t periods[8];
2003
    uint8_t cipher;
2004
    bool encrypted;
2005
    uint8_t mac_len;
2006
    uint32_t client_datagram_number;
2007
    uint32_t server_datagram_number;
2008
} ccm_session_data;
2009
2010
typedef struct _ccm_packet_data
2011
{
2012
    uint32_t nid;
2013
    uint32_t dn;
2014
    uint32_t period;
2015
} ccm_packet_data;
2016
2017
#define CCM_PDU_PROBE            (0)
2018
2019
static const value_string ccm_opcode_strings[] = {
2020
    { CCM_PDU_PROBE, "Probe" },
2021
    { 0, NULL }
2022
};
2023
2024
/* DOF OBJECT IDENTIFIER (OID) */
2025
30
#define DOF_OBJECT_IDENTIFIER "DOF Object Identifier"
2026
2027
static dissector_handle_t dof_oid_handle;
2028
2029
static int oid_proto = -1;
2030
2031
static int hf_oid_class;
2032
static int hf_oid_header;
2033
static int hf_oid_attribute;
2034
static int hf_oid_length;
2035
static int hf_oid_data;
2036
static int hf_oid_all_attribute_data;
2037
static int hf_oid_attribute_header;
2038
static int hf_oid_attribute_attribute;
2039
static int hf_oid_attribute_id;
2040
static int hf_oid_attribute_length;
2041
static int hf_oid_attribute_data;
2042
static int hf_oid_attribute_oid;
2043
2044
static int ett_oid;
2045
static int ett_oid_header;
2046
static int ett_oid_attribute;
2047
static int ett_oid_attribute_header;
2048
static int ett_oid_attribute_oid;
2049
2050
/**
2051
 * EXPERT INFOS
2052
 * Expert infos are related to either a PDU type or a specification, and so
2053
 * they are listed separately.
2054
 */
2055
#if 0
2056
static expert_field ei_undecoded;
2057
#endif
2058
static expert_field ei_malformed;
2059
static expert_field ei_implicit_no_op;
2060
static expert_field ei_c2_c3_c4_format;
2061
static expert_field ei_type_4_header_zero;
2062
static expert_field ei_dof_10_flags_zero;
2063
#if 0
2064
static expert_field ei_dof_13_length_specified;
2065
#endif
2066
2067
static expert_field ei_dpp2_dof_10_flags_zero;
2068
static expert_field ei_dpp_default_flags;
2069
static expert_field ei_dpp_explicit_sender_sid_included;
2070
static expert_field ei_dpp_explicit_receiver_sid_included;
2071
static expert_field ei_dpp_no_security_context;
2072
static expert_field ei_dof_6_timeout;
2073
2074
static expert_field ei_security_3_1_invalid_stage;
2075
static expert_field ei_security_4_invalid_bit;
2076
static expert_field ei_security_13_out_of_range;
2077
2078
/**
2079
 * SOURCE IDENTIFIER (SID) SUPPORT
2080
 * Source identifiers are used as part of operation tracking in the
2081
 * DOF Protocol Stack. They are version independent, and associated with
2082
 * a node in the DOF mesh network. Each session is associated with a SID.
2083
 *
2084
 * DPP Manages the SID information, since it is DPP that learns about SIDs.
2085
 * SIDs are complicated because the can be 'unknown' for periods, and then
2086
 * learned later. The requirement here is that all SIDs that can be known
2087
 * are known by the second pass of the dissector (pinfo->visited != 0).
2088
 *
2089
 * There are two hash tables to map to an actual SID. The first goes
2090
 * from sender information to SID ID. During the first pass multiple SID ID
2091
 * may actually refer to the same SID, and so the system must be able to "patch"
2092
 * these values as actual SIDs are learned. The second hash table goes from SID ID
2093
 * to actual SID. This lookup is only known after a real SID has been learned.
2094
 *
2095
 * The hash tables are used in order to look up full SID information when only
2096
 * partial information is known, and must support looking up in both directions
2097
 * based on what is known from a particular PDU.
2098
 */
2099
static GHashTable *node_key_to_sid_id;
2100
static GHashTable *sid_buffer_to_sid_id;
2101
static GHashTable *sid_id_to_sid_buffer;
2102
2103
typedef struct _node_key_to_sid_id_key
2104
{
2105
    int transport_id;
2106
    int transport_node_id;
2107
    int dof_id;
2108
    int dof_node_id;
2109
    int dof_session_id;
2110
} node_key_to_sid_id_key;
2111
2112
static unsigned sender_key_hash_fn(const void *key)
2113
777
{
2114
777
    const node_key_to_sid_id_key *sid_key_ptr = (const node_key_to_sid_id_key *)key;
2115
777
    unsigned result = 0;
2116
2117
777
    result += g_int_hash(&(sid_key_ptr->transport_id));
2118
777
    result += g_int_hash(&(sid_key_ptr->transport_node_id));
2119
777
    result += g_int_hash(&(sid_key_ptr->dof_id));
2120
777
    result += g_int_hash(&(sid_key_ptr->dof_node_id));
2121
777
    result += g_int_hash(&(sid_key_ptr->dof_session_id));
2122
2123
777
    return result;
2124
777
}
2125
2126
static unsigned sid_buffer_hash_fn(const void *key)
2127
178
{
2128
    /* The sid buffer is a length byte followed by data. */
2129
178
    unsigned hash = 5381;
2130
178
    const uint8_t *str = (const uint8_t *)key;
2131
178
    uint16_t i;
2132
2133
9.63k
    for (i = 0; i <= str[0]; i++)
2134
9.45k
        hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
2135
2136
178
    return hash;
2137
178
}
2138
2139
static gboolean sender_key_equal_fn(const void *key1, const void *key2)
2140
780
{
2141
780
    const node_key_to_sid_id_key *sid_key_ptr1 = (const node_key_to_sid_id_key *)key1;
2142
780
    const node_key_to_sid_id_key *sid_key_ptr2 = (const node_key_to_sid_id_key *)key2;
2143
2144
780
    if (sid_key_ptr1->transport_id != sid_key_ptr2->transport_id)
2145
0
        return FALSE;
2146
2147
780
    if (sid_key_ptr1->transport_node_id != sid_key_ptr2->transport_node_id)
2148
209
        return FALSE;
2149
2150
571
    if (sid_key_ptr1->dof_id != sid_key_ptr2->dof_id)
2151
0
        return FALSE;
2152
2153
571
    if (sid_key_ptr1->dof_node_id != sid_key_ptr2->dof_node_id)
2154
0
        return FALSE;
2155
2156
571
    if (sid_key_ptr1->dof_session_id != sid_key_ptr2->dof_session_id)
2157
0
        return FALSE;
2158
2159
571
    return TRUE;
2160
571
}
2161
2162
static gboolean sid_buffer_equal_fn(const void *key1, const void *key2)
2163
44
{
2164
44
    const uint8_t *sb1 = (const uint8_t *)key1;
2165
44
    const uint8_t *sb2 = (const uint8_t *)key2;
2166
2167
44
    if (sb1[0] != sb2[0])
2168
0
        return FALSE;
2169
2170
44
    return memcmp(sb1 + 1, sb2 + 1, sb1[0]) == 0;
2171
44
}
2172
2173
static unsigned dpp_next_sid_id = 1;
2174
2175
/**
2176
 * This routine is called for each reset (file load, capture) and is responsible
2177
 * for allocating the SID support hash tables. Previous information is freed
2178
 * if needed.
2179
 */
2180
static void dpp_reset_sid_support(void)
2181
15
{
2182
15
    dpp_next_sid_id = 1;
2183
2184
15
    if (node_key_to_sid_id != NULL)
2185
0
    {
2186
0
        g_hash_table_destroy(node_key_to_sid_id);
2187
0
        node_key_to_sid_id = NULL;
2188
0
    }
2189
2190
15
    if (sid_buffer_to_sid_id != NULL)
2191
0
    {
2192
0
        g_hash_table_destroy(sid_buffer_to_sid_id);
2193
0
        sid_buffer_to_sid_id = NULL;
2194
0
    }
2195
2196
15
    if (sid_id_to_sid_buffer != NULL)
2197
0
    {
2198
0
        g_hash_table_destroy(sid_id_to_sid_buffer);
2199
0
        sid_id_to_sid_buffer = NULL;
2200
0
    }
2201
2202
    /* The value is not allocated, so does not need to be freed. */
2203
15
    node_key_to_sid_id = g_hash_table_new_full(sender_key_hash_fn, sender_key_equal_fn, g_free, NULL);
2204
15
    sid_buffer_to_sid_id = g_hash_table_new_full(sid_buffer_hash_fn, sid_buffer_equal_fn, g_free, NULL);
2205
15
    sid_id_to_sid_buffer = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
2206
15
}
2207
2208
/**
2209
 * OPERATION IDENTIFIER SUPPORT
2210
 * Operation identifiers are an extension of a SID, and represent each separate
2211
 * operation in the DOF. They are identified by a SID and an operation count.
2212
 * Like SIDs, they are independent of version (at least in meaning, the formatting
2213
 * may change).
2214
 *
2215
 * The hash is used to look up common operation information each time an operation
2216
 * is seen in any packet.
2217
 */
2218
static GHashTable *dpp_opid_to_packet_data;
2219
2220
static unsigned dpp_opid_hash_fn(const void *opid)
2221
259
{
2222
259
    const dof_2009_1_pdu_20_opid *ptr = (const dof_2009_1_pdu_20_opid *)opid;
2223
259
    return g_int_hash(&ptr->op_sid_id) + g_int_hash(&ptr->op_cnt);
2224
259
}
2225
2226
static gboolean dpp_opid_equal_fn(const void *opid1, const void *opid2)
2227
86
{
2228
86
    const dof_2009_1_pdu_20_opid *ptr1 = (const dof_2009_1_pdu_20_opid *)opid1;
2229
86
    const dof_2009_1_pdu_20_opid *ptr2 = (const dof_2009_1_pdu_20_opid *)opid2;
2230
86
    if (ptr1->op_cnt != ptr2->op_cnt)
2231
13
        return FALSE;
2232
73
    if (ptr1->op_sid_id != ptr2->op_sid_id)
2233
0
        return FALSE;
2234
2235
73
    return TRUE;
2236
73
}
2237
2238
static void dpp_reset_opid_support(void)
2239
15
{
2240
15
    if (dpp_opid_to_packet_data != NULL)
2241
0
    {
2242
        /* Clear it out. Note that this calls the destroy functions for each element. */
2243
0
        g_hash_table_destroy(dpp_opid_to_packet_data);
2244
0
        dpp_opid_to_packet_data = NULL;
2245
0
    }
2246
2247
15
    dpp_opid_to_packet_data = g_hash_table_new_full(dpp_opid_hash_fn, dpp_opid_equal_fn, NULL, NULL);
2248
15
}
2249
2250
/**
2251
 * NON-SECURE SESSION LOOKUP SUPPORT
2252
 */
2253
static GHashTable *dof_ns_session_lookup;
2254
2255
/**
2256
 * NON-SECURE DPS SESSION
2257
 * This is defined by the transport session and the DNP port information.
2258
 */
2259
typedef struct _dof_ns_session_key
2260
{
2261
    unsigned transport_session_id;
2262
    unsigned client;
2263
    unsigned server;
2264
    bool is_secure;
2265
} dof_ns_session_key;
2266
2267
static dof_session_data* dof_ns_session_retrieve(unsigned transport_session_id, unsigned client, unsigned server)
2268
352
{
2269
352
    dof_ns_session_key lookup_key;
2270
352
    dof_session_data *value;
2271
2272
    /* Build a (non-allocated) key to do the lookup. */
2273
352
    lookup_key.transport_session_id = transport_session_id;
2274
352
    lookup_key.client = client;
2275
352
    lookup_key.server = server;
2276
2277
352
    value = (dof_session_data *)g_hash_table_lookup(dof_ns_session_lookup, &lookup_key);
2278
352
    if (value)
2279
295
    {
2280
        /* We found a match. */
2281
295
        return value;
2282
295
    }
2283
2284
57
    return NULL;
2285
352
}
2286
2287
static void dof_ns_session_define(unsigned transport_session_id, unsigned client, unsigned server, dof_session_data *session_data)
2288
57
{
2289
57
    dof_ns_session_key *key;
2290
2291
    /* No match, need to add a key. */
2292
57
    key = g_new0(dof_ns_session_key, 1);
2293
57
    key->transport_session_id = transport_session_id;
2294
57
    key->client = client;
2295
57
    key->server = server;
2296
2297
    /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
2298
57
    g_hash_table_insert(dof_ns_session_lookup, key, session_data);
2299
57
}
2300
2301
/* COMMON PDU DISSECTORS */
2302
2303
/* Security.1 */
2304
static int hf_security_1_permission_type;
2305
static int hf_security_1_length;
2306
static int hf_security_1_data;
2307
2308
static const value_string dof_2008_16_permission_type[] = {
2309
    { 1, "Binding" },
2310
    { 3, "IAM" },
2311
    { 5, "ACTAS" },
2312
    { 128, "Requestor" },
2313
    { 130, "Provider" },
2314
    { 131, "Define" },
2315
    { 133, "Tunnel Domain" },
2316
    { 0, NULL }
2317
};
2318
2319
/* Security.2 */
2320
static int hf_security_2_count;
2321
static int ett_security_2_permission;
2322
static int hf_security_2_permission;
2323
2324
/* Security.3.1 */
2325
static int hf_security_3_1_credential_type;
2326
static int hf_security_3_1_stage;
2327
static int ett_security_3_1_security_node_identifier;
2328
static int hf_security_3_1_security_node_identifier;
2329
2330
/* Security.3.2 */
2331
static int hf_security_3_2_credential_type;
2332
static int hf_security_3_2_stage;
2333
static int hf_security_3_2_length;
2334
static int hf_security_3_2_public_data;
2335
2336
/* Security.4 */
2337
static int hf_security_4_l;
2338
static int hf_security_4_f;
2339
static int hf_security_4_ln;
2340
static int ett_security_4_identity;
2341
static int hf_security_4_identity;
2342
static int hf_security_4_nonce;
2343
static int ett_security_4_permission_set;
2344
static int hf_security_4_permission_set;
2345
2346
/* Security.5 */
2347
static int hf_security_5_mac;
2348
static int hf_security_5_key;
2349
2350
/* Security.6.1 */
2351
static int hf_security_6_1_desired_duration;
2352
static int ett_security_6_1_desired_security_mode;
2353
static int hf_security_6_1_desired_security_mode;
2354
static int ett_security_6_1_initiator_request;
2355
static int hf_security_6_1_initiator_request;
2356
2357
/* Security.6.2 */
2358
static int ett_security_6_2_responder_request;
2359
static int hf_security_6_2_responder_request;
2360
2361
/* Security.6.3 */
2362
static int hf_security_6_3_granted_duration;
2363
static int ett_security_6_3_session_security_scope;
2364
static int hf_security_6_3_session_security_scope;
2365
static int ett_security_6_3_initiator_validation;
2366
static int hf_security_6_3_initiator_validation;
2367
static int ett_security_6_3_responder_validation;
2368
static int hf_security_6_3_responder_validation;
2369
2370
/* Security.9 */
2371
static int hf_security_9_length;
2372
static int hf_security_9_initial_state;
2373
2374
/* Security.10 */
2375
static int hf_security_10_count;
2376
static int hf_security_10_permission_group_identifier;
2377
2378
/* Security.11 */
2379
static int hf_security_11_count;
2380
static int ett_security_11_permission_security_scope;
2381
static int hf_security_11_permission_security_scope;
2382
2383
/* Security.12 */
2384
static int hf_security_12_m;
2385
2386
static const value_string dof_2008_16_security_12_m[] = {
2387
    { 0, "Reference" },
2388
    { 1, "Relative" },
2389
    { 2, "Absolute" },
2390
    { 3, "Continued" },
2391
    { 0, NULL }
2392
};
2393
2394
static int hf_security_12_count;
2395
static int hf_security_12_permission_group_identifier;
2396
2397
static bool
2398
dof_sessions_destroy_cb(wmem_allocator_t *allocator _U_, wmem_cb_event_t event _U_, void *user_data)
2399
0
{
2400
0
    ccm_session_data *ccm_data = (ccm_session_data*) user_data;
2401
0
    gcry_cipher_close(ccm_data->cipher_data);
2402
0
    if (ccm_data->cipher_data_table) {
2403
0
        g_hash_table_destroy(ccm_data->cipher_data_table);
2404
0
    }
2405
    /* unregister this callback */
2406
0
    return false;
2407
0
}
2408
2409
static void dof_cipher_data_destroy (void *data)
2410
0
{
2411
0
    gcry_cipher_hd_t cipher_data = (gcry_cipher_hd_t) data;
2412
0
    gcry_cipher_close(cipher_data);
2413
0
}
2414
2415
static int dissect_2008_1_dsp_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2416
204
{
2417
204
    proto_item *parent = proto_tree_get_parent(tree);
2418
204
    uint8_t attribute_code = tvb_get_uint8(tvb, 0);
2419
204
    uint16_t attribute_data = tvb_get_ntohs(tvb, 1);
2420
204
    uint8_t option_length = tvb_get_uint8(tvb, 3);
2421
2422
    /* Add the generic representation of the fields. */
2423
204
    proto_tree_add_item(tree, hf_2008_1_dsp_attribute_code, tvb, 0, 1, ENC_NA);
2424
204
    proto_tree_add_item(tree, hf_2008_1_dsp_attribute_data, tvb, 1, 2, ENC_BIG_ENDIAN);
2425
204
    proto_tree_add_item(tree, hf_2008_1_dsp_value_length, tvb, 3, 1, ENC_NA);
2426
2427
    /* Append description to the parent. */
2428
204
    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);
2429
2430
204
    if (option_length)
2431
98
    {
2432
98
        proto_tree_add_item(tree, hf_2008_1_dsp_value_data, tvb, 4, option_length, ENC_NA);
2433
2434
        /* call the next dissector */
2435
98
        tvb_set_reported_length(tvb, option_length + 4);
2436
98
        dissector_try_uint(dsp_option_dissectors, (attribute_code << 16) | attribute_data, tvb, pinfo, tree);
2437
98
    }
2438
204
    return option_length + 4;
2439
204
}
2440
2441
/**
2442
 * Security.1: Permission. This is the base type for
2443
 * permissions, and supports extension.
2444
 */
2445
static int dissect_2008_16_security_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2446
763
{
2447
763
    int offset = 0;
2448
763
    bool has_length;
2449
763
    uint16_t length;
2450
2451
    /* Permission Type */
2452
763
    {
2453
763
        int start = offset;
2454
763
        uint16_t value;
2455
763
        int val_len;
2456
763
        proto_item *pi;
2457
763
        offset = read_c2(tvb, offset, &value, &val_len);
2458
763
        has_length = (bool)(value % 2);
2459
763
        pi = proto_tree_add_uint(tree, hf_security_1_permission_type, tvb, start, offset - start, value);
2460
763
        validate_c2(pinfo, pi, value, val_len);
2461
763
    }
2462
2463
763
    if (!has_length)
2464
672
        return offset;
2465
2466
    /* Length */
2467
91
    {
2468
91
        int start = offset;
2469
91
        uint16_t value;
2470
91
        int value_len;
2471
91
        proto_item *pi;
2472
91
        offset = read_c2(tvb, offset, &value, &value_len);
2473
91
        length = value;
2474
91
        pi = proto_tree_add_uint(tree, hf_security_1_length, tvb, start, offset - start, value);
2475
91
        validate_c2(pinfo, pi, value, value_len);
2476
91
    }
2477
2478
    /* Data */
2479
91
    proto_tree_add_item(tree, hf_security_1_data, tvb, offset, length, ENC_NA);
2480
91
    offset += length;
2481
2482
91
    return offset;
2483
763
}
2484
2485
/**
2486
 * Security.2: Permission Request.
2487
 */
2488
static int dissect_2008_16_security_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2489
79
{
2490
79
    int offset = 0;
2491
79
    uint16_t count;
2492
2493
    /* Count */
2494
79
    {
2495
79
        int start = offset;
2496
79
        uint16_t value;
2497
79
        int length;
2498
79
        proto_item *pi;
2499
79
        offset = read_c2(tvb, offset, &value, &length);
2500
79
        count = value;
2501
79
        pi = proto_tree_add_uint(tree, hf_security_2_count, tvb, start, offset - start, value);
2502
79
        validate_c2(pinfo, pi, value, length);
2503
79
    }
2504
2505
843
    while (count--)
2506
764
    {
2507
764
        proto_item *ti = proto_tree_add_item(tree, hf_security_2_permission, tvb, offset, -1, ENC_NA);
2508
764
        proto_tree *subtree = proto_item_add_subtree(ti, ett_security_2_permission);
2509
764
        tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
2510
764
        int len = dissect_2008_16_security_1(next_tvb, pinfo, subtree, NULL);
2511
764
        proto_item_set_len(ti, len);
2512
764
        offset += len;
2513
764
    }
2514
2515
79
    return offset;
2516
79
}
2517
2518
/**
2519
 * Security.3.1: Base Credential Format.
2520
 * Returns: dof_2008_16_security_3_1
2521
 */
2522
static int dissect_2008_16_security_3_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2523
17
{
2524
17
    int offset = 0;
2525
17
    uint8_t stage;
2526
17
    proto_item *ti;
2527
17
    dof_2008_16_security_3_1 *return_data = (dof_2008_16_security_3_1 *)data;
2528
2529
    /* Credential Type */
2530
17
    {
2531
17
        int start = offset;
2532
17
        uint16_t value;
2533
17
        int length;
2534
17
        proto_item *pi;
2535
17
        offset = read_c2(tvb, offset, &value, &length);
2536
17
        pi = proto_tree_add_uint(tree, hf_security_3_1_credential_type, tvb, start, offset - start, value);
2537
17
        validate_c2(pinfo, pi, value, length);
2538
17
    }
2539
2540
    /* Stage */
2541
17
    ti = proto_tree_add_item_ret_uint8(tree, hf_security_3_1_stage, tvb, offset, 1, ENC_NA, &stage);
2542
17
    offset += 1;
2543
2544
17
    if (stage != 0)
2545
14
        expert_add_info(pinfo, ti, &ei_security_3_1_invalid_stage);
2546
2547
    /* Security Node Identifier */
2548
17
    {
2549
17
        int block_length;
2550
17
        tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2551
17
        proto_tree *subtree;
2552
17
        ti = proto_tree_add_item(tree, hf_security_3_1_security_node_identifier, tvb, offset, 0, ENC_NA);
2553
17
        subtree = proto_item_add_subtree(ti, ett_security_3_1_security_node_identifier);
2554
17
        block_length = dissect_2008_16_security_8(start, pinfo, subtree, NULL);
2555
17
        proto_item_set_len(ti, block_length);
2556
17
        offset += block_length;
2557
17
        tvb_set_reported_length(start, block_length);
2558
17
        if (return_data)
2559
13
            return_data->identity = start;
2560
17
    }
2561
2562
17
    return offset;
2563
17
}
2564
2565
/**
2566
 * Security.3.2: Identity Resolution.
2567
 */
2568
int dissect_2008_16_security_3_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2569
0
{
2570
0
    int offset = 0;
2571
0
    uint16_t length;
2572
2573
    /* Credential Type */
2574
0
    {
2575
0
        int start = offset;
2576
0
        uint16_t value;
2577
0
        int val_len;
2578
0
        proto_item *pi;
2579
0
        offset = read_c2(tvb, offset, &value, &val_len);
2580
0
        pi = proto_tree_add_uint(tree, hf_security_3_2_credential_type, tvb, start, offset - start, value);
2581
0
        validate_c2(pinfo, pi, value, val_len);
2582
0
    }
2583
2584
    /* Stage */
2585
0
    proto_tree_add_item(tree, hf_security_3_2_stage, tvb, offset, 1, ENC_NA);
2586
0
    offset += 1;
2587
2588
    /* Length */
2589
0
    {
2590
0
        int start = offset;
2591
0
        uint16_t value;
2592
0
        int value_len;
2593
0
        proto_item *pi;
2594
0
        offset = read_c2(tvb, offset, &value, &value_len);
2595
0
        length = value;
2596
0
        pi = proto_tree_add_uint(tree, hf_security_3_2_length, tvb, start, offset - start, value);
2597
0
        validate_c2(pinfo, pi, value, value_len);
2598
0
    }
2599
2600
    /* Public Data */
2601
0
    proto_tree_add_item(tree, hf_security_3_2_public_data, tvb, offset, length, ENC_NA);
2602
0
    offset += length;
2603
2604
0
    return offset;
2605
0
}
2606
2607
/**
2608
 * Security.4: Key Request. Returns: dof_2008_16_security_4
2609
 */
2610
static int dissect_2008_16_security_4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2611
17
{
2612
17
    int offset = 0;
2613
17
    uint8_t flag;
2614
17
    dof_2008_16_security_4 *return_data = (dof_2008_16_security_4 *)data;
2615
2616
17
    flag = tvb_get_uint8(tvb, offset);
2617
17
    if (flag & 0x30)
2618
12
        expert_add_info(pinfo, tree, &ei_security_4_invalid_bit);
2619
2620
17
    proto_tree_add_item(tree, hf_security_4_l, tvb, offset, 1, ENC_NA);
2621
17
    proto_tree_add_item(tree, hf_security_4_f, tvb, offset, 1, ENC_NA);
2622
17
    proto_tree_add_item(tree, hf_security_4_ln, tvb, offset, 1, ENC_NA);
2623
17
    offset += 1;
2624
2625
17
    {
2626
17
        int block_length;
2627
17
        tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2628
17
        proto_item *ti;
2629
17
        proto_tree *subtree;
2630
17
        dof_2008_16_security_3_1 return_3_1;
2631
2632
17
        ti = proto_tree_add_item(tree, hf_security_4_identity, tvb, offset, 0, ENC_NA);
2633
17
        subtree = proto_item_add_subtree(ti, ett_security_4_identity);
2634
2635
17
        block_length = dissect_2008_16_security_3_1(start, pinfo, subtree, &return_3_1);
2636
17
        proto_item_set_len(ti, block_length);
2637
17
        offset += block_length;
2638
17
        if (return_data)
2639
13
        {
2640
13
            return_data->identity = return_3_1.identity;
2641
13
        }
2642
17
    }
2643
2644
17
    {
2645
17
        tvbuff_t *start = tvb_new_subset_length(tvb, offset, (flag & 0x0F) + 1);
2646
17
        if (return_data)
2647
13
            return_data->nonce = start;
2648
2649
17
        proto_tree_add_item(tree, hf_security_4_nonce, start, 0, (flag & 0x0F) + 1, ENC_NA);
2650
17
        offset += (flag & 0x0F) + 1;
2651
17
    }
2652
2653
17
    {
2654
17
        int block_length;
2655
17
        tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2656
17
        proto_item *ti;
2657
17
        proto_tree *subtree;
2658
2659
17
        ti = proto_tree_add_item(tree, hf_security_4_permission_set, tvb, offset, 0, ENC_NA);
2660
17
        subtree = proto_item_add_subtree(ti, ett_security_4_permission_set);
2661
17
        block_length = dissect_2008_16_security_2(start, pinfo, subtree, NULL);
2662
17
        proto_item_set_len(ti, block_length);
2663
17
        offset += block_length;
2664
17
    }
2665
2666
17
    return offset;
2667
17
}
2668
2669
/**
2670
 * Security.5: Key Grant.
2671
 */
2672
static int dissect_2008_16_security_5(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
2673
109
{
2674
109
    int offset = 0;
2675
2676
109
    proto_tree_add_item(tree, hf_security_5_mac, tvb, offset, 32, ENC_NA);
2677
109
    offset += 32;
2678
2679
109
    proto_tree_add_item(tree, hf_security_5_key, tvb, offset, 32, ENC_NA);
2680
109
    offset += 32;
2681
2682
109
    return offset;
2683
109
}
2684
2685
/**
2686
 * Security.6.1: Session Initiator Block.
2687
 * Returns dof_2008_16_security_6_1
2688
 */
2689
static int dissect_2008_16_security_6_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2690
1
{
2691
1
    int offset = 0;
2692
2693
    /* Allocate the return structure. */
2694
1
    dof_2008_16_security_6_1 *return_data = (dof_2008_16_security_6_1 *)data;
2695
2696
    /* Desired Duration */
2697
1
    proto_tree_add_item(tree, hf_security_6_1_desired_duration, tvb, offset, 1, ENC_NA);
2698
1
    offset += 1;
2699
2700
    /* Desired Security Mode */
2701
1
    {
2702
1
        int block_length;
2703
1
        tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2704
1
        proto_item *ti;
2705
1
        proto_tree *subtree;
2706
2707
1
        ti = proto_tree_add_item(tree, hf_security_6_1_desired_security_mode, tvb, offset, 0, ENC_NA);
2708
1
        subtree = proto_item_add_subtree(ti, ett_security_6_1_desired_security_mode);
2709
2710
1
        block_length = dissect_2008_16_security_13(start, pinfo, subtree, NULL);
2711
1
        offset += block_length;
2712
1
        tvb_set_reported_length(start, block_length);
2713
1
        proto_item_set_len(ti, block_length);
2714
2715
1
        if (return_data)
2716
0
        {
2717
0
            return_data->security_mode = tvb_get_ntohs(start, 1);
2718
0
            return_data->security_mode_data_length = block_length - 4;
2719
0
            return_data->security_mode_data = (uint8_t *)tvb_memdup(wmem_file_scope(), start, 4, block_length - 4);
2720
0
        }
2721
1
    }
2722
2723
    /* Initiator Request */
2724
1
    {
2725
1
        int block_length;
2726
1
        dof_2008_16_security_4 output;
2727
1
        tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2728
1
        proto_item *ti;
2729
1
        proto_tree *subtree;
2730
2731
1
        ti = proto_tree_add_item(tree, hf_security_6_1_initiator_request, tvb, offset, 0, ENC_NA);
2732
1
        subtree = proto_item_add_subtree(ti, ett_security_6_1_initiator_request);
2733
2734
1
        block_length = dissect_2008_16_security_4(start, pinfo, subtree, &output);
2735
1
        proto_item_set_len(ti, block_length);
2736
1
        offset += block_length;
2737
1
        if (return_data)
2738
0
        {
2739
0
            return_data->i_identity = output.identity;
2740
0
            return_data->i_nonce = output.nonce;
2741
0
        }
2742
1
    }
2743
2744
1
    return offset;
2745
1
}
2746
2747
/**
2748
 * Security.6.2: Session Responder Block.
2749
 * Returns dof_2008_16_security_6_2
2750
 */
2751
static int dissect_2008_16_security_6_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2752
1
{
2753
1
    int offset = 0;
2754
1
    dof_2008_16_security_6_2 *return_data = (dof_2008_16_security_6_2 *)data;
2755
2756
    /* Responder Request */
2757
1
    {
2758
1
        int block_length;
2759
1
        dof_2008_16_security_4 output;
2760
1
        tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2761
1
        proto_item *ti;
2762
1
        proto_tree *subtree;
2763
2764
1
        ti = proto_tree_add_item(tree, hf_security_6_2_responder_request, tvb, offset, 0, ENC_NA);
2765
1
        subtree = proto_item_add_subtree(ti, ett_security_6_2_responder_request);
2766
2767
1
        block_length = dissect_2008_16_security_4(start, pinfo, subtree, &output);
2768
1
        proto_item_set_len(ti, block_length);
2769
1
        offset += block_length;
2770
1
        if (return_data)
2771
0
        {
2772
0
            return_data->r_identity = output.identity;
2773
0
            return_data->r_nonce = output.nonce;
2774
0
        }
2775
1
    }
2776
2777
1
    return offset;
2778
1
}
2779
2780
/**
2781
 * Security.6.3: Authentication Response Block.
2782
 */
2783
static int dissect_2008_16_security_6_3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2784
0
{
2785
0
    int offset = 0;
2786
2787
    /* Granted Duration */
2788
0
    proto_tree_add_item(tree, hf_security_6_3_granted_duration, tvb, offset, 1, ENC_NA);
2789
0
    offset += 1;
2790
2791
    /* Session Security Scope */
2792
0
    {
2793
0
        int block_length;
2794
0
        tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2795
0
        proto_item *ti;
2796
0
        proto_tree *subtree;
2797
2798
0
        ti = proto_tree_add_item(tree, hf_security_6_3_session_security_scope, tvb, offset, 0, ENC_NA);
2799
0
        subtree = proto_item_add_subtree(ti, ett_security_6_3_session_security_scope);
2800
0
        block_length = dissect_2008_16_security_10(start, pinfo, subtree, NULL);
2801
0
        proto_item_set_len(ti, block_length);
2802
0
        offset += block_length;
2803
0
    }
2804
2805
    /* Initiator Validation */
2806
0
    {
2807
0
        int block_length;
2808
0
        tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2809
0
        proto_item *ti;
2810
0
        proto_tree *subtree;
2811
2812
0
        ti = proto_tree_add_item(tree, hf_security_6_3_initiator_validation, tvb, offset, 0, ENC_NA);
2813
0
        subtree = proto_item_add_subtree(ti, ett_security_6_3_initiator_validation);
2814
0
        block_length = dissect_2008_16_security_11(start, pinfo, subtree, NULL);
2815
0
        proto_item_set_len(ti, block_length);
2816
0
        offset += block_length;
2817
0
    }
2818
2819
    /* Responder Validation */
2820
0
    {
2821
0
        int block_length;
2822
0
        tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2823
0
        proto_item *ti;
2824
0
        proto_tree *subtree;
2825
2826
0
        ti = proto_tree_add_item(tree, hf_security_6_3_responder_validation, tvb, offset, 0, ENC_NA);
2827
0
        subtree = proto_item_add_subtree(ti, ett_security_6_3_responder_validation);
2828
0
        block_length = dissect_2008_16_security_11(start, pinfo, subtree, NULL);
2829
0
        proto_item_set_len(ti, block_length);
2830
0
        offset += block_length;
2831
0
    }
2832
2833
0
    return offset;
2834
0
}
2835
2836
/**
2837
 * Security.7: Security Domain.
2838
 */
2839
static int dissect_2008_16_security_7(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2840
17
{
2841
    /* Parse the base type. */
2842
17
    int block_length;
2843
2844
17
    block_length = dissect_2009_11_type_4(tvb, pinfo, tree, NULL);
2845
2846
17
    return block_length;
2847
17
}
2848
2849
/**
2850
 * Security.8: Security Node Identifier.
2851
 */
2852
static int dissect_2008_16_security_8(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2853
22
{
2854
    /* Parse the base type. */
2855
22
    int block_length;
2856
2857
22
    block_length = dissect_2009_11_type_4(tvb, pinfo, tree, NULL);
2858
2859
22
    return block_length;
2860
22
}
2861
2862
/**
2863
 * Security.9: Security Mode of Operation Initialization.
2864
 * If the packet info has knowledge of the active security mode
2865
 * of operation then this datagram can be further decoded.
2866
 */
2867
static int dissect_2008_16_security_9(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2868
1
{
2869
1
    int offset = 0;
2870
1
    uint16_t length;
2871
2872
    /* Length */
2873
1
    {
2874
1
        int start = offset;
2875
1
        uint16_t value;
2876
1
        int value_len;
2877
1
        proto_item *pi;
2878
1
        offset = read_c2(tvb, offset, &value, &value_len);
2879
1
        length = value;
2880
1
        pi = proto_tree_add_uint(tree, hf_security_9_length, tvb, start, offset - start, value);
2881
1
        validate_c2(pinfo, pi, value, value_len);
2882
1
    }
2883
2884
1
    if (length > 0)
2885
1
    {
2886
1
        proto_tree_add_item(tree, hf_security_9_initial_state, tvb, offset, length, ENC_NA);
2887
1
        offset += length;
2888
1
    }
2889
2890
1
    return offset;
2891
1
}
2892
2893
/**
2894
 * Security.10: Security Scope.
2895
 */
2896
static int dissect_2008_16_security_10(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2897
127
{
2898
127
    int offset = 0;
2899
127
    uint16_t count;
2900
2901
    /* Count */
2902
127
    {
2903
127
        int start = offset;
2904
127
        uint16_t value;
2905
127
        int length;
2906
127
        proto_item *pi;
2907
127
        offset = read_c2(tvb, offset, &value, &length);
2908
127
        count = value;
2909
127
        pi = proto_tree_add_uint(tree, hf_security_10_count, tvb, start, offset - start, value);
2910
127
        validate_c2(pinfo, pi, value, length);
2911
127
    }
2912
2913
4.96k
    while (count--)
2914
4.87k
    {
2915
4.87k
        const char *def = "";
2916
2917
4.87k
        int start = offset;
2918
4.87k
        uint32_t value;
2919
4.87k
        int length;
2920
4.87k
        proto_item *pi;
2921
2922
4.87k
        offset = read_c4(tvb, offset, &value, &length);
2923
2924
4.87k
        switch (value)
2925
4.87k
        {
2926
192
        case 0x3FFFFFFF:
2927
192
            def = " (all scopes)";
2928
192
            break;
2929
0
        case 0x3FFFFFFE:
2930
0
            def = " (doesn't mask)";
2931
0
            break;
2932
0
        case 0x3FFFFFFD:
2933
0
            def = " (session scope)";
2934
0
            break;
2935
4.87k
        }
2936
2937
4.83k
        pi = proto_tree_add_uint_format_value(tree, hf_security_10_permission_group_identifier, tvb, start, offset - start, value, "%u%s", value, def);
2938
4.83k
        validate_c4(pinfo, pi, value, length);
2939
4.83k
    }
2940
2941
94
    return offset;
2942
127
}
2943
2944
/**
2945
 * Security.11: Permission Validation.
2946
 */
2947
static int dissect_2008_16_security_11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2948
84
{
2949
84
    int offset = 0;
2950
84
    uint16_t count;
2951
2952
    /* Count */
2953
84
    {
2954
84
        int start = offset;
2955
84
        uint16_t value;
2956
84
        int length;
2957
84
        proto_item *pi;
2958
84
        offset = read_c2(tvb, offset, &value, &length);
2959
84
        count = value;
2960
84
        pi = proto_tree_add_uint(tree, hf_security_11_count, tvb, start, offset - start, value);
2961
84
        validate_c2(pinfo, pi, value, length);
2962
84
    }
2963
2964
1.27k
    while (count--)
2965
1.18k
    {
2966
1.18k
        proto_item *ti = proto_tree_add_item(tree, hf_security_11_permission_security_scope, tvb, offset, -1, ENC_NA);
2967
1.18k
        proto_tree *subtree = proto_item_add_subtree(ti, ett_security_11_permission_security_scope);
2968
1.18k
        tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
2969
1.18k
        int len;
2970
1.18k
        len = dissect_2008_16_security_12(next_tvb, pinfo, subtree, NULL);
2971
1.18k
        proto_item_set_len(ti, len);
2972
1.18k
        offset += len;
2973
1.18k
    }
2974
2975
84
    return offset;
2976
84
}
2977
2978
/**
2979
 * Security.12: Permission Security Scope.
2980
 */
2981
static int dissect_2008_16_security_12(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2982
1.18k
{
2983
1.18k
    int offset = 0;
2984
1.18k
    uint8_t m = tvb_get_uint8(tvb, offset) >> 6;
2985
1.18k
    uint16_t count = tvb_get_uint8(tvb, offset) & 0x3F;
2986
1.18k
    proto_item *pi;
2987
2988
1.18k
    proto_tree_add_item(tree, hf_security_12_m, tvb, offset, 1, ENC_NA);
2989
1.18k
    proto_tree_add_item(tree, hf_security_12_count, tvb, offset, 1, ENC_NA);
2990
1.18k
    offset += 1;
2991
2992
1.18k
    if (m == 0)
2993
916
        return offset;
2994
2995
4.36k
    while (count--)
2996
4.14k
    {
2997
4.14k
        const char *def = "";
2998
2999
4.14k
        int start = offset;
3000
4.14k
        uint32_t value;
3001
4.14k
        int length;
3002
4.14k
        offset = read_c4(tvb, offset, &value, &length);
3003
3004
4.14k
        switch (value)
3005
4.14k
        {
3006
423
        case 0x3FFFFFFF:
3007
423
            def = " (all scopes)";
3008
423
            break;
3009
0
        case 0x3FFFFFFE:
3010
0
            def = " (doesn't mask)";
3011
0
            break;
3012
0
        case 0x3FFFFFFD:
3013
0
            def = " (session scope)";
3014
0
            break;
3015
4.14k
        }
3016
3017
4.10k
        pi = proto_tree_add_uint_format_value(tree, hf_security_12_permission_group_identifier, tvb, start, offset - start, value, "%u%s", value, def);
3018
4.10k
        validate_c4(pinfo, pi, value, length);
3019
4.10k
    }
3020
3021
226
    return offset;
3022
265
}
3023
3024
/**
3025
 * Security.13: Security Mode of Operation Negotiation.
3026
 */
3027
static int dissect_2008_16_security_13(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
3028
73
{
3029
    /* Parse the base type. */
3030
73
    int block_length;
3031
73
    uint16_t attribute_data;
3032
3033
    /* TODO: Skipping this first byte means that no other encryption modes can be supported. */
3034
73
    attribute_data = tvb_get_ntohs(tvb, 1);
3035
73
    if (attribute_data < 0x6000 || attribute_data >= 0x7000)
3036
72
        expert_add_info(pinfo, tree, &ei_security_13_out_of_range);
3037
3038
73
    block_length = dissect_2008_1_dsp_1(tvb, pinfo, tree);
3039
3040
73
    return block_length;
3041
73
}
3042
3043
/**
3044
 * Dissects a buffer that is pointing at an OID.
3045
 * Adds a subtree with detailed information about the fields of
3046
 * the OID,
3047
 * returns the length of the OID,
3048
 * and appends text to the tree (really a tree item) that is
3049
 * passed in that gives a more accurate description of the OID.
3050
 * Note that the tree already shows the bytes of the OID, so if
3051
 * no additional information can be displayed then it should not
3052
 * be.
3053
 *
3054
 * If 'tree' is NULL then just return the length.
3055
 */
3056
// NOLINTNEXTLINE(misc-no-recursion)
3057
static int dissect_2009_11_type_4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
3058
1.55k
{
3059
1.55k
    proto_item *ti;
3060
1.55k
    int start_offset = 0;
3061
1.55k
    int offset = 0;
3062
1.55k
    uint32_t oid_class;
3063
1.55k
    int oid_class_len;
3064
1.55k
    uint8_t oid_len_byte;
3065
1.55k
    proto_tree *oid_tree = tree;
3066
1.55k
    proto_tree *header_tree;
3067
3068
1.55k
    if (tree)
3069
1.55k
    {
3070
1.55k
        ti = proto_tree_get_parent(tree);
3071
1.55k
        proto_item_set_text(ti, "Object ID: %s", dof_oid_create_standard_string(pinfo->pool, tvb_reported_length(tvb), tvb_get_ptr(tvb, 0, tvb_reported_length(tvb)), pinfo));
3072
1.55k
    }
3073
3074
1.55k
    offset = read_c4(tvb, offset, &oid_class, &oid_class_len);
3075
1.55k
    ti = proto_tree_add_uint_format(oid_tree, hf_oid_class, tvb, start_offset, offset - start_offset, oid_class, "Class: %u", oid_class);
3076
1.55k
    validate_c4(pinfo, ti, oid_class, oid_class_len);
3077
3078
1.55k
    oid_len_byte = tvb_get_uint8(tvb, offset);
3079
1.55k
    ti = proto_tree_add_uint_format(oid_tree, hf_oid_header, tvb,
3080
1.55k
                                    offset, 1, oid_len_byte, "Header: 0x%02x (%sLength=%d)", oid_len_byte, oid_len_byte & 0x80 ? "Attribute, " : "", oid_len_byte & 0x3F);
3081
3082
1.55k
    header_tree = proto_item_add_subtree(ti, ett_oid_header);
3083
1.55k
    proto_tree_add_item(header_tree, hf_oid_attribute, tvb, offset, 1, ENC_NA);
3084
1.55k
    proto_tree_add_item(header_tree, hf_oid_length, tvb, offset, 1, ENC_NA);
3085
1.55k
    offset += 1;
3086
3087
    /* Validate the flag byte */
3088
1.55k
    if (oid_len_byte & 0x40)
3089
288
    {
3090
        /* Type.4 Malformed (bit mandated zero). */
3091
288
        expert_add_info(pinfo, ti, &ei_type_4_header_zero);
3092
288
    }
3093
3094
1.55k
    if ((oid_len_byte & 0x3F) > 0)
3095
843
    {
3096
        /* Add the raw data. */
3097
843
        proto_tree_add_item(oid_tree, hf_oid_data, tvb, offset, oid_len_byte & 0x3F, ENC_NA);
3098
843
        offset += oid_len_byte & 0x3F;
3099
843
    }
3100
3101
    /* Check for attributes */
3102
1.55k
    if (oid_len_byte & 0x80)
3103
225
    {
3104
        /* Read attributes, adding them to oid_tree. */
3105
225
        uint8_t flag;
3106
3107
225
        do
3108
325
        {
3109
325
            tvbuff_t *packet = tvb_new_subset_remaining(tvb, offset);
3110
325
            proto_tree *attribute_tree;
3111
325
            int attribute_length;
3112
3113
325
            ti = proto_tree_add_item(tree, hf_oid_all_attribute_data, tvb, offset, -1, ENC_NA);
3114
325
            attribute_tree = proto_item_add_subtree(ti, ett_oid_attribute);
3115
325
            flag = tvb_get_uint8(tvb, offset);
3116
325
            increment_dissection_depth(pinfo);
3117
325
            attribute_length = dissect_2009_11_type_5(packet, pinfo, attribute_tree);
3118
325
            decrement_dissection_depth(pinfo);
3119
325
            proto_item_set_len(ti, (const int)attribute_length);
3120
325
            offset += attribute_length;
3121
325
        }
3122
325
        while (flag & 0x80);
3123
225
    }
3124
3125
1.55k
    if (tree)
3126
1.43k
    {
3127
1.43k
        ti = proto_tree_get_parent(tree);
3128
1.43k
        proto_item_set_len(ti, offset - start_offset);
3129
1.43k
    }
3130
3131
    /* TODO: Add the description. */
3132
    /* proto_item_append_text( oid_tree, ": %s", "TODO" ); */
3133
1.55k
    return offset;
3134
1.55k
}
3135
3136
/**
3137
 * Dissects a buffer that is pointing at an attribute.
3138
 * Adds a subtree with detailed information about the fields of
3139
 * the attribute,
3140
 * returns the new offset,
3141
 * and appends text to the tree (really a tree item) that is
3142
 * passed in that gives a more accurate description of the
3143
 * attribute.
3144
 * Note that the tree already shows the bytes of the OID, so if
3145
 * no additional information can be displayed then it should not
3146
 * be.
3147
 *
3148
 * If 'tree' is NULL then just return the length.
3149
 */
3150
// NOLINTNEXTLINE(misc-no-recursion)
3151
static int dissect_2009_11_type_5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3152
325
{
3153
325
    proto_item *ti;
3154
325
    int offset = 0;
3155
325
    uint8_t attribute_id_byte;
3156
325
    uint8_t attribute_length_byte;
3157
325
    proto_tree *oid_tree = tree;
3158
325
    proto_tree *header_tree;
3159
3160
325
    attribute_id_byte = tvb_get_uint8(tvb, offset);
3161
325
    ti = proto_tree_add_uint_format(oid_tree, hf_oid_attribute_header, tvb,
3162
325
                                    offset, 1, attribute_id_byte, "Header: 0x%02x (%sLength=%d)", attribute_id_byte, attribute_id_byte & 0x80 ? "Attribute, " : "", attribute_id_byte & 0x3F);
3163
3164
325
    header_tree = proto_item_add_subtree(ti, ett_oid_attribute_header);
3165
325
    proto_tree_add_item(header_tree, hf_oid_attribute_attribute, tvb, offset, 1, ENC_NA);
3166
325
    proto_tree_add_item(header_tree, hf_oid_attribute_id, tvb, offset, 1, ENC_NA);
3167
325
    offset += 1;
3168
3169
325
    attribute_length_byte = tvb_get_uint8(tvb, offset);
3170
325
    proto_tree_add_item(oid_tree, hf_oid_attribute_length, tvb, offset, 1, ENC_NA);
3171
325
    offset += 1;
3172
3173
325
    switch (attribute_id_byte & 0x7F)
3174
325
    {
3175
18
    case 1:
3176
        /* TODO: Check length */
3177
18
        proto_tree_add_item(oid_tree, hf_oid_attribute_data, tvb, offset, attribute_length_byte, ENC_NA);
3178
18
        offset += attribute_length_byte;
3179
18
        break;
3180
3181
43
    case 0:
3182
50
    case 2:
3183
50
    {
3184
50
        tvbuff_t *packet = tvb_new_subset_length(tvb, offset, attribute_length_byte);
3185
50
        proto_tree *attribute_tree;
3186
3187
50
        ti = proto_tree_add_item(tree, hf_oid_attribute_oid, tvb, offset, -1, ENC_NA);
3188
50
        attribute_tree = proto_item_add_subtree(ti, ett_oid_attribute_oid);
3189
50
        increment_dissection_depth(pinfo);
3190
50
        offset += dissect_2009_11_type_4(packet, pinfo, attribute_tree, NULL);
3191
50
        decrement_dissection_depth(pinfo);
3192
50
    }
3193
50
        break;
3194
3195
256
    default:
3196
256
        proto_tree_add_item(oid_tree, hf_oid_attribute_data, tvb, offset, attribute_length_byte, ENC_NA);
3197
256
        offset += attribute_length_byte;
3198
325
    }
3199
3200
280
    return offset;
3201
325
}
3202
3203
3204
/* Transport Session ID */
3205
static dof_globals globals;
3206
3207
/* Static Methods. */
3208
3209
static dof_packet_data* create_packet_data(packet_info *pinfo);
3210
static int dof_dissect_dnp_length(tvbuff_t *tvb, packet_info *pinfo, uint8_t version, int *offset);
3211
0
#define VALIDHEX(c) ( ((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f') )
3212
3213
3214
/* Configuration structures. These tables allow for security
3215
 * mode templates, security keys, and secrets to be configured.
3216
 */
3217
3218
static bool decrypt_all_packets;
3219
static bool track_operations;
3220
static unsigned track_operations_window = 5;
3221
static uint32_t next_dof_frame = 1;
3222
3223
/* Structure for security mode of operation templates. */
3224
typedef struct _secmode_field_t {
3225
    char *domain;
3226
    char *identity;
3227
    char *kek;
3228
} secmode_field_t;
3229
3230
static secmode_field_t *secmode_list;
3231
static unsigned num_secmode_list;
3232
3233
/* Structure for security keys. */
3234
typedef struct _seckey_field_t {
3235
    char *key;
3236
} seckey_field_t;
3237
3238
/* Structure for secrets (for identities) */
3239
typedef struct _identsecret_field_t {
3240
    char *domain;
3241
    char *identity;
3242
    char *secret;
3243
} identsecret_field_t;
3244
3245
typedef struct _tcp_ignore_data
3246
{
3247
    uint32_t sequence;
3248
    bool ignore;
3249
    struct _tcp_ignore_data *next;
3250
} tcp_ignore_data;
3251
3252
typedef struct _tcp_dof_packet_ref
3253
{
3254
    /* A single TCP frame can contain multiple packets. We must
3255
     * be able to keep track of them all.
3256
     */
3257
    dof_api_data api_data;
3258
3259
    uint16_t start_offset;
3260
    dof_transport_packet transport_packet;
3261
    struct _tcp_dof_packet_ref *next;
3262
} tcp_dof_packet_ref;
3263
3264
/**
3265
 * This structure exists for TCP packets and allows matching Wireshark frames to
3266
 * DPS packets.
3267
 */
3268
typedef struct _tcp_packet_data
3269
{
3270
    /* Packets are ignored based on the starting TCP SEQ (sequence of first byte). */
3271
    tcp_ignore_data *from_client_ignore_list;
3272
    tcp_ignore_data *from_server_ignore_list;
3273
3274
    /* DPS packet structures contained within a TCP frame. */
3275
    tcp_dof_packet_ref *dof_packets;
3276
} tcp_packet_data;
3277
3278
/**
3279
 * This structure exists for UDP sessions and allows for advanced stream handling
3280
 * and matching Wireshark frames to DPS packets.
3281
 */
3282
typedef struct _udp_session_data
3283
{
3284
    /* This must be the first structure, as a pointer to this type is stored in each DPS packet. */
3285
    dof_transport_session common;
3286
3287
    /* For the associated TCP conversation, this tracks the client and server
3288
     * addresses.
3289
     */
3290
    ws_node server;
3291
} udp_session_data;
3292
3293
/* This structure exists for TCP sessions and allows for advanced stream handling
3294
 * and matching Wireshark frames to DPS packets.
3295
 */
3296
typedef struct _tcp_session_data
3297
{
3298
    /* This must be the first structure, as a pointer to this type is stored in each DPS packet. */
3299
    dof_transport_session common;
3300
3301
    /* This flag is used to determine that an entire TCP session is NOT OpenDOF.
3302
     * Because of TCP/IP negotiation in the DPS it is easy to confuse arbitrary
3303
     * protocols as OpenDOF. Once it is determined that it is not then this
3304
     * flag can be set, which will turn off all the OpenDOF dissectors.
3305
     */
3306
    bool not_dps;
3307
3308
    /* For the associated TCP conversation, this tracks the client and server
3309
     * addresses.
3310
     */
3311
    ws_node client, server;
3312
3313
    /* TCP sequence numbers, used to detect retransmissions. These are only valid
3314
     * during the first pass through the packets.
3315
     */
3316
    uint32_t from_client_seq;
3317
    uint32_t from_server_seq;
3318
3319
} tcp_session_data;
3320
3321
static dof_security_data global_security;
3322
3323
static uint8_t count_hex_bytes(char *str);
3324
3325
/* Global DPS data structures for security keys. */
3326
static seckey_field_t *seckey_list;
3327
static unsigned num_seckey_list;
3328
3329
/* Global DPS data structures for identity secrets. */
3330
static identsecret_field_t *identsecret_list;
3331
static unsigned num_identsecret_list;
3332
3333
3334
/* Callbacks for Configuration security templates. */
3335
0
UAT_CSTRING_CB_DEF(secmode_list, domain, secmode_field_t)
3336
0
UAT_CSTRING_CB_DEF(secmode_list, identity, secmode_field_t)
3337
0
UAT_CSTRING_CB_DEF(secmode_list, kek, secmode_field_t)
3338
3339
static void secmode_list_post_update_cb(void)
3340
15
{
3341
15
}
3342
3343
static bool secmode_list_update_cb(void *r, char **err)
3344
0
{
3345
0
    secmode_field_t *rec = (secmode_field_t *)r;
3346
0
    uint32_t size;
3347
3348
0
    *err = NULL;
3349
3350
0
    size = (uint32_t)strlen(rec->domain);
3351
0
    if (!VALIDHEX(rec->domain[0]) && !dof_oid_create_internal(rec->domain, &size, NULL))
3352
0
    {
3353
0
        *err = g_strdup("Invalid domain [must be valid OID].");
3354
0
        return false;
3355
0
    }
3356
0
    else if (!count_hex_bytes(rec->domain))
3357
0
    {
3358
0
        *err = g_strdup("Invalid domain [must be valid OID].");
3359
0
        return false;
3360
0
    }
3361
3362
0
    size = (uint32_t)strlen(rec->identity);
3363
0
    if (!VALIDHEX(rec->identity[0]) && !dof_oid_create_internal(rec->identity, &size, NULL))
3364
0
    {
3365
0
        *err = g_strdup("Invalid identity [must be valid OID].");
3366
0
        return false;
3367
0
    }
3368
0
    else if (!count_hex_bytes(rec->identity))
3369
0
    {
3370
0
        *err = g_strdup("Invalid identity [must be valid OID].");
3371
0
        return false;
3372
0
    }
3373
3374
0
    if (count_hex_bytes(rec->kek) != 32)
3375
0
    {
3376
0
        *err = g_strdup("Invalid KEK [must be 32 byte key].");
3377
0
        return false;
3378
0
    }
3379
0
    return true;
3380
0
}
3381
3382
static void* secmode_list_copy_cb(void *n, const void *o, size_t siz _U_)
3383
0
{
3384
0
    secmode_field_t *new_rec = (secmode_field_t *)n;
3385
0
    const secmode_field_t *old_rec = (const secmode_field_t *)o;
3386
3387
0
    new_rec->domain = g_strdup(old_rec->domain);
3388
0
    new_rec->identity = g_strdup(old_rec->identity);
3389
0
    new_rec->kek = g_strdup(old_rec->kek);
3390
3391
0
    return new_rec;
3392
0
}
3393
3394
static void secmode_list_free_cb(void *r)
3395
0
{
3396
0
    secmode_field_t *rec = (secmode_field_t *)r;
3397
3398
0
    g_free(rec->domain);
3399
0
    g_free(rec->identity);
3400
0
    g_free(rec->kek);
3401
0
}
3402
3403
3404
/* Callbacks for security keys. */
3405
0
UAT_CSTRING_CB_DEF(seckey_list, key, seckey_field_t)
3406
3407
static void seckey_list_post_update_cb(void)
3408
15
{
3409
15
}
3410
3411
static bool seckey_list_update_cb(void *r, char **err)
3412
0
{
3413
0
    seckey_field_t *rec = (seckey_field_t *)r;
3414
3415
0
    *err = NULL;
3416
0
    if (count_hex_bytes(rec->key) != 32)
3417
0
    {
3418
0
        *err = g_strdup("Invalid secret [must be 32 bytes].");
3419
0
        return false;
3420
0
    }
3421
0
    return true;
3422
0
}
3423
3424
static void* seckey_list_copy_cb(void *n, const void *o, size_t siz _U_)
3425
0
{
3426
0
    seckey_field_t *new_rec = (seckey_field_t *)n;
3427
0
    const seckey_field_t *old_rec = (const seckey_field_t *)o;
3428
3429
0
    new_rec->key = g_strdup(old_rec->key);
3430
3431
0
    return new_rec;
3432
0
}
3433
3434
static void seckey_list_free_cb(void *r)
3435
0
{
3436
0
    seckey_field_t *rec = (seckey_field_t *)r;
3437
3438
0
    g_free(rec->key);
3439
0
}
3440
3441
3442
/* Callbacks for identity secrets. */
3443
0
UAT_CSTRING_CB_DEF(identsecret_list, domain, identsecret_field_t)
3444
0
UAT_CSTRING_CB_DEF(identsecret_list, identity, identsecret_field_t)
3445
0
UAT_CSTRING_CB_DEF(identsecret_list, secret, identsecret_field_t)
3446
3447
static void identsecret_list_post_update_cb(void)
3448
15
{
3449
15
}
3450
3451
static bool identsecret_list_update_cb(void *r, char **err)
3452
0
{
3453
0
    identsecret_field_t *rec = (identsecret_field_t *)r;
3454
0
    uint32_t size;
3455
3456
0
    *err = NULL;
3457
3458
0
    size = (uint32_t)strlen(rec->domain);
3459
0
    if (!VALIDHEX(rec->domain[0]))
3460
0
    {
3461
0
        if (dof_oid_create_internal(rec->domain, &size, NULL))
3462
0
        {
3463
0
            *err = g_strdup("Invalid domain [must be valid OID].");
3464
0
            return false;
3465
0
        }
3466
0
    }
3467
0
    else if (!count_hex_bytes(rec->domain))
3468
0
    {
3469
0
        *err = g_strdup("Invalid domain [must be valid OID].");
3470
0
        return false;
3471
0
    }
3472
3473
0
    size = (uint32_t)strlen(rec->identity);
3474
0
    if (!VALIDHEX(rec->identity[0]))
3475
0
    {
3476
0
        if (dof_oid_create_internal(rec->identity, &size, NULL))
3477
0
        {
3478
0
            *err = g_strdup("Invalid identity [must be valid OID].");
3479
0
            return false;
3480
0
        }
3481
0
    }
3482
0
    else if (!count_hex_bytes(rec->identity))
3483
0
    {
3484
0
        *err = g_strdup("Invalid identity [must be valid OID].");
3485
0
        return false;
3486
0
    }
3487
3488
0
    if (count_hex_bytes(rec->secret) != 32)
3489
0
    {
3490
0
        *err = g_strdup("Invalid secret [must be 32 byte key].");
3491
0
        return false;
3492
0
    }
3493
0
    return true;
3494
0
}
3495
3496
static void* identsecret_list_copy_cb(void *n, const void *o, size_t siz _U_)
3497
0
{
3498
0
    identsecret_field_t *new_rec = (identsecret_field_t *)n;
3499
0
    const identsecret_field_t *old_rec = (const identsecret_field_t *)o;
3500
3501
0
    new_rec->domain = g_strdup(old_rec->domain);
3502
0
    new_rec->identity = g_strdup(old_rec->identity);
3503
0
    new_rec->secret = g_strdup(old_rec->secret);
3504
3505
0
    return new_rec;
3506
0
}
3507
3508
static void identsecret_list_free_cb(void *r)
3509
0
{
3510
0
    identsecret_field_t *rec = (identsecret_field_t *)r;
3511
3512
0
    g_free(rec->domain);
3513
0
    g_free(rec->identity);
3514
0
    g_free(rec->secret);
3515
0
}
3516
3517
static void init_addr_port_tables(void);
3518
3519
/* The IP transport protocols need to assign SENDER ID based on the
3520
 * transport address. This requires a hash lookup from address/port to ID.
3521
 */
3522
3523
static GHashTable *addr_port_to_id;
3524
3525
typedef struct _addr_port_key
3526
{
3527
    address addr;
3528
    uint16_t port;
3529
} addr_port_key;
3530
3531
static unsigned addr_port_key_hash_fn(const void *key)
3532
327
{
3533
327
    const addr_port_key *addr_key = (const addr_port_key *)key;
3534
327
    unsigned result = 0;
3535
327
    unsigned port_as_int = addr_key->port;
3536
327
    unsigned type_as_int = addr_key->addr.type;
3537
3538
327
    result += g_int_hash(&port_as_int);
3539
327
    result += g_int_hash(&type_as_int);
3540
3541
327
    {
3542
327
        unsigned hash = 5381;
3543
327
        const uint8_t *str = (const uint8_t *)addr_key->addr.data;
3544
3545
1.63k
        for (int i = 0; i < addr_key->addr.len; i++)
3546
1.30k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
3547
3548
327
        result += hash;
3549
327
    }
3550
3551
327
    return result;
3552
327
}
3553
3554
static gboolean addr_port_key_equal_fn(const void *key1, const void *key2)
3555
243
{
3556
243
    const addr_port_key *addr_key_ptr1 = (const addr_port_key *)key1;
3557
243
    const addr_port_key *addr_key_ptr2 = (const addr_port_key *)key2;
3558
3559
243
    if (addr_key_ptr1->port != addr_key_ptr2->port)
3560
2
        return FALSE;
3561
3562
241
    return addresses_equal(&addr_key_ptr1->addr, &addr_key_ptr2->addr);
3563
243
}
3564
3565
static void addr_port_key_free_fn(void *key)
3566
0
{
3567
0
    addr_port_key *addr_port = (addr_port_key *)key;
3568
0
    g_free(addr_port->addr.priv);
3569
0
    g_free(addr_port);
3570
0
}
3571
3572
static void init_addr_port_tables(void)
3573
15
{
3574
    /* This routine is called each time the system is reset (file load, capture)
3575
     * and so it should take care of freeing any of our persistent stuff.
3576
     */
3577
15
    if (addr_port_to_id != NULL)
3578
0
    {
3579
        /* Clear it out. Note that this calls the destroy functions for each element. */
3580
0
        g_hash_table_destroy(addr_port_to_id);
3581
0
        addr_port_to_id = NULL;
3582
0
    }
3583
3584
    /* The value is not allocated, so does not need to be freed. */
3585
15
    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);
3586
15
}
3587
3588
static unsigned next_addr_port_id = 1;
3589
3590
284
#define EP_COPY_ADDRESS(alloc, to, from) { \
3591
284
    uint8_t *EP_COPY_ADDRESS_data; \
3592
284
    (to)->type = (from)->type; \
3593
284
    (to)->len = (from)->len; \
3594
284
    EP_COPY_ADDRESS_data = (uint8_t*) wmem_alloc(alloc,(from)->len); \
3595
284
    memcpy(EP_COPY_ADDRESS_data, (from)->data, (from)->len); \
3596
284
    (to)->priv = EP_COPY_ADDRESS_data; \
3597
284
    (to)->data = (to)->priv; \
3598
284
    }
3599
3600
/* Return the transport ID, a unique number for each transport sender.
3601
 */
3602
static unsigned assign_addr_port_id(wmem_allocator_t* allocator, address *addr, uint16_t port)
3603
746
{
3604
746
    addr_port_key lookup_key;
3605
746
    addr_port_key *key;
3606
746
    unsigned value;
3607
3608
    /* ensure the address contains actual data */
3609
746
    if (addr->type == AT_NONE)
3610
462
        return 0;
3611
3612
    /* Build a (non-allocated) key to do the lookup. */
3613
3614
284
    EP_COPY_ADDRESS(allocator, &lookup_key.addr, addr);
3615
284
    lookup_key.port = port;
3616
3617
284
    value = GPOINTER_TO_UINT(g_hash_table_lookup(addr_port_to_id, &lookup_key));
3618
284
    if (value)
3619
241
    {
3620
        /* We found a match. */
3621
241
        return value;
3622
241
    }
3623
3624
    /* No match, need to add a key. */
3625
43
    key = g_new0(addr_port_key, 1);
3626
43
    copy_address(&key->addr, addr);
3627
43
    key->port = port;
3628
3629
    /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
3630
43
    g_hash_table_insert(addr_port_to_id, key, GUINT_TO_POINTER(next_addr_port_id));
3631
43
    return next_addr_port_id++;
3632
284
}
3633
3634
/* Wireshark Configuration Dialog Routines*/
3635
3636
static bool identsecret_chk_cb(void *r _U_, const char *p _U_, unsigned len _U_, const void *u1 _U_, const void *u2 _U_, char **err _U_)
3637
0
{
3638
#if 0
3639
    char** protos;
3640
    char* line = ep_strndup(p, len);
3641
    unsigned num_protos, i;
3642
3643
    g_strstrip(line);
3644
    ascii_strdown_inplace(line);
3645
3646
    protos = ep_strsplit(line, ":", 0);
3647
3648
    for (num_protos = 0; protos[num_protos]; num_protos++)
3649
    g_strstrip(protos[num_protos]);
3650
3651
    if (!num_protos)
3652
    {
3653
        *err = g_strdup("No protocols given");
3654
        return false;
3655
    }
3656
3657
    for (i = 0; i < num_protos; i++)
3658
    {
3659
        if (!find_dissector(protos[i]))
3660
        {
3661
            *err = g_strdup("Could not find dissector for: '%s'", protos[i]);
3662
            return false;
3663
        }
3664
    }
3665
#endif
3666
0
    return true;
3667
0
}
3668
3669
/* Utility Methods */
3670
3671
static uint8_t count_hex_bytes(char *str)
3672
0
{
3673
0
    uint8_t total = 0;
3674
3675
0
    while (str != NULL && *str != '\0' && *str != '#')
3676
0
    {
3677
0
        if (!g_ascii_isxdigit(*str))
3678
0
        {
3679
0
            str += 1;
3680
0
            continue;
3681
0
        }
3682
3683
0
        if (!g_ascii_isxdigit(str[1]))
3684
0
            return 0;
3685
3686
0
        total += 1;
3687
0
        str += 2;
3688
0
    }
3689
3690
0
    return total;
3691
0
}
3692
3693
static void parse_hex_string(char *str, uint8_t **ptr, uint8_t *len)
3694
0
{
3695
0
    uint8_t j = 0;
3696
0
    *len = count_hex_bytes(str);
3697
0
    *ptr = (uint8_t *)g_malloc0(*len);
3698
3699
0
    while (j < *len)
3700
0
    {
3701
0
        int high, low;
3702
3703
0
        if (!g_ascii_isxdigit(*str))
3704
0
        {
3705
0
            str += 1;
3706
0
            continue;
3707
0
        }
3708
3709
0
        high = ws_xton(str[0]);
3710
0
        low = ws_xton(str[1]);
3711
0
        (*ptr)[j++] = (high << 4) | low;
3712
0
        str += 2;
3713
0
    }
3714
0
}
3715
3716
/* OID and IID Parsing */
3717
3718
static const uint8_t OALString_HexChar[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
3719
3720
60.9k
#define IS_PRINTABLE(c)         ( ((uint8_t)c) >= 32U && ((uint8_t)c) < 127U )
3721
27.1k
#define IS_ESCAPED(c)           ( (c) == '(' || (c) == ')' || (c) == '[' || (c) == ']' || (c) == '{' || (c) == '}' || (c) == '\\' || (c) == '|' )
3722
17.4k
#define DOFOBJECTID_MAX_CLASS_SIZE (4)
3723
7.24k
#define MAX_OID_DATA_SIZE                 (63)
3724
7.24k
#define OID_DATA_LEN_MASK                 (MAX_OID_DATA_SIZE)
3725
3726
1.44k
#define ObjectID_DataToStringLength( data, dataSize ) ObjectID_DataToString( (data), (dataSize), NULL )
3727
62.4k
#define OALString_HexDigitToChar(c)     (OALString_HexChar[(c)])
3728
574
#define DOFObjectIDAttribute_IsValid( attribute ) ((attribute).id < DOFOBJECTIDATTRIBUTE_INVALID)
3729
856
#define DOFObjectIDAttribute_GetValueSize( attribute ) ((attribute).dataSize)
3730
856
#define DOFObjectIDAttribute_GetValue( attribute ) ((attribute).data)
3731
#define DOFObjectIDAttribute_GetType( attribute ) ((DOFObjectIDAttributeType)(attribute).id)
3732
3733
typedef enum DOFObjectIDAttributeID_t
3734
{
3735
    /**
3736
    * Provider attribute. This attribute identifies an object as being
3737
    * provided by a specific service provider. The associated data must
3738
    * be an object identifier.
3739
    */
3740
    DOFOBJECTIDATTRIBUTE_PROVIDER = 0,
3741
3742
    /**
3743
    * Session attribute. This attribute associates the object with the
3744
    * specified session. The associated data must be exactly 16 bytes long.
3745
    */
3746
    DOFOBJECTIDATTRIBUTE_SESSION = 1,
3747
3748
    /**
3749
    * Group attribute. This attribute is normally used in association
3750
    * with the BROADCAST object identifier. It defines a target that is
3751
    * a multicast group in the DOF network (as opposed to the transport).
3752
    * The associated data must be an object identifier.
3753
    */
3754
    DOFOBJECTIDATTRIBUTE_GROUP = 2,
3755
3756
    /**
3757
    * Invalid, used to signal that an error has occurred.
3758
    */
3759
    DOFOBJECTIDATTRIBUTE_INVALID = 128
3760
} DOFObjectIDAttributeType;
3761
typedef uint32_t                       DOFObjectIDClass;
3762
3763
typedef struct DOFObjectID_t
3764
{
3765
    uint32_t refCount;
3766
    uint16_t len;                /* Actual length of oid's wire representation. Max is 32707: 4 + 1 + 63 + (127 * 257). */
3767
    uint8_t oid[];               /* Extends beyond end of this defined structure, so oid MUST be last structure member! */
3768
} DOFObjectID_t;
3769
3770
typedef DOFObjectID_t *DOFObjectID;
3771
3772
typedef uint8_t                        DOFObjectIDAttributeDataSize;
3773
3774
typedef struct DOFObjectIDAttribute_t
3775
{
3776
    uint8_t                         id;         /**< Attribute Identifier.  Intentionally defined as uint8 for size, but holds all valid values for DOFObjectIDAttributeType.  **/
3777
    DOFObjectIDAttributeDataSize   dataSize;    /**< Size of the attribute data. **/
3778
    const uint8_t *data;                         /**< Attribute data. **/
3779
} DOFObjectIDAttribute;
3780
3781
/**
3782
* Read variable-length value from buffer.
3783
*
3784
* @param maxSize   [in]        Maximum size of value to be read
3785
* @param bufLength [in,out]    Input: size of buffer, output: size of value in buffer
3786
* @param buffer    [in]        Actual buffer
3787
* @return                      Uncompressed value if buffer size is valid (or 0 on error)
3788
*/
3789
static uint32_t OALMarshal_UncompressValue(uint8_t maxSize, uint32_t *bufLength, const uint8_t *buffer)
3790
17.4k
{
3791
17.4k
    uint32_t value = 0;
3792
17.4k
    uint8_t used = 0;
3793
17.4k
    uint8_t size = maxSize;
3794
17.4k
    uint8_t mask;
3795
3796
17.4k
    switch (buffer[0] >> 6)
3797
17.4k
    {
3798
1.89k
    case 0x02:
3799
        /* Two Bytes */
3800
1.89k
        if (maxSize > 2)
3801
1.89k
            mask = 0x3F;
3802
0
        else
3803
0
            mask = 0x7F;
3804
1.89k
        size = 2;
3805
1.89k
        break;
3806
3807
1.57k
    case 0x03:
3808
        /* Three/Four Bytes */
3809
1.57k
        if (maxSize > 2)
3810
1.57k
            mask = 0x3F;
3811
0
        else
3812
0
            mask = 0x7F;
3813
1.57k
        break;
3814
3815
13.9k
    default:
3816
        /* One Byte */
3817
13.9k
        size = 1;
3818
13.9k
        mask = 0x7F;
3819
13.9k
        break;
3820
17.4k
    }
3821
3822
    /* Sanity check */
3823
17.4k
    if (size > *bufLength)
3824
16
        return 0;
3825
3826
17.4k
    value = buffer[used++] & mask;
3827
24.0k
    while (used < size)
3828
6.58k
        value = (value << 8) | buffer[used++];
3829
3830
17.4k
    *bufLength = used;
3831
17.4k
    return (value);
3832
17.4k
}
3833
3834
static uint32_t DOFObjectID_GetClassSize(DOFObjectID self)
3835
10.8k
{
3836
10.8k
    uint32_t size = self->len;
3837
3838
10.8k
    (void)OALMarshal_UncompressValue(DOFOBJECTID_MAX_CLASS_SIZE, &size, self->oid);
3839
3840
10.8k
    return size;
3841
10.8k
}
3842
3843
static uint32_t DOFObjectID_GetDataSize(const DOFObjectID self)
3844
5.58k
{
3845
5.58k
    return ((*((const uint8_t *)self->oid + DOFObjectID_GetClassSize(self))) & OID_DATA_LEN_MASK);
3846
5.58k
}
3847
3848
static uint32_t ObjectID_DataToString(const uint8_t *data, uint32_t dataSize, char *pBuf)
3849
2.89k
{
3850
2.89k
    uint32_t len = 0, i, nonprintable, escaped;
3851
3852
    /* Determine if the data is printable... */
3853
63.8k
    for (i = 0, nonprintable = 0, escaped = 0; i < dataSize; i++)
3854
60.9k
    {
3855
60.9k
        if (!IS_PRINTABLE(data[i]))
3856
34.8k
            nonprintable++;
3857
26.0k
        else if (IS_ESCAPED(data[i]))
3858
9.88k
            escaped++;
3859
60.9k
    }
3860
2.89k
    if (nonprintable == 0)
3861
1.42k
    {
3862
        /* Printable, so copy as a string, escaping where necessary. */
3863
1.42k
        if (pBuf)
3864
714
        {
3865
1.76k
            for (i = 0; i < dataSize; i++)
3866
1.05k
            {
3867
1.05k
                if (IS_ESCAPED(data[i]))
3868
276
                {
3869
276
                    pBuf[len++] = '\\';
3870
276
                    pBuf[len++] = data[i];
3871
276
                }
3872
776
                else
3873
776
                    pBuf[len++] = data[i];
3874
1.05k
            }
3875
714
        }
3876
714
        else
3877
714
        {
3878
714
            len = dataSize + escaped; /* Count escaped characters twice. */
3879
714
        }
3880
1.42k
    }
3881
1.46k
    else
3882
1.46k
    {
3883
        /* Non-printable, so format as hex string. */
3884
1.46k
        if (pBuf)
3885
734
        {
3886
734
            pBuf[len++] = '{';
3887
30.1k
            for (i = 0; i < dataSize; i++)
3888
29.4k
            {
3889
29.4k
                pBuf[len++] = OALString_HexDigitToChar((data[i] >> 4) & 0x0F);
3890
29.4k
                pBuf[len++] = OALString_HexDigitToChar((data[i]) & 0x0F);
3891
29.4k
            }
3892
734
            pBuf[len++] = '}';
3893
734
        }
3894
734
        else
3895
734
        {
3896
734
            len = dataSize * 2 + 2;
3897
734
        }
3898
1.46k
    }
3899
2.89k
    return len;
3900
2.89k
}
3901
3902
static const uint8_t* DOFObjectID_GetData(const DOFObjectID self)
3903
2.33k
{
3904
2.33k
    if (DOFObjectID_GetDataSize(self) > 0)
3905
1.10k
        return (const uint8_t *)self->oid + DOFObjectID_GetClassSize(self) + 1;          /* 1: length of length byte. */
3906
3907
1.22k
    return NULL;
3908
2.33k
}
3909
3910
static uint32_t DOFObjectID_GetIDClass(const DOFObjectID self)
3911
4.47k
{
3912
4.47k
    uint32_t size = 4;
3913
3914
4.47k
    return OALMarshal_UncompressValue(DOFOBJECTID_MAX_CLASS_SIZE, &size, self->oid);
3915
4.47k
}
3916
3917
static bool DOFObjectID_HasAttributes(const DOFObjectID self)
3918
3.25k
{
3919
3.25k
    if (!self)
3920
0
        return false;
3921
3922
    /* bit 7: next attribute flag. */
3923
3.25k
    return (bool)(((*(const uint8_t *)((const uint8_t *)(self->oid) + DOFObjectID_GetClassSize(self))) & 0x80) != 0);
3924
3.25k
}
3925
3926
static uint8_t DOFObjectID_GetBaseSize(const DOFObjectID oid)
3927
918
{
3928
918
    return DOFObjectID_GetClassSize(oid) + 1 + DOFObjectID_GetDataSize(oid);
3929
918
}
3930
3931
static uint8_t DOFObjectID_GetAttributeCount(const DOFObjectID self)
3932
344
{
3933
344
    uint8_t retVal = 0;
3934
3935
    /* Note: No OID can duplicate an attribute ID. Legal attribute IDs can be from 0-126. So max count fits in uint8. */
3936
344
    if (self && DOFObjectID_HasAttributes(self))
3937
344
    {
3938
344
        const uint8_t *pNextAttribute = (const uint8_t *)self->oid + DOFObjectID_GetBaseSize(self);
3939
3940
344
        ++retVal;
3941
574
        while (*pNextAttribute & 0x80)                                         /* bit 7: next attribute present flag. */
3942
230
        {
3943
230
            ++retVal;
3944
230
            pNextAttribute += (2 + *((const uint8_t *)pNextAttribute + 1));      /* 2: attribute marshalling overhead. */
3945
230
        }
3946
344
    }
3947
3948
344
    return retVal;
3949
344
}
3950
3951
static DOFObjectIDAttribute DOFObjectID_GetAttributeAtIndex(const DOFObjectID self, uint8_t attribute_index)
3952
574
{
3953
574
    DOFObjectIDAttribute retAttributeDescriptor = { DOFOBJECTIDATTRIBUTE_INVALID, 0, NULL };
3954
3955
    /* Note: No OID can duplicate an attribute ID. Legal attribute IDs can be from 0-127. So max index fits in uint8. */
3956
574
    if (self && attribute_index < DOFOBJECTIDATTRIBUTE_INVALID)
3957
574
    {
3958
574
        if (DOFObjectID_HasAttributes(self))
3959
574
        {
3960
574
            uint8_t        count = 0;
3961
574
            const uint8_t *pNextAttribute = (const uint8_t *)self->oid + DOFObjectID_GetBaseSize(self);
3962
3963
986
            while (1)                                           /* Parse through the N Attributes. */
3964
986
            {
3965
986
                if (attribute_index == count++)
3966
574
                {
3967
574
                    retAttributeDescriptor.id = *pNextAttribute & 0x7F;
3968
574
                    retAttributeDescriptor.dataSize = (DOFObjectIDAttributeDataSize) * ((const uint8_t *)pNextAttribute + 1);
3969
574
                    retAttributeDescriptor.data = (const uint8_t *)pNextAttribute + 2; /* 2: attr marshalling overhead. */
3970
574
                    break;                                      /* Success. */
3971
574
                }
3972
412
                if (!(*pNextAttribute & 0x80))
3973
0
                    break;                                      /* Fail: no more Attributes */
3974
412
                pNextAttribute += (2 + *((const uint8_t *)pNextAttribute + 1));
3975
412
            }
3976
574
        }
3977
574
    }
3978
3979
574
    return retAttributeDescriptor;
3980
574
}
3981
3982
static void DOFObjectID_Destroy(DOFObjectID self _U_)
3983
184
{
3984
    /* Ephemeral memory doesn't need to be freed. */
3985
184
}
3986
3987
static void DOFObjectID_InitStruct(DOFObjectID newObjID, uint32_t dataLen)
3988
1.34k
{
3989
1.34k
    newObjID->refCount = 1;
3990
1.34k
    newObjID->len = dataLen;
3991
1.34k
}
3992
3993
static DOFObjectID DOFObjectID_Create_Unmarshal(wmem_allocator_t* allocator, uint32_t *length, const uint8_t *buffer)
3994
2.24k
{
3995
2.24k
    uint32_t len = *length;
3996
3997
    /* Legal OID described at buffer must have at least 2 bytes. */
3998
2.24k
    if (buffer && len >= 2)
3999
2.11k
    {
4000
2.11k
        uint32_t classSize = len;
4001
2.11k
        uint32_t classv = OALMarshal_UncompressValue(DOFOBJECTID_MAX_CLASS_SIZE, &classSize, buffer);
4002
4003
        /* Legal OID described at buffer must have its class representation be correctly compressed. */
4004
2.11k
        if (1)
4005
2.11k
        {
4006
2.11k
            uint32_t computedSize;
4007
4008
            /* Above call won't return 3 because DOFOBJECTID_MAX_CLASS_SIZE (4) was passed in. */
4009
2.11k
            computedSize = classSize + 1;                              /* 1: length of length byte. */
4010
            /* Legal OID described at buffer must have enough bytes to describe its OID class. */
4011
2.11k
            if (len >= computedSize)
4012
2.09k
            {
4013
2.09k
                uint8_t lenByte = buffer[classSize];
4014
4015
                /* Legal OID described at buffer must have its length byte bit 6 be 0. */
4016
2.09k
                if (!(lenByte & 0x40))
4017
1.66k
                {
4018
1.66k
                    bool hasAttr;
4019
1.66k
                    uint8_t  dataLen = lenByte & OID_DATA_LEN_MASK;
4020
4021
                    /* Legal broadcast OID described at buffer must have no base data, though it can have attribute(s)*/
4022
1.66k
                    if ((classv == 0) && (dataLen > 0))
4023
59
                        goto notvalid;
4024
1.60k
                    computedSize += dataLen;
4025
1.60k
                    hasAttr = lenByte & 0x80;                       /* Valid OID base; check attributes. */
4026
2.12k
                    while (hasAttr)
4027
556
                    {
4028
                        /* Legal OID described at buffer must have enough bytes to hold each new found attribute. */
4029
556
                        if (len >= computedSize + 2)                /* 2: attribute marshalling overhead. */
4030
523
                        {
4031
523
                            hasAttr = buffer[computedSize] & 0x80;  /* bit 7: next attribute present flag. */
4032
523
                            computedSize += (2 + buffer[computedSize + 1]);
4033
523
                        }
4034
33
                        else
4035
33
                            goto notvalid;
4036
556
                    }
4037
                    /* Legal OID described at buffer must have enough buffer bytes, final check. */
4038
1.56k
                    if (len >= computedSize)
4039
1.34k
                    {
4040
1.34k
                        DOFObjectID newObjID = (DOFObjectID)wmem_alloc0(allocator, sizeof(DOFObjectID_t) + (sizeof(uint8_t) * (computedSize + 1)));
4041
                        /* Adds space for null-terminator, just in case. */
4042
4043
1.34k
                        *length = computedSize;
4044
1.34k
                        if (newObjID)
4045
1.34k
                        {
4046
1.34k
                            DOFObjectID_InitStruct(newObjID, computedSize);
4047
1.34k
                            memcpy(newObjID->oid, buffer, computedSize);
4048
1.34k
                            newObjID->oid[computedSize] = 0;
4049
1.34k
                            return newObjID;                    /* Success. */
4050
1.34k
                        }
4051
                        /* buffer describes valid OID, but due to alloc failure we cannot return the newly created OID*/
4052
0
                        goto allocErrorOut;
4053
1.34k
                    }
4054
1.56k
                }
4055
2.09k
            }
4056
2.11k
        }
4057
2.11k
    }
4058
896
notvalid:
4059
    /* buffer does not describe a valid OID, but do not log a message. The caller may have called us to find out if the
4060
    buffer does or does not obey the rules of a valid OID. He learns that by our NULL return. */
4061
896
allocErrorOut :
4062
896
    *length = 0;
4063
4064
896
    return NULL;
4065
896
}
4066
4067
static DOFObjectID DOFObjectID_Create_Bytes(wmem_allocator_t* allocator, uint32_t bufferSize, const uint8_t *pOIDBuffer)
4068
574
{
4069
574
    uint32_t     len = bufferSize;
4070
574
    DOFObjectID rval = DOFObjectID_Create_Unmarshal(allocator, &len, pOIDBuffer);
4071
4072
574
    if (rval)
4073
184
    {
4074
184
        if (len != bufferSize)
4075
174
        {
4076
174
            DOFObjectID_Destroy(rval);
4077
174
            rval = NULL;
4078
174
        }
4079
184
    }
4080
574
    return rval;
4081
574
}
4082
4083
// NOLINTNEXTLINE(misc-no-recursion)
4084
static uint32_t ObjectID_ToStringLength(const DOFObjectID oid, packet_info *pinfo)
4085
1.16k
{
4086
1.16k
    uint32_t len = 0;
4087
4088
    /* Note: All these string functions can be exercised with objectid_test.c, which outputs the string to console. */
4089
1.16k
    len = 7 /* [{xx}: and trailing ] */ + ObjectID_DataToStringLength(DOFObjectID_GetData(oid),
4090
1.16k
                                                                      DOFObjectID_GetDataSize(oid));
4091
1.16k
    if (DOFObjectID_GetIDClass(oid) & 0xFF000000)
4092
91
        len += 6;                                           /* Six more hex digits. */
4093
1.07k
    else if (DOFObjectID_GetIDClass(oid) & 0xFF0000)
4094
3
        len += 4;                                           /* Four more hex digits. */
4095
1.07k
    else if (DOFObjectID_GetIDClass(oid) & 0xFF00)
4096
75
        len += 2;                                           /* Two more hex digits. */
4097
1.16k
    increment_dissection_depth(pinfo);
4098
    /* Handle Attributes, if any. */
4099
1.16k
    if (DOFObjectID_HasAttributes(oid))
4100
172
    {
4101
172
        uint8_t i;                                            /* Max attribute count is under uint8. */
4102
172
        uint8_t attributeCount = DOFObjectID_GetAttributeCount(oid);
4103
4104
172
        len += 2;                                           /* surrounding ( ) */
4105
459
        for (i = 0; i < attributeCount; i++)
4106
287
        {
4107
287
            DOFObjectID embedOID;
4108
287
            DOFObjectIDAttribute avpDescriptor = DOFObjectID_GetAttributeAtIndex(oid, i);
4109
4110
287
            if (!DOFObjectIDAttribute_IsValid(avpDescriptor))
4111
0
                break;  /* Done with Attributes. If here, some error took place. */
4112
4113
287
            if (i)
4114
115
                len++;
4115
287
            len += 5;  /* {xx}: */
4116
            /* Handle embedded Object IDs. */
4117
287
            embedOID = DOFObjectID_Create_Bytes(pinfo->pool, DOFObjectIDAttribute_GetValueSize(avpDescriptor),
4118
287
                                                DOFObjectIDAttribute_GetValue(avpDescriptor));
4119
287
            if (embedOID)
4120
5
            {
4121
5
                len += ObjectID_ToStringLength(embedOID, pinfo); /* Recurse to compute string rep length of found OID. */
4122
5
                DOFObjectID_Destroy(embedOID);
4123
5
            }
4124
282
            else
4125
282
            {
4126
                /* Hex Data. */
4127
282
                len += ObjectID_DataToStringLength(DOFObjectIDAttribute_GetValue(avpDescriptor),
4128
282
                                                   DOFObjectIDAttribute_GetValueSize(avpDescriptor));
4129
282
            }
4130
287
        } /* end for(). */
4131
172
    }
4132
1.16k
    decrement_dissection_depth(pinfo);
4133
4134
1.16k
    return len;
4135
1.16k
}
4136
4137
static uint32_t InterfaceID_ToString(const uint8_t *iid, char *pBuf)
4138
0
{
4139
0
    uint32_t          len = 0;
4140
0
    unsigned iid_len = iid[0] & 0x03;
4141
0
    unsigned i;
4142
4143
    /* XXX - The handling for iid_len 0 is not the same as in
4144
     * oap_1_tree_add_interface. */
4145
0
    if (iid_len == 3)
4146
0
        iid_len = 4;
4147
4148
0
    pBuf[len++] = '[';
4149
0
    pBuf[len++] = '{';
4150
4151
0
    pBuf[len++] = OALString_HexDigitToChar((iid[0] >> 6) & 0x0F);
4152
0
    pBuf[len++] = OALString_HexDigitToChar((iid[0] >> 2) & 0x0F);
4153
4154
0
    pBuf[len++] = '}';
4155
0
    pBuf[len++] = ':';
4156
0
    pBuf[len++] = '{';
4157
4158
    /* Data */
4159
0
    for (i = 0; i < iid_len; i++)
4160
0
    {
4161
0
        pBuf[len++] = OALString_HexDigitToChar((iid[i + 1] >> 4) & 0x0F);
4162
0
        pBuf[len++] = OALString_HexDigitToChar(iid[i + 1] & 0x0F);
4163
0
    }
4164
4165
0
    pBuf[len++] = '}';
4166
0
    pBuf[len++] = ']';
4167
4168
0
    return len;
4169
0
}
4170
4171
// NOLINTNEXTLINE(misc-no-recursion)
4172
static uint32_t ObjectID_ToString(const DOFObjectID oid, char *pBuf, packet_info *pinfo)
4173
1.16k
{
4174
1.16k
    DOFObjectIDClass oidClass;
4175
1.16k
    uint32_t          len = 0;
4176
4177
1.16k
    pBuf[len++] = '[';
4178
1.16k
    pBuf[len++] = '{';
4179
    /* Class */
4180
1.16k
    oidClass = DOFObjectID_GetIDClass(oid);
4181
1.16k
    if (oidClass & 0xFF000000)
4182
91
    {
4183
91
        pBuf[len++] = OALString_HexDigitToChar((oidClass >> 28) & 0x0F);
4184
91
        pBuf[len++] = OALString_HexDigitToChar((oidClass >> 24) & 0x0F);
4185
91
    }
4186
1.16k
    if (oidClass & 0xFFFF0000)
4187
94
    {
4188
94
        pBuf[len++] = OALString_HexDigitToChar((oidClass >> 20) & 0x0F);
4189
94
        pBuf[len++] = OALString_HexDigitToChar((oidClass >> 16) & 0x0F);
4190
94
    }
4191
1.16k
    if (oidClass & 0xFFFFFF00)
4192
169
    {
4193
169
        pBuf[len++] = OALString_HexDigitToChar((oidClass >> 12) & 0x0F);
4194
169
        pBuf[len++] = OALString_HexDigitToChar((oidClass >> 8) & 0x0F);
4195
169
    }
4196
1.16k
    pBuf[len++] = OALString_HexDigitToChar((oidClass >> 4) & 0x0F);
4197
1.16k
    pBuf[len++] = OALString_HexDigitToChar((oidClass) & 0x0F);
4198
1.16k
    pBuf[len++] = '}';
4199
1.16k
    pBuf[len++] = ':';
4200
    /* Data */
4201
1.16k
    len += ObjectID_DataToString(DOFObjectID_GetData(oid), DOFObjectID_GetDataSize(oid), &pBuf[len]);
4202
    /* Handle Attributes, if any. */
4203
1.16k
    if (DOFObjectID_HasAttributes(oid))
4204
172
    {
4205
172
        uint8_t i;
4206
172
        uint8_t attributeCount = DOFObjectID_GetAttributeCount(oid);
4207
4208
172
        pBuf[len++] = '(';
4209
459
        for (i = 0; i < attributeCount; i++)
4210
287
        {
4211
287
            DOFObjectID embedOID;
4212
287
            DOFObjectIDAttribute avpDescriptor = DOFObjectID_GetAttributeAtIndex(oid, i);
4213
4214
287
            if (!DOFObjectIDAttribute_IsValid(avpDescriptor))
4215
0
                break;  /* Done with Attributes. If here, some error took place. */
4216
4217
287
            if (i)
4218
115
                pBuf[len++] = '|';
4219
287
            pBuf[len++] = '{';
4220
287
            pBuf[len++] = OALString_HexDigitToChar((DOFObjectIDAttribute_GetType(avpDescriptor) >> 4) & 0x0F);
4221
287
            pBuf[len++] = OALString_HexDigitToChar((DOFObjectIDAttribute_GetType(avpDescriptor)) & 0x0F);
4222
287
            pBuf[len++] = '}';
4223
287
            pBuf[len++] = ':';
4224
4225
            /* Handle embedded Object IDs. */
4226
287
            embedOID = DOFObjectID_Create_Bytes(pinfo->pool, DOFObjectIDAttribute_GetValueSize(avpDescriptor),
4227
287
                                                DOFObjectIDAttribute_GetValue(avpDescriptor));
4228
287
            if (embedOID)
4229
5
            {
4230
5
                increment_dissection_depth(pinfo);
4231
5
                len += ObjectID_ToString(embedOID, &pBuf[len], pinfo); /* Recurse to output string rep of found OID. */
4232
5
                decrement_dissection_depth(pinfo);
4233
5
                DOFObjectID_Destroy(embedOID);
4234
5
            }
4235
282
            else
4236
282
            {
4237
                /* Hex Data. */
4238
282
                len += ObjectID_DataToString(DOFObjectIDAttribute_GetValue(avpDescriptor),
4239
282
                                             DOFObjectIDAttribute_GetValueSize(avpDescriptor), &pBuf[len]);
4240
282
            }
4241
287
        } /* end for(). */
4242
172
        pBuf[len++] = ')';
4243
172
    }
4244
1.16k
    pBuf[len++] = ']';
4245
4246
1.16k
    return len;
4247
1.16k
}
4248
4249
static const char* dof_iid_create_standard_string(wmem_allocator_t* allocator, uint32_t bufferSize, const uint8_t *pIIDBuffer)
4250
0
{
4251
0
    char *pRetval;
4252
0
    unsigned len = 9 + (bufferSize - 1) * 2;   /* Alias is always [{AA}:{01234567}] */
4253
4254
0
    pRetval = (char *)wmem_alloc(allocator, len + 1);
4255
0
    if (pRetval)
4256
0
    {
4257
0
        len = InterfaceID_ToString(pIIDBuffer, pRetval);
4258
0
        pRetval[len] = 0;
4259
0
    }
4260
4261
0
    return pRetval;
4262
0
}
4263
4264
static const char* dof_oid_create_standard_string(wmem_allocator_t* allocator, uint32_t bufferSize, const uint8_t *pOIDBuffer, packet_info *pinfo)
4265
1.66k
{
4266
1.66k
    DOFObjectID oid;
4267
1.66k
    char *pRetval;
4268
1.66k
    uint32_t len = bufferSize;
4269
4270
1.66k
    oid = DOFObjectID_Create_Unmarshal(allocator, &len, pOIDBuffer);
4271
1.66k
    if (!oid)
4272
506
        return "Illegal OID";
4273
4274
1.16k
    len = ObjectID_ToStringLength(oid, pinfo);
4275
    /* Use PCRMem_Alloc() and not DOFMem_Alloc() because app caller will be freeing memory with PCRMem_Destroy(). */
4276
1.16k
    pRetval = (char *)wmem_alloc(allocator, len + 1);
4277
1.16k
    if (pRetval)
4278
1.16k
    {
4279
1.16k
        ObjectID_ToString(oid, pRetval, pinfo);
4280
1.16k
        pRetval[len] = 0;
4281
1.16k
    }
4282
4283
1.16k
    return pRetval;
4284
1.66k
}
4285
4286
struct parseCtx
4287
{
4288
    const char *oid;
4289
    uint8_t *buffer;
4290
    uint32_t buffLen;
4291
    uint32_t oidLen;
4292
    uint32_t currOidPos;
4293
    uint32_t currBufferPos;
4294
    unsigned depth;
4295
}parseCtx;
4296
4297
/* Operations on OID string */
4298
0
#define PARSECTX_PEEK_CHAR_OID(ctx) ( (ctx)->oid[(ctx)->currOidPos] )
4299
0
#define PARSECTX_PEEK_NEXT_CHAR_OID(ctx) ( (ctx)->oid[(ctx)->currOidPos+1] )
4300
0
#define PARSECTX_READ_CHAR_OID(ctx) ( (ctx)->oid[(ctx)->currOidPos++] )
4301
#define PARSECTX_GET_CURRENT_POS_OID(ctx) ( (ctx)->oid+(ctx)->currOidPos )
4302
0
#define PARSECTX_STEP_OID(ctx, count)((ctx)->currOidPos+=(count))
4303
4304
/* Operations on DOFObjectID buffer */
4305
0
#define PARSECTX_GET_CURRENT_POS_BUF(ctx)( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos: NULL )
4306
0
#define PARSECTX_STEP_BUF(ctx, count)( (ctx)->currBufferPos+=(count))
4307
0
#define PARSECTX_WRITE_AT_POS_BUF(ctx, pos, value) do{ if((ctx)->buffer) *(pos) = (value); } while(0)
4308
0
#define PARSECTX_OR_AT_POS_BUF(ctx, pos, value) do{ if((ctx)->buffer) *(pos) |= (value); } while(0)
4309
0
#define PARSECTX_WRITE_BUF(ctx, value)( ((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos++] = (value): (ctx)->currBufferPos++ )
4310
0
#define PARSECTX_CHECK_LEN(ctx, len) (((ctx)->buffer)? (((ctx)->currBufferPos+len <= (ctx)->buffLen)? 0: 1): 0)
4311
4312
/* Operation to read from OID straight to buffer */
4313
0
#define PARSECTX_WRITE_BUF_FROM_OID(ctx) (((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos++] = (ctx)->oid[(ctx)->currOidPos]: ((ctx)->currBufferPos++),((ctx)->currOidPos++))
4314
4315
0
#define IS_DIGIT(c) (((c) >= '0' && (c) <= '9'))
4316
0
#define DIGIT2VALUE(c) (c-48)
4317
4318
0
#define HEX2VALUE(c) ( (IS_DIGIT(c))? DIGIT2VALUE(c) : ((c) >= 'A' && (c) <= 'F')? (c-55): (c-87) )
4319
0
#define VALIDHEXSEP(c) ( (c) == ' ' || (c) == ':' || (c) == '-' )
4320
0
#define VALIDHEX(c) ( ((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f') )
4321
0
#define VALIDHEXBYTE(s) ( VALIDHEX((s)[0]) && VALIDHEX((s)[1]) )
4322
#define VALIDNUMBER(c) ((c) >= '0' && (c) <= '9')
4323
4324
0
#define VALIDASCIICHAR(c) (((uint8_t)c) >= 32 && ((uint8_t)c) <= 126 )
4325
4326
0
#define IS_ESCAPED(c) ( (c) == '(' || (c) == ')' || (c) == '[' || (c) == ']' || (c) == '{' || (c) == '}' || (c) == '\\' || (c) == '|' )
4327
4328
static uint8_t parseFormatOID(struct parseCtx *ctx);
4329
4330
static uint8_t parseHexField(struct parseCtx *ctx)
4331
0
{
4332
    /* Hex fields start with { and end with } can contain space, dash and colon*/
4333
0
    if (PARSECTX_READ_CHAR_OID(ctx) == '{' && PARSECTX_PEEK_CHAR_OID(ctx) != '}')
4334
0
    {
4335
0
        while (PARSECTX_PEEK_CHAR_OID(ctx) != '}')
4336
0
        {
4337
0
            if (VALIDHEXBYTE(PARSECTX_GET_CURRENT_POS_OID(ctx)))
4338
0
            {
4339
0
                if (PARSECTX_CHECK_LEN(ctx, 1) == 0)
4340
0
                {
4341
0
                    PARSECTX_WRITE_BUF(ctx, HEX2VALUE(PARSECTX_PEEK_CHAR_OID(ctx)) << 4 | HEX2VALUE(PARSECTX_PEEK_NEXT_CHAR_OID(ctx)));
4342
0
                    PARSECTX_STEP_OID(ctx, 2);
4343
4344
0
                    if (VALIDHEXSEP(PARSECTX_PEEK_CHAR_OID(ctx)))
4345
0
                    {
4346
0
                        if (PARSECTX_PEEK_NEXT_CHAR_OID(ctx) == '}')
4347
0
                        {
4348
                            /* no separator after byte block */
4349
0
                            return 1;
4350
0
                        }
4351
0
                        PARSECTX_STEP_OID(ctx, 1);
4352
0
                    }
4353
0
                }
4354
0
                else
4355
0
                {
4356
0
                    return 1;
4357
0
                }
4358
0
            }
4359
0
            else
4360
0
            {
4361
0
                return 1;
4362
0
            }
4363
0
        }
4364
0
        PARSECTX_STEP_OID(ctx, 1);
4365
0
        return 0;
4366
0
    }
4367
0
    return 1;
4368
0
}
4369
4370
static uint8_t parseStringField(struct parseCtx *ctx)
4371
0
{
4372
    /* Copy into buffer until end or */
4373
0
    while (ctx->currOidPos < (ctx->oidLen - 1))
4374
0
    {
4375
0
        char curr = PARSECTX_PEEK_CHAR_OID(ctx);
4376
0
        if (curr == ']' || curr == '(')
4377
0
        {
4378
0
            break; /* End of string field */
4379
0
        }
4380
0
        else if (curr == '\\')
4381
0
        {
4382
            /* Handle escaped char */
4383
0
            PARSECTX_STEP_OID(ctx, 1);
4384
0
            if (!IS_ESCAPED(PARSECTX_PEEK_CHAR_OID(ctx)) || PARSECTX_CHECK_LEN(ctx, 1) != 0)
4385
0
                return 1;
4386
0
            PARSECTX_WRITE_BUF_FROM_OID(ctx);
4387
0
        }
4388
0
        else
4389
0
        {
4390
0
            if (VALIDASCIICHAR(curr) && PARSECTX_CHECK_LEN(ctx, 1) == 0)
4391
0
                PARSECTX_WRITE_BUF_FROM_OID(ctx);
4392
0
            else
4393
0
                return 1;
4394
0
        }
4395
0
    }
4396
0
    return 0;
4397
0
}
4398
4399
static uint8_t OALMarshal_GetCompressedValueSize(uint8_t maxSize, uint32_t value)
4400
0
{
4401
0
    uint8_t lenbytes = (1 + (value > 0x7F) + (value > 0x3FFF));
4402
0
    if (lenbytes > 2)
4403
0
        return (maxSize);
4404
0
    return (lenbytes);
4405
0
}
4406
4407
static uint32_t OALMarshal_CompressValue(uint8_t maxSize, uint32_t value, uint32_t bufLength, uint8_t *buffer)
4408
0
{
4409
0
    uint8_t lenSize = OALMarshal_GetCompressedValueSize(maxSize, value);
4410
4411
0
    if (bufLength < lenSize)
4412
0
        return 0;
4413
0
    switch (lenSize)
4414
0
    {
4415
0
    case 4:
4416
0
        *(buffer++) = (uint8_t)((value >> 24) & 0x3F) | 0xC0;
4417
0
        *(buffer++) = (uint8_t)((value >> 16) & 0xFF);
4418
0
        *(buffer++) = (uint8_t)((value >> 8) & 0xFF);
4419
0
        *(buffer++) = (uint8_t)(value & 0xFF);
4420
0
        break;
4421
4422
0
    case 3:
4423
0
        *(buffer++) = (uint8_t)((value >> 16) & 0x3F) | 0xC0;
4424
0
        *(buffer++) = (uint8_t)((value >> 8) & 0xFF);
4425
0
        *(buffer++) = (uint8_t)(value & 0xFF);
4426
0
        break;
4427
4428
0
    case 2:
4429
0
        if (maxSize == 2)
4430
0
        {
4431
0
            *(buffer++) = (uint8_t)((value >> 8) & 0x7F) | 0x80;
4432
0
        }
4433
0
        else
4434
0
        {
4435
0
            *(buffer++) = (uint8_t)((value >> 8) & 0x3F) | 0x80;
4436
0
        }
4437
0
        *(buffer++) = (uint8_t)(value & 0xFF);
4438
0
        break;
4439
4440
0
    case 1:
4441
0
        *(buffer++) = (uint8_t)(value & 0x7F);
4442
0
        break;
4443
4444
0
    default:
4445
        /* Invalid computed size! */
4446
0
        break;
4447
0
    }
4448
0
    return (lenSize);
4449
0
}
4450
4451
static uint8_t parseOIDClass(struct parseCtx *ctx)
4452
0
{
4453
0
    if (PARSECTX_PEEK_CHAR_OID(ctx) == '{' && PARSECTX_PEEK_NEXT_CHAR_OID(ctx) != '}')
4454
0
    {
4455
        /* Hex */
4456
0
        uint8_t classSize = 0;
4457
0
        uint32_t oidClass = 0;
4458
0
        PARSECTX_STEP_OID(ctx, 1);
4459
0
        while (PARSECTX_PEEK_CHAR_OID(ctx) != '}')
4460
0
        {
4461
0
            if (VALIDHEXBYTE(PARSECTX_GET_CURRENT_POS_OID(ctx)))
4462
0
            {
4463
0
                oidClass <<= 8;
4464
0
                oidClass += (HEX2VALUE(PARSECTX_PEEK_CHAR_OID(ctx)) << 4 | HEX2VALUE(PARSECTX_PEEK_NEXT_CHAR_OID(ctx)));
4465
0
                PARSECTX_STEP_OID(ctx, 2);
4466
4467
0
                if (VALIDHEXSEP(PARSECTX_PEEK_CHAR_OID(ctx)))
4468
0
                {
4469
0
                    if (PARSECTX_PEEK_NEXT_CHAR_OID(ctx) == '}')
4470
0
                    {
4471
                        /* no separator after byte block */
4472
0
                        return 1;
4473
0
                    }
4474
0
                    PARSECTX_STEP_OID(ctx, 1);
4475
0
                }
4476
0
            }
4477
0
            else
4478
0
            {
4479
0
                return 1;
4480
0
            }
4481
0
        }
4482
0
        PARSECTX_STEP_OID(ctx, 1);
4483
4484
0
        classSize = OALMarshal_GetCompressedValueSize(4, oidClass);
4485
0
        if (PARSECTX_CHECK_LEN(ctx, classSize) == 0)
4486
0
        {
4487
0
            if (PARSECTX_GET_CURRENT_POS_BUF(ctx))
4488
0
                classSize = OALMarshal_CompressValue(4, oidClass, classSize, PARSECTX_GET_CURRENT_POS_BUF(ctx));
4489
4490
0
            PARSECTX_STEP_BUF(ctx, classSize);
4491
0
        }
4492
4493
0
        return 0;
4494
0
    }
4495
0
    else
4496
0
    {
4497
        /* Number */
4498
0
        uint8_t classSize = 0;
4499
0
        uint32_t oidClass = 0;
4500
0
        while (IS_DIGIT(PARSECTX_PEEK_CHAR_OID(ctx)))
4501
0
        {
4502
0
            oidClass *= 10;
4503
0
            oidClass += DIGIT2VALUE(PARSECTX_PEEK_CHAR_OID(ctx));
4504
0
            PARSECTX_STEP_OID(ctx, 1);
4505
0
        }
4506
4507
0
        classSize = OALMarshal_GetCompressedValueSize(4, oidClass);
4508
0
        if (PARSECTX_CHECK_LEN(ctx, classSize) == 0)
4509
0
        {
4510
0
            if (PARSECTX_GET_CURRENT_POS_BUF(ctx))
4511
0
                classSize = OALMarshal_CompressValue(4, oidClass, classSize, PARSECTX_GET_CURRENT_POS_BUF(ctx));
4512
4513
0
            PARSECTX_STEP_BUF(ctx, classSize);
4514
0
        }
4515
4516
0
        return 0;
4517
0
    }
4518
0
}
4519
4520
static uint8_t parseAttributeID(struct parseCtx *ctx)
4521
0
{
4522
0
    if (PARSECTX_PEEK_CHAR_OID(ctx) == '{')
4523
0
    {
4524
0
        return parseHexField(ctx);
4525
0
    }
4526
0
    else
4527
0
    {
4528
0
        uint8_t avpid = 0;
4529
0
        while (IS_DIGIT(PARSECTX_PEEK_CHAR_OID(ctx)))
4530
0
        {
4531
0
            avpid *= 10;
4532
0
            avpid += DIGIT2VALUE(PARSECTX_PEEK_CHAR_OID(ctx));
4533
0
            PARSECTX_STEP_OID(ctx, 1);
4534
0
        }
4535
4536
0
        if (PARSECTX_CHECK_LEN(ctx, 1) == 0)
4537
0
        {
4538
0
            PARSECTX_WRITE_BUF(ctx, avpid);
4539
0
            return 0;
4540
0
        }
4541
0
    }
4542
0
    return 1;
4543
0
}
4544
4545
// NOLINTNEXTLINE(misc-no-recursion)
4546
static uint8_t parseAttributeData(struct parseCtx *ctx)
4547
0
{
4548
0
    uint8_t ret;
4549
0
    ctx->depth++;
4550
0
    DISSECTOR_ASSERT(ctx->depth < prefs.gui_max_tree_depth);
4551
0
    if (PARSECTX_PEEK_CHAR_OID(ctx) == '[')
4552
0
    {
4553
0
        ret = parseFormatOID(ctx);
4554
0
    }
4555
0
    else if (PARSECTX_PEEK_CHAR_OID(ctx) == '{')
4556
0
    {
4557
0
        ret = parseHexField(ctx);
4558
0
    }
4559
0
    else
4560
0
    {
4561
0
        ret = parseStringField(ctx);
4562
0
    }
4563
0
    ctx->depth--;
4564
0
    return ret;
4565
0
}
4566
4567
// NOLINTNEXTLINE(misc-no-recursion)
4568
static uint8_t parseAttribute(struct parseCtx *ctx)
4569
0
{
4570
0
    if (parseAttributeID(ctx) == 0)
4571
0
    {
4572
        /* separated by ':' */
4573
0
        if (PARSECTX_READ_CHAR_OID(ctx) == ':' && PARSECTX_CHECK_LEN(ctx, 1) == 0)
4574
0
        {
4575
0
            uint8_t *length = PARSECTX_GET_CURRENT_POS_BUF(ctx);
4576
0
            if (length == NULL)
4577
0
                return 0;
4578
4579
0
            PARSECTX_STEP_BUF(ctx, 1);
4580
4581
0
            if (parseAttributeData(ctx) == 0)
4582
0
            {
4583
0
                PARSECTX_WRITE_AT_POS_BUF(ctx, length, (uint8_t)(PARSECTX_GET_CURRENT_POS_BUF(ctx) - (length + 1)));
4584
0
                return 0;
4585
0
            }
4586
0
        }
4587
0
    }
4588
0
    return 1;
4589
0
}
4590
4591
// NOLINTNEXTLINE(misc-no-recursion)
4592
static uint8_t parseAttributes(struct parseCtx *ctx)
4593
0
{
4594
    /* AVPs surrounded by '(' ')' but needs at least an avp */
4595
0
    if (PARSECTX_READ_CHAR_OID(ctx) == '(' &&  PARSECTX_PEEK_CHAR_OID(ctx) != ')')
4596
0
    {
4597
0
        while (PARSECTX_PEEK_CHAR_OID(ctx) != ')')
4598
0
        {
4599
0
            uint8_t *avpID = PARSECTX_GET_CURRENT_POS_BUF(ctx);
4600
0
            if (avpID == NULL)
4601
0
                return 0;
4602
4603
0
            if (parseAttribute(ctx) != 0)
4604
0
                return 1;
4605
4606
            /* multiple separated by '|' */
4607
0
            if (PARSECTX_PEEK_CHAR_OID(ctx) == '|' && PARSECTX_PEEK_NEXT_CHAR_OID(ctx) != ')')
4608
0
            {
4609
0
                PARSECTX_OR_AT_POS_BUF(ctx, avpID, 0x80); /* set that there is a next attribute */
4610
0
                PARSECTX_STEP_OID(ctx, 1);
4611
0
            }
4612
0
        }
4613
0
        PARSECTX_STEP_OID(ctx, 1);
4614
0
        return 0;
4615
0
    }
4616
0
    return 1;
4617
0
}
4618
4619
// NOLINTNEXTLINE(misc-no-recursion)
4620
static uint8_t parseFormatOID(struct parseCtx *ctx)
4621
0
{
4622
    /* oid must start with '[' */
4623
0
    if (PARSECTX_PEEK_CHAR_OID(ctx) == '[')
4624
0
    {
4625
0
        PARSECTX_STEP_OID(ctx, 1);
4626
        /* Get class id */
4627
0
        if (parseOIDClass(ctx) == 0)
4628
0
        {
4629
            /* separated by ':' */
4630
0
            if (PARSECTX_READ_CHAR_OID(ctx) == ':' && PARSECTX_CHECK_LEN(ctx, 1) == 0)
4631
0
            {
4632
0
                uint8_t *length = PARSECTX_GET_CURRENT_POS_BUF(ctx);
4633
0
                PARSECTX_STEP_BUF(ctx, 1);
4634
4635
                /* Get data */
4636
0
                if (PARSECTX_PEEK_CHAR_OID(ctx) == '{')
4637
0
                {
4638
                    /* hex data */
4639
0
                    if (parseHexField(ctx) != 0)
4640
0
                        return 1;
4641
0
                }
4642
0
                else
4643
0
                {
4644
                    /* string data */
4645
0
                    if (parseStringField(ctx) != 0)
4646
0
                        return 1;
4647
0
                }
4648
4649
                /* Write length */
4650
0
                if (length == NULL)
4651
0
                    return 0;
4652
0
                PARSECTX_WRITE_AT_POS_BUF(ctx, length, (uint8_t)(PARSECTX_GET_CURRENT_POS_BUF(ctx) - (length + 1)));
4653
4654
                /* Check if attributes exist */
4655
0
                if (PARSECTX_PEEK_CHAR_OID(ctx) == '(')
4656
0
                {
4657
0
                    PARSECTX_OR_AT_POS_BUF(ctx, length, 0x80); /* set that there are attributes */
4658
0
                    if (parseAttributes(ctx) != 0)
4659
0
                        return 1;
4660
0
                }
4661
4662
                /* Ends with ] */
4663
0
                if (PARSECTX_READ_CHAR_OID(ctx) == ']')
4664
0
                {
4665
0
                    return 0;
4666
0
                }
4667
0
            }
4668
0
        }
4669
0
    }
4670
0
    return 1;
4671
0
}
4672
4673
static uint8_t dof_oid_create_internal(const char *oid, uint32_t *size, uint8_t *buffer)
4674
0
{
4675
0
    struct parseCtx ctx = {0};
4676
4677
0
    ctx.oid = oid;
4678
0
    ctx.buffer = buffer;
4679
4680
0
    if (oid)
4681
0
    {
4682
0
        if (size)
4683
0
        {
4684
0
            ctx.buffLen = (*size);
4685
0
            ctx.oidLen = (uint32_t)strlen(oid);
4686
0
            if (PARSECTX_PEEK_CHAR_OID(&ctx) == '[')
4687
0
            {
4688
                /* Format OID */
4689
0
                if (parseFormatOID(&ctx) == 0)
4690
0
                {
4691
0
                    (*size) = ctx.currBufferPos;
4692
0
                    return 0;
4693
0
                }
4694
0
            }
4695
0
            else if (PARSECTX_PEEK_CHAR_OID(&ctx) == '{')
4696
0
            {
4697
                /* HEX OID */
4698
0
                if (parseHexField(&ctx) == 0)
4699
0
                {
4700
0
                    (*size) = ctx.currBufferPos;
4701
0
                    return 0;
4702
0
                }
4703
0
            }
4704
0
            (*size) = 0;
4705
0
        }
4706
0
    }
4707
0
    return 1;
4708
0
}
4709
4710
static void dof_oid_new_standard_string(const char *data, uint32_t *rsize, uint8_t **oid)
4711
0
{
4712
0
    if (data)
4713
0
    {
4714
0
        uint8_t err;
4715
0
        uint32_t size = 0;
4716
4717
        /* Call parseInternal to find out how big the buffer needs to be. */
4718
0
        err = dof_oid_create_internal(data, &size, NULL);
4719
4720
0
        if (err == 0)
4721
0
        {
4722
            /* Create the DOFObjectID using the size that was just computed. */
4723
0
            *oid = (uint8_t *)g_malloc(size + 1); /* Adds space for null-terminator, just in case. */
4724
4725
0
            if (*oid)
4726
0
            {
4727
                /* Now that the size is computed and the DOFObjectID is created, call parseInternal again to fill the oid buffer. */
4728
0
                err = dof_oid_create_internal(data, &size, *oid);
4729
4730
0
                if (err == 0)
4731
0
                {
4732
0
                    *rsize = size;
4733
0
                    return;
4734
0
                }
4735
4736
0
                g_free(*oid);
4737
0
            }
4738
0
        }
4739
0
    }
4740
4741
0
    *rsize = 0;
4742
0
    *oid = NULL;
4743
0
}
4744
4745
/* Binary Parsing Support */
4746
4747
/**
4748
 * Read a compressed 32-bit quantity (PDU Type.3).
4749
 * Since the value is variable length, the new offset is
4750
 * returned. The value can also be returned, along with the size, although
4751
 * NULL is allowed for those parameters.
4752
 */
4753
static int read_c4(tvbuff_t *tvb, int offset, uint32_t *v, int *L)
4754
10.8k
{
4755
10.8k
    uint32_t val = 0;
4756
10.8k
    uint8_t len = 0;
4757
10.8k
    uint8_t b = tvb_get_uint8(tvb, offset++);
4758
10.8k
    int i;
4759
4760
10.8k
    if ((b & 0x80) == 0)
4761
7.54k
    {
4762
7.54k
        len = 1;
4763
7.54k
        b = b & 0x7F;
4764
7.54k
    }
4765
3.29k
    else if ((b & 0x40) == 0)
4766
1.41k
    {
4767
1.41k
        len = 2;
4768
1.41k
        b = b & 0x3F;
4769
1.41k
    }
4770
1.88k
    else
4771
1.88k
    {
4772
1.88k
        len = 4;
4773
1.88k
        b = b & 0x3F;
4774
1.88k
    }
4775
4776
10.8k
    val = b;
4777
17.6k
    for (i = 1; i < len; i++)
4778
6.83k
        val = (val << 8) | tvb_get_uint8(tvb, offset++);
4779
4780
10.8k
    if (L)
4781
10.7k
        *L = len;
4782
10.8k
    if (v)
4783
10.7k
        *v = val;
4784
10.8k
    return offset;
4785
10.8k
}
4786
4787
/**
4788
 * Validate PDU Type.3
4789
 * Validates the encoding.
4790
 * Add Expert Info if format invalid
4791
 * This also validates Spec Type.3.1.
4792
 */
4793
static void validate_c4(packet_info *pinfo, proto_item *pi, uint32_t val, int len)
4794
10.7k
{
4795
10.7k
    if (len > 1 && val < 0x80)
4796
79
    {
4797
        /* SPEC Type.3.1 Violation. */
4798
79
        expert_add_info_format(pinfo, pi, &ei_c2_c3_c4_format, "DOF Violation: Type.3.1: Compressed 32-bit Compression Mandatory.");
4799
79
    }
4800
4801
10.7k
    if (len > 2 && val < 0x4000)
4802
5
    {
4803
        /* SPEC Type.3.1 Violation. */
4804
5
        expert_add_info_format(pinfo, pi, &ei_c2_c3_c4_format, "DOF Violation: Type.3.1: Compressed 32-bit Compression Mandatory.");
4805
5
    }
4806
10.7k
}
4807
4808
/**
4809
 * Reads a compressed 24-bit quantity (PDU Type.2).
4810
 * Since the value is variable length, the new offset is
4811
 * returned.
4812
 * The value can also be returned, along with the size, although
4813
 * NULL is allowed for those parameters.
4814
 */
4815
static int read_c3(tvbuff_t *tvb, int offset, uint32_t *v, int *L)
4816
10
{
4817
10
    uint32_t val = 0;
4818
10
    uint8_t len = 0;
4819
10
    uint8_t b = tvb_get_uint8(tvb, offset++);
4820
10
    int i;
4821
4822
10
    if ((b & 0x80) == 0)
4823
8
    {
4824
8
        len = 1;
4825
8
        b = b & 0x7F;
4826
8
    }
4827
2
    else if ((b & 0x40) == 0)
4828
0
    {
4829
0
        len = 2;
4830
0
        b = b & 0x3F;
4831
0
    }
4832
2
    else
4833
2
    {
4834
2
        len = 3;
4835
2
        b = b & 0x3F;
4836
2
    }
4837
4838
10
    val = b;
4839
14
    for (i = 1; i < len; i++)
4840
4
        val = (val << 8) | tvb_get_uint8(tvb, offset++);
4841
4842
10
    if (L)
4843
10
        *L = len;
4844
10
    if (v)
4845
10
        *v = val;
4846
10
    return offset;
4847
10
}
4848
4849
/**
4850
 * Validate PDU Type.2
4851
 * Validates the encoding.
4852
 * Adds Expert Info if format invalid
4853
 * This also validates Spec Type.2.1.
4854
 */
4855
static void validate_c3(packet_info *pinfo, proto_item *pi, uint32_t val, int len)
4856
10
{
4857
10
    if (len > 1 && val < 0x80)
4858
0
    {
4859
        /* SPEC Type.2.1 Violation. */
4860
0
        expert_add_info_format(pinfo, pi, &ei_c2_c3_c4_format, "DOF Violation: Type.2.1: Compressed 24-bit Compression Mandatory." );
4861
0
    }
4862
4863
10
    if (len > 2 && val < 0x4000)
4864
0
    {
4865
        /* SPEC Type.2.1 Violation. */
4866
0
        expert_add_info_format(pinfo, pi, &ei_c2_c3_c4_format, "DOF Violation: Type.2.1: Compressed 24-bit Compression Mandatory.");
4867
0
    }
4868
10
}
4869
4870
/**
4871
 * Reads a compressed 16-bit quantity (PDU Type.1).
4872
 * Since the value is variable length, the new offset is
4873
 * returned. The value can also be returned, along with the size, although
4874
 * NULL is allowed for those parameters.
4875
 */
4876
static int read_c2(tvbuff_t *tvb, int offset, uint16_t *v, int *L)
4877
2.79k
{
4878
2.79k
    uint16_t val = 0;
4879
2.79k
    uint8_t b = tvb_get_uint8(tvb, offset++);
4880
2.79k
    if (b & 0x80)
4881
1.09k
    {
4882
1.09k
        b = b & 0x7F;
4883
1.09k
        val = (b << 8) | tvb_get_uint8(tvb, offset++);
4884
1.09k
        if (L)
4885
888
            *L = 2;
4886
1.09k
    }
4887
1.70k
    else
4888
1.70k
    {
4889
1.70k
        val = b;
4890
1.70k
        if (L)
4891
1.59k
            *L = 1;
4892
1.70k
    }
4893
4894
2.79k
    if (v)
4895
2.78k
        *v = val;
4896
2.79k
    return offset;
4897
2.79k
}
4898
4899
/**
4900
 * Validates PDU Type.1
4901
 * Validates the encoding.
4902
 * Adds Expert Info if format invalid
4903
 * This also validates Spec Type.1.1.
4904
 */
4905
static void validate_c2(packet_info *pinfo, proto_item *pi, uint16_t val, int len)
4906
2.18k
{
4907
2.18k
    if (len > 1 && val < 0x80)
4908
72
    {
4909
        /* SPEC Type.1.1 Violation. */
4910
72
        expert_add_info_format(pinfo, pi, &ei_c2_c3_c4_format, "DOF Violation: Type.1.1: Compressed 16-bit Compression Mandatory." );
4911
72
    }
4912
2.18k
}
4913
4914
/**
4915
 * Given a packet data, and assuming that all of the prerequisite information is known,
4916
 * assign a SID ID to the packet if not already assigned.
4917
 * A SID ID is the *possibility* of a unique SID, but until the SID is learned the
4918
 * association is not made. Further, multiple SID ID may end up referring to the
4919
 * same SID, in which case the assignment must be repaired.
4920
 */
4921
static void assign_sid_id(dof_api_data *api_data)
4922
340
{
4923
340
    node_key_to_sid_id_key lookup_key;
4924
340
    node_key_to_sid_id_key *key;
4925
340
    dof_session_data *session;
4926
340
    dof_packet_data *packet;
4927
340
    unsigned value;
4928
4929
    /* Validate input. These represent dissector misuse, not decoding problems. */
4930
    /* TODO: Diagnostic/programmer message. */
4931
340
    if (!api_data || !api_data->packet || !api_data->session)
4932
3
        return;
4933
4934
337
    session = api_data->session;
4935
337
    packet = (dof_packet_data *)api_data->packet;
4936
4937
4938
    /* Check if the sender_sid_id is already assigned, if so we are done. */
4939
337
    if (!packet->sender_sid_id)
4940
337
    {
4941
        /* Build a (non-allocated) key to do the lookup. */
4942
337
        lookup_key.transport_id = api_data->transport_session->transport_id;
4943
337
        lookup_key.transport_node_id = api_data->transport_packet->sender_id;
4944
337
        lookup_key.dof_id = session->dof_id;
4945
337
        lookup_key.dof_node_id = packet->sender_id;
4946
337
        lookup_key.dof_session_id = session->session_id;
4947
4948
337
        value = GPOINTER_TO_UINT(g_hash_table_lookup(node_key_to_sid_id, &lookup_key));
4949
337
        if (value)
4950
285
        {
4951
285
            void *sid_id_key = GUINT_TO_POINTER(value);
4952
285
            void *sid_buffer;
4953
4954
            /* We found a match. */
4955
285
            packet->sender_sid_id = value;
4956
4957
            /* If we know the SID, we must get it now. */
4958
285
            sid_buffer = g_hash_table_lookup(sid_id_to_sid_buffer, sid_id_key);
4959
285
            if (sid_buffer)
4960
60
            {
4961
                /* We found a match. */
4962
60
                packet->sender_sid = (dof_2009_1_pdu_19_sid)sid_buffer;
4963
60
            }
4964
285
        }
4965
52
        else
4966
52
        {
4967
            /* No match, need to add a key. */
4968
52
            key = g_new0(node_key_to_sid_id_key, 1);
4969
52
            memcpy(key, &lookup_key, sizeof(node_key_to_sid_id_key));
4970
4971
            /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
4972
52
            g_hash_table_insert(node_key_to_sid_id, key, GUINT_TO_POINTER(dpp_next_sid_id));
4973
52
            packet->sender_sid_id = dpp_next_sid_id++;
4974
52
        }
4975
337
    }
4976
4977
    /* Check if the receiver_sid_id is already assigned, if so we are done. */
4978
337
    if (!packet->receiver_sid_id)
4979
337
    {
4980
        /* Build a (non-allocated) key to do the lookup. */
4981
337
        lookup_key.transport_id = api_data->transport_session->transport_id;
4982
337
        lookup_key.transport_node_id = api_data->transport_packet->receiver_id;
4983
337
        lookup_key.dof_id = session->dof_id;
4984
337
        lookup_key.dof_node_id = packet->receiver_id;
4985
337
        lookup_key.dof_session_id = session->session_id;
4986
4987
337
        value = GPOINTER_TO_UINT(g_hash_table_lookup(node_key_to_sid_id, &lookup_key));
4988
337
        if (value)
4989
286
        {
4990
286
            void *sid_id_key = GUINT_TO_POINTER(value);
4991
286
            void *sid_buffer;
4992
4993
            /* We found a match. */
4994
286
            packet->receiver_sid_id = value;
4995
4996
            /* If we know the SID, we must get it now. */
4997
286
            sid_buffer = g_hash_table_lookup(sid_id_to_sid_buffer, sid_id_key);
4998
286
            if (sid_buffer)
4999
58
            {
5000
                /* We found a match. */
5001
58
                packet->receiver_sid = (dof_2009_1_pdu_19_sid)sid_buffer;
5002
58
            }
5003
286
        }
5004
51
        else
5005
51
        {
5006
            /* No match, need to add a key. */
5007
51
            key = g_new0(node_key_to_sid_id_key, 1);
5008
51
            memcpy(key, &lookup_key, sizeof(node_key_to_sid_id_key));
5009
5010
            /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
5011
51
            g_hash_table_insert(node_key_to_sid_id, key, GUINT_TO_POINTER(dpp_next_sid_id));
5012
51
            packet->receiver_sid_id = dpp_next_sid_id++;
5013
51
        }
5014
337
    }
5015
5016
337
}
5017
5018
/**
5019
 * Declare that the sender of the packet is known to have a SID
5020
 * that is identified by the specified buffer. There are a few
5021
 * cases here:
5022
 *  1. The sid of the sender is already assigned. This is a NOP.
5023
 *  2. The sid has never been seen. This associates the SID with the sender SID ID.
5024
 *  3. The sid has been seen, and matches the SID ID of the sender. This just sets the sid field.
5025
 *  4. The sid has been seen, but with a different SID ID than ours. Patch up all the packets.
5026
 */
5027
static void learn_sender_sid(dof_api_data *api_data, uint8_t length, const uint8_t *sid)
5028
10
{
5029
10
    dof_packet_data *packet;
5030
10
    uint8_t lookup_key[256];
5031
10
    uint8_t *key;
5032
10
    void *value;
5033
5034
    /* Validate input. */
5035
10
    if (!api_data)
5036
0
    {
5037
        /* TODO: Print error. */
5038
0
        return;
5039
0
    }
5040
5041
10
    if (!api_data->packet)
5042
0
    {
5043
        /* TODO: Print error. */
5044
0
        return;
5045
0
    }
5046
5047
10
    packet = (dof_packet_data *)api_data->packet;
5048
10
    if (!packet->sender_sid_id)
5049
0
        return;
5050
5051
    /* Check for sender SID already known. */
5052
10
    if (packet->sender_sid)
5053
3
        return;
5054
5055
    /* Check for SID already known (has assigned SID ID) */
5056
    /* Build a (non-allocated) key to do the lookup. */
5057
7
    lookup_key[0] = length;
5058
7
    memcpy(lookup_key + 1, sid, length);
5059
5060
7
    if (g_hash_table_lookup_extended(sid_buffer_to_sid_id, &lookup_key, (void * *)&key, &value))
5061
1
    {
5062
1
        unsigned sid_id = GPOINTER_TO_UINT(value);
5063
5064
        /* We found a match. */
5065
1
        if (packet->sender_sid_id == sid_id)
5066
0
        {
5067
            /* It matches our SID ID. Set the sid field. */
5068
0
            packet->sender_sid = key;
5069
0
            return;
5070
0
        }
5071
1
        else
5072
1
        {
5073
            /* There is a mis-match between SID and SID ID. We have to go through
5074
            * all the packets that have SID ID (ours) and update them to SID ID (sid).
5075
            */
5076
1
            unsigned sid_id_correct = sid_id;
5077
1
            unsigned sid_id_incorrect = packet->sender_sid_id;
5078
1
            dof_packet_data *ptr = globals.dof_packet_head;
5079
5080
134
            while (ptr)
5081
133
            {
5082
133
                if (ptr->sender_sid_id == sid_id_incorrect)
5083
3
                    ptr->sender_sid_id = sid_id_correct;
5084
5085
133
                if (ptr->receiver_sid_id == sid_id_incorrect)
5086
0
                    ptr->receiver_sid_id = sid_id_correct;
5087
5088
133
                if (ptr->op.op_sid_id == sid_id_incorrect)
5089
0
                    ptr->op.op_sid_id = sid_id_correct;
5090
5091
133
                if (ptr->ref_op.op_sid_id == sid_id_incorrect)
5092
0
                    ptr->ref_op.op_sid_id = sid_id_correct;
5093
5094
133
                ptr = ptr->next;
5095
133
            }
5096
1
        }
5097
5098
1
        return;
5099
1
    }
5100
5101
    /* The SID has never been seen. Associate with the SID ID. */
5102
6
    key = (dof_2009_1_pdu_19_sid)g_malloc0(length + 1);
5103
6
    memcpy(key, lookup_key, length + 1);
5104
5105
    /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
5106
6
    g_hash_table_insert(sid_buffer_to_sid_id, key, GUINT_TO_POINTER(packet->sender_sid_id));
5107
6
    g_hash_table_insert(sid_id_to_sid_buffer, GUINT_TO_POINTER(packet->sender_sid_id), key);
5108
5109
    /* NOTE: We are storing a reference to the SID in the packet data. This memory
5110
    * will be freed by the dissector init routine when the SID hash table is destroyed.
5111
    * Nothing else should free this SID.
5112
    */
5113
6
    packet->sender_sid = (dof_2009_1_pdu_19_sid)key;
5114
5115
    /* We have learned the "correct" sid and sid_id, so we can set the sid of
5116
    * any packets that have this sid_id (saves hash lookups in the future).
5117
    */
5118
6
    {
5119
6
        dof_packet_data *ptr = globals.dof_packet_head;
5120
5121
673
        while (ptr)
5122
667
        {
5123
667
            if (ptr->sender_sid_id == packet->sender_sid_id)
5124
154
                ptr->sender_sid = key;
5125
5126
667
            if (ptr->receiver_sid_id == packet->sender_sid_id)
5127
147
                ptr->receiver_sid = key;
5128
5129
667
            ptr = ptr->next;
5130
667
        }
5131
6
    }
5132
6
}
5133
5134
/**
5135
 * Learn a SID from an explicit operation. This only defines sids and sid ids.
5136
 */
5137
static void learn_operation_sid(dof_2009_1_pdu_20_opid *opid, uint8_t length, const uint8_t *sid)
5138
104
{
5139
104
    uint8_t lookup_key[256];
5140
104
    uint8_t *key;
5141
104
    void *value;
5142
5143
    /* Check for sender SID already known. */
5144
104
    if (opid->op_sid)
5145
0
        return;
5146
5147
    /* Check for SID already known (has assigned SID ID) */
5148
    /* Build a (non-allocated) key to do the lookup. */
5149
104
    lookup_key[0] = length;
5150
104
    memcpy(lookup_key + 1, sid, length);
5151
5152
104
    if (g_hash_table_lookup_extended(sid_buffer_to_sid_id, &lookup_key, (void * *)&key, &value))
5153
43
    {
5154
43
        unsigned sid_id = GPOINTER_TO_UINT(value);
5155
5156
43
        opid->op_sid_id = sid_id;
5157
43
        opid->op_sid = key;
5158
43
        return;
5159
43
    }
5160
5161
    /* The SID has never been seen. Associate with the SID ID. */
5162
61
    key = (dof_2009_1_pdu_19_sid)g_malloc0(length + 1);
5163
61
    memcpy(key, lookup_key, length + 1);
5164
5165
    /* Assign the op_sid_id. */
5166
61
    opid->op_sid_id = dpp_next_sid_id++;
5167
5168
    /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
5169
61
    g_hash_table_insert(sid_buffer_to_sid_id, key, GUINT_TO_POINTER(opid->op_sid_id));
5170
61
    g_hash_table_insert(sid_id_to_sid_buffer, GUINT_TO_POINTER(opid->op_sid_id), key);
5171
5172
    /* NOTE: We are storing a reference to the SID in the packet data. This memory
5173
    * will be freed by the dissector init routine when the SID hash table is destroyed.
5174
    * Nothing else should free this SID.
5175
    */
5176
61
    opid->op_sid = (dof_2009_1_pdu_19_sid)key;
5177
61
}
5178
5179
static void generateMac(gcry_cipher_hd_t cipher_state, uint8_t *nonce, const uint8_t *epp, int a_len, uint8_t *data, int len, uint8_t *mac, int mac_len)
5180
0
{
5181
0
    uint16_t i;
5182
5183
    /* a_len = 1, t = mac_len, q = 4: (t-2)/2 : (q-1) -> 4B */
5184
0
    mac[0] = 0x43 | (((mac_len - 2) / 2) << 3);
5185
0
    memcpy(mac + 1, nonce, 11);
5186
0
    memset(mac + 12, 0, 4);
5187
0
    mac[14] = len >> 8;
5188
0
    mac[15] = len & 0xFF;
5189
5190
0
    gcry_cipher_encrypt(cipher_state, mac, 16, NULL, 0);
5191
5192
0
    mac[0] ^= (a_len >> 8);
5193
0
    mac[1] ^= (a_len);
5194
0
    i = 2;
5195
5196
0
    for (int cnt = 0; cnt < a_len; cnt++, i++)
5197
0
    {
5198
0
        if (i % 16 == 0)
5199
0
            gcry_cipher_encrypt(cipher_state, mac, 16, NULL, 0);
5200
5201
0
        mac[i % 16] ^= epp[cnt];
5202
0
    }
5203
5204
0
    i = 0;
5205
0
    for (int cnt = 0; cnt < len; cnt++, i++)
5206
0
    {
5207
0
        if (i % 16 == 0)
5208
0
            gcry_cipher_encrypt(cipher_state, mac, 16, NULL, 0);
5209
5210
0
        mac[i % 16] ^= data[cnt];
5211
0
    }
5212
5213
0
    gcry_cipher_encrypt(cipher_state, mac, 16, NULL, 0);
5214
0
}
5215
5216
static int decrypt(ccm_session_data *session, ccm_packet_data *pdata, uint8_t *nonce, const uint8_t *epp, int a_len, uint8_t *data, int len)
5217
0
{
5218
0
    int i;
5219
0
    unsigned char ctr[16];
5220
0
    unsigned char encrypted_ctr[16];
5221
0
    unsigned char mac[16];
5222
0
    unsigned char computed_mac[16];
5223
0
    unsigned int skip;
5224
0
    uint8_t *ekey;
5225
5226
0
    if (data == NULL || len == 0)
5227
0
        return 0;
5228
5229
    /* Check the mac length. */
5230
0
    if (session->mac_len < 4 || session->mac_len > 16)
5231
0
        return 0;
5232
5233
0
    if (pdata->period == 0)
5234
0
        ekey = (uint8_t *)session->cipher_data;
5235
0
    else
5236
0
        ekey = (uint8_t *)g_hash_table_lookup(session->cipher_data_table, GUINT_TO_POINTER(pdata->period));
5237
5238
0
    if (!ekey)
5239
0
        return 0;
5240
5241
    /* Determine how many blocks are skipped. */
5242
#if 0 /* seems to be dead code... check this! */
5243
    skip = a_len + 2;
5244
    skip /= 16;
5245
    if ((a_len + 2) % 16)
5246
        skip += 1;
5247
#endif
5248
0
    skip = 0;
5249
5250
    /* This is hard-coded for q=4. This can only change with a protocol revision.
5251
    Note the value is stored as (q-1). */
5252
0
    ctr[0] = 0x03;
5253
0
    memcpy(ctr + 1, nonce, 11);
5254
0
    ctr[12] = 0;
5255
0
    ctr[13] = 0;
5256
0
    ctr[14] = 0;
5257
0
    ctr[15] = skip; /* Preincremented below. */
5258
5259
5260
0
    for (i = 0; i < len - session->mac_len; i++)
5261
0
    {
5262
0
        if (i % 16 == 0)
5263
0
        {
5264
0
            if (ctr[15] == 255)
5265
0
                ctr[14] += 1;
5266
0
            ctr[15] += 1;
5267
0
            memcpy(encrypted_ctr, ctr, 16);
5268
0
            gcry_cipher_encrypt(session->cipher_data, encrypted_ctr, 16, NULL, 0);
5269
0
        }
5270
5271
0
        data[i] ^= encrypted_ctr[i % 16];
5272
0
    }
5273
5274
0
    memcpy(mac, data + i, session->mac_len);
5275
5276
0
    ctr[12] = 0;
5277
0
    ctr[13] = 0;
5278
0
    ctr[14] = 0;
5279
0
    ctr[15] = 0;
5280
0
    memcpy(encrypted_ctr, ctr, 16);
5281
0
    gcry_cipher_encrypt(session->cipher_data, encrypted_ctr, 16, NULL, 0);
5282
5283
0
    for (i = 0; i < session->mac_len; i++)
5284
0
        mac[i] ^= encrypted_ctr[i];
5285
5286
    /* Now we have to generate the MAC... */
5287
0
    generateMac(session->cipher_data, nonce, epp, a_len, data, (int)(len - session->mac_len), computed_mac, session->mac_len);
5288
0
    if (!memcmp(mac, computed_mac, session->mac_len))
5289
0
        return 1;
5290
5291
    /* Failure */
5292
0
    return 0;
5293
0
}
5294
5295
/* Master Protocol Layer Handlers */
5296
5297
/**
5298
 * This dissector is handed a DPP packet of any version. It is responsible for decoding
5299
 * the common header fields and then passing off to the specific DPP dissector
5300
 */
5301
static int dissect_app_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5302
291
{
5303
291
    col_clear(pinfo->cinfo, COL_INFO);
5304
5305
    /* Compute the APP control information. This is the version and the flags byte.
5306
    * The flags byte is either present, or is based on the version (and can be defaulted).
5307
    */
5308
291
    {
5309
291
        uint16_t app;
5310
291
        int app_len;
5311
5312
291
        read_c2(tvb, 0, &app, &app_len);
5313
5314
291
        col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "APP(%u)", app);
5315
5316
        /* call the next dissector */
5317
291
        if (dissector_try_uint_with_data(app_dissectors, app, tvb, pinfo, tree, true, data))
5318
67
        {
5319
67
            col_set_fence(pinfo->cinfo, COL_PROTOCOL);
5320
67
            col_set_fence(pinfo->cinfo, COL_INFO);
5321
5322
67
            return tvb_reported_length(tvb);
5323
67
        }
5324
224
        else
5325
224
        {
5326
224
            proto_tree_add_protocol_format(tree, proto_2008_1_app, tvb, 0, app_len,
5327
224
                                           DOF_APPLICATION_PROTOCOL ", Version: %u", app);
5328
224
        }
5329
291
    }
5330
5331
224
    return 0;
5332
291
}
5333
5334
/**
5335
 * This dissector is handed a DPP packet of any version. It is responsible for decoding
5336
 * the common header fields and then passing off to the specific DPP dissector
5337
 */
5338
static int dof_dissect_dpp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5339
355
{
5340
355
    dof_api_data *api_data = (dof_api_data *)data;
5341
355
    unsigned offset = 0;
5342
5343
355
    DISSECTOR_ASSERT(api_data != NULL);
5344
5345
355
    col_clear(pinfo->cinfo, COL_INFO);
5346
5347
    /* Compute the DPP control information. This is the version and the flags byte.
5348
    * The flags byte is either present, or is based on the version (and can be defaulted).
5349
    */
5350
355
    {
5351
355
        uint8_t header = tvb_get_uint8(tvb, offset);
5352
355
        uint8_t dpp_version = header & 0x7F;
5353
355
        uint8_t dpp_flags_included = header & 0x80;
5354
355
        proto_item *hi;
5355
355
        proto_tree * dpp_root,*dpp_tree;
5356
5357
355
        col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "DPPv%u", dpp_version);
5358
5359
5360
355
        hi = proto_tree_add_protocol_format(tree, proto_2008_1_dpp, tvb, offset, 0,
5361
355
                                            DOF_PRESENTATION_PROTOCOL " Version %u, Flags: %s", dpp_version, dpp_flags_included ? "Included" : "Default");
5362
5363
355
        dpp_root = proto_item_add_subtree(hi, ett_2008_1_dpp);
5364
5365
355
        dpp_tree = proto_tree_add_subtree(dpp_root, tvb, offset, 1, ett_2008_1_dpp_1_header, NULL, "Header");
5366
5367
5368
        /* Version and Flag bit */
5369
355
        proto_tree_add_item(dpp_tree, hf_2008_1_dpp_1_flag, tvb, offset, 1, ENC_NA);
5370
355
        proto_tree_add_item(dpp_tree, hf_2008_1_dpp_1_version, tvb, offset, 1, ENC_NA);
5371
355
        offset += 1;
5372
5373
        /* This may, in some cases, be the end of the packet. This is only valid in some
5374
        * situations, which are checked here.
5375
        */
5376
355
        if (offset == tvb_reported_length(tvb))
5377
1
        {
5378
            /* TODO: Complete this logic. */
5379
5380
1
            proto_item_set_len(hi, offset);
5381
5382
1
            if (!api_data)
5383
0
                return offset;
5384
5385
1
            if (api_data->transport_session->is_streaming)
5386
0
            {
5387
0
                col_append_str(pinfo->cinfo, COL_INFO, "DNP/DPP Negotiation");
5388
5389
0
                if (pinfo->fd->visited &&
5390
0
                    api_data->transport_session->negotiation_required &&
5391
0
                    ((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)))
5392
0
                {
5393
                    /* This is the second pass, so we can check for timeouts. */
5394
0
                    expert_add_info(pinfo, hi, &ei_dof_6_timeout);
5395
0
                }
5396
5397
0
                return offset;
5398
0
            }
5399
1
        }
5400
5401
        /* call the next dissector */
5402
355
        if (dissector_try_uint_with_data(dof_dpp_dissectors, dpp_version, tvb, pinfo, dpp_root, false, data))
5403
111
        {
5404
111
            col_set_fence(pinfo->cinfo, COL_PROTOCOL);
5405
111
            col_set_fence(pinfo->cinfo, COL_INFO);
5406
5407
111
            return tvb_reported_length(tvb);
5408
111
        }
5409
355
    }
5410
5411
244
    return 0;
5412
355
}
5413
5414
/**
5415
 * This dissector is handed a DNP packet of any version. It is responsible for decoding
5416
 * the common header fields and then passing off to the specific DNP dissector
5417
 */
5418
static int dof_dissect_dnp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, dof_api_data *api_data, int offset)
5419
372
{
5420
372
    uint8_t header = tvb_get_uint8(tvb, offset);
5421
372
    uint8_t dnp_version = header & 0x7F;
5422
372
    uint8_t dnp_flags_included = header & 0x80;
5423
372
    proto_item *main_ti;
5424
372
    proto_tree * dnp_root,*dnp_tree;
5425
5426
372
    col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "DNPv%u", dnp_version);
5427
5428
372
    main_ti = proto_tree_add_protocol_format(tree, proto_2008_1_dnp, tvb, offset, 0,
5429
372
                                             DOF_NETWORK_PROTOCOL " Version %u, Flags: %s", dnp_version, dnp_flags_included ? "Included" : "Default");
5430
5431
372
    dnp_root = proto_item_add_subtree(main_ti, ett_2008_1_dnp);
5432
5433
372
    dnp_tree = proto_tree_add_subtree(dnp_root, tvb, offset, 1, ett_2008_1_dnp_header, NULL, "Header");
5434
5435
    /* Version and Flag bit */
5436
372
    proto_tree_add_item(dnp_tree, hf_2008_1_dnp_1_flag, tvb, offset, 1, ENC_NA);
5437
372
    proto_tree_add_item(dnp_tree, hf_2008_1_dnp_1_version, tvb, offset, 1, ENC_NA);
5438
5439
    /* call the next dissector */
5440
372
    if (dissector_try_uint_with_data(dnp_dissectors, dnp_version, tvb, pinfo, dnp_root, false, api_data))
5441
125
    {
5442
        /* Since the transport may have additional packets in this frame, protect our work. */
5443
125
        col_set_fence(pinfo->cinfo, COL_PROTOCOL);
5444
125
        col_set_fence(pinfo->cinfo, COL_INFO);
5445
125
    }
5446
247
    else
5447
247
    {
5448
247
        proto_item_set_end(main_ti, tvb, 1);
5449
5450
        /* During negotiation, we can move past DNP even if it is not known. */
5451
247
        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)))
5452
3
        {
5453
3
            offset += dof_dissect_dpp_common(tvb_new_subset_remaining(tvb, offset + 1), pinfo, tree, api_data);
5454
3
        }
5455
247
    }
5456
5457
372
    if (dnp_flags_included && !api_data->transport_session->negotiation_complete_at)
5458
4
    {
5459
4
        api_data->transport_session->negotiation_complete_at = pinfo->fd->num;
5460
4
        api_data->transport_session->negotiation_complete_at_ts = pinfo->abs_ts;
5461
4
    }
5462
5463
372
    return offset;
5464
372
}
5465
5466
/**
5467
 * This dissector is called for each DPS packet. It assumes that the first layer is
5468
 * DNP, but it does not know anything about versioning. Further, it only worries
5469
 * about decoding DNP (DNP will decode DPP, and so on).
5470
 *
5471
 * This routine is given the DPS packet for the first packet, but doesn't know anything
5472
 * about DPS sessions. It may understand transport sessions, but these are surprisingly
5473
 * worthless for DPS.
5474
 */
5475
static int dissect_dof_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5476
372
{
5477
372
    dof_api_data *api_data = (dof_api_data *)data;
5478
372
    proto_tree *dof_root;
5479
372
    dof_packet_data *packet;
5480
5481
372
    DISSECTOR_ASSERT(api_data != NULL);
5482
372
    DISSECTOR_ASSERT(api_data->transport_session != NULL);
5483
372
    DISSECTOR_ASSERT(api_data->transport_packet != NULL);
5484
5485
372
    packet = (dof_packet_data *)api_data->packet;
5486
5487
    /* Create the packet if it doesn't exist. */
5488
372
    if (packet == NULL)
5489
372
    {
5490
372
        api_data->packet = packet = create_packet_data(pinfo);
5491
372
        DISSECTOR_ASSERT(packet != NULL);
5492
5493
        /* TODO: This is not correct for reversed sessions. */
5494
372
        packet->is_sent_by_initiator = api_data->transport_packet->is_sent_by_client;
5495
372
    }
5496
5497
    /* Assign the transport sequence if it does not exist. */
5498
372
    if (api_data->transport_session->transport_session_id == 0)
5499
57
        api_data->transport_session->transport_session_id = globals.next_transport_session++;
5500
5501
    /* Compute the DPS information. This is a master holder for general information. */
5502
372
    {
5503
372
        proto_item *ti;
5504
5505
372
        ti = proto_tree_add_protocol_format(tree, proto_2008_1_dof, tvb, 0, tvb_reported_length(tvb), DOF_PROTOCOL_STACK);
5506
372
        dof_root = proto_item_add_subtree(ti, ett_2008_1_dof);
5507
5508
        /* Add the general packet information. */
5509
372
        {
5510
372
            ti = proto_tree_add_uint(dof_root, hf_2008_1_dof_session_transport, tvb, 0, 0, api_data->transport_session->transport_session_id);
5511
372
            proto_item_set_generated(ti);
5512
5513
372
            ti = proto_tree_add_boolean(dof_root, hf_2008_1_dof_is_2_node, tvb, 0, 0, api_data->transport_session->is_2_node);
5514
372
            proto_item_set_generated(ti);
5515
5516
372
            ti = proto_tree_add_boolean(dof_root, hf_2008_1_dof_is_streaming, tvb, 0, 0, api_data->transport_session->is_streaming);
5517
372
            proto_item_set_generated(ti);
5518
5519
372
            if (api_data->session)
5520
0
            {
5521
0
                ti = proto_tree_add_uint(dof_root, hf_2008_1_dof_session, tvb, 0, 0, api_data->session->session_id);
5522
0
                proto_item_set_generated(ti);
5523
0
            }
5524
5525
372
            if (api_data->secure_session)
5526
0
            {
5527
0
                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);
5528
0
                proto_item_set_generated(ti);
5529
0
            }
5530
5531
372
            ti = proto_tree_add_uint(dof_root, hf_2008_1_dof_frame, tvb, 0, 0, packet->dof_frame);
5532
372
            proto_item_set_generated(ti);
5533
5534
372
            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);
5535
372
            proto_item_set_generated(ti);
5536
372
        }
5537
372
    }
5538
5539
372
    dof_dissect_dnp_common(tvb, pinfo, tree, api_data, 0);
5540
5541
372
    packet->processed = true;
5542
372
    return tvb_reported_length(tvb);
5543
372
}
5544
5545
/**
5546
 * This dissector is called for each DPS packet. It assumes that the first layer is
5547
 * ENP, but it does not know anything about versioning. Further, it only worries
5548
 * about decoding ENP (ENP will decode EPP, and so on).
5549
 *
5550
 * This routine is given the DPS packet for the first packet, but doesn't know anything
5551
 * about DPS sessions. It may understand transport sessions, but these are surprisingly
5552
 * worthless for DPS.
5553
 */
5554
static int dissect_tunnel_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5555
153
{
5556
    /* The packet data is the private_data, and must exist. */
5557
153
    tcp_dof_packet_ref *ref = (tcp_dof_packet_ref *)data;
5558
153
    int offset = 0;
5559
5560
153
    offset = 0;
5561
5562
    /* Compute the APP control information. This is the version and the length bytes.
5563
    * The flags byte is either present, or is based on the version (and can be defaulted).
5564
    */
5565
153
    {
5566
153
        uint8_t version = tvb_get_uint8(tvb, offset);
5567
153
        uint8_t opcode;
5568
153
        proto_item *ti;
5569
153
        proto_tree *app_root;
5570
5571
153
        col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "TUNv%u", version);
5572
5573
153
        ti = proto_tree_add_protocol_format(tree, proto_2012_1_tunnel, tvb, offset, 0,
5574
153
                                            "DOF Tunnel Protocol, Version: %u", version);
5575
5576
153
        app_root = proto_item_add_subtree(ti, ett_2012_1_tunnel);
5577
153
        proto_tree_add_item(app_root, hf_2012_1_tunnel_1_version, tvb, offset, 1, ENC_NA);
5578
153
        proto_tree_add_item(app_root, hf_2012_1_tunnel_1_length, tvb, offset + 1, 2, ENC_BIG_ENDIAN);
5579
5580
153
        opcode = tvb_get_uint8(tvb, offset + 3);
5581
153
        if (opcode == 3)
5582
141
        {
5583
141
            tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset + 5);
5584
5585
141
            dissect_dof_common(next_tvb, pinfo, tree, &ref->api_data);
5586
141
        }
5587
153
    }
5588
5589
153
    return tvb_captured_length(tvb);
5590
153
}
5591
5592
static int dissect_tun_app_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5593
0
{
5594
0
    col_clear(pinfo->cinfo, COL_INFO);
5595
5596
    /* Compute the APP control information. This is the version and the flags byte.
5597
    * The flags byte is either present, or is based on the version (and can be defaulted).
5598
    */
5599
0
    {
5600
0
        uint16_t app;
5601
0
        int app_len;
5602
5603
5604
0
        app = tvb_get_uint8(tvb, 0);
5605
0
        app_len = 1;
5606
5607
0
        col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "APP(%u)", app);
5608
5609
        /* call the next dissector */
5610
0
        if (dissector_try_uint(dof_tun_app_dissectors, app, tvb, pinfo, tree))
5611
0
        {
5612
0
            col_set_fence(pinfo->cinfo, COL_PROTOCOL);
5613
0
            col_set_fence(pinfo->cinfo, COL_INFO);
5614
5615
0
            return tvb_captured_length(tvb);
5616
0
        }
5617
0
        else
5618
0
        {
5619
0
            proto_tree_add_protocol_format(tree, proto_2012_1_tunnel, tvb, 0, app_len,
5620
0
                                                DOF_APPLICATION_PROTOCOL ", Version: %u", app);
5621
0
        }
5622
0
    }
5623
5624
0
    return 0;
5625
0
}
5626
5627
/* Packet and Session Data Creation */
5628
5629
static udp_session_data* create_udp_session_data(packet_info *pinfo, conversation_t *conversation _U_)
5630
3
{
5631
3
    udp_session_data *packet = wmem_new0(wmem_file_scope(), udp_session_data);
5632
5633
    /* TODO: Determine if this is valid or not. */
5634
    /* WMEM_COPY_ADDRESS( wmem_file_scope(), &packet->server.address, &conversation->key_ptr->addr1 );
5635
    packet->server.port = conversation->key_ptr->port1; */
5636
3
    copy_address_wmem(wmem_file_scope(), &packet->server.addr, &pinfo->dst);
5637
3
    packet->server.port = pinfo->destport;
5638
5639
3
    packet->common.transport_id = proto_2008_1_dof_udp;
5640
5641
3
    {
5642
3
        const uint8_t *addr = (const uint8_t *)packet->server.addr.data;
5643
3
        if ((packet->server.addr.type == AT_IPv4) && (addr != NULL) && (addr[0] != 224))
5644
0
            packet->common.is_2_node = true;
5645
3
        else
5646
3
            packet->common.is_2_node = false;
5647
3
    }
5648
5649
3
    packet->common.is_streaming = false;
5650
3
    packet->common.session_start_ts = pinfo->abs_ts;
5651
3
    packet->common.negotiation_required = false;
5652
3
    packet->common.negotiation_complete_at = 0;
5653
5654
3
    return packet;
5655
3
}
5656
5657
static tcp_session_data* create_tcp_session_data(packet_info *pinfo, conversation_t *conversation)
5658
57
{
5659
57
    tcp_session_data *packet = wmem_new0(wmem_file_scope(), tcp_session_data);
5660
5661
57
    copy_address_wmem(wmem_file_scope(), &packet->client.addr, conversation_key_addr1(conversation->key_ptr));
5662
57
    packet->client.port = conversation_key_port1(conversation->key_ptr);
5663
57
    copy_address_wmem(wmem_file_scope(), &packet->server.addr, conversation_key_addr2(conversation->key_ptr));
5664
57
    packet->server.port = conversation_key_port2(conversation->key_ptr);
5665
5666
57
    packet->not_dps = false;
5667
5668
57
    packet->common.transport_id = proto_2008_1_dof_tcp;
5669
57
    packet->common.is_2_node = true;
5670
57
    packet->common.is_streaming = true;
5671
57
    packet->common.session_start_ts = pinfo->abs_ts;
5672
57
    packet->common.negotiation_required = true;
5673
57
    packet->common.negotiation_complete_at = 0;
5674
5675
57
    return packet;
5676
57
}
5677
5678
static dof_packet_data* create_packet_data(packet_info *pinfo)
5679
372
{
5680
    /* Create the packet data. */
5681
372
    dof_packet_data *packet = wmem_new0(wmem_file_scope(), dof_packet_data);
5682
5683
372
    packet->data_list = wmem_list_new(wmem_file_scope());
5684
372
    packet->frame = pinfo->fd->num;
5685
372
    packet->dof_frame = next_dof_frame++;
5686
5687
    /* Add the packet into the list of packets. */
5688
372
    if (!globals.dof_packet_head)
5689
2
    {
5690
2
        globals.dof_packet_head = packet;
5691
2
        globals.dof_packet_tail = packet;
5692
2
    }
5693
370
    else
5694
370
    {
5695
370
        globals.dof_packet_tail->next = packet;
5696
370
        globals.dof_packet_tail = packet;
5697
370
    }
5698
5699
372
    return packet;
5700
372
}
5701
5702
/* Dissectors for Transports (UDP/TCP) */
5703
5704
/**
5705
 * Dissect a UDP packet. The parent protocol is UDP. No assumptions about DPS
5706
 * data structures are made on input, but before calling common they must
5707
 * be set up.
5708
 * This dissector is registered with the UDP protocol on the standard DPS port.
5709
 * It will be used for anything that involves that port (source or destination).
5710
 */
5711
static int dissect_dof_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5712
231
{
5713
231
    dof_api_data *api_data = (dof_api_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_2008_1_dof_udp, 0);
5714
231
    if (api_data == NULL)
5715
231
    {
5716
231
        conversation_t *conversation;
5717
231
        udp_session_data *transport_session;
5718
231
        dof_transport_packet *transport_packet;
5719
        /* bool mcast = false; */
5720
5721
        /* {
5722
            uint8_t* addr = (uint8_t*) pinfo->dst.data;
5723
            if ( (pinfo->dst.type == AT_IPv4) && (addr != NULL) && (addr[0] != 224) )
5724
                mcast = true;
5725
        } */
5726
5727
        /* Register the source address as being DPS for the sender UDP port. */
5728
231
        conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport, pinfo->destport, NO_ADDR_B | NO_PORT_B);
5729
231
        if (!conversation)
5730
3
        {
5731
3
            conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport, pinfo->destport, NO_ADDR2 | NO_PORT2);
5732
3
            conversation_set_dissector(conversation, dof_udp_handle);
5733
3
        }
5734
5735
        /* Find or create the conversation for this transport session. For UDP, the transport session is determined entirely by the
5736
         * server port. This assumes that the first packet seen is from a client to the server.
5737
         */
5738
231
        conversation = find_conversation(pinfo->fd->num, &pinfo->dst, &pinfo->src, CONVERSATION_UDP, pinfo->destport, pinfo->srcport, NO_ADDR_B | NO_PORT_B);
5739
231
        if (conversation)
5740
231
        {
5741
            /* TODO: Determine if this is valid or not. */
5742
            /*if ( conversation->key_ptr->port1 != pinfo->destport || ! addresses_equal( &conversation->key_ptr->addr1, &pinfo->dst ) )
5743
                conversation = NULL; */
5744
231
        }
5745
5746
231
        if (!conversation)
5747
0
            conversation = conversation_new(pinfo->fd->num, &pinfo->dst, &pinfo->src, CONVERSATION_UDP, pinfo->destport, pinfo->srcport, NO_ADDR2 | NO_PORT2 | CONVERSATION_TEMPLATE);
5748
5749
231
        transport_session = (udp_session_data *)conversation_get_proto_data(conversation, proto_2008_1_dof_udp);
5750
231
        if (transport_session == NULL)
5751
3
        {
5752
3
            transport_session = create_udp_session_data(pinfo, conversation);
5753
3
            conversation_add_proto_data(conversation, proto_2008_1_dof_udp, transport_session);
5754
3
        }
5755
5756
        /* UDP has no framing or retransmission issues, so the dof_api_data is stored directly on the frame. */
5757
231
        api_data = wmem_new0(wmem_file_scope(), dof_api_data);
5758
231
        if (api_data == NULL)
5759
0
            return 0;
5760
5761
231
        transport_packet = wmem_new0(wmem_file_scope(), dof_transport_packet);
5762
231
        if (transport_packet == NULL)
5763
0
            return 0;
5764
5765
231
        transport_packet->is_sent_by_client = true;
5766
231
        if (addresses_equal(&transport_session->server.addr, &pinfo->src) && (transport_session->server.port == pinfo->srcport))
5767
0
            transport_packet->is_sent_by_client = false;
5768
5769
231
        transport_packet->sender_id = assign_addr_port_id(pinfo->pool, &pinfo->src, pinfo->srcport);
5770
231
        transport_packet->receiver_id = assign_addr_port_id(pinfo->pool, &pinfo->dst, pinfo->destport);
5771
5772
231
        api_data->transport_session = &transport_session->common;
5773
231
        api_data->transport_packet = transport_packet;
5774
231
        p_add_proto_data(wmem_file_scope(), pinfo, proto_2008_1_dof_udp, 0, api_data);
5775
231
    }
5776
5777
231
    return dissect_dof_common(tvb, pinfo, tree, api_data);
5778
231
}
5779
5780
/**
5781
 * Determine if the current offset has already been processed.
5782
 * This is specific to the TCP dissector.
5783
 */
5784
static bool is_retransmission(packet_info *pinfo, tcp_session_data *session, tcp_packet_data *packet, struct tcpinfo *tcpinfo)
5785
146
{
5786
    /* TODO: Determine why we get big numbers sometimes... */
5787
    /* if ( tcpinfo->seq != 0 && tcpinfo->seq < 1000000) */
5788
146
    {
5789
146
        tcp_ignore_data *id;
5790
146
        uint32_t sequence = tcpinfo->seq;
5791
5792
146
        if (addresses_equal(&pinfo->src, &session->client.addr) && (pinfo->srcport == session->client.port))
5793
146
        {
5794
146
            id = packet->from_client_ignore_list;
5795
146
        }
5796
0
        else
5797
0
        {
5798
0
            id = packet->from_server_ignore_list;
5799
0
        }
5800
5801
146
        while (id != NULL && id->sequence != sequence)
5802
0
        {
5803
0
            id = id->next;
5804
0
        }
5805
5806
146
        if (id == NULL)
5807
146
            return false;
5808
5809
0
        return id->ignore;
5810
146
    }
5811
5812
0
    return false;
5813
146
}
5814
5815
/**
5816
 * We have found and processed packets starting at offset, so
5817
 * don't allow the same (or previous) packets.
5818
 * This only applies to TCP dissector conversations.
5819
 */
5820
static void remember_offset(packet_info *pinfo, tcp_session_data *session, tcp_packet_data *packet, struct tcpinfo *tcpinfo)
5821
0
{
5822
0
    bool ignore = false;
5823
5824
    /* TODO: Determine why we get big numbers sometimes... */
5825
    /* if ( tcpinfo->seq != 0 && tcpinfo->seq < 1000000) */
5826
0
    {
5827
0
        tcp_ignore_data **last;
5828
0
        tcp_ignore_data *id;
5829
0
        uint32_t sequence;
5830
0
        uint32_t *seqptr = NULL;
5831
5832
0
        if (addresses_equal(&pinfo->src, &session->client.addr) && (pinfo->srcport == session->client.port))
5833
0
        {
5834
0
            last = &(packet->from_client_ignore_list);
5835
0
            id = packet->from_client_ignore_list;
5836
0
            sequence = tcpinfo->seq;
5837
0
            seqptr = &session->from_client_seq;
5838
5839
0
            if (LE_SEQ(tcpinfo->seq, session->from_client_seq))
5840
0
                ignore = true;
5841
0
        }
5842
0
        else
5843
0
        {
5844
0
            last = &(packet->from_server_ignore_list);
5845
0
            id = packet->from_server_ignore_list;
5846
0
            sequence = tcpinfo->seq;
5847
0
            seqptr = &session->from_server_seq;
5848
5849
0
            if (LE_SEQ(tcpinfo->seq, session->from_server_seq))
5850
0
                ignore = true;
5851
0
        }
5852
5853
0
        while (id != NULL && id->sequence != tcpinfo->seq)
5854
0
        {
5855
0
            last = &(id->next);
5856
0
            id = id->next;
5857
0
        }
5858
5859
0
        *seqptr = sequence;
5860
0
        if (id == NULL)
5861
0
        {
5862
0
            *last = wmem_new0(wmem_file_scope(), tcp_ignore_data);
5863
0
            id = *last;
5864
0
            id->ignore = ignore;
5865
0
            id->sequence = tcpinfo->seq;
5866
0
        }
5867
0
    }
5868
0
}
5869
5870
/**
5871
 * This dissector is registered with TCP using the standard port. It uses registered
5872
 * protocols to determine framing, and those dissectors will call into the base
5873
 * DPS dissector for each packet.
5874
 */
5875
static int dissect_dof_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5876
4
{
5877
4
    conversation_t *conversation;
5878
4
    tcp_session_data *session;
5879
4
    tcp_packet_data *packet;
5880
4
    struct tcpinfo *tcpinfo = (struct tcpinfo *)data;
5881
4
    uint8_t header;
5882
5883
    /* Get the TCP conversation. TCP creates a new conversation for each TCP connection,12
5884
     * so we can "mirror" that by attaching our own data to that conversation. If our
5885
     * data cannot be found, then it is a new connection (to us).
5886
     */
5887
4
    conversation = find_conversation_pinfo(pinfo, 0);
5888
4
    {
5889
        /* This should be impossible - the TCP dissector requires this conversation.
5890
         * Bail...
5891
         */
5892
4
        DISSECTOR_ASSERT(conversation != NULL);
5893
4
    }
5894
5895
5896
    /* This requires explanation. TCP will call this dissector, and we know
5897
     * that the first byte (offset 0 of this tvb) is the first byte of an
5898
     * DPS packet. The TCP dissector ensures this.
5899
     *
5900
     * We do *not* know that this is the only packet, and
5901
     * so the dissector that we call below must handle framing. All of
5902
     * this state must be stored, and so we store it in a transport
5903
     * data structure. DPS packet data is created later and associated
5904
     * differently.
5905
     *
5906
     * Further, this routine MAY be called MULTIPLE times for the SAME
5907
     * frame with DIFFERENT sequence numbers. This makes handling
5908
     * retransmissions very difficult - we must track each call to this
5909
     * routine with its associated offset and ignore flag. However, due
5910
     * to the way that Wireshark handles asking for more data we cannot
5911
     * mark an offset as "duplicate" until after it has been processed.
5912
     */
5913
5914
    /* TCP packet data is only associated with TCP frames that hold DPS packets. */
5915
4
    session = (tcp_session_data *)conversation_get_proto_data(conversation, proto_2008_1_dof_tcp);
5916
4
    if (session == NULL)
5917
1
    {
5918
1
        session = create_tcp_session_data(pinfo, conversation);
5919
1
        conversation_add_proto_data(conversation, proto_2008_1_dof_tcp, session);
5920
1
    }
5921
5922
4
    if (session->not_dps)
5923
3
        return 0;
5924
5925
1
    packet = (tcp_packet_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_2008_1_dof_tcp, 0);
5926
1
    if (packet == NULL)
5927
1
    {
5928
1
        packet = wmem_new0(wmem_file_scope(), tcp_packet_data);
5929
1
        p_add_proto_data(wmem_file_scope(), pinfo, proto_2008_1_dof_tcp, 0, packet);
5930
1
    }
5931
5932
1
    if (is_retransmission(pinfo, session, packet, tcpinfo))
5933
0
        return 0;
5934
5935
    /* Loop, checking all the packets in this frame and communicating with the TCP
5936
     * desegmenter. The framing dissector entry is used to determine the size
5937
     * of the current frame.
5938
     */
5939
1
    {
5940
        /* Note that we must handle fragmentation on TCP... */
5941
1
        int offset = 0;
5942
5943
1
        while (offset < (int)tvb_reported_length(tvb))
5944
1
        {
5945
1
            int available = tvb_ensure_captured_length_remaining(tvb, offset);
5946
1
            int packet_length;
5947
5948
1
            header = tvb_get_uint8(tvb, offset);
5949
5950
            /* If we are negotiating, then we do not need the framing dissector
5951
             * as we know the packet length is two. Note that for the first byte
5952
             * of a TCP session there are only two cases, both handled here. An error
5953
             * of not understanding the first byte will trigger that this is not
5954
             * a DPS session.
5955
             */
5956
1
            if (((header & 0x80) == 0) && session->common.negotiation_required && ((pinfo->fd->num < session->common.negotiation_complete_at) || (session->common.negotiation_complete_at == 0)))
5957
1
            {
5958
1
                packet_length = 2;
5959
1
                if (header > DNP_MAX_VERSION)
5960
1
                {
5961
1
                    session->not_dps = true;
5962
1
                    return 0;
5963
1
                }
5964
1
            }
5965
0
            else
5966
0
            {
5967
0
                packet_length = dof_dissect_dnp_length(tvb, pinfo, header & 0x7F, &offset);
5968
0
                if (packet_length < 0)
5969
0
                {
5970
0
                    session->not_dps = true;
5971
0
                    return offset;
5972
0
                }
5973
0
            }
5974
5975
0
            if (packet_length == 0)
5976
0
            {
5977
0
                pinfo->desegment_offset = offset;
5978
0
                pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
5979
0
                return offset + available;
5980
0
            }
5981
5982
0
            if (available < packet_length)
5983
0
            {
5984
0
                pinfo->desegment_offset = offset;
5985
0
                pinfo->desegment_len = packet_length - available;
5986
0
                return offset + available;
5987
0
            }
5988
5989
0
            remember_offset(pinfo, session, packet, tcpinfo);
5990
0
            if (is_retransmission(pinfo, session, packet, tcpinfo))
5991
0
                return 0;
5992
5993
            /* We have a packet. We have to store the dof_packet_data in a list, as there may be
5994
             * multiple DPS packets in a single Wireshark frame.
5995
             */
5996
0
            {
5997
0
                tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, packet_length);
5998
0
                tcp_dof_packet_ref *ref;
5999
0
                int raw_offset = tvb_raw_offset(tvb) + offset;
6000
0
                bool ref_is_new = false;
6001
6002
                /* Get the packet data. This is a list in increasing sequence order. */
6003
0
                if (packet->dof_packets == NULL)
6004
0
                {
6005
0
                    ref_is_new = true;
6006
0
                    ref = wmem_new0(wmem_file_scope(), tcp_dof_packet_ref);
6007
0
                    ref->transport_packet.sender_id = assign_addr_port_id(pinfo->pool, &pinfo->src, pinfo->srcport);
6008
0
                    ref->transport_packet.receiver_id = assign_addr_port_id(pinfo->pool, &pinfo->dst, pinfo->destport);
6009
0
                    packet->dof_packets = ref;
6010
0
                    ref->start_offset = raw_offset;
6011
0
                }
6012
0
                else
6013
0
                    ref = packet->dof_packets;
6014
6015
                /* Find the entry for our offset. */
6016
0
                while (ref->start_offset != raw_offset)
6017
0
                {
6018
0
                    if (ref->next)
6019
0
                    {
6020
0
                        ref = ref->next;
6021
0
                        continue;
6022
0
                    }
6023
6024
0
                    {
6025
0
                        tcp_dof_packet_ref *last = ref;
6026
6027
                        /* This is the default state, NULL and 0. */
6028
0
                        ref_is_new = true;
6029
0
                        ref = wmem_new0(wmem_file_scope(), tcp_dof_packet_ref);
6030
0
                        ref->transport_packet.sender_id = last->transport_packet.sender_id;
6031
0
                        ref->transport_packet.receiver_id = last->transport_packet.receiver_id;
6032
0
                        ref->start_offset = raw_offset;
6033
0
                        last->next = ref;
6034
0
                    }
6035
0
                }
6036
6037
0
                if (ref_is_new)
6038
0
                {
6039
0
                    dof_transport_packet *tp = &(ref->transport_packet);
6040
6041
0
                    tp->is_sent_by_client = false;
6042
0
                    if (addresses_equal(&session->client.addr, &pinfo->src) &&
6043
0
                        (session->client.port == pinfo->srcport))
6044
0
                        tp->is_sent_by_client = true;
6045
6046
0
                    ref->api_data.transport_session = (dof_transport_session *)&(session->common);
6047
0
                    ref->api_data.transport_packet = tp;
6048
0
                }
6049
6050
6051
0
                dissect_dof_common(next_tvb, pinfo, tree, &ref->api_data);
6052
0
            }
6053
6054
0
            offset += packet_length;
6055
0
        }
6056
6057
0
        return offset;
6058
1
    }
6059
1
}
6060
6061
#if 0 /* TODO not used yet */
6062
/**
6063
 * This dissector is registered with the UDP protocol on the standard DPS port.
6064
 * It will be used for anything that involves that port (source or destination).
6065
 */
6066
#if 0
6067
static int dissect_tunnel_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
6068
{
6069
    conversation_t *conversation;
6070
    dof_packet_data *packet;
6071
6072
    /* Initialize the default transport session structure. */
6073
    if (!udp_transport_session)
6074
    udp_transport_session = se_alloc0(sizeof(*udp_transport_session));
6075
6076
    conversation = find_or_create_conversation(pinfo);
6077
6078
    /* Add the packet data. */
6079
    packet = p_get_proto_data(wmem_file_scope(), proto_2012_1_tunnel, 0);
6080
    if (!packet)
6081
    {
6082
        packet = wmem_alloc0(wmem_file_scope(), sizeof(dof_packet_data));
6083
        packet->frame = pinfo->fd->num;
6084
        packet->next = NULL;
6085
        packet->start_offset = 0;
6086
        packet->session_counter = &session_counter;
6087
        packet->transport_session = udp_transport_session;
6088
        p_add_proto_data(wmem_file_scope(), proto_2012_1_tunnel, 0, packet);
6089
    }
6090
6091
    pinfo->private_data = packet;
6092
    return dissect_tunnel_common(tvb, pinfo, tree);
6093
#else
6094
static int dissect_tunnel_udp(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, void *data _U_)
6095
{
6096
#endif
6097
    return 0;
6098
}
6099
#endif
6100
6101
6102
/**
6103
 * This dissector is registered with TCP using the standard port. It uses registered
6104
 * protocols to determine framing, and those dissectors will call into the base
6105
 * DPS dissector for each packet.
6106
 */
6107
static int dissect_tunnel_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6108
145
{
6109
145
    conversation_t *conversation;
6110
145
    tcp_session_data *session;
6111
145
    tcp_packet_data *packet;
6112
145
    struct tcpinfo *tcpinfo = (struct tcpinfo *)data;
6113
6114
    /* Get the TCP conversation. TCP creates a new conversation for each TCP connection,
6115
    * so we can "mirror" that by attaching our own data to that conversation. If our
6116
    * data cannot be found, then it is a new connection (to us).
6117
    */
6118
145
    conversation = find_conversation_pinfo(pinfo, 0);
6119
145
    {
6120
        /* This should be impossible - the TCP dissector requires this conversation.
6121
        * Bail...
6122
        */
6123
145
        DISSECTOR_ASSERT(conversation != NULL);
6124
145
    }
6125
6126
6127
    /* This requires explanation. TCP will call this dissector, and we know
6128
    * that the first byte (offset 0 of this tvb) is the first byte of an
6129
    * DPS packet. The TCP dissector ensures this.
6130
    *
6131
    * We do *not* know that this is the only packet, and
6132
    * so the dissector that we call below must handle framing. All of
6133
    * this state must be stored, and so we store it in a transport
6134
    * data structure. DPS packet data is created later and associated
6135
    * differently.
6136
    *
6137
    * Further, this routine MAY be called MULTIPLE times for the SAME
6138
    * frame with DIFFERENT sequence numbers. This makes handling
6139
    * retransmissions very difficult - we must track each call to this
6140
    * routine with its associated offset and ignore flag. However, due
6141
    * to the way that Wireshark handles asking for more data we cannot
6142
    * mark an offset as "duplicate" until after it has been processed.
6143
    */
6144
6145
    /* TCP packet data is only associated with TCP frames that hold DPS packets. */
6146
145
    session = (tcp_session_data *)conversation_get_proto_data(conversation, proto_2012_1_tunnel);
6147
145
    if (session == NULL)
6148
56
    {
6149
56
        session = create_tcp_session_data(pinfo, conversation);
6150
56
        conversation_add_proto_data(conversation, proto_2012_1_tunnel, session);
6151
56
    }
6152
6153
145
    packet = (tcp_packet_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_2012_1_tunnel, 0);
6154
145
    if (packet == NULL)
6155
145
    {
6156
145
        packet = wmem_new0(wmem_file_scope(), tcp_packet_data);
6157
145
        p_add_proto_data(wmem_file_scope(), pinfo, proto_2012_1_tunnel, 0, packet);
6158
145
    }
6159
6160
145
    if (is_retransmission(pinfo, session, packet, tcpinfo))
6161
0
        return 0;
6162
6163
    /* Loop, checking all the packets in this TCP frame.
6164
    */
6165
145
    {
6166
        /* Note that we must handle fragmentation on TCP... */
6167
145
        int offset = 0;
6168
6169
298
        while (offset < (int)tvb_reported_length(tvb))
6170
201
        {
6171
201
            int available = tvb_reported_length_remaining(tvb, offset);
6172
201
            int packet_length;
6173
201
            int header_length;
6174
201
            int i;
6175
6176
201
            if (available < 3)
6177
3
            {
6178
3
                pinfo->desegment_offset = offset;
6179
3
                pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
6180
3
                return offset + available;
6181
3
            }
6182
6183
198
            packet_length = 0;
6184
198
            header_length = 3;
6185
6186
594
            for (i = 0; i < 2; i++)
6187
396
                packet_length = packet_length * 256 + tvb_get_uint8(tvb, offset + 1 + i);
6188
6189
198
            packet_length += header_length;
6190
6191
198
            if (available < packet_length)
6192
45
            {
6193
45
                pinfo->desegment_offset = offset;
6194
45
                pinfo->desegment_len = packet_length - available;
6195
45
                return offset + available;
6196
45
            }
6197
6198
            /* We have a packet. We have to store the dof_packet_data in a list, as there may be
6199
            * multiple DPS packets in a single Wireshark frame.
6200
            */
6201
153
            {
6202
153
                tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, packet_length);
6203
153
                tcp_dof_packet_ref *ref;
6204
153
                int raw_offset = tvb_raw_offset(tvb) + offset;
6205
153
                bool ref_is_new = false;
6206
6207
                /* Get the packet data. This is a list in increasing sequence order. */
6208
153
                if (packet->dof_packets == NULL)
6209
142
                {
6210
142
                    ref_is_new = true;
6211
142
                    ref = wmem_new0(wmem_file_scope(), tcp_dof_packet_ref);
6212
142
                    ref->transport_packet.sender_id = assign_addr_port_id(pinfo->pool, &pinfo->src, pinfo->srcport);
6213
142
                    ref->transport_packet.receiver_id = assign_addr_port_id(pinfo->pool, &pinfo->dst, pinfo->destport);
6214
142
                    packet->dof_packets = ref;
6215
142
                    ref->start_offset = raw_offset;
6216
142
                }
6217
11
                else
6218
11
                    ref = packet->dof_packets;
6219
6220
                /* Find the entry for our offset. */
6221
166
                while (ref->start_offset != raw_offset)
6222
13
                {
6223
13
                    if (ref->next)
6224
2
                    {
6225
2
                        ref = ref->next;
6226
2
                        continue;
6227
2
                    }
6228
6229
11
                    {
6230
11
                        tcp_dof_packet_ref *last = ref;
6231
6232
                        /* This is the default state, NULL and 0. */
6233
11
                        ref_is_new = true;
6234
11
                        ref = wmem_new0(wmem_file_scope(), tcp_dof_packet_ref);
6235
11
                        ref->transport_packet.sender_id = last->transport_packet.sender_id;
6236
11
                        ref->transport_packet.receiver_id = last->transport_packet.receiver_id;
6237
11
                        ref->start_offset = raw_offset;
6238
11
                        last->next = ref;
6239
11
                    }
6240
11
                }
6241
6242
153
                if (ref_is_new)
6243
153
                {
6244
153
                    dof_transport_packet *tp = &(ref->transport_packet);
6245
6246
153
                    tp->is_sent_by_client = false;
6247
153
                    if (addresses_equal(&session->client.addr, &pinfo->src) &&
6248
153
                        (session->client.port == pinfo->srcport))
6249
153
                        tp->is_sent_by_client = true;
6250
6251
153
                    ref->api_data.transport_session = (dof_transport_session *)&(session->common);
6252
153
                    ref->api_data.transport_packet = tp;
6253
153
                }
6254
6255
                /* Manage the private data, restoring the existing value. Call the common dissector. */
6256
153
                {
6257
153
                    dissect_tunnel_common(next_tvb, pinfo, tree, ref);
6258
153
                }
6259
153
            }
6260
6261
153
            offset += packet_length;
6262
153
        }
6263
6264
97
        return tvb_captured_length(tvb);
6265
145
    }
6266
145
}
6267
6268
/* Dissectors */
6269
6270
static int dissect_dnp_0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
6271
12
{
6272
12
    unsigned offset = 0;
6273
6274
12
    uint8_t dnp_flags_included = 0;
6275
6276
12
    offset = 0;
6277
12
    col_clear(pinfo->cinfo, COL_INFO);
6278
6279
    /* Compute the DNP control information. This is the version and the flags byte.
6280
    * The flags byte is either present, or is based on the version (and can be defaulted).
6281
    */
6282
12
    {
6283
12
        uint8_t header = tvb_get_uint8(tvb, offset);
6284
6285
12
        dnp_flags_included = (header & 0x80) != 0;
6286
6287
12
        offset += 1;
6288
6289
12
        {
6290
12
            col_set_str(pinfo->cinfo, COL_PROTOCOL, "DNPv0 ");
6291
6292
12
            if (dnp_flags_included)
6293
1
            {
6294
                /* TODO: Protocol violation. */
6295
1
            }
6296
6297
12
            if (tvb_reported_length(tvb) == offset)
6298
1
                col_set_str(pinfo->cinfo, COL_INFO, "Query");
6299
11
            else
6300
11
            {
6301
11
                uint8_t first = tvb_get_uint8(tvb, offset);
6302
11
                if (first == 0)
6303
1
                {
6304
                    /* Query with padding. */
6305
1
                    col_set_str(pinfo->cinfo, COL_INFO, "Query");
6306
1
                    proto_tree_add_item(tree, hf_2008_1_dnp_0_1_1_padding, tvb, offset, -1, ENC_NA);
6307
1
                }
6308
10
                else
6309
10
                {
6310
                    /* Response. */
6311
10
                    col_set_str(pinfo->cinfo, COL_INFO, "Query Response");
6312
139
                    while (first)
6313
131
                    {
6314
131
                        proto_tree_add_item(tree, hf_2008_1_dnp_0_1_1_version, tvb, offset, 1, ENC_NA);
6315
131
                        offset += 1;
6316
131
                        if (offset == tvb_reported_length(tvb))
6317
2
                            break;
6318
6319
129
                        first = tvb_get_uint8(tvb, offset);
6320
129
                    }
6321
6322
10
                    if (offset < tvb_reported_length(tvb))
6323
8
                        proto_tree_add_item(tree, hf_2008_1_dnp_0_1_1_padding, tvb, offset, -1, ENC_NA);
6324
10
                }
6325
11
            }
6326
12
        }
6327
12
    }
6328
6329
12
    col_set_fence(pinfo->cinfo, COL_PROTOCOL);
6330
12
    col_set_fence(pinfo->cinfo, COL_INFO);
6331
12
    return tvb_reported_length(tvb);
6332
12
}
6333
6334
/**
6335
 * Determine the length of the packet in tvb, starting at an offset that is passed as a
6336
 * pointer in private_data.
6337
 * Return 0 if the length cannot be determined because there is not enough data in
6338
 * the buffer, otherwise return the length of the packet.
6339
 */
6340
static int determine_packet_length_1(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, void *data)
6341
0
{
6342
    /* Note that we must handle fragmentation on TCP... */
6343
0
    int offset = *((int *)data);
6344
6345
0
    {
6346
0
        int available = tvb_ensure_captured_length_remaining(tvb, offset);
6347
0
        uint8_t header, flags;
6348
0
        uint8_t size;
6349
0
        uint8_t i;
6350
0
        int data_len, header_len;
6351
6352
0
        if (available < 2)
6353
0
            return 0;
6354
6355
0
        header = tvb_get_uint8(tvb, offset);
6356
0
        data_len = 0;
6357
6358
0
        if ((header & 0x80) == 0)
6359
0
        {
6360
            /* The length is fixed in this case... */
6361
0
            data_len = 0;
6362
0
            header_len = 2;
6363
0
            size = 0;
6364
0
        }
6365
0
        else
6366
0
        {
6367
0
            flags = tvb_get_uint8(tvb, offset + 1);
6368
0
            size = flags & 0x03;
6369
0
            header_len = 2 + size;
6370
0
        }
6371
6372
0
        if (available < header_len)
6373
0
            return 0;
6374
6375
0
        for (i = 0; i < size; i++)
6376
0
            data_len = data_len * 256 + tvb_get_uint8(tvb, offset + 2 + i);
6377
6378
0
        return header_len + data_len;
6379
0
    }
6380
0
}
6381
6382
static int dissect_dnp_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6383
352
{
6384
352
    int offset = 0;
6385
352
    dof_api_data *api_data = (dof_api_data *)data;
6386
352
    dof_packet_data *packet;
6387
6388
352
    int8_t dnp_version = -1;
6389
352
    uint8_t dnp_flags_included = 0;
6390
352
    uint8_t dnp_length_length = 0;
6391
352
    uint32_t dnp_flags = 0;
6392
6393
352
    unsigned length = 0;
6394
352
    unsigned encapsulated_length = 0;
6395
6396
352
    int i;
6397
6398
352
    proto_tree *dnp_tree = tree;
6399
6400
352
    if (!api_data)
6401
0
    {
6402
        /* TODO: Print error */
6403
0
        return 0;
6404
0
    }
6405
6406
352
    if (!api_data->packet)
6407
0
    {
6408
        /* TODO: Print error */
6409
0
        return 0;
6410
0
    }
6411
6412
352
    packet = api_data->packet;
6413
6414
352
    offset = 0;
6415
352
    col_clear(pinfo->cinfo, COL_INFO);
6416
6417
    /* Compute the DNP control information. This is the version and the flags byte.
6418
    * The flags byte is either present, or is based on the version (and can be defaulted).
6419
    */
6420
352
    {
6421
352
        uint8_t header = tvb_get_uint8(tvb, offset);
6422
352
        uint32_t dnp_src_port = 0;
6423
352
        uint32_t dnp_dst_port = 0;
6424
6425
352
        dnp_version = header & 0x7F;
6426
352
        dnp_flags_included = (header & 0x80) != 0;
6427
6428
6429
352
        offset += 1;
6430
6431
352
        {
6432
352
            col_set_str(pinfo->cinfo, COL_PROTOCOL, "DNPv1 ");
6433
6434
352
            if (dnp_flags_included)
6435
11
            {
6436
                /* Including flags always terminates negotiation. */
6437
                /* packet->negotiated = true; */
6438
6439
11
                dnp_flags = tvb_get_uint8(tvb, offset);
6440
11
                if ((dnp_flags & 0xF0) != 0)
6441
4
                    expert_add_info(pinfo, NULL, &ei_dof_10_flags_zero);
6442
6443
11
                proto_tree_add_bitmask(dnp_tree, tvb, offset, hf_2009_9_dnp_1_flags, ett_2009_9_dnp_1_flags, bitmask_2009_9_dnp_1_flags, ENC_BIG_ENDIAN);
6444
6445
11
                offset += 1;
6446
11
            }
6447
341
            else
6448
341
                dnp_flags = DNP_V1_DEFAULT_FLAGS;
6449
6450
            /* Determine the size of the length field. */
6451
352
            dnp_length_length = dnp_flags & 0x03;
6452
352
            if (dnp_length_length)
6453
5
                proto_tree_add_item(dnp_tree, hf_2009_9_dnp_1_length, tvb, offset, dnp_length_length, ENC_BIG_ENDIAN);
6454
6455
            /* Read the length. */
6456
352
            length = 0;
6457
365
            for (i = 0; i < dnp_length_length; i++)
6458
13
                length = (length << 8) | tvb_get_uint8(tvb, offset + i);
6459
6460
            /* Validate the length. */
6461
#if 0
6462
            if ( (length == 0) && packet->negotiated && session && ! session->connectionless )
6463
            {
6464
            expert_add_info( pinfo, NULL, &ei_dof_13_length_specified );
6465
            }
6466
#endif
6467
6468
352
            offset += dnp_length_length;
6469
6470
            /* If there isn't a length specified then use the packet size. */
6471
352
            if (dnp_length_length == 0)
6472
347
                length = tvb_reported_length_remaining(tvb, offset);
6473
6474
352
            encapsulated_length = length;
6475
6476
            /* Read the srcport */
6477
352
            if (dnp_flags & 0x04)
6478
8
            {
6479
8
                int s_offset = offset;
6480
8
                proto_item *item;
6481
8
                int dnp_src_port_len;
6482
6483
8
                offset = read_c3(tvb, offset, &dnp_src_port, &dnp_src_port_len);
6484
8
                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);
6485
8
                validate_c3(pinfo, item, dnp_src_port, dnp_src_port_len);
6486
8
                encapsulated_length -= (offset - s_offset);
6487
8
            }
6488
344
            else
6489
344
            {
6490
344
                proto_item *item = proto_tree_add_uint_format(dnp_tree, hf_2009_9_dnp_1_srcport, tvb, 0, 0, 0, "Source Address: %u", 0);
6491
344
                proto_item_set_generated(item);
6492
344
            }
6493
6494
            /* Read the dstport */
6495
352
            if (dnp_flags & 0x08)
6496
2
            {
6497
2
                int s_offset = offset;
6498
2
                int dnp_dst_port_len;
6499
2
                proto_item *item;
6500
6501
2
                offset = read_c3(tvb, offset, &dnp_dst_port, &dnp_dst_port_len);
6502
2
                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);
6503
2
                validate_c3(pinfo, item, dnp_dst_port, dnp_dst_port_len);
6504
2
                encapsulated_length -= (offset - s_offset);
6505
2
            }
6506
350
            else
6507
350
            {
6508
350
                proto_item *item = proto_tree_add_uint_format(dnp_tree, hf_2009_9_dnp_1_dstport, tvb, 0, 0, 0, "Destination Address: %u", 0);
6509
350
                proto_item_set_generated(item);
6510
350
            }
6511
352
        }
6512
6513
352
        proto_item_set_end(tree, tvb, offset);
6514
6515
        /* Given the transport session and the DPS port information, determine the DPS session. */
6516
352
        if (api_data->session == NULL)
6517
352
        {
6518
352
            uint32_t client;
6519
352
            uint32_t server;
6520
6521
352
            if (api_data->transport_packet->is_sent_by_client)
6522
352
            {
6523
352
                client = dnp_src_port;
6524
352
                server = dnp_dst_port;
6525
352
            }
6526
0
            else
6527
0
            {
6528
0
                client = dnp_dst_port;
6529
0
                server = dnp_src_port;
6530
0
            }
6531
6532
352
            api_data->session = dof_ns_session_retrieve(api_data->transport_session->transport_session_id, client, server);
6533
352
            if (api_data->session == NULL)
6534
57
            {
6535
57
                dof_session_data *sdata = wmem_new0(wmem_file_scope(), dof_session_data);
6536
57
                dof_ns_session_define(api_data->transport_session->transport_session_id, client, server, sdata);
6537
57
                sdata->session_id = globals.next_session++;
6538
57
                sdata->dof_id = dnp_version;
6539
57
                api_data->session = sdata;
6540
57
            }
6541
352
        }
6542
6543
352
        packet->sender_id = dnp_src_port;
6544
352
        packet->receiver_id = dnp_dst_port;
6545
6546
        /* Assuming there is more, it must be DPP. */
6547
6548
        /* We have a packet. */
6549
352
        {
6550
352
            tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, encapsulated_length);
6551
352
            offset += dof_dissect_dpp_common(next_tvb, pinfo, proto_item_get_parent(tree), data);
6552
352
        }
6553
352
    }
6554
6555
352
    col_set_fence(pinfo->cinfo, COL_PROTOCOL);
6556
352
    col_set_fence(pinfo->cinfo, COL_INFO);
6557
352
    return offset;
6558
352
}
6559
6560
static int dissect_dpp_0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
6561
10
{
6562
10
    unsigned offset = 0;
6563
6564
10
    uint8_t dpp_flags_included = 0;
6565
6566
10
    offset = 0;
6567
10
    col_clear(pinfo->cinfo, COL_INFO);
6568
6569
    /* Compute the DPP control information. This is the version and the flags byte.
6570
    * The flags byte is either present, or is based on the version (and can be defaulted).
6571
    */
6572
10
    {
6573
10
        uint8_t header = tvb_get_uint8(tvb, offset);
6574
6575
10
        dpp_flags_included = (header & 0x80) != 0;
6576
6577
10
        offset += 1;
6578
6579
10
        {
6580
10
            col_set_str(pinfo->cinfo, COL_PROTOCOL, "DPPv0 ");
6581
6582
10
            if (dpp_flags_included)
6583
1
            {
6584
                /* TODO: Protocol violation. */
6585
1
            }
6586
6587
10
            if (tvb_reported_length(tvb) == offset)
6588
0
                col_set_str(pinfo->cinfo, COL_INFO, "Query");
6589
10
            else
6590
10
            {
6591
10
                uint8_t first = tvb_get_uint8(tvb, offset);
6592
                /* Response. */
6593
10
                col_set_str(pinfo->cinfo, COL_INFO, "Query Response");
6594
209
                while (first)
6595
201
                {
6596
201
                    proto_tree_add_item(tree, hf_2008_1_dpp_0_1_1_version, tvb, offset, 1, ENC_NA);
6597
201
                    offset += 1;
6598
201
                    if (offset == tvb_reported_length(tvb))
6599
2
                        break;
6600
6601
199
                    first = tvb_get_uint8(tvb, offset);
6602
199
                }
6603
10
            }
6604
10
        }
6605
10
    }
6606
6607
10
    col_set_fence(pinfo->cinfo, COL_PROTOCOL);
6608
10
    col_set_fence(pinfo->cinfo, COL_INFO);
6609
10
    return tvb_reported_length(tvb);
6610
10
}
6611
6612
static int dissect_dpp_v2_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6613
15
{
6614
15
    dof_api_data *api_data = (dof_api_data *)data;
6615
15
    dof_packet_data *packet_data;
6616
15
    int offset = 0;
6617
15
    uint8_t opcode;
6618
15
    uint16_t app;
6619
15
    int app_len;
6620
15
    proto_item *ti;
6621
15
    proto_tree *dpps_tree;
6622
15
    proto_tree *opid_tree;
6623
6624
15
    if (api_data == NULL)
6625
0
    {
6626
        /* TODO: Output error. */
6627
0
        return 0;
6628
0
    }
6629
6630
15
    packet_data = api_data->packet;
6631
15
    if (packet_data == NULL)
6632
0
    {
6633
        /* TODO: Output error. */
6634
0
        return 0;
6635
0
    }
6636
6637
    /* Make entries in Protocol column and Info column on summary display */
6638
15
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "DPPs ");
6639
6640
    /* Create the protocol tree. */
6641
15
    offset = 0;
6642
15
    ti = proto_tree_add_item(tree, proto_2009_12_dpp_common, tvb, offset, -1, ENC_NA);
6643
15
    dpps_tree = proto_item_add_subtree(ti, ett_2009_12_dpp_common);
6644
6645
    /* Add the APPID. */
6646
15
    offset = read_c2(tvb, offset, &app, &app_len);
6647
15
    ti = proto_tree_add_uint(dpps_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
6648
15
    validate_c2(pinfo, ti, app, app_len);
6649
6650
6651
    /* Retrieve the opcode. */
6652
15
    opcode = tvb_get_uint8(tvb, offset);
6653
15
    if (!packet_data->is_command)
6654
1
        opcode |= OP_2009_12_RESPONSE_FLAG;
6655
6656
15
    col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, opcode, strings_2009_12_dpp_common_opcodes, "Unknown Opcode (%d)"));
6657
6658
    /* Opcode */
6659
15
    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);
6660
15
    offset += 1;
6661
6662
15
    switch (opcode)
6663
15
    {
6664
5
    case OP_2009_12_SOURCE_LOST_CMD:
6665
5
    case OP_2009_12_SOURCE_FOUND_CMD:
6666
10
    case OP_2009_12_RENAME_CMD:
6667
10
        packet_data->has_referenced_opid = true;
6668
6669
        /* FALL THROUGH */
6670
6671
10
    case OP_2009_12_CANCEL_ALL_CMD:
6672
12
    case OP_2009_12_NODE_DOWN_CMD:
6673
12
    case OP_2009_12_QUERY_RSP:
6674
        /* SID */
6675
12
    {
6676
12
        proto_tree *oid_tree;
6677
12
        int opid_len;
6678
12
        tvbuff_t *next_tvb;
6679
6680
12
        if (packet_data->has_referenced_opid)
6681
10
        {
6682
10
            opid_tree = proto_tree_add_subtree(dpps_tree, tvb, offset, 0, ett_2009_12_dpp_2_opid, NULL, "Operation Identifier");
6683
10
        }
6684
2
        else
6685
2
        {
6686
2
            opid_tree = dpps_tree;
6687
2
        }
6688
6689
12
        oid_tree = proto_tree_add_subtree(opid_tree, tvb, offset, 0, ett_2009_12_dpp_2_opid, NULL, "Source Identifier");
6690
6691
12
        next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length(tvb) - offset);
6692
12
        opid_len = call_dissector_only(dof_oid_handle, next_tvb, pinfo, oid_tree, NULL);
6693
6694
12
        learn_sender_sid(api_data, opid_len, tvb_get_ptr(next_tvb, 0, opid_len));
6695
12
        if (packet_data->has_referenced_opid)
6696
8
            learn_operation_sid(&packet_data->ref_op, opid_len, tvb_get_ptr(next_tvb, 0, opid_len));
6697
6698
12
        offset += opid_len;
6699
12
    }
6700
6701
12
        if (packet_data->has_referenced_opid)
6702
8
        {
6703
8
            uint32_t opcnt;
6704
8
            int opcnt_len;
6705
8
            proto_item *pi;
6706
6707
8
            read_c4(tvb, offset, &opcnt, &opcnt_len);
6708
8
            pi = proto_tree_add_uint_format(opid_tree, hf_2009_12_dpp_2_1_opcnt, tvb, offset, opcnt_len, opcnt, "Operation Count: %u", opcnt);
6709
8
            validate_c4(pinfo, pi, opcnt, opcnt_len);
6710
8
            offset += opcnt_len;
6711
6712
8
            packet_data->ref_op.op_cnt = opcnt;
6713
8
        }
6714
6715
12
        break;
6716
15
    }
6717
13
    return offset;
6718
15
}
6719
6720
static int dissect_dpp_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6721
340
{
6722
340
    dof_api_data *api_data = (dof_api_data *)data;
6723
340
    dof_packet_data *packet_data;
6724
6725
340
    proto_item *ti = NULL;
6726
340
    proto_item *tf = NULL;
6727
340
    proto_item *opid = NULL;
6728
6729
340
    int opid_start = -1;
6730
340
    uint8_t dpp_flags_included = 0;
6731
340
    uint32_t dpp_flags = 0;
6732
340
    uint8_t dpp_opid_keytype = 0;
6733
6734
340
    proto_tree *dpp_flags_tree;
6735
340
    proto_tree *opid_tree = NULL;
6736
6737
6738
340
    int offset = 0;
6739
6740
340
    proto_tree *dpp_tree = tree;
6741
6742
340
    if (api_data == NULL)
6743
0
    {
6744
        /* TODO: Output error. */
6745
0
        return 0;
6746
0
    }
6747
6748
340
    packet_data = api_data->packet;
6749
340
    if (packet_data == NULL)
6750
0
    {
6751
        /* TODO: Output error. */
6752
0
        return 0;
6753
0
    }
6754
6755
    /* We should have everything required for determining the SID ID. */
6756
340
    assign_sid_id(api_data);
6757
6758
340
    offset = 0;
6759
340
    col_clear(pinfo->cinfo, COL_INFO);
6760
6761
    /* Compute the DPP control information. This is the version and the flags byte.
6762
    * The flags byte is either present, or is based on the version (and can be defaulted).
6763
    */
6764
340
    {
6765
340
        uint8_t header = tvb_get_uint8(tvb, offset);
6766
340
        dpp_flags_included = (header & 0x80) != 0;
6767
340
        offset += 1;
6768
6769
340
        {
6770
340
            col_set_str(pinfo->cinfo, COL_PROTOCOL, "DPPv2 ");
6771
6772
340
            ti = proto_tree_add_uint_format(tree, hf_2008_1_dpp_sid_num, tvb,
6773
340
                                            0, 0, packet_data->sender_sid_id, "SID ID: %d", packet_data->sender_sid_id);
6774
340
            proto_item_set_generated(ti);
6775
6776
340
            if (packet_data->sender_sid)
6777
60
            {
6778
60
                const char *SID = dof_oid_create_standard_string(pinfo->pool, packet_data->sender_sid[0], packet_data->sender_sid + 1, pinfo);
6779
60
                ti = proto_tree_add_bytes_format_value(tree, hf_2008_1_dpp_sid_str, tvb, 0, 0, packet_data->sender_sid, "%s", SID);
6780
60
                proto_item_set_generated(ti);
6781
60
            }
6782
6783
340
            ti = proto_tree_add_uint_format(tree, hf_2008_1_dpp_rid_num, tvb,
6784
340
                                            0, 0, packet_data->receiver_sid_id, "RID ID: %d", packet_data->receiver_sid_id);
6785
340
            proto_item_set_generated(ti);
6786
6787
340
            if (packet_data->receiver_sid)
6788
58
            {
6789
58
                const char *SID = dof_oid_create_standard_string(pinfo->pool, packet_data->receiver_sid[0], packet_data->receiver_sid + 1, pinfo);
6790
58
                ti = proto_tree_add_bytes_format_value(tree, hf_2008_1_dpp_rid_str, tvb, 0, 0, packet_data->receiver_sid, "%s", SID);
6791
58
                proto_item_set_generated(ti);
6792
58
            }
6793
6794
340
            if (dpp_flags_included)
6795
181
            {
6796
181
                dpp_flags = tvb_get_uint8(tvb, offset);
6797
181
                if (((dpp_flags & 0x10) != 0) && ((dpp_flags & 0x0F) != 0))
6798
108
                    expert_add_info(pinfo, NULL, &ei_dpp2_dof_10_flags_zero);
6799
181
                if (((dpp_flags & 0x10) == 0) && ((dpp_flags & 0x09) != 0))
6800
56
                    expert_add_info(pinfo, NULL, &ei_dpp2_dof_10_flags_zero);
6801
6802
181
                tf = proto_tree_add_uint_format(dpp_tree, hf_2009_12_dpp_2_1_flags, tvb,
6803
181
                                                offset, 1, dpp_flags, "Flags: 0x%02x", dpp_flags);
6804
6805
181
                dpp_flags_tree = proto_item_add_subtree(tf, ett_2009_12_dpp_2_1_flags);
6806
6807
181
                if (dpp_flags == DPP_V2_DEFAULT_FLAGS)
6808
3
                    expert_add_info(pinfo, dpp_flags_tree, &ei_dpp_default_flags);
6809
6810
181
                proto_tree_add_item(dpp_flags_tree, hf_2009_12_dpp_2_1_flag_security, tvb, offset, 1, ENC_NA);
6811
181
                proto_tree_add_item(dpp_flags_tree, hf_2009_12_dpp_2_1_flag_opid, tvb, offset, 1, ENC_NA);
6812
181
                proto_tree_add_item(dpp_flags_tree, hf_2009_12_dpp_2_1_flag_cmdrsp, tvb, offset, 1, ENC_NA);
6813
181
                if ((dpp_flags & 0x10) == 0)
6814
70
                {
6815
70
                    proto_tree_add_item(dpp_flags_tree, hf_2009_12_dpp_2_1_flag_seq, tvb, offset, 1, ENC_NA);
6816
70
                    proto_tree_add_item(dpp_flags_tree, hf_2009_12_dpp_2_1_flag_retry, tvb, offset, 1, ENC_NA);
6817
70
                }
6818
6819
181
                offset += 1;
6820
181
            }
6821
159
            else
6822
159
                dpp_flags = DPP_V2_DEFAULT_FLAGS;
6823
6824
340
            packet_data->is_command = (dpp_flags & 0x10) == 0;
6825
6826
            /* We are allowed to be complete here if still negotiating. */
6827
            /*if ( ! packet->negotiated && (offset == tvb_reported_length(tvb)) )
6828
            {
6829
            col_set_str( pinfo->cinfo, COL_INFO, "DPS Negotiation" );
6830
            return 1;
6831
            }*/
6832
6833
340
            dpp_opid_keytype = (dpp_flags & 0x60) >> 5;
6834
340
            switch (dpp_opid_keytype)
6835
340
            {
6836
163
            case 0: /* No OPID */
6837
163
                packet_data->has_opid = false;
6838
163
                break;
6839
6840
48
            case 1: /* Implied sender. */
6841
48
                packet_data->has_opid = true;
6842
48
                packet_data->op.op_sid_id = packet_data->sender_sid_id;
6843
48
                packet_data->op.op_sid = packet_data->sender_sid;
6844
48
                break;
6845
6846
27
            case 2: /* Implied receiver. */
6847
27
                packet_data->has_opid = true;
6848
27
                packet_data->op.op_sid_id = packet_data->receiver_sid_id;
6849
27
                packet_data->op.op_sid = packet_data->receiver_sid;
6850
27
                break;
6851
6852
102
            case 3: /* Explicit. */
6853
102
                packet_data->has_opid = true;
6854
102
                break;
6855
340
            }
6856
6857
340
            if (dpp_opid_keytype != 0)
6858
177
            {
6859
177
                opid_start = offset;
6860
177
                opid_tree = proto_tree_add_subtree(dpp_tree, tvb, offset, 0, ett_2009_12_dpp_2_opid, NULL, "Operation Identifier");
6861
177
            }
6862
6863
340
            switch (dpp_opid_keytype)
6864
340
            {
6865
163
            case 0: /* We have no opid. */
6866
163
                break;
6867
6868
102
            case 3: /* Explicit. */
6869
102
            {
6870
102
                proto_tree *oid_tree;
6871
102
                tvbuff_t *next_tvb;
6872
102
                int opid_len;
6873
6874
102
                oid_tree = proto_tree_add_subtree(opid_tree, tvb, offset, 0, ett_2009_12_dpp_2_opid, NULL, "Source Identifier");
6875
6876
102
                next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length(tvb) - offset);
6877
102
                opid_len = call_dissector_only(dof_oid_handle, next_tvb, pinfo, oid_tree, NULL);
6878
102
                proto_item_set_len(oid_tree, opid_len);
6879
6880
102
                learn_operation_sid(&packet_data->op, opid_len, tvb_get_ptr(next_tvb, 0, opid_len));
6881
6882
                /* Warn if Explicit SID could be optimized. */
6883
102
                if (packet_data->op.op_sid_id == packet_data->sender_sid_id)
6884
0
                    expert_add_info(pinfo, ti, &ei_dpp_explicit_sender_sid_included);
6885
102
                if (packet_data->op.op_sid_id == packet_data->receiver_sid_id)
6886
0
                    expert_add_info(pinfo, ti, &ei_dpp_explicit_receiver_sid_included);
6887
6888
102
                offset += opid_len;
6889
102
            }
6890
6891
                /* FALL THROUGH */
6892
6893
150
            case 1: /* Implied sender. */
6894
177
            case 2: /* Implied receiver. */
6895
177
            {
6896
177
                uint32_t opcnt;
6897
177
                int opcnt_len;
6898
177
                proto_item *pi;
6899
6900
                /* Display the SID if known. */
6901
177
                if ((dpp_opid_keytype != 3) && packet_data->op.op_sid)
6902
0
                {
6903
0
                    proto_tree *oid_tree;
6904
6905
0
                    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]);
6906
0
                    oid_tree = proto_tree_add_subtree(opid_tree, tvb, 0, 0, ett_2009_12_dpp_2_opid, NULL, "Source Identifier");
6907
6908
0
                    call_dissector_only(dof_oid_handle, next_tvb, pinfo, oid_tree, NULL);
6909
6910
0
                    proto_item_set_generated(ti);
6911
0
                }
6912
6913
177
                read_c4(tvb, offset, &opcnt, &opcnt_len);
6914
177
                pi = proto_tree_add_uint_format(opid_tree, hf_2009_12_dpp_2_1_opcnt, tvb, offset, opcnt_len, opcnt, "Operation Count: %u", opcnt);
6915
177
                validate_c4(pinfo, pi, opcnt, opcnt_len);
6916
177
                offset += opcnt_len;
6917
6918
177
                proto_item_set_len(opid, offset - opid_start);
6919
6920
177
                packet_data->op.op_cnt = opcnt;
6921
6922
                /* At this point we have a packet with an operation identifier. We need to
6923
                * update the master list of operation identifiers, and do any checking that
6924
                * we can in order to validate things.
6925
                */
6926
177
                if (packet_data->has_opid && !packet_data->opid_first)
6927
166
                {
6928
166
                    dof_packet_data *first = (dof_packet_data *)g_hash_table_lookup(dpp_opid_to_packet_data, (const void *) & packet_data->op);
6929
166
                    if (first == NULL)
6930
93
                    {
6931
                        /* First reference to this operation. */
6932
93
                        g_hash_table_insert(dpp_opid_to_packet_data, (void *) & packet_data->op, (void *)packet_data);
6933
93
                        packet_data->opid_first = packet_data;
6934
93
                        packet_data->opid_last = packet_data;
6935
6936
                        /* The first opid must be a command. */
6937
93
                    }
6938
73
                    else
6939
73
                    {
6940
                        /* Operation exists, time to patch things in. */
6941
73
                        packet_data->opid_first = first;
6942
73
                        first->opid_last->opid_next = packet_data;
6943
73
                        first->opid_last = packet_data;
6944
6945
73
                        if (!packet_data->is_command)
6946
44
                        {
6947
44
                            if (!first->opid_first_response)
6948
14
                            {
6949
14
                                first->opid_first_response = packet_data;
6950
14
                                first->opid_last_response = packet_data;
6951
14
                            }
6952
30
                            else
6953
30
                            {
6954
30
                                first->opid_last_response->opid_next_response = packet_data;
6955
30
                                first->opid_last_response = packet_data;
6956
30
                            }
6957
44
                        }
6958
73
                    }
6959
166
                }
6960
6961
6962
                /* Add all the reference information to the tree. */
6963
177
                if (globals.track_operations && tree)
6964
0
                {
6965
0
                    proto_tree *ophistory_tree = proto_tree_add_subtree(tree, tvb, 0, 0, ett_2009_12_dpp_2_opid_history, NULL, "Operation History");
6966
6967
0
                    dof_packet_data *ptr = packet_data->opid_first;
6968
6969
0
                    if (ptr)
6970
0
                        proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_first_command,
6971
0
                                                   tvb, 0, 0, ptr->frame,
6972
0
                                                   "First Operation: %u",
6973
0
                                                   ptr->frame);
6974
6975
0
                    if (ptr->opid_last && ptr->opid_last != ptr)
6976
0
                        proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_last_command,
6977
0
                                                   tvb, 0, 0, ptr->opid_last->frame,
6978
0
                                                   "Last Operation: %u",
6979
0
                                                   ptr->opid_last->frame);
6980
6981
0
                    if (ptr->opid_first_response)
6982
0
                        proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_first_response,
6983
0
                                                   tvb, 0, 0, ptr->opid_first_response->frame,
6984
0
                                                   "First Response: %u",
6985
0
                                                   ptr->opid_first_response->frame);
6986
6987
0
                    if (ptr->opid_last_response && ptr->opid_last_response != ptr->opid_first_response)
6988
0
                        proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_last_response,
6989
0
                                                   tvb, 0, 0, ptr->opid_last_response->frame,
6990
0
                                                   "Last Response: %u",
6991
0
                                                   ptr->opid_last_response->frame);
6992
6993
                    /* Determine the window start, then output the number of packets. Output the number of skipped packets before
6994
                    * and after.
6995
                    */
6996
0
                    {
6997
0
                        dof_packet_data *start = packet_data->opid_first;
6998
0
                        unsigned diff = 0;
6999
0
                        while (ptr)
7000
0
                        {
7001
0
                            if (ptr == packet_data)
7002
0
                                break;
7003
7004
0
                            ptr = ptr->opid_next;
7005
0
                            diff += 1;
7006
7007
0
                            if (diff > globals.track_operations_window)
7008
0
                            {
7009
0
                                start = start->opid_next;
7010
0
                                diff -= 1;
7011
0
                            }
7012
0
                        }
7013
7014
0
                        ptr = start;
7015
0
                        diff = 0;
7016
7017
0
                        while (ptr)
7018
0
                        {
7019
0
                            const char *THIS = "";
7020
7021
0
                            if (ptr == packet_data)
7022
0
                            {
7023
0
                                THIS = "this ";
7024
0
                                diff = globals.track_operations_window + 1;
7025
0
                            }
7026
7027
                            /* (DPS Frame) [ws WS Frame]: (SID)->(RID): (THIS) (SUMMARY) */
7028
0
                            proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_related_frame,
7029
0
                                                       tvb, 0, 0, ptr->frame,
7030
0
                                                       "%u[ws %u]: %u->%u: %s%s",
7031
0
                                                       ptr->dof_frame, ptr->frame,
7032
0
                                                       ptr->sender_sid_id, ptr->receiver_sid_id,
7033
0
                                                       THIS,
7034
0
                                                       ptr->summary ? ptr->summary : "");
7035
7036
0
                            ptr = ptr->opid_next;
7037
0
                            if (diff && !--diff)
7038
0
                                break;
7039
0
                        }
7040
0
                    }
7041
0
                }
7042
177
            }
7043
177
                break;
7044
340
            }
7045
7046
329
            proto_item_set_len(opid_tree, offset - opid_start);
7047
7048
329
            {
7049
329
                if ((dpp_flags & 0x10) == 0)
7050
227
                {
7051
227
                    uint8_t dpp_seq = 0;
7052
227
                    uint8_t dpp_retry = 0;
7053
227
                    uint16_t dpp_delay = 0;
7054
7055
                    /* Extract SEQ */
7056
227
                    if (dpp_flags & 0x04)
7057
9
                    {
7058
9
                        dpp_seq = tvb_get_uint8(tvb, offset);
7059
9
                        proto_tree_add_uint_format(dpp_tree, hf_2009_12_dpp_2_1_seq, tvb, offset, 1, dpp_seq, "Sequence: %u", dpp_seq);
7060
9
                        offset += 1;
7061
9
                    }
7062
7063
                    /* Extract Retry */
7064
227
                    if (dpp_flags & 0x02)
7065
37
                    {
7066
37
                        dpp_retry = tvb_get_uint8(tvb, offset);
7067
37
                        proto_tree_add_uint_format(dpp_tree, hf_2009_12_dpp_2_1_retry, tvb, offset, 1, dpp_retry, "Retry: %u", dpp_retry);
7068
37
                        offset += 1;
7069
37
                    }
7070
7071
                    /* Extract Delay */
7072
227
                    {
7073
227
                        dpp_delay = tvb_get_uint8(tvb, offset);
7074
227
                        if (dpp_delay > 128)
7075
88
                            dpp_delay = 128 + ((dpp_delay - 128) * 32);
7076
7077
227
                        proto_tree_add_uint_format(dpp_tree, hf_2009_12_dpp_2_1_delay, tvb, offset, 1, dpp_delay, "Delay: %u seconds", dpp_delay);
7078
227
                        offset += 1;
7079
227
                    }
7080
7081
227
                    packet_data->summary = wmem_strdup_printf(wmem_file_scope(), "command seq %u, retry %u, delay %u", dpp_seq, dpp_retry, dpp_delay);
7082
227
                }
7083
102
                else
7084
102
                    packet_data->summary = "response";
7085
329
            }
7086
7087
            /* Extract session information. */
7088
329
            if (dpp_flags & 0x80)
7089
30
            {
7090
30
                uint32_t sec_offset = offset;
7091
30
                uint8_t sh_flags;
7092
30
                uint32_t ssid;
7093
30
                proto_tree *security_tree;
7094
30
                proto_tree *sec_flags_tree;
7095
30
                proto_item *item;
7096
7097
30
                security_tree = proto_tree_add_subtree(dpp_tree, tvb, offset, -1, ett_2009_12_dpp_2_3_security, NULL, "Security Header");
7098
7099
30
                sh_flags = tvb_get_uint8(tvb, offset);
7100
30
                item = proto_tree_add_uint_format(security_tree, hf_2009_12_dpp_2_3_sec_flags, tvb,
7101
30
                                                  offset, 1, sh_flags, "Flags: 0x%02x", sh_flags);
7102
7103
30
                sec_flags_tree = proto_item_add_subtree(item, ett_2009_12_dpp_2_3_sec_flags);
7104
30
                proto_tree_add_item(sec_flags_tree, hf_2009_12_dpp_2_3_sec_flag_secure, tvb, offset, 1, ENC_NA);
7105
30
                proto_tree_add_item(sec_flags_tree, hf_2009_12_dpp_2_3_sec_flag_rdid, tvb, offset, 1, ENC_NA);
7106
30
                proto_tree_add_item(sec_flags_tree, hf_2009_12_dpp_2_3_sec_flag_partition, tvb, offset, 1, ENC_NA);
7107
30
                proto_tree_add_item(sec_flags_tree, hf_2009_12_dpp_2_3_sec_flag_as, tvb, offset, 1, ENC_NA);
7108
30
                proto_tree_add_item(sec_flags_tree, hf_2009_12_dpp_2_3_sec_flag_ssid, tvb, offset, 1, ENC_NA);
7109
30
                offset += 1;
7110
7111
30
                ssid = 0;
7112
30
                if (sh_flags & DPP_V2_SEC_FLAG_S)
7113
18
                {
7114
18
                    int s_offset = offset;
7115
18
                    int ssid_len;
7116
18
                    proto_item *pi;
7117
18
                    offset = read_c4(tvb, offset, &ssid, &ssid_len);
7118
18
                    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);
7119
18
                    validate_c4(pinfo, pi, ssid, ssid_len);
7120
18
                }
7121
7122
                /* At this point we know the transport information, DNP port information, and the
7123
                * SSID. This means that we can isolate the session that this communication belongs
7124
                * to. Note that all uses of an SSID are scoped by the transport.
7125
                */
7126
30
                if (sh_flags & DPP_V2_SEC_FLAG_A)
7127
20
                    ssid |= AS_ASSIGNED_SSID;
7128
7129
30
                if (api_data->session && !api_data->secure_session)
7130
29
                {
7131
29
                    dof_secure_session_data *search = api_data->session->secure_sessions;
7132
29
                    while (search)
7133
0
                    {
7134
0
                        if (ssid == search->ssid)
7135
0
                            break;
7136
7137
0
                        search = search->next;
7138
0
                    }
7139
7140
29
                    if (search)
7141
0
                    {
7142
0
                        api_data->session = search->parent;
7143
0
                        api_data->secure_session = search;
7144
0
                    }
7145
29
                }
7146
7147
30
                if (sh_flags & DPP_V2_SEC_FLAG_D)
7148
17
                {
7149
17
                    int s_offset = offset;
7150
17
                    uint32_t rdid;
7151
17
                    int rdid_len;
7152
17
                    proto_item *pi;
7153
17
                    offset = read_c4(tvb, offset, &rdid, &rdid_len);
7154
17
                    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);
7155
17
                    validate_c4(pinfo, pi, rdid, rdid_len);
7156
7157
17
                    offset = dof_dissect_pdu_as_field(dissect_2008_16_security_10, tvb, pinfo, security_tree,
7158
17
                                                      offset, hf_2009_12_dpp_2_3_sec_remote_partition, ett_2009_12_dpp_2_3_sec_remote_partition, NULL);
7159
17
                }
7160
7161
30
                if (sh_flags & DPP_V2_SEC_FLAG_P)
7162
9
                {
7163
9
                    offset = dof_dissect_pdu_as_field(dissect_2008_16_security_10, tvb, pinfo, security_tree,
7164
9
                                                      offset, hf_2009_12_dpp_2_3_sec_partition, ett_2009_12_dpp_2_3_sec_partition, NULL);
7165
9
                }
7166
7167
30
                if (sh_flags & DPP_V2_SEC_FLAG_E)
7168
3
                {
7169
                    /* If we get here without success, then we can only bail. */
7170
3
                    if (packet_data->security_session_error)
7171
0
                    {
7172
0
                        col_set_str(pinfo->cinfo, COL_INFO, packet_data->security_session_error);
7173
0
                        proto_item_set_end(tree, tvb, offset);
7174
0
                        expert_add_info(pinfo, security_tree, &ei_dpp_no_security_context);
7175
0
                        {
7176
0
                            tvbuff_t *data_tvb = tvb_new_subset_remaining(tvb, offset);
7177
0
                            call_data_dissector(data_tvb, pinfo, tree);
7178
0
                        }
7179
0
                        proto_item_set_len(security_tree, offset - sec_offset);
7180
0
                        return offset;
7181
0
                    }
7182
7183
3
                    if (!api_data->secure_session)
7184
3
                    {
7185
3
                        packet_data->security_session_error = "[Encrypted - No Session Available]";
7186
3
                        proto_item_set_len(security_tree, offset - sec_offset);
7187
3
                        return offset;
7188
3
                    }
7189
7190
                    /* Security has not failed, and we have a security session. */
7191
0
                    {
7192
0
                        dissector_table_t sec_header = find_dissector_table("dof.secmode");
7193
                        /* TODO: CCM is hardcoded. We should try all of the sessions, which could mean multiple security modes. */
7194
0
                        dissector_handle_t dp = dissector_get_uint_handle(sec_header, 0x6001); /* packet_data->security_session->security_mode); */
7195
0
                        if (dp)
7196
0
                        {
7197
0
                            dof_secmode_api_data sdata;
7198
7199
0
                            sdata.context = HEADER;
7200
0
                            sdata.security_mode_offset = offset;
7201
0
                            sdata.dof_api = api_data;
7202
0
                            sdata.secure_session = api_data->secure_session;
7203
0
                            sdata.session_key_data = NULL;
7204
7205
0
                            offset += call_dissector_only(dp, tvb, pinfo, security_tree, &sdata);
7206
7207
0
                            if (!packet_data->decrypted_buffer)
7208
0
                            {
7209
0
                                proto_item_set_end(tree, tvb, offset);
7210
0
                                proto_item_set_len(security_tree, offset - sec_offset);
7211
0
                                return offset;
7212
0
                            }
7213
0
                        }
7214
0
                    }
7215
0
                }
7216
27
                proto_item_set_len(security_tree, offset - sec_offset);
7217
27
            }
7218
7219
            /* The end of the packet must be called in the original tvb or chaos ensues... */
7220
326
            proto_item_set_end(tree, tvb, offset);
7221
326
        }
7222
7223
7224
326
        if (packet_data->decrypted_tvb)
7225
0
        {
7226
0
            tvb = packet_data->decrypted_tvb;
7227
0
            offset = packet_data->decrypted_offset;
7228
0
        }
7229
7230
        /* Assuming there is more, it must be DPP. */
7231
        /* We have a packet. We must handle the special case of this being *our* application
7232
        * protocol (0x7FFF). If it is, then *we* are the dissector...
7233
        */
7234
326
        {
7235
326
            uint16_t app;
7236
326
            tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length(tvb) - offset);
7237
7238
326
            read_c2(tvb, offset, &app, NULL);
7239
326
            if (app == 0x7FFF)
7240
15
            {
7241
15
                offset += dissect_dpp_v2_common(next_tvb, pinfo, proto_item_get_parent(tree), data);
7242
15
            }
7243
311
            else
7244
311
            {
7245
311
                offset += dissect_app_common(next_tvb, pinfo, proto_item_get_parent(tree), data);
7246
311
            }
7247
326
        }
7248
326
    }
7249
7250
0
    col_set_fence(pinfo->cinfo, COL_PROTOCOL);
7251
326
    col_set_fence(pinfo->cinfo, COL_INFO);
7252
326
    return offset;
7253
329
}
7254
7255
static int dissect_options(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void *data _U_)
7256
17
{
7257
148
    while (offset < (int)tvb_captured_length(tvb))
7258
131
    {
7259
131
        proto_tree *subtree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_2008_1_dsp_12_option, NULL, "Option");
7260
131
        tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
7261
131
        int len = dissect_2008_1_dsp_1(next_tvb, pinfo, subtree);
7262
131
        proto_item_set_len(proto_tree_get_parent(subtree), len);
7263
131
        offset += len;
7264
131
    }
7265
7266
17
    return offset;
7267
17
}
7268
7269
static int dissect_dsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
7270
30
{
7271
30
    dof_api_data *api_data = (dof_api_data *)data;
7272
30
    dof_packet_data *packet_data;
7273
30
    unsigned offset = 0;
7274
30
    uint8_t opcode;
7275
30
    uint16_t app;
7276
30
    int app_len;
7277
30
    proto_item *ti;
7278
30
    proto_tree *dsp_tree;
7279
30
    proto_tree *options_tree;
7280
7281
30
    if (api_data == NULL)
7282
0
    {
7283
        /* TODO: Output error. */
7284
0
        return 0;
7285
0
    }
7286
7287
30
    packet_data = api_data->packet;
7288
30
    if (packet_data == NULL)
7289
0
    {
7290
        /* TODO: Output error. */
7291
0
        return 0;
7292
0
    }
7293
7294
    /* Make entries in Protocol column and Info column on summary display */
7295
30
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "DSPv2 ");
7296
7297
    /* Create the protocol tree. */
7298
30
    offset = 0;
7299
30
    ti = proto_tree_add_item(tree, proto_2008_1_dsp, tvb, offset, -1, ENC_NA);
7300
30
    dsp_tree = proto_item_add_subtree(ti, ett_2008_1_dsp_12);
7301
7302
    /* Add the APPID. */
7303
30
    offset = read_c2(tvb, offset, &app, &app_len);
7304
30
    ti = proto_tree_add_uint(dsp_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
7305
30
    validate_c2(pinfo, ti, app, app_len);
7306
7307
#if 0
7308
    if (!packet->is_streaming)
7309
    {
7310
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "DSPv2 ");
7311
7312
        if (tvb_captured_length(tvb) == offset)
7313
        col_set_str(pinfo->cinfo, COL_INFO, "Query");
7314
        else
7315
        {
7316
            col_set_str(pinfo->cinfo, COL_INFO, "Query Response");
7317
            while (offset < tvb_captured_length(tvb))
7318
            {
7319
                uint16_t app;
7320
                int start = offset;
7321
                offset = read_c2(tvb, offset, &app, NULL);
7322
                proto_tree_add_uint(dsp_tree, hf_2008_1_app_version, tvb, start, offset - start, app);
7323
            }
7324
        }
7325
7326
        return offset;
7327
    }
7328
#endif
7329
7330
30
    if (offset == tvb_captured_length(tvb))
7331
0
    {
7332
0
        col_append_str(pinfo->cinfo, COL_INFO, "DSP [nop]");
7333
0
        expert_add_info(pinfo, dsp_tree, &ei_implicit_no_op);
7334
7335
0
        return offset;
7336
0
    }
7337
7338
    /* Determine the ESP opcode. */
7339
30
    opcode = tvb_get_uint8(tvb, offset);
7340
7341
30
    if (!packet_data->is_command)
7342
11
        opcode |= OP_2008_1_RSP;
7343
7344
30
    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);
7345
30
    offset += 1;
7346
30
    col_append_sep_str(pinfo->cinfo, COL_INFO, "/", val_to_str(pinfo->pool, opcode, strings_2008_1_dsp_opcodes, "Unknown Opcode (%d)"));
7347
7348
30
    switch (opcode)
7349
30
    {
7350
0
    case OP_2008_1_OPEN_CMD: /* 2008.1 DSP.14.1 */
7351
0
        break;
7352
7353
1
    case OP_2008_1_OPEN_RSP: /* 2008.1 DSP.14.2 */
7354
6
    case OP_2008_1_OPEN_SECURE_RSP: /* 2008.1 DSP.14.3 */
7355
6
    {
7356
663
        while (offset < tvb_captured_length(tvb))
7357
657
        {
7358
657
            uint16_t ap;
7359
657
            int length;
7360
657
            proto_item *pi;
7361
657
            int start = offset;
7362
657
            offset = read_c2(tvb, offset, &ap, &length);
7363
657
            pi = proto_tree_add_uint(dsp_tree, hf_2008_1_app_version, tvb, start, offset - start, ap);
7364
657
            validate_c2(pinfo, pi, ap, length);
7365
657
        }
7366
6
    }
7367
6
        break;
7368
7369
2
    case OP_2008_1_QUERY_CMD:
7370
2
        break;
7371
7372
2
    case OP_2008_1_QUERY_RSP:
7373
2
        break;
7374
7375
0
    case OP_2008_1_CONFIG_ACK:
7376
0
        break;
7377
7378
15
    case OP_2008_1_CONFIG_REQ:
7379
        /* This will start a session if not existing... */
7380
        /* FALL THROUGH */
7381
7382
17
    case OP_2008_1_CONFIG_NAK:
7383
17
    {
7384
17
        int length = tvb_captured_length(tvb) - offset;
7385
7386
17
        options_tree = proto_tree_add_subtree_format(dsp_tree, tvb, offset, length, ett_2008_1_dsp_12_options, NULL,
7387
17
                                                     "DSP Options: (%d byte%s)", length, plurality(length, "", "s"));
7388
17
        offset = dissect_options(tvb, offset, pinfo, options_tree, NULL);
7389
17
    }
7390
17
        break;
7391
7392
0
    case OP_2008_1_CONFIG_REJ:
7393
        /* TODO: Handle reject. */
7394
0
        break;
7395
7396
0
    case OP_2008_1_TERMINATE_CMD:
7397
0
    case OP_2008_1_TERMINATE_RSP:
7398
        /* Nothing */
7399
0
        break;
7400
30
    }
7401
7402
14
    return offset;
7403
30
}
7404
7405
static int dissect_ccm_dsp(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
7406
0
{
7407
    /* We are handed a buffer that starts with an option and our protocol id. Any options follow that. */
7408
0
    int offset = 0;
7409
0
    proto_item *parent = proto_tree_get_parent(tree);
7410
0
    uint8_t len, strength_count, i;
7411
0
    proto_item *ti;
7412
0
    proto_tree *ccm_tree;
7413
7414
    /* Append description to the parent. */
7415
0
    proto_item_append_text(parent, " (CCM)");
7416
7417
    /* Compute the version and flags, masking off other bits. */
7418
0
    offset += 3; /* Skip the type and protocol. */
7419
0
    len = tvb_get_uint8(tvb, offset++);
7420
7421
0
    ti = proto_tree_add_item(tree, hf_ccm_dsp_option, tvb, offset, len, ENC_NA);
7422
0
    ccm_tree = proto_item_add_subtree(ti, ett_ccm_dsp_option);
7423
7424
0
    proto_tree_add_item_ret_uint8(ccm_tree, hf_ccm_dsp_strength_count, tvb, offset++, 1, ENC_NA, &strength_count);
7425
7426
0
    for (i = 0; i < strength_count; i++)
7427
0
        proto_tree_add_item(ccm_tree, hf_ccm_dsp_strength, tvb, offset++, 1, ENC_NA);
7428
7429
0
    proto_tree_add_item(ccm_tree, hf_ccm_dsp_e_flag, tvb, offset, 1, ENC_NA);
7430
0
    proto_tree_add_item(ccm_tree, hf_ccm_dsp_m_flag, tvb, offset, 1, ENC_NA);
7431
0
    proto_tree_add_item(ccm_tree, hf_ccm_dsp_tmax, tvb, offset, 1, ENC_NA);
7432
0
    proto_tree_add_item(ccm_tree, hf_ccm_dsp_tmin, tvb, offset, 1, ENC_NA);
7433
7434
0
    offset += 1;
7435
0
    return offset;
7436
0
}
7437
7438
/**
7439
 * This is the main entry point for the CCM dissector. It is always called from an DPS
7440
 * dissector, and is always passed the dof_secmode_data structure.
7441
 */
7442
static int dissect_ccm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
7443
0
{
7444
0
    dof_secmode_api_data *secmode_api_data;
7445
0
    dof_session_key_exchange_data *key_data;
7446
7447
0
    secmode_api_data = (dof_secmode_api_data *)data;
7448
0
    if (secmode_api_data == NULL)
7449
0
    {
7450
0
        return 0;
7451
0
    }
7452
7453
0
    key_data = secmode_api_data->session_key_data;
7454
7455
    /* Based on the context of the request, handle the work. */
7456
0
    switch (secmode_api_data->context)
7457
0
    {
7458
0
    case INITIALIZE:
7459
        /* Parse off the initialization fields, and if necessary create the security mode state
7460
        * that is being initialized. This is passed the DPS data, DPS session data, and Key Exchange Data.
7461
        */
7462
0
    {
7463
0
        ccm_session_data *ccm_data = (ccm_session_data *)key_data->security_mode_key_data;
7464
0
        int offset = 0;
7465
0
        uint8_t header;
7466
0
        uint16_t length;
7467
7468
0
        if (!ccm_data)
7469
0
        {
7470
            /* We need to parse the initialization data. */
7471
0
            ccm_data = wmem_new0(wmem_file_scope(), ccm_session_data);
7472
0
            if (!ccm_data)
7473
0
                return 0;
7474
0
            wmem_register_callback(wmem_file_scope(), dof_sessions_destroy_cb, ccm_data);
7475
7476
0
            key_data->security_mode_key_data = ccm_data;
7477
7478
0
            if (!key_data->security_mode_data || key_data->security_mode_data_length < 3)
7479
0
                return 0;
7480
7481
            /* TODO: Not sure that these are all right. */
7482
0
            ccm_data->protocol_id = DOF_PROTOCOL_CCM;
7483
0
            ccm_data->cipher = key_data->security_mode_data[1];
7484
0
            ccm_data->encrypted = key_data->security_mode_data[key_data->security_mode_data_length - 1] & 0x80;
7485
0
            ccm_data->mac_len = (key_data->security_mode_data[key_data->security_mode_data_length - 1] & 0x07) * 2 + 2;
7486
0
            ccm_data->client_datagram_number = 0;
7487
0
            ccm_data->server_datagram_number = 0;
7488
7489
0
            switch (ccm_data->protocol_id)
7490
0
            {
7491
0
            case DOF_PROTOCOL_CCM:
7492
0
                if (gcry_cipher_open(&ccm_data->cipher_data, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0)) {
7493
0
                    return 0;
7494
0
                }
7495
0
                break;
7496
7497
0
            default:
7498
0
                return 0;
7499
0
            }
7500
0
        }
7501
7502
0
        if (secmode_api_data->dof_api->transport_session->is_2_node)
7503
0
        {
7504
0
            switch (ccm_data->protocol_id)
7505
0
            {
7506
0
            case DOF_PROTOCOL_CCM:
7507
0
                if (gcry_cipher_setkey(ccm_data->cipher_data, key_data->session_key, 32)) {
7508
0
                    gcry_cipher_close(ccm_data->cipher_data);
7509
0
                    ccm_data->cipher_data = NULL;
7510
0
                    return 0;
7511
0
                }
7512
0
                break;
7513
7514
0
            default:
7515
0
                return 0;
7516
0
            }
7517
7518
            /* This mode has a fixed size, so we can return here without parsing further. */
7519
0
            return 2;
7520
0
        }
7521
7522
0
        offset = read_c2(tvb, offset, &length, NULL);
7523
        /* TODO validate C2 */
7524
0
        header = tvb_get_uint8(tvb, offset);
7525
0
        offset += 1;
7526
7527
        /* Determine the period, and store the key. */
7528
0
        {
7529
0
            uint8_t period = (header & 0x70) >> 4;
7530
0
            if (ccm_data->cipher_data_table == NULL)
7531
0
            {
7532
0
                gcry_cipher_hd_t ekey;
7533
0
                if (gcry_cipher_open(&ekey, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0)) {
7534
0
                    return 0;
7535
0
                }
7536
7537
0
                ccm_data->cipher_data_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, dof_cipher_data_destroy);
7538
0
                ccm_data->period = 1;
7539
0
                ccm_data->periods[period] = ccm_data->period;
7540
7541
0
                switch (ccm_data->protocol_id)
7542
0
                {
7543
0
                case DOF_PROTOCOL_CCM:
7544
0
                    if (gcry_cipher_setkey(ekey, key_data->session_key, 32)) {
7545
0
                        gcry_cipher_close(ekey);
7546
0
                        return 0;
7547
0
                    }
7548
0
                    break;
7549
7550
0
                default:
7551
0
                    gcry_cipher_close(ekey);
7552
0
                    return 0;
7553
0
                }
7554
7555
0
                g_hash_table_insert(ccm_data->cipher_data_table, GUINT_TO_POINTER(ccm_data->period), ekey);
7556
0
            }
7557
0
            else
7558
0
            {
7559
0
                uint32_t lookup = ccm_data->periods[period];
7560
7561
0
                if (!lookup)
7562
0
                {
7563
0
                    gcry_cipher_hd_t ekey;
7564
0
                    if (gcry_cipher_open(&ekey, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0)) {
7565
0
                        return 0;
7566
0
                    }
7567
0
                    switch (ccm_data->protocol_id)
7568
0
                    {
7569
0
                    case DOF_PROTOCOL_CCM:
7570
0
                        if (gcry_cipher_setkey(ekey, key_data->session_key, 32)) {
7571
0
                            gcry_cipher_close(ekey);
7572
0
                            return 0;
7573
0
                        }
7574
0
                        break;
7575
7576
0
                    default:
7577
0
                        gcry_cipher_close(ekey);
7578
0
                        return 0;
7579
0
                    }
7580
7581
0
                    ccm_data->period += 1;
7582
0
                    ccm_data->periods[period] = ccm_data->period;
7583
0
                    g_hash_table_insert(ccm_data->cipher_data_table, GUINT_TO_POINTER(ccm_data->period), ekey);
7584
0
                }
7585
0
                else
7586
0
                {
7587
0
                    uint8_t *in_table = (uint8_t *)g_hash_table_lookup(ccm_data->cipher_data_table, GUINT_TO_POINTER(lookup));
7588
0
                    if (memcmp(key_data->session_key, in_table, 32) != 0)
7589
0
                    {
7590
0
                        gcry_cipher_hd_t ekey;
7591
0
                        if (gcry_cipher_open(&ekey, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0)) {
7592
0
                            return 0;
7593
0
                        }
7594
0
                        switch (ccm_data->protocol_id)
7595
0
                        {
7596
0
                        case DOF_PROTOCOL_CCM:
7597
0
                            if (gcry_cipher_setkey(ekey, key_data->session_key, 32)) {
7598
0
                                gcry_cipher_close(ekey);
7599
0
                                return 0;
7600
0
                            }
7601
0
                            break;
7602
7603
0
                        default:
7604
0
                            gcry_cipher_close(ekey);
7605
0
                            return 0;
7606
0
                        }
7607
7608
0
                        ccm_data->period += 1;
7609
0
                        ccm_data->periods[period] = ccm_data->period;
7610
0
                        g_hash_table_insert(ccm_data->cipher_data_table, GUINT_TO_POINTER(ccm_data->period), ekey);
7611
0
                    }
7612
0
                }
7613
0
            }
7614
0
        }
7615
7616
0
        return offset + length - 1;
7617
0
    }
7618
7619
0
    case HEADER:
7620
0
    {
7621
0
        ccm_session_data *session;
7622
0
        dof_transport_session *transport_session = (dof_transport_session *)secmode_api_data->dof_api->transport_session;
7623
0
        dof_secure_session_data *secure_session = secmode_api_data->secure_session;
7624
0
        dof_session_key_exchange_data *security_data = NULL;
7625
0
        dof_packet_data *dof_packet = secmode_api_data->dof_api->packet;
7626
0
        uint8_t ccm_flags;
7627
0
        uint32_t nid;
7628
0
        uint16_t slot = 0;
7629
0
        uint32_t pn = 0;
7630
0
        bool pn_present = false;
7631
0
        uint32_t tnid;
7632
0
        uint32_t nnid;
7633
0
        proto_tree *ccm_flags_tree;
7634
0
        proto_tree *header_tree;
7635
0
        proto_item * item,*header;
7636
0
        ccm_packet_data *pdata;
7637
0
        int offset = 0;
7638
7639
0
        if (!dof_packet->security_session)
7640
0
        {
7641
0
            if (transport_session->is_streaming)
7642
0
            {
7643
                /* Find the first security data that is applicable - they are in order of packet sequence. */
7644
0
                security_data = secure_session->session_security_data;
7645
0
                while (security_data)
7646
0
                {
7647
0
                    if (dof_packet->is_sent_by_initiator && (dof_packet->dof_frame > security_data->i_valid))
7648
0
                        break;
7649
7650
0
                    if (!dof_packet->is_sent_by_initiator && (dof_packet->dof_frame > security_data->r_valid))
7651
0
                        break;
7652
7653
0
                    security_data = security_data->next;
7654
0
                }
7655
7656
0
                if (security_data)
7657
0
                    dof_packet->security_session = security_data;
7658
0
                else
7659
0
                {
7660
0
                    dof_packet->security_session_error = "[Encrypted - No Session Available]";
7661
0
                    return offset;
7662
0
                }
7663
0
            }
7664
0
            else
7665
0
            {
7666
0
                dof_packet->security_session = secure_session->session_security_data;
7667
0
                security_data = dof_packet->security_session;
7668
0
            }
7669
0
        }
7670
0
        else
7671
0
        {
7672
0
            security_data = dof_packet->security_session;
7673
0
        }
7674
7675
0
        if (!security_data || !security_data->session_key || !security_data->security_mode_key_data)
7676
0
        {
7677
0
            dof_packet->security_session_error = "[Encrypted - No Session Available]";
7678
0
            return offset;
7679
0
        }
7680
7681
0
        session = (ccm_session_data *)security_data->security_mode_key_data;
7682
0
        offset = secmode_api_data->security_mode_offset;
7683
7684
        /* Add a master header for this protocol. */
7685
0
        header = proto_tree_add_protocol_format(tree, proto_ccm, tvb, offset, 0,
7686
0
                                                "CCM Security Mode, Version: 1");
7687
0
        header_tree = proto_item_add_subtree(header, ett_header);
7688
0
        tree = header_tree;
7689
7690
0
        ccm_flags = tvb_get_uint8(tvb, offset);
7691
0
        item = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_flags, tvb,
7692
0
                                          offset, 1, ccm_flags, "Flags: 0x%02x", ccm_flags);
7693
7694
0
        ccm_flags_tree = proto_item_add_subtree(item, ett_epp_v1_ccm_flags);
7695
0
        proto_tree_add_item(ccm_flags_tree, hf_epp_v1_ccm_flags_manager, tvb, offset, 1, ENC_NA);
7696
0
        proto_tree_add_item(ccm_flags_tree, hf_epp_v1_ccm_flags_period, tvb, offset, 1, ENC_NA);
7697
0
        proto_tree_add_item(ccm_flags_tree, hf_epp_v1_ccm_flags_target, tvb, offset, 1, ENC_NA);
7698
0
        proto_tree_add_item(ccm_flags_tree, hf_epp_v1_ccm_flags_next_nid, tvb, offset, 1, ENC_NA);
7699
0
        proto_tree_add_item(ccm_flags_tree, hf_epp_v1_ccm_flags_packet, tvb, offset, 1, ENC_NA);
7700
0
        offset += 1;
7701
7702
0
        if (ccm_flags & 0x01)
7703
0
            pn_present = true;
7704
7705
0
        pdata = (ccm_packet_data *)dof_packet->security_packet;
7706
0
        if (!pdata)
7707
0
        {
7708
0
            pdata = wmem_new0(wmem_file_scope(), ccm_packet_data);
7709
0
            if (pdata)
7710
0
            {
7711
0
                dof_packet->security_packet = pdata;
7712
7713
0
                if (transport_session->is_2_node)
7714
0
                {
7715
0
                    if (dof_packet->is_sent_by_initiator)
7716
0
                    {
7717
0
                        pdata->nid = 0;
7718
0
                        if (pn_present == false)
7719
0
                            pdata->dn = ++session->client_datagram_number;
7720
0
                        else
7721
0
                            pdata->dn = pn;
7722
0
                    }
7723
0
                    else
7724
0
                    {
7725
0
                        pdata->nid = 1;
7726
0
                        if (pn_present == 0)
7727
0
                            pdata->dn = ++session->server_datagram_number;
7728
0
                        else
7729
0
                            pdata->dn = pn;
7730
0
                    }
7731
0
                }
7732
0
                else
7733
0
                {
7734
0
                    uint8_t packet_period = (ccm_flags & 0x70) >> 4;
7735
0
                    pdata->period = session->periods[packet_period];
7736
0
                }
7737
0
            }
7738
0
        }
7739
7740
0
        if (!pdata)
7741
0
            return offset - secmode_api_data->security_mode_offset;
7742
7743
0
        if (!secure_session->is_2_node)
7744
0
        {
7745
0
            int nid_len;
7746
0
            proto_item *pi;
7747
0
            read_c4(tvb, offset, &nid, &nid_len);
7748
            /* TODO: Do this right, as offset from BNID. */
7749
0
            nid /= 2;
7750
0
            pdata->nid = nid;
7751
0
            pi = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_nid, tvb, offset, nid_len, nid, "Node ID: %u", nid);
7752
0
            validate_c4(pinfo, pi, nid, nid_len);
7753
0
            offset += nid_len;
7754
0
        }
7755
0
        else
7756
0
        {
7757
0
            item = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_nid, tvb, 0, 0, pdata->nid, "Node ID: %u", pdata->nid);
7758
0
            proto_item_set_generated(item);
7759
0
        }
7760
7761
0
        if (!secure_session->is_2_node)
7762
0
        {
7763
0
            int slot_len;
7764
0
            proto_item *pi;
7765
0
            read_c2(tvb, offset, &slot, &slot_len);
7766
0
            pi = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_slot, tvb, offset, slot_len, slot, "Slot: %hu", slot);
7767
0
            validate_c2(pinfo, pi, slot, slot_len);
7768
0
            offset += slot_len;
7769
0
        }
7770
0
        else
7771
0
        {
7772
0
            item = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_slot, tvb, 0, 0, 0, "Slot: %u", 0);
7773
0
            proto_item_set_generated(item);
7774
0
        }
7775
7776
0
        if (ccm_flags & 0x01)
7777
0
        {
7778
0
            int pn_len;
7779
0
            proto_item *pi;
7780
0
            read_c4(tvb, offset, &pn, &pn_len);
7781
0
            pi = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_pn, tvb, offset, pn_len, pn, "Packet Number: %u", pn);
7782
0
            validate_c4(pinfo, pi, pn, pn_len);
7783
0
            pdata->dn = pn;
7784
0
            offset += pn_len;
7785
0
        }
7786
0
        else
7787
0
        {
7788
0
            item = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_pn, tvb, 0, 0, pdata->dn, "Packet Number: %u", pdata->dn);
7789
0
            proto_item_set_generated(item);
7790
0
        }
7791
7792
0
        if (ccm_flags & 0x08)
7793
0
        {
7794
0
            int tnid_len;
7795
0
            proto_item *pi;
7796
0
            read_c4(tvb, offset, &tnid, &tnid_len);
7797
0
            pi = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_tnid, tvb, offset, tnid_len, tnid, "Target Node ID: %u", tnid);
7798
0
            validate_c4(pinfo, pi, tnid, tnid_len);
7799
0
            offset += tnid_len;
7800
0
        }
7801
7802
0
        if (ccm_flags & 0x02)
7803
0
        {
7804
0
            int nnid_len;
7805
0
            proto_item *pi;
7806
0
            read_c4(tvb, offset, &nnid, &nnid_len);
7807
0
            pi = proto_tree_add_uint_format(tree, hf_epp_v1_ccm_nnid, tvb, offset, nnid_len, nnid, "Next Node ID: %u", nnid);
7808
0
            validate_c4(pinfo, pi, nnid, nnid_len);
7809
0
            offset += nnid_len;
7810
0
        }
7811
7812
0
        proto_item_set_len(header, offset - secmode_api_data->security_mode_offset);
7813
7814
0
        if (dof_packet->decrypted_buffer_error)
7815
0
        {
7816
0
            col_set_str(pinfo->cinfo, COL_INFO, dof_packet->decrypted_buffer_error);
7817
0
            expert_add_info(pinfo, tree, &ei_decode_failure);
7818
0
            return offset - secmode_api_data->security_mode_offset;
7819
0
        }
7820
7821
        /* We have reached the encryption boundary. At this point the rest of the packet
7822
        * is encrypted, and we may or may not be able to decrypt it.
7823
        *
7824
        * If we can decrypt it (which for now means that it uses a Session Key of [0]
7825
        * the we switch to decoding the decrypted PDU. Otherwise we create an entry
7826
        * for the encrypted bytes and move on...
7827
        */
7828
7829
0
        {
7830
0
            unsigned a_len = offset;
7831
0
            const uint8_t *epp_buf = tvb_get_ptr(tvb, 0, offset);
7832
0
            unsigned e_len = tvb_captured_length_remaining(tvb, offset);
7833
0
            uint8_t *buf = (uint8_t *)tvb_memdup(pinfo->pool, tvb, offset, e_len);
7834
0
            tvbuff_t *app;
7835
7836
            /* The default nonce is a function of whether or not this is the server
7837
            * or the client and the packet count. The packet count either comes from
7838
            * the PDU or is a function of the previous value (of the sending node).
7839
            */
7840
0
            uint8_t nonce[11];
7841
7842
0
            nonce[0] = (pdata->nid) >> 24;
7843
0
            nonce[1] = (pdata->nid) >> 16;
7844
0
            nonce[2] = (pdata->nid) >> 8;
7845
0
            nonce[3] = (uint8_t)(pdata->nid);
7846
0
            nonce[4] = slot >> 8;
7847
0
            nonce[5] = (uint8_t)slot;
7848
0
            nonce[7] = (pdata->dn) >> 24;
7849
0
            nonce[8] = (pdata->dn) >> 16;
7850
0
            nonce[9] = (pdata->dn) >> 8;
7851
0
            nonce[10] = (uint8_t)(pdata->dn);
7852
7853
            /* Now the hard part. We need to determine the current packet number.
7854
            * This is a function of the sending node, the previous state and the
7855
            * current PDU.
7856
            */
7857
7858
0
            app = NULL;
7859
7860
0
            proto_item_set_end(tree, tvb, offset);
7861
0
            if (!session->encrypted)
7862
0
            {
7863
                /* There is still a MAC involved, and even though we don't need a new
7864
                * buffer we need to adjust the length of the existing buffer.
7865
                */
7866
0
                app = tvb_new_subset_length(tvb, offset, e_len - session->mac_len);
7867
0
                dof_packet->decrypted_tvb = app;
7868
0
                dof_packet->decrypted_offset = 0;
7869
0
            }
7870
0
            else
7871
0
            {
7872
0
                if (dof_packet->decrypted_buffer)
7873
0
                {
7874
                    /* No need to decrypt, but still need to create buffer. */
7875
0
                    app = tvb_new_real_data((const uint8_t *)dof_packet->decrypted_buffer, e_len - session->mac_len, e_len - session->mac_len);
7876
0
                    tvb_set_child_real_data_tvbuff(tvb, app);
7877
0
                    add_new_data_source(pinfo, app, "Decrypted DOF");
7878
0
                    dof_packet->decrypted_tvb = app;
7879
0
                    dof_packet->decrypted_offset = 0;
7880
0
                }
7881
0
                else
7882
0
                {
7883
0
                    if (decrypt(session, pdata, nonce, epp_buf, a_len, buf, e_len))
7884
0
                    {
7885
                        /* store decrypted buffer in file scope for reuse in next pass */
7886
0
                        uint8_t *cache = (uint8_t *)wmem_alloc0(wmem_file_scope(), e_len - session->mac_len);
7887
0
                        memcpy(cache, buf, e_len - session->mac_len);
7888
0
                        app = tvb_new_real_data(cache, e_len - session->mac_len, e_len - session->mac_len);
7889
0
                        tvb_set_child_real_data_tvbuff(tvb, app);
7890
0
                        add_new_data_source(pinfo, app, "Decrypted DOF");
7891
0
                        dof_packet->decrypted_buffer = cache;
7892
0
                        dof_packet->decrypted_offset = 0;
7893
0
                        dof_packet->decrypted_tvb = app;
7894
0
                    }
7895
0
                    else
7896
0
                    {
7897
                        /* Failure to decrypt or validate the MAC.
7898
                        * The packet is secure, so there is nothing we can do!
7899
                        */
7900
0
                        dof_packet->decrypted_buffer_error = "[Encrypted packet - decryption failure]";
7901
0
                    }
7902
0
                }
7903
0
            }
7904
0
        }
7905
7906
0
        return offset - secmode_api_data->security_mode_offset;
7907
0
    }
7908
0
        break;
7909
7910
0
    case TRAILER:
7911
       /* TODO check this case */
7912
0
        break;
7913
7914
0
    }
7915
7916
0
    return 0;
7917
0
}
7918
7919
static int dissect_ccm_app(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
7920
0
{
7921
0
    int offset = 0;
7922
0
    uint8_t opcode = 0;
7923
0
    uint16_t app;
7924
0
    int app_len;
7925
7926
0
    proto_item *ti;
7927
0
    proto_tree *ccm_tree;
7928
7929
    /* Make entries in Protocol column and Info column on summary display */
7930
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "CCM ");
7931
7932
    /* Create the protocol tree. */
7933
0
    offset = 0;
7934
0
    ti = proto_tree_add_item(tree, proto_ccm_app, tvb, offset, -1, ENC_NA);
7935
0
    ccm_tree = proto_item_add_subtree(ti, ett_ccm);
7936
7937
    /* Add the APPID. */
7938
0
    offset = read_c2(tvb, offset, &app, &app_len);
7939
0
    ti = proto_tree_add_uint(ccm_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
7940
0
    validate_c2(pinfo, ti, app, app_len);
7941
7942
    /* Retrieve the opcode. */
7943
0
    opcode = tvb_get_uint8(tvb, offset);
7944
7945
0
    col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, opcode, ccm_opcode_strings, "Unknown Opcode (%d)"));
7946
7947
0
    if (tree)
7948
0
    {
7949
        /* Opcode */
7950
0
        proto_tree_add_item(ccm_tree, hf_ccm_opcode, tvb, offset, 1, ENC_NA);
7951
#if 0  /* this needs completion */
7952
        offset += 1;
7953
7954
        switch (opcode)
7955
        {
7956
        case CCM_PDU_PROBE:
7957
        {
7958
        }
7959
            break;
7960
7961
        }
7962
#endif
7963
0
    }
7964
7965
0
    return 1;
7966
0
}
7967
7968
#if 0 /* TODO not used yet */
7969
static int dissect_ccm_validate(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data)
7970
{
7971
    dof_api_data *api_data = (dof_api_data *)data;
7972
    dof_packet_data *packet;
7973
    ccm_session_data *session;
7974
    int offset;
7975
    uint8_t ccm_flags;
7976
    uint32_t nid;
7977
    uint16_t slot;
7978
    uint32_t pn;
7979
    uint32_t tnid;
7980
7981
    if (api_data == NULL)
7982
    {
7983
        fprintf(stderr, "api_data is NULL.");
7984
        return 0;
7985
    }
7986
7987
    packet = api_data->packet;
7988
    if (packet == NULL)
7989
    {
7990
        fprintf(stderr, "api_data->packet is NULL.");
7991
        return 0;
7992
    }
7993
7994
    if (!packet->security_session)
7995
    {
7996
        fprintf(stderr, "packet->security_session is NULL");
7997
        return 0;
7998
    }
7999
8000
    if (packet->security_session->security_mode != DOF_PROTOCOL_CCM)
8001
    {
8002
        fprintf(stderr, "packet->security_session->security_mode != DOF_PROTOCOL_CCM");
8003
        return 0;
8004
    }
8005
8006
    session = (ccm_session_data *)packet->security_session->security_mode_key_data;
8007
8008
    /* The buffer we have been passed includes the entire EPP frame. The packet
8009
    * structure gives us the offset to our header.
8010
    */
8011
    offset = 0;
8012
8013
    ccm_flags = tvb_get_uint8(tvb, offset);
8014
    offset += 1;
8015
8016
    /* TODO validate the C2 and C4 fields below? */
8017
    if (ccm_flags & 0x04)
8018
        offset = read_c4(tvb, offset, &nid, NULL);
8019
8020
    if (ccm_flags & 0x02)
8021
        offset = read_c2(tvb, offset, &slot, NULL);
8022
8023
    if (ccm_flags & 0x01)
8024
        offset = read_c4(tvb, offset, &pn, NULL);
8025
8026
    if (ccm_flags & 0x08)
8027
        offset = read_c4(tvb, offset, &tnid, NULL);
8028
8029
8030
    /* We have reached the encryption boundary. At this point the rest of the packet
8031
    * is encrypted, and we may or may not be able to decrypt it.
8032
    *
8033
    * If we can decrypt it (which for now means that it uses a Session Key of [0]
8034
    * the we switch to decoding the decrypted PDU. Otherwise we create an entry
8035
    * for the encrypted bytes and move on...
8036
    */
8037
8038
    {
8039
        unsigned a_len = offset;
8040
        const uint8_t *epp_buf = tvb_get_ptr(tvb, 0, offset);
8041
        unsigned e_len = tvb_captured_length_remaining(tvb, offset);
8042
        uint16_t e_off;
8043
        uint8_t *buf = (uint8_t *)g_malloc(e_len);
8044
8045
        /* The default nonce is a function of whether or not this is the server
8046
        * or the client and the packet count. The packet count either comes from
8047
        * the PDU or is a function of the previous value (of the sending node).
8048
        */
8049
        uint8_t nonce[] = { 0x00, 0x00, 0x00, 0x01,
8050
            0x00, 0x00,
8051
            0x00,
8052
            0x00, 0x00, 0x00, 0x00 };
8053
8054
        nonce[0] = nid >> 24;
8055
        nonce[1] = nid >> 16;
8056
        nonce[2] = nid >> 8;
8057
        nonce[3] = (uint8_t)nid;
8058
        nonce[4] = slot >> 8;
8059
        nonce[5] = (uint8_t)slot;
8060
        nonce[7] = pn >> 24;
8061
        nonce[8] = pn >> 16;
8062
        nonce[9] = pn >> 8;
8063
        nonce[10] = (uint8_t)pn;
8064
8065
        /* Now the hard part. We need to determine the current packet number.
8066
        * This is a function of the sending node, the previous state and the
8067
        * current PDU.
8068
        */
8069
        for (e_off = 0; e_off < e_len; e_off++)
8070
            buf[e_off] = tvb_get_uint8(tvb, offset + e_off);
8071
8072
        /* TODO: This is hardcoded for a 4-byte MAC */
8073
8074
        proto_item_set_end(tree, tvb, offset);
8075
        if (decrypt(session, (ccm_packet_data *)packet->security_packet, nonce, epp_buf, a_len, buf, e_len))
8076
        {
8077
            g_free(buf);
8078
            return 1;
8079
        }
8080
        else
8081
        {
8082
            /* Failure to decrypt or validate the MAC.
8083
            * The packet is secure, so there is nothing we can do!
8084
            */
8085
            g_free(buf);
8086
            return 1;
8087
        }
8088
    }
8089
}
8090
#endif
8091
8092
static int dissect_oap_dsp(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
8093
0
{
8094
    /* We are handed a buffer that starts with our protocol id. Any options follow that. */
8095
0
    int offset = 0;
8096
8097
    /* We don't care except for the treeview. */
8098
0
    if (!tree)
8099
0
        return 0;
8100
8101
    /* Compute the version and flags, masking off other bits. */
8102
0
    offset += 4; /* Skip the type and protocol. */
8103
8104
0
    proto_tree_add_item(tree, hf_oap_1_dsp_option, tvb, 0, -1, ENC_NA);
8105
0
    return offset;
8106
0
}
8107
8108
static int dissect_oap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
8109
108
{
8110
108
    dof_api_data *api_data = (dof_api_data *)data;
8111
108
    dof_packet_data *packet_data;
8112
8113
108
    int offset = 0;
8114
108
    uint8_t opcode = 0;
8115
108
    uint8_t flags = 0;
8116
108
    uint16_t item_id = 0;
8117
108
    uint16_t app;
8118
108
    int app_len;
8119
8120
108
    oap_1_packet_data *oap_packet = NULL;
8121
8122
108
    proto_item *ti;
8123
108
    proto_tree *oap_tree;
8124
8125
108
    if (api_data == NULL)
8126
0
    {
8127
0
        return 0;
8128
0
    }
8129
8130
108
    packet_data = api_data->packet;
8131
108
    if (packet_data == NULL)
8132
0
    {
8133
0
        return 0;
8134
0
    }
8135
8136
8137
    /* Make entries in Protocol column and Info column on summary display */
8138
108
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "OAPv1 ");
8139
8140
    /* Create the protocol tree. */
8141
108
    offset = 0;
8142
108
    ti = proto_tree_add_item(tree, proto_oap_1, tvb, offset, -1, ENC_NA);
8143
108
    oap_tree = proto_item_add_subtree(ti, ett_oap_1);
8144
8145
    /* Add the APPID. */
8146
108
    offset = read_c2(tvb, offset, &app, &app_len);
8147
108
    ti = proto_tree_add_uint(oap_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
8148
108
    validate_c2(pinfo, ti, app, app_len);
8149
8150
108
    if ((unsigned)app_len == tvb_captured_length(tvb))
8151
1
    {
8152
1
        col_append_str(pinfo->cinfo, COL_INFO, "OAP [nop]");
8153
1
        expert_add_info(pinfo, oap_tree, &ei_implicit_no_op);
8154
8155
1
        return app_len;
8156
1
    }
8157
8158
107
    oap_packet = (oap_1_packet_data *)dof_packet_get_proto_data(packet_data, proto_oap_1);
8159
107
    if (!oap_packet)
8160
107
    {
8161
107
        oap_packet = wmem_new0(wmem_file_scope(), oap_1_packet_data);
8162
107
        dof_packet_add_proto_data(packet_data, proto_oap_1, oap_packet);
8163
107
    }
8164
8165
    /* Compute the version and flags, masking off other bits. */
8166
107
    opcode = tvb_get_uint8(tvb, offset) & 0x1F;
8167
107
    if (!packet_data->is_command)
8168
3
        opcode |= OAP_1_RESPONSE;
8169
8170
107
    flags = tvb_get_uint8(tvb, offset) & 0xE0;
8171
8172
107
    col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, opcode, oap_opcode_strings, "Unknown Opcode (%d)"));
8173
8174
8175
    /* Opcode */
8176
107
    {
8177
107
        uint8_t mask = 0x10;
8178
107
        char str[20];
8179
107
        uint8_t no_of_bits = 5;
8180
107
        uint8_t i;
8181
107
        uint8_t bit = 3;
8182
107
        (void) g_strlcpy(str, "...", 20);
8183
8184
        /* read the bits for the int */
8185
642
        for (i = 0; i < no_of_bits; i++)
8186
535
        {
8187
535
            if (bit && (!(bit % 4)))
8188
107
                (void) g_strlcat(str, " ", 20);
8189
8190
535
            bit++;
8191
8192
535
            if (opcode & mask)
8193
190
                (void) g_strlcat(str, "1", 20);
8194
345
            else
8195
345
                (void) g_strlcat(str, "0", 20);
8196
8197
535
            mask = mask >> 1;
8198
535
        }
8199
8200
107
        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);
8201
107
    }
8202
8203
8204
    /* Flags, based on opcode.
8205
    * Each opcode needs to define the flags, however, the fall into major categories...
8206
    */
8207
107
    switch (opcode)
8208
107
    {
8209
        /* Both alias and a flag that equals command control. */
8210
2
    case OAP_1_CMD_ACTIVATE:
8211
6
    case OAP_1_CMD_CONNECT:
8212
7
    case OAP_1_CMD_FULL_CONNECT:
8213
46
    case OAP_1_CMD_GET:
8214
78
    case OAP_1_CMD_INVOKE:
8215
78
    case OAP_1_CMD_REGISTER:
8216
81
    case OAP_1_CMD_SET:
8217
81
    case OAP_1_CMD_SUBSCRIBE:
8218
81
    case OAP_1_CMD_WATCH:
8219
81
        proto_tree_add_item(oap_tree, hf_oap_1_alias_size, tvb, offset, 1, ENC_NA);
8220
81
        proto_tree_add_item(oap_tree, hf_oap_1_flags, tvb, offset, 1, ENC_NA);
8221
81
        if (flags & 0x20)
8222
80
        {
8223
80
            offset += 1;
8224
80
            offset = oap_1_tree_add_cmdcontrol(pinfo, oap_tree, tvb, offset);
8225
80
        }
8226
1
        else
8227
1
            offset += 1;
8228
8229
81
        break;
8230
8231
        /* No alias, but flags for command control. */
8232
1
    case OAP_1_CMD_ADVERTISE:
8233
        /* TODO: Expert info on top two bits.*/
8234
1
        proto_tree_add_item(oap_tree, hf_oap_1_flags, tvb, offset, 1, ENC_NA);
8235
1
        if (flags & 0x20)
8236
0
        {
8237
0
            offset = oap_1_tree_add_cmdcontrol(pinfo, oap_tree, tvb, ENC_BIG_ENDIAN);
8238
0
        }
8239
1
        else
8240
1
            offset += 1;
8241
8242
1
        break;
8243
8244
        /* No alias, but flag for provider. */
8245
0
    case OAP_1_RSP_GET:
8246
0
    case OAP_1_RSP_INVOKE:
8247
0
    case OAP_1_RSP_REGISTER:
8248
0
    case OAP_1_RSP_SET:
8249
0
    case OAP_1_RSP_SUBSCRIBE:
8250
        /* TODO: Expert info on top two bits.*/
8251
0
        proto_tree_add_item(oap_tree, hf_oap_1_flags, tvb, offset, 1, ENC_NA);
8252
0
        if (flags & 0x20)
8253
0
        {
8254
0
            offset += 1;
8255
0
            offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, oap_tree,
8256
0
                                              offset, hf_oap_1_providerid, ett_oap_1_1_providerid, NULL);
8257
0
        }
8258
0
        else
8259
0
            offset += 1;
8260
0
        if ((opcode == OAP_1_RSP_GET) || (opcode == OAP_1_RSP_INVOKE))
8261
0
        {
8262
0
            proto_tree_add_item(oap_tree, hf_oap_1_value_list, tvb, offset, -1, ENC_NA);
8263
0
            offset += tvb_reported_length_remaining(tvb, offset);
8264
0
        }
8265
8266
0
        break;
8267
8268
        /* Alias, but no flags. */
8269
17
    case OAP_1_CMD_CHANGE:
8270
18
    case OAP_1_CMD_OPEN:
8271
19
    case OAP_1_CMD_PROVIDE:
8272
20
    case OAP_1_CMD_SIGNAL:
8273
20
        proto_tree_add_item(oap_tree, hf_oap_1_alias_size, tvb, offset, 1, ENC_NA);
8274
20
        offset += 1;
8275
20
        break;
8276
8277
        /* Special flags. */
8278
0
    case OAP_1_RSP_EXCEPTION:
8279
0
        proto_tree_add_item(oap_tree, hf_oap_1_exception_internal_flag, tvb, offset, 1, ENC_NA);
8280
0
        proto_tree_add_item(oap_tree, hf_oap_1_exception_final_flag, tvb, offset, 1, ENC_NA);
8281
0
        proto_tree_add_item(oap_tree, hf_oap_1_exception_provider_flag, tvb, offset, 1, ENC_NA);
8282
0
        offset += 1;
8283
0
        break;
8284
8285
        /* No flags. */
8286
1
    case OAP_1_CMD_DEFINE:
8287
1
    case OAP_1_RSP_DEFINE:
8288
1
    case OAP_1_RSP_OPEN:
8289
        /* TODO: Non-zero not allowed.*/
8290
1
        offset += 1;
8291
1
        break;
8292
8293
4
    default:
8294
        /* TODO: Illegal opcode.*/
8295
4
        return offset;
8296
107
    }
8297
8298
    /* Parse off arguments based on opcodes. */
8299
37
    switch (opcode)
8300
37
    {
8301
0
    case OAP_1_CMD_SUBSCRIBE:
8302
0
    {
8303
0
        uint8_t alias_len = (flags & 0xC0) >> 6;
8304
0
        if (alias_len == 3)
8305
0
            alias_len = 4;
8306
8307
        /* The item identifier comes first, but it is compressed. */
8308
0
        {
8309
0
            int item_id_len;
8310
0
            proto_item *pi;
8311
8312
0
            read_c2(tvb, offset, &item_id, &item_id_len);
8313
0
            pi = proto_tree_add_uint_format(oap_tree, hf_oap_1_itemid, tvb, offset, item_id_len, item_id, "Item ID: %u", item_id);
8314
0
            validate_c2(pinfo, pi, item_id, item_id_len);
8315
0
            offset += item_id_len;
8316
0
        }
8317
8318
0
        if (alias_len > 0)
8319
0
        {
8320
0
            if (api_data->session == NULL)
8321
0
            {
8322
0
                expert_add_info(pinfo, ti, &ei_oap_no_session);
8323
0
                return offset;
8324
0
            }
8325
0
            offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8326
0
        }
8327
0
        else
8328
0
            offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8329
8330
        /* Read the minimum delta. */
8331
0
        {
8332
0
            int delta_len;
8333
0
            uint16_t delta;
8334
0
            proto_item *pi;
8335
8336
0
            read_c2(tvb, offset, &delta, &delta_len);
8337
0
            pi = proto_tree_add_uint_format(oap_tree, hf_oap_1_subscription_delta, tvb, offset, delta_len, delta, "Minimum Delta: %u", delta);
8338
0
            validate_c2(pinfo, pi, delta, delta_len);
8339
0
            offset += delta_len;
8340
0
        }
8341
0
    }
8342
0
        break;
8343
8344
0
    case OAP_1_CMD_REGISTER:
8345
0
    {
8346
0
        uint8_t alias_len = (flags & 0xC0) >> 6;
8347
0
        if (alias_len == 3)
8348
0
            alias_len = 4;
8349
8350
        /* The item identifier comes first, but it is compressed. */
8351
0
        {
8352
0
            int item_id_len;
8353
0
            proto_item *pi;
8354
8355
0
            read_c2(tvb, offset, &item_id, &item_id_len);
8356
0
            pi = proto_tree_add_uint_format(oap_tree, hf_oap_1_itemid, tvb, offset, item_id_len, item_id, "Item ID: %u", item_id);
8357
0
            validate_c2(pinfo, pi, item_id, item_id_len);
8358
0
            offset += item_id_len;
8359
0
        }
8360
8361
0
        if (alias_len > 0)
8362
0
        {
8363
0
            if (api_data->session == NULL)
8364
0
            {
8365
0
                expert_add_info(pinfo, ti, &ei_oap_no_session);
8366
0
                return offset;
8367
0
            }
8368
0
            offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8369
0
        }
8370
0
        else
8371
0
            offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8372
0
    }
8373
0
        break;
8374
8375
0
    case OAP_1_RSP_REGISTER:
8376
0
    {
8377
0
        if (flags & 0x20)
8378
0
        {
8379
            /* offset = add_oid( tvb, offset, NULL, oap_tree ); */
8380
0
        }
8381
8382
        /* Sequence is next. */
8383
0
        proto_tree_add_item(oap_tree, hf_oap_1_update_sequence, tvb, offset, 2, ENC_BIG_ENDIAN);
8384
0
        offset += 2;
8385
0
    }
8386
0
        break;
8387
8388
0
    case OAP_1_CMD_WATCH:
8389
0
    case OAP_1_CMD_ACTIVATE:
8390
1
    case OAP_1_CMD_CONNECT:
8391
1
    case OAP_1_CMD_FULL_CONNECT:
8392
1
    {
8393
1
        uint8_t alias_len = (flags & 0xC0) >> 6;
8394
1
        if (alias_len == 3)
8395
0
            alias_len = 4;
8396
8397
1
        if (alias_len > 0)
8398
0
        {
8399
0
            if (api_data->session == NULL)
8400
0
            {
8401
0
                expert_add_info(pinfo, ti, &ei_oap_no_session);
8402
0
                return offset;
8403
0
            }
8404
0
            offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8405
0
        }
8406
1
        else
8407
1
            offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8408
1
    }
8409
1
        break;
8410
8411
1
    case OAP_1_CMD_ADVERTISE:
8412
1
        offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8413
1
        break;
8414
8415
9
    case OAP_1_CMD_GET:
8416
13
    case OAP_1_CMD_INVOKE:
8417
14
    case OAP_1_CMD_SET:
8418
14
    {
8419
14
        uint8_t alias_len = (flags & 0xC0) >> 6;
8420
14
        if (alias_len == 3)
8421
0
            alias_len = 4;
8422
8423
        /* The item identifier comes first, but it is compressed. */
8424
14
        {
8425
14
            int item_id_len;
8426
14
            proto_item *pi;
8427
8428
14
            read_c2(tvb, offset, &item_id, &item_id_len);
8429
14
            pi = proto_tree_add_uint_format(oap_tree, hf_oap_1_itemid, tvb, offset, item_id_len, item_id, "Item ID: %u", item_id);
8430
14
            validate_c2(pinfo, pi, item_id, item_id_len);
8431
14
            offset += item_id_len;
8432
14
        }
8433
8434
14
        if (alias_len > 0)
8435
3
        {
8436
3
            if (api_data->session == NULL)
8437
0
            {
8438
0
                expert_add_info(pinfo, ti, &ei_oap_no_session);
8439
0
                return offset;
8440
0
            }
8441
3
            offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8442
3
        }
8443
11
        else
8444
11
            offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8445
8446
14
        if ((opcode == OAP_1_CMD_SET) || (opcode == OAP_1_CMD_INVOKE))
8447
1
        {
8448
1
            proto_tree_add_item(oap_tree, hf_oap_1_value_list, tvb, offset, -1, ENC_NA);
8449
1
            offset += tvb_reported_length_remaining(tvb, offset);
8450
1
        }
8451
14
    }
8452
0
        break;
8453
8454
1
    case OAP_1_CMD_OPEN:
8455
1
    {
8456
1
        uint8_t alias_len = (flags & 0xC0) >> 6;
8457
1
        if (alias_len == 3)
8458
0
            alias_len = 4;
8459
8460
1
        if (alias_len > 0)
8461
1
        {
8462
1
            if (api_data->session == NULL)
8463
0
            {
8464
0
                expert_add_info(pinfo, ti, &ei_oap_no_session);
8465
0
                return offset;
8466
0
            }
8467
1
            offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8468
1
        }
8469
0
        else
8470
0
            offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8471
8472
1
        offset = oap_1_tree_add_interface(oap_tree, tvb, offset);
8473
8474
1
        offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, oap_tree,
8475
1
                                          offset, hf_oap_1_objectid, ett_oap_1_objectid, NULL);
8476
1
    }
8477
0
        break;
8478
8479
1
    case OAP_1_CMD_PROVIDE:
8480
1
    {
8481
1
        uint8_t alias_length = flags >> 6;
8482
1
        int alias_offset;
8483
1
        int iid_offset;
8484
1
        int oid_offset;
8485
8486
1
        if (alias_length == 3)
8487
0
            alias_length = 4;
8488
8489
1
        alias_offset = offset;
8490
1
        if (alias_length == 0)
8491
1
        {
8492
1
            expert_add_info_format(pinfo, ti, &ei_malformed, "alias_length == 0");
8493
1
            return offset;
8494
1
        }
8495
0
        if (api_data->session == NULL)
8496
0
        {
8497
0
            expert_add_info(pinfo, ti, &ei_oap_no_session);
8498
0
            return offset;
8499
0
        }
8500
0
        offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_length, false);
8501
8502
0
        iid_offset = offset;
8503
0
        offset = oap_1_tree_add_interface(oap_tree, tvb, offset);
8504
8505
0
        oid_offset = offset;
8506
0
        offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, oap_tree,
8507
0
                                          offset, hf_oap_1_objectid, ett_oap_1_objectid, NULL);
8508
8509
0
        if (alias_length && !packet_data->processed)
8510
0
        {
8511
0
            uint32_t alias;
8512
0
            oap_1_binding *binding = wmem_new0(wmem_file_scope(), oap_1_binding);
8513
0
            int i;
8514
8515
0
            alias = 0;
8516
0
            for (i = 0; i < alias_length; i++)
8517
0
                alias = (alias << 8) | tvb_get_uint8(tvb, alias_offset + i);
8518
8519
0
            binding->iid_length = oid_offset - iid_offset;
8520
0
            binding->iid = (uint8_t *)wmem_alloc0(wmem_file_scope(), binding->iid_length);
8521
0
            tvb_memcpy(tvb, binding->iid, iid_offset, binding->iid_length);
8522
8523
0
            binding->oid_length = offset - oid_offset;
8524
0
            binding->oid = (uint8_t *)wmem_alloc0(wmem_file_scope(), binding->oid_length);
8525
0
            tvb_memcpy(tvb, binding->oid, oid_offset, binding->oid_length);
8526
8527
0
            binding->frame = pinfo->fd->num;
8528
0
            oap_1_define_alias(api_data, alias, binding);
8529
0
        }
8530
0
    }
8531
0
        break;
8532
8533
17
    case OAP_1_CMD_CHANGE:
8534
18
    case OAP_1_CMD_SIGNAL:
8535
18
    {
8536
18
        uint8_t alias_len = (flags & 0xC0) >> 6;
8537
18
        if (alias_len == 3)
8538
1
            alias_len = 4;
8539
8540
        /* The item identifier comes first, but it is compressed. */
8541
18
        {
8542
18
            int item_id_len;
8543
18
            proto_item *pi;
8544
8545
18
            read_c2(tvb, offset, &item_id, &item_id_len);
8546
18
            pi = proto_tree_add_uint_format(oap_tree, hf_oap_1_itemid, tvb, offset, item_id_len, item_id, "Item ID: %u", item_id);
8547
18
            validate_c2(pinfo, pi, item_id, item_id_len);
8548
18
            offset += item_id_len;
8549
18
        }
8550
8551
18
        if (alias_len > 0)
8552
1
        {
8553
1
            if (api_data->session == NULL)
8554
0
            {
8555
0
                expert_add_info(pinfo, ti, &ei_oap_no_session);
8556
0
                return offset;
8557
0
            }
8558
1
            offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8559
1
        }
8560
17
        else
8561
17
            offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8562
8563
        /* Sequence is next. */
8564
18
        proto_tree_add_item(oap_tree, hf_oap_1_update_sequence, tvb, offset, 2, ENC_BIG_ENDIAN);
8565
18
        offset += 2;
8566
8567
18
        proto_tree_add_item(oap_tree, hf_oap_1_value_list, tvb, offset, -1, ENC_NA);
8568
18
        offset += tvb_reported_length_remaining(tvb, offset);
8569
18
    }
8570
0
        break;
8571
8572
0
    case OAP_1_RSP_EXCEPTION:
8573
0
    {
8574
0
        if (flags & 0x20)
8575
0
        {
8576
            /* offset = add_oid( tvb, offset, NULL, oap_tree );*/
8577
0
        }
8578
8579
        /* The response code, compressed. */
8580
0
        {
8581
0
            int rsp_len;
8582
0
            uint16_t rsp;
8583
8584
            /* TODO: Validate*/
8585
0
            read_c2(tvb, offset, &rsp, &rsp_len);
8586
            /* TODO: Add to tree with error codes. */
8587
0
            offset += rsp_len;
8588
0
        }
8589
0
        proto_tree_add_item(oap_tree, hf_oap_1_value_list, tvb, offset, -1, ENC_NA);
8590
0
        offset += tvb_reported_length_remaining(tvb, offset);
8591
0
    }
8592
0
        break;
8593
8594
1
    default:
8595
        /* TODO: Bad opcode!*/
8596
1
        break;
8597
37
    }
8598
8599
22
    return offset;
8600
37
}
8601
8602
static int dissect_sgmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
8603
4
{
8604
4
    dof_api_data *api_data = (dof_api_data *)data;
8605
4
    dof_packet_data *packet_data;
8606
4
    unsigned offset = 0;
8607
4
    uint8_t opcode;
8608
4
    uint16_t app;
8609
4
    int app_len;
8610
4
    proto_item *ti;
8611
4
    proto_tree *sgmp_tree;
8612
8613
4
    if (api_data == NULL)
8614
0
    {
8615
        /* TODO: Output error. */
8616
0
        return 0;
8617
0
    }
8618
8619
4
    packet_data = api_data->packet;
8620
4
    if (packet_data == NULL)
8621
0
    {
8622
        /* TODO: Output error. */
8623
0
        return 0;
8624
0
    }
8625
8626
    /* Make entries in Protocol column and Info column on summary display */
8627
4
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "SGMPv1 ");
8628
8629
    /* Create the protocol tree. */
8630
4
    offset = 0;
8631
4
    ti = proto_tree_add_item(tree, proto_sgmp, tvb, offset, -1, ENC_NA);
8632
4
    sgmp_tree = proto_item_add_subtree(ti, ett_sgmp);
8633
8634
    /* Add the APPID. */
8635
4
    offset = read_c2(tvb, offset, &app, &app_len);
8636
4
    ti = proto_tree_add_uint(sgmp_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
8637
4
    validate_c2(pinfo, ti, app, app_len);
8638
8639
4
    if (offset == tvb_captured_length(tvb))
8640
0
    {
8641
0
        col_append_str(pinfo->cinfo, COL_INFO, "SGMP [nop]");
8642
0
        expert_add_info(pinfo, sgmp_tree, &ei_implicit_no_op);
8643
8644
0
        return offset;
8645
0
    }
8646
8647
8648
    /* Retrieve the opcode. */
8649
4
    opcode = tvb_get_uint8(tvb, offset);
8650
4
    if (!packet_data->is_command)
8651
0
        opcode |= SGMP_RESPONSE;
8652
8653
4
    col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, opcode, sgmp_opcode_strings, "Unknown Opcode (%d)"));
8654
8655
    /* Opcode */
8656
4
    proto_tree_add_item(sgmp_tree, hf_opcode, tvb, offset, 1, ENC_NA);
8657
4
    offset += 1;
8658
8659
4
    switch (opcode)
8660
4
    {
8661
1
    case SGMP_CMD_EPOCH_CHANGED:
8662
1
    {
8663
        /* TMIN - 2 bytes */
8664
1
        {
8665
1
            proto_tree_add_item(sgmp_tree, hf_sgmp_tmin, tvb, offset, 2, ENC_BIG_ENDIAN);
8666
1
            offset += 2;
8667
1
        }
8668
8669
        /* EPOCH - 2 bytes */
8670
1
        {
8671
1
            proto_tree_add_item(sgmp_tree, hf_sgmp_epoch, tvb, offset, 2, ENC_BIG_ENDIAN);
8672
1
            offset += 2;
8673
1
        }
8674
1
    }
8675
1
        break;
8676
8677
1
    case SGMP_CMD_HEARTBEAT:
8678
1
    {
8679
1
        int start_offset;
8680
8681
        /* Latest SGMP Version - Type.1 */
8682
1
        {
8683
1
            uint16_t version;
8684
1
            int length;
8685
1
            proto_item *pi;
8686
8687
1
            start_offset = offset;
8688
1
            offset = read_c2(tvb, offset, &version, &length);
8689
1
            pi = proto_tree_add_uint(sgmp_tree, hf_latest_version, tvb, start_offset, offset - start_offset, version);
8690
1
            validate_c2(pinfo, pi, version, length);
8691
1
        }
8692
8693
        /* Desire - 1 byte */
8694
1
        {
8695
1
            proto_tree_add_item(sgmp_tree, hf_desire, tvb, offset, 1, ENC_NA);
8696
1
            offset += 1;
8697
1
        }
8698
8699
        /* Tie Breaker - 4 bytes */
8700
1
        {
8701
1
            proto_tree_add_item(sgmp_tree, hf_tie_breaker, tvb, offset, 4, ENC_BIG_ENDIAN);
8702
1
            offset += 4;
8703
1
        }
8704
1
    }
8705
1
        break;
8706
8707
0
    case SGMP_CMD_REKEY:
8708
0
    case SGMP_CMD_REKEY_EPOCH:
8709
1
    case SGMP_CMD_REKEY_MERGE:
8710
1
    {
8711
#if 0 /*TODO check this */
8712
        int start_offset;
8713
        tvbuff_t *initial_state;
8714
#endif
8715
1
        uint8_t key[32];
8716
8717
        /* Delay - one byte */
8718
1
        if (opcode != SGMP_CMD_REKEY_MERGE)
8719
0
        {
8720
0
            proto_tree_add_item(sgmp_tree, hf_delay, tvb, offset, 1, ENC_NA);
8721
0
            offset += 1;
8722
0
        }
8723
8724
        /* Initial State - Security.9 (not REKEY_MERGE) */
8725
1
        {
8726
1
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_9, tvb, pinfo, sgmp_tree,
8727
1
                                              offset, hf_initial_state, ett_initial_state, NULL);
8728
#if 0 /*TODO check this */
8729
            initial_state = tvb_new_subset_length(tvb, start_offset, offset - start_offset);
8730
#endif
8731
1
        }
8732
8733
        /* Epoch - 2 bytes (only REKEY_EPOCH) */
8734
1
        if (opcode == SGMP_CMD_REKEY_EPOCH)
8735
0
        {
8736
0
            proto_tree_add_item(sgmp_tree, hf_sgmp_epoch, tvb, offset, 2, ENC_BIG_ENDIAN);
8737
0
            offset += 2;
8738
0
        }
8739
8740
        /* Kgm - 32 bytes */
8741
1
        {
8742
1
            proto_tree_add_item(sgmp_tree, hf_key, tvb, offset, 32, ENC_NA);
8743
1
            tvb_memcpy(tvb, key, offset, 32);
8744
1
            offset += 32;
8745
1
        }
8746
8747
        /* Handle the initialization block. */
8748
1
        if (!packet_data->processed && api_data->session)
8749
1
        {
8750
            /*dof_session_data* session = (dof_session_data*)api_data->session;*/
8751
8752
            /* Look up the field-dissector table, and determine if it is registered. */
8753
1
            dissector_table_t field_dissector = find_dissector_table("dof.secmode");
8754
1
            if (field_dissector != NULL)
8755
1
            {
8756
#if 0
8757
                dissector_handle_t field_handle = dissector_get_port_handle(field_dissector, packet_data->security_mode);
8758
                if (field_handle != NULL)
8759
                {
8760
                    void *saved_private = pinfo->private_data;
8761
                    dof_secmode_api_data setup_data;
8762
                    int block_length;
8763
8764
                    setup_data.version = DOF_API_VERSION;
8765
                    setup_data.context = INITIALIZE;
8766
                    setup_data.dof_api = api_data;
8767
                    setup_data.secure_session = rekey_data->security_session;
8768
                    /* TODO FIX THIS setup_data.session_key = session_key; */
8769
                    pinfo->private_data = &setup_data;
8770
                    block_length = call_dissector_only(field_handle, NULL, pinfo, NULL);
8771
                    pinfo->private_data = saved_private;
8772
                }
8773
#endif
8774
1
            }
8775
1
        }
8776
1
    }
8777
1
        break;
8778
8779
0
    case SGMP_CMD_REQUEST_GROUP:
8780
0
    {
8781
0
        uint8_t *domain_buf = NULL;
8782
0
        uint8_t domain_length = 0;
8783
0
        int start_offset;
8784
0
        unsigned I_offset = offset;
8785
0
        sgmp_packet_data *sgmp_data = NULL;
8786
0
        uint16_t epoch;
8787
8788
        /* START OF I BLOCK */
8789
        /* Domain - Security.7 */
8790
0
        {
8791
0
            start_offset = offset;
8792
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, sgmp_tree,
8793
0
                                              offset, hf_sgmp_domain, ett_sgmp_domain, NULL);
8794
0
            if (!packet_data->processed)
8795
0
            {
8796
0
                domain_length = offset - start_offset;
8797
0
                domain_buf = (uint8_t *)wmem_alloc0(pinfo->pool, domain_length);
8798
0
                tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
8799
0
            }
8800
0
        }
8801
8802
        /* Epoch - 2 bytes */
8803
0
        {
8804
0
            proto_tree_add_item_ret_uint16(sgmp_tree, hf_sgmp_epoch, tvb, offset, 2, ENC_BIG_ENDIAN, &epoch);
8805
0
            offset += 2;
8806
0
        }
8807
8808
        /* Initiator Block - SGMP.6.3 */
8809
0
        {
8810
            /* SGMP Key Request - Security.4 */
8811
0
            {
8812
0
                dof_2008_16_security_4 response;
8813
0
                offset = dof_dissect_pdu_as_field(dissect_2008_16_security_4, tvb, pinfo, sgmp_tree,
8814
0
                                                  offset, hf_initiator_block, ett_initiator_block, &response);
8815
0
                if (!packet_data->processed)
8816
0
                {
8817
0
                    tvbuff_t *identity = response.identity;
8818
0
                    uint8_t identity_length = tvb_reported_length(identity);
8819
0
                    uint8_t *identity_buf = (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length);
8820
8821
                    /* Get the buffer. */
8822
0
                    tvb_memcpy(identity, identity_buf, 0, identity_length);
8823
8824
0
                    {
8825
0
                        sgmp_data = wmem_new0(wmem_file_scope(), sgmp_packet_data);
8826
0
                        dof_packet_add_proto_data(packet_data, proto_sgmp, sgmp_data);
8827
8828
0
                        sgmp_data->domain_length = domain_length;
8829
0
                        sgmp_data->domain = (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length);
8830
0
                        memcpy(sgmp_data->domain, domain_buf, domain_length);
8831
8832
0
                        sgmp_data->group_length = identity_length;
8833
0
                        sgmp_data->group = (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length);
8834
0
                        memcpy(sgmp_data->group, identity_buf, identity_length);
8835
8836
0
                        sgmp_data->epoch = epoch;
8837
0
                        sgmp_data->request_session = api_data->session;
8838
0
                    }
8839
0
                }
8840
0
            }
8841
0
        }
8842
8843
        /* Security Scope - Security.10 */
8844
0
        {
8845
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_10, tvb, pinfo, sgmp_tree,
8846
0
                                              offset, hf_sgmp_security_scope, ett_sgmp_security_scope, NULL);
8847
0
        }
8848
8849
        /* END OF I BLOCK */
8850
0
        if (sgmp_data && !sgmp_data->I)
8851
0
        {
8852
0
            sgmp_data->I_length = offset - I_offset;
8853
0
            sgmp_data->I = (uint8_t *)wmem_alloc0(wmem_file_scope(), sgmp_data->I_length);
8854
0
            tvb_memcpy(tvb, sgmp_data->I, I_offset, sgmp_data->I_length);
8855
0
        }
8856
0
    }
8857
0
        break;
8858
8859
0
    case SGMP_RSP_REQUEST_GROUP:
8860
0
    {
8861
0
        int start_offset;
8862
#if 0 /*TODO check this */
8863
        unsigned A_offset;
8864
        tvbuff_t *initial_state;
8865
        unsigned A_end;
8866
#endif
8867
8868
        /* START OF A BLOCK */
8869
        /* Initial State - SGMP.6.2.1 */
8870
0
        {
8871
         /*   A_offset = offset;*/
8872
8873
            /* Initial State - Security.9 */
8874
0
            {
8875
0
                offset = dof_dissect_pdu_as_field(dissect_2008_16_security_9, tvb, pinfo, sgmp_tree,
8876
0
                                                  offset, hf_initial_state, ett_initial_state, NULL);
8877
#if 0 /*TODO check this */
8878
                initial_state = tvb_new_subset_length(tvb, start_offset, offset - start_offset);
8879
#endif
8880
0
            }
8881
8882
            /* Latest SGMP Version - Type.1 */
8883
0
            {
8884
0
                uint16_t version;
8885
0
                int length;
8886
0
                proto_item *pi;
8887
8888
0
                start_offset = offset;
8889
0
                offset = read_c2(tvb, offset, &version, &length);
8890
0
                pi = proto_tree_add_uint(sgmp_tree, hf_latest_version, tvb, start_offset, offset - start_offset, version);
8891
0
                validate_c2(pinfo, pi, version, length);
8892
0
            }
8893
8894
            /* Desire - 1 byte */
8895
0
            {
8896
0
                proto_tree_add_item(sgmp_tree, hf_desire, tvb, offset, 1, ENC_NA);
8897
0
                offset += 1;
8898
0
            }
8899
0
        }
8900
8901
        /* END OF A BLOCK */
8902
        /* A block data handled in first part of the next block. */
8903
#if 0 /*TODO check this */
8904
        A_end = offset;
8905
#endif
8906
8907
        /* Ticket - Security.5 */
8908
0
        {
8909
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, sgmp_tree,
8910
0
                                              offset, hf_ticket, ett_ticket, NULL);
8911
0
        }
8912
8913
        /* Try to match up the information learned here with any groups that exist.
8914
        * Note that we do not know the SSID, and so we can only match based on the
8915
        * domain and group identifier. We will learn the SSID based on a successful
8916
        * match to a secure session.
8917
        */
8918
0
        if (packet_data->opid_first && !api_data->secure_session)
8919
0
        {
8920
#if 0
8921
            sgmp_packet_data* cmd_data = (sgmp_packet_data*)dof_packet_get_proto_data(packet_data->opid_first, proto_sgmp);
8922
            extern struct BlockCipher BlockCipher_AES_256;
8923
            struct BlockCipher* cipher = &BlockCipher_AES_256;
8924
            uint8_t* ekey = (uint8_t*)ep_alloc(cipher->keyStateSize);
8925
8926
            if (cmd_data && !cmd_data->A)
8927
            {
8928
                cmd_data->A_length = A_end - A_offset;
8929
                cmd_data->A = (uint8_t*)wmem_alloc0(wmem_file_scope(), cmd_data->A_length);
8930
                tvb_memcpy(tvb, cmd_data->A, A_offset, cmd_data->A_length);
8931
            }
8932
8933
            /* Search through the appropriate keks to find a match. */
8934
            {
8935
                dof_learned_group_data* group = globals.learned_group_data;
8936
                struct list;
8937
                struct list
8938
                { dof_learned_group_data *group;
8939
                    struct list *next; };
8940
                struct list *to_try = NULL;
8941
                uint8_t confirmation[32];
8942
                uint8_t* discovered_kek = NULL;
8943
                dof_learned_group_auth_data *auth = NULL;
8944
8945
                tvb_memcpy(tvb, confirmation, start_offset, 32);
8946
8947
                while (group)
8948
                {
8949
                    if ((cmd_data->domain_length == group->domain_length) &&
8950
                        (memcmp(cmd_data->domain, group->domain, group->domain_length) == 0) &&
8951
                        (cmd_data->group_length == group->group_length) &&
8952
                        (memcmp(cmd_data->group, group->group, group->group_length) == 0))
8953
                    {
8954
                        struct list *n = (struct list *) ep_alloc0(sizeof(struct list));
8955
                        n->group = group;
8956
                        n->next = to_try;
8957
                        to_try = n;
8958
                    }
8959
8960
                    group = group->next;
8961
                }
8962
8963
                /* At this point we may be able to learn the session key. */
8964
                while (to_try && !discovered_kek)
8965
                {
8966
                    group = to_try->group;
8967
8968
                    auth = group->keys;
8969
8970
                    while (auth && !discovered_kek)
8971
                    {
8972
                        uint8_t mac[32];
8973
                        uint8_t key[32];
8974
                        int j;
8975
8976
                        /* It only makes sense to check matching epochs. */
8977
                        if (auth->epoch == cmd_data->epoch)
8978
                        {
8979
                            tvb_memcpy(tvb, mac, start_offset, 32);
8980
                            tvb_memcpy(tvb, key, start_offset + 32, 32);
8981
8982
                            if (cipher != NULL)
8983
                            {
8984
                                cipher->GenerateKeyState(ekey, auth->kek);
8985
                                cipher->Encrypt(ekey, mac);
8986
                                cipher->Encrypt(ekey, mac + 16);
8987
                            }
8988
8989
                            for (j = 0; j < 32; j++)
8990
                            key[j] ^= mac[j];
8991
8992
                            if (sgmp_validate_session_key(cmd_data, confirmation, auth->kek, key))
8993
                            {
8994
                                discovered_kek = (uint8_t*)se_alloc0(32);
8995
                                memcpy(discovered_kek, key, 32);
8996
                                break;
8997
                            }
8998
                        }
8999
9000
                        auth = auth->next;
9001
                    }
9002
9003
                    to_try = to_try->next;
9004
                }
9005
9006
                /* Determine if there is already a secure session for this information. If there is, then
9007
                * EPP will find it to decode any packets. If there is not, then we must create a secure
9008
                * session and initialize it so that future packets can be decoded.
9009
                * NOTE: None of the actual decoding is done here, because this packet is not encrypted
9010
                * in the session that it defines.
9011
                * NOTE: SGMP secure sessions are always attached to the DPS session, which is always
9012
                * associated with the transport session (server address).
9013
                */
9014
                if (discovered_kek)
9015
                {
9016
                    dissector_table_t field_dissector;
9017
                    dissector_handle_t field_handle;
9018
                    dof_session_key_exchange_data *key_exchange = NULL;
9019
9020
                    dof_secure_session_data *dof_secure_session = cmd_data->request_session->secure_sessions;
9021
                    while (dof_secure_session)
9022
                    {
9023
                        if ((dof_secure_session->ssid == group->ssid) &&
9024
                            (dof_secure_session->domain_length == group->domain_length) &&
9025
                            (memcmp(dof_secure_session->domain, group->domain, group->domain_length) == 0))
9026
                        break;
9027
9028
                        dof_secure_session = dof_secure_session->next;
9029
                    }
9030
9031
                    if (!dof_secure_session)
9032
                    {
9033
                        dof_session_data *dof_session = wmem_alloc0(wmem_file_scope(), sizeof(dof_session_data));
9034
                        dof_session->session_id = globals.next_session++;
9035
                        dof_session->dof_id = api_data->session->dof_id;
9036
9037
                        dof_secure_session = wmem_alloc0(wmem_file_scope(), sizeof(dof_secure_session_data));
9038
                        dof_secure_session->ssid = group->ssid;
9039
                        dof_secure_session->domain_length = group->domain_length;
9040
                        dof_secure_session->domain = group->domain;
9041
                        dof_secure_session->original_session_id = cmd_data->request_session->session_id;
9042
                        dof_secure_session->parent = dof_session;
9043
                        dof_secure_session->is_2_node = false;
9044
                        dof_secure_session->next = cmd_data->request_session->secure_sessions;
9045
                        cmd_data->request_session->secure_sessions = dof_secure_session;
9046
                    }
9047
9048
                    /* This packet represents a new key exchange, and so a new key exchange data
9049
                    * structure needs to be created.
9050
                    */
9051
                    {
9052
                        key_exchange = wmem_alloc0(wmem_file_scope(), sizeof(dof_session_key_exchange_data));
9053
                        if (!key_exchange)
9054
                        return offset;
9055
9056
                        key_exchange->i_valid = packet_data->opid_first->dof_frame;
9057
                        key_exchange->r_valid = packet_data->dof_frame;
9058
                        key_exchange->security_mode = auth->security_mode;
9059
                        key_exchange->security_mode_data = auth->mode;
9060
                        key_exchange->security_mode_data_length = auth->mode_length;
9061
                        key_exchange->session_key = discovered_kek;
9062
9063
                        /* Insert the new key information at the front of the list. */
9064
                        if (!dof_secure_session->session_security_data_last)
9065
                        dof_secure_session->session_security_data = key_exchange;
9066
                        else
9067
                        dof_secure_session->session_security_data_last->next = key_exchange;
9068
9069
                        dof_secure_session->session_security_data_last = key_exchange;
9070
                    }
9071
9072
                    /* Look up the field-dissector table, and determine if it is registered. */
9073
                    field_dissector = find_dissector_table("dps.secmode");
9074
                    if (field_dissector != NULL)
9075
                    {
9076
                        field_handle = dissector_get_uint_handle(field_dissector, auth->security_mode);
9077
                        if (field_handle != NULL)
9078
                        {
9079
                            dof_secmode_api_data setup_data;
9080
                            int block_length;
9081
                            tvbuff_t *ntvb = tvb_new_subset_remaining(tvb, A_offset);
9082
9083
                            setup_data.context = INITIALIZE;
9084
                            setup_data.security_mode_offset = 0;
9085
                            setup_data.dof_api = api_data;
9086
                            setup_data.secure_session = dof_secure_session;
9087
                            setup_data.session_key_data = key_exchange;
9088
                            block_length = call_dissector_only(field_handle, ntvb, pinfo, tree, &setup_data);
9089
                        }
9090
                    }
9091
                }
9092
            }
9093
#endif
9094
0
        }
9095
0
    }
9096
0
        break;
9097
9098
1
    default:
9099
1
        break;
9100
4
    }
9101
9102
3
    return offset;
9103
4
}
9104
9105
static bool validate_session_key(tep_rekey_data *rekey, unsigned S_length, uint8_t *S, uint8_t *confirmation, uint8_t *key)
9106
0
{
9107
0
    uint8_t pad[16];
9108
0
    gcry_mac_hd_t hmac;
9109
0
    gcry_error_t result;
9110
9111
0
    memset(pad, 0, sizeof(pad));
9112
0
    result = gcry_mac_open(&hmac, GCRY_MAC_HMAC_SHA256, 0, NULL);
9113
0
    if (result != 0)
9114
0
        return false;
9115
9116
0
    gcry_mac_setkey(hmac, key, 32);
9117
0
    gcry_mac_write(hmac, pad, 16 - rekey->i_nonce_length);
9118
0
    gcry_mac_write(hmac, rekey->i_nonce, rekey->i_nonce_length);
9119
0
    gcry_mac_write(hmac, pad, 16 - rekey->r_nonce_length);
9120
0
    gcry_mac_write(hmac, rekey->r_nonce, rekey->r_nonce_length);
9121
0
    gcry_mac_write(hmac, S, S_length);
9122
0
    gcry_mac_write(hmac, rekey->r_identity, rekey->r_identity_length);
9123
0
    result = gcry_mac_verify(hmac, confirmation, 32);
9124
0
    return result == 0;
9125
0
}
9126
9127
static int dissect_tep_dsp(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
9128
2
{
9129
    /* We are handed a buffer that starts with our protocol id. Any options follow that. */
9130
2
    int offset = 0;
9131
9132
    /* We don't care except for the treeview. */
9133
2
    if (!tree)
9134
0
        return 0;
9135
9136
    /* Compute the version and flags, masking off other bits. */
9137
2
    offset += 4; /* Skip the type and protocol. */
9138
9139
2
    proto_tree_add_item(tree, hf_dsp_option, tvb, 0, -1, ENC_NA);
9140
2
    return offset;
9141
2
}
9142
9143
static int dissect_2008_4_tep_2_2_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t *ssid, void *data)
9144
0
{
9145
0
    int offset = 0;
9146
0
    proto_item *ti;
9147
0
    dof_api_data *api_data = (dof_api_data *)data;
9148
0
    dof_packet_data *packet_data;
9149
9150
0
    if (api_data == NULL)
9151
0
    {
9152
        /* TODO: Output error. */
9153
0
        return 0;
9154
0
    }
9155
9156
0
    packet_data = api_data->packet;
9157
0
    if (packet_data == NULL)
9158
0
    {
9159
        /* TODO: Output error. */
9160
0
        return 0;
9161
0
    }
9162
9163
    /* State Identifier - Only if Unsecured */
9164
0
    if (packet_data->decrypted_buffer == NULL)
9165
0
    {
9166
0
        proto_item *pi;
9167
0
        int ssid_len;
9168
0
        int start = offset;
9169
0
        offset = read_c4(tvb, offset, ssid, &ssid_len);
9170
0
        pi = proto_tree_add_uint(tree, hf_tep_2_2_1_state_identifier, tvb, start, offset - start, *ssid);
9171
0
        validate_c4(pinfo, pi, *ssid, ssid_len);
9172
0
    }
9173
9174
    /* Initial State */
9175
0
    {
9176
0
        int block_length;
9177
0
        tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
9178
0
        ti = proto_tree_add_item(tree, hf_tep_2_2_1_initial_state, tvb, offset, 0, ENC_NA);
9179
0
        ti = proto_item_add_subtree(ti, ett_tep_2_2_1_initial_state);
9180
0
        block_length = dof_dissect_pdu(dissect_2008_16_security_9, start, pinfo, ti, NULL);
9181
0
        proto_item_set_len(ti, block_length);
9182
0
        offset += block_length;
9183
0
    }
9184
9185
0
    return offset;
9186
0
}
9187
9188
/**
9189
 * This is the main entry point for the CCM dissector.
9190
 * TEP operations create security periods.
9191
 * They can also create sessions when used with "None" sessions.
9192
 * In any case, these PDUs need to pass information between
9193
 * them.
9194
 * They also must maintain state for each rekey request, some of
9195
 * which modify the session key, some of which create new
9196
 * sessions, and others that determine new session information
9197
 * like permission sets.
9198
 *
9199
 * In order to store information appropriately, the following structures are
9200
 * used:
9201
 *   1. api_data (dof_api_data*) source for all other state.
9202
 *   2. packet (dof_packet_data*) dps packet information.
9203
 *   3. rekey_data (tep_rekey_data*) tep information for rekey/accept/confirm.
9204
 */
9205
static int dissect_tep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
9206
2
{
9207
2
    dof_api_data *api_data = (dof_api_data *)data;
9208
2
    dof_packet_data *packet;
9209
2
    tep_rekey_data *rekey_data;
9210
9211
2
    unsigned offset = 0;
9212
2
    uint8_t operation;
9213
2
    uint16_t app;
9214
2
    int app_len;
9215
2
    proto_item *ti;
9216
2
    proto_tree *tep_tree, *operation_tree;
9217
9218
2
    if (api_data == NULL)
9219
0
    {
9220
        /* TODO: Output error. */
9221
0
        return 0;
9222
0
    }
9223
9224
2
    packet = api_data->packet;
9225
2
    if (packet == NULL)
9226
0
    {
9227
        /* TODO: Output error. */
9228
0
        return 0;
9229
0
    }
9230
9231
    /* Make entries in Protocol column and Info column on summary display */
9232
2
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "TEPv1 ");
9233
9234
    /* Create the protocol tree. */
9235
2
    offset = 0;
9236
2
    ti = proto_tree_add_item(tree, proto_tep, tvb, offset, -1, ENC_NA);
9237
2
    tep_tree = proto_item_add_subtree(ti, ett_tep);
9238
9239
    /* Add the APPID. */
9240
2
    offset = read_c2(tvb, offset, &app, &app_len);
9241
2
    ti = proto_tree_add_uint(tep_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
9242
2
    validate_c2(pinfo,ti, app, app_len);
9243
9244
    /* Check for empty packet. */
9245
2
    if (offset == tvb_captured_length(tvb))
9246
0
    {
9247
0
        col_append_str(pinfo->cinfo, COL_INFO, "TEP [nop]");
9248
0
        expert_add_info(pinfo, tep_tree, &ei_implicit_no_op);
9249
9250
0
        return offset;
9251
0
    }
9252
9253
    /* Retrieve the opcode. */
9254
2
    operation = tvb_get_uint8(tvb, offset);
9255
2
    if (!packet->is_command)
9256
1
        operation |= TEP_OPCODE_RSP;
9257
9258
2
    col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, operation, tep_opcode_strings, "Unknown Opcode (%d)"));
9259
9260
2
    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);
9261
9262
2
    operation_tree = proto_item_add_subtree(ti, ett_tep_operation);
9263
2
    ti = proto_tree_add_boolean(operation_tree, hf_tep_operation_type, tvb, offset, 0, operation);
9264
2
    proto_item_set_generated(ti);
9265
9266
    /* The flags are reserved except for OPCODE=1 & COMMAND */
9267
2
    if ((operation & 0x8F) == 0x01)
9268
0
    {
9269
0
        proto_tree_add_item(operation_tree, hf_tep_c, tvb, offset, 1, ENC_NA);
9270
0
        proto_tree_add_item(operation_tree, hf_tep_k, tvb, offset, 1, ENC_NA);
9271
0
    }
9272
9273
2
    proto_tree_add_item(operation_tree, hf_tep_opcode, tvb, offset, 1, ENC_NA);
9274
2
    offset += 1;
9275
9276
2
    switch (operation)
9277
2
    {
9278
0
    case TEP_PDU_REQUEST_KEY:
9279
        /* The K bit must be set, so there is a domain ONLY IF NOT SECURED. */
9280
9281
        /* Remember the current request. */
9282
0
        rekey_data = (tep_rekey_data *)packet->opid_data;
9283
0
        if (!rekey_data)
9284
0
        {
9285
0
            packet->opid_data = rekey_data = wmem_new0(wmem_file_scope(), tep_rekey_data);
9286
0
        }
9287
9288
0
        rekey_data->key_data = wmem_new0(wmem_file_scope(), dof_session_key_exchange_data);
9289
0
        rekey_data->is_rekey = true;
9290
9291
        /* The K bit must be set, so there is a domain ONLY IF NOT SECURED. */
9292
0
        if (packet->decrypted_buffer == NULL)
9293
0
        {
9294
0
            int start_offset = offset;
9295
9296
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, tep_tree,
9297
0
                                              offset, hf_tep_2_1_domain, ett_tep_2_1_domain, NULL);
9298
9299
0
            if (!rekey_data->domain)
9300
0
            {
9301
0
                rekey_data->domain_length = offset - start_offset;
9302
0
                rekey_data->domain = (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data->domain_length);
9303
9304
                /* Get the buffer. */
9305
0
                tvb_memcpy(tvb, rekey_data->domain, start_offset, rekey_data->domain_length);
9306
0
            }
9307
0
        }
9308
0
        else
9309
0
        {
9310
            /* The domain is not present, but this is a secure packet and so the domain can be obtained
9311
            * through the session.
9312
            */
9313
0
            if (!rekey_data->domain)
9314
0
            {
9315
0
                rekey_data->domain_length = api_data->secure_session->domain_length;
9316
0
                rekey_data->domain = api_data->secure_session->domain;
9317
0
            }
9318
0
        }
9319
9320
        /* FALL THROUGH */
9321
9322
0
    case TEP_PDU_REQUEST:
9323
9324
        /* Remember the current request. */
9325
0
        rekey_data = (tep_rekey_data *)packet->opid_data;
9326
0
        if (!rekey_data)
9327
0
        {
9328
0
            if (api_data->secure_session == NULL)
9329
0
            {
9330
                /* TODO: Output error. */
9331
0
                return 0;
9332
0
            }
9333
0
            packet->opid_data = rekey_data = wmem_new0(wmem_file_scope(), tep_rekey_data);
9334
0
            rekey_data->domain_length = api_data->secure_session->domain_length;
9335
0
            rekey_data->domain = api_data->secure_session->domain;
9336
0
        }
9337
9338
        /* The C bit must be clear, so there is an Initiator Block. */
9339
0
        {
9340
0
            dof_2008_16_security_6_1 response;
9341
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_1, tvb, pinfo, tep_tree,
9342
0
                                              offset, hf_tep_2_1_initiator_block, ett_tep_2_1_initiator_block, &response);
9343
0
            if (!packet->processed)
9344
0
            {
9345
0
                tvbuff_t *inonce = response.i_nonce;
9346
0
                tvbuff_t *iidentity = response.i_identity;
9347
9348
0
                rekey_data->i_nonce_length = tvb_reported_length(inonce);
9349
0
                rekey_data->i_nonce = (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data->i_nonce_length);
9350
0
                tvb_memcpy(inonce, rekey_data->i_nonce, 0, rekey_data->i_nonce_length);
9351
9352
0
                rekey_data->i_identity_length = tvb_reported_length(iidentity);
9353
0
                rekey_data->i_identity = (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data->i_identity_length);
9354
0
                tvb_memcpy(iidentity, rekey_data->i_identity, 0, rekey_data->i_identity_length);
9355
9356
0
                rekey_data->security_mode = response.security_mode;
9357
0
                rekey_data->security_mode_data_length = response.security_mode_data_length;
9358
0
                rekey_data->security_mode_data = response.security_mode_data;
9359
0
            }
9360
0
        }
9361
0
        break;
9362
9363
1
    case TEP_PDU_ACCEPT:
9364
1
    {
9365
1
        uint32_t ssid = 0;
9366
1
        uint8_t *S = NULL;
9367
1
        uint8_t S_length = 0;
9368
1
        uint8_t confirmation[32];
9369
1
        typedef struct identity_key
9370
1
        {
9371
1
            uint8_t *session_key;
9372
1
            struct identity_key *next;
9373
1
        } identity_key;
9374
1
        identity_key *identity_key_list = NULL;
9375
1
        dof_secure_session_data *dof_secure_session = NULL;
9376
9377
1
        if (!packet->opid_first)
9378
0
        {
9379
            /* TODO: Print error */
9380
0
            return 0;
9381
0
        }
9382
9383
1
        rekey_data = (tep_rekey_data *)packet->opid_first->opid_data;
9384
1
        if (!rekey_data)
9385
1
            return tvb_captured_length(tvb);
9386
9387
        /* Initiator Ticket */
9388
0
        {
9389
0
            int start_offset;
9390
0
            uint8_t ticket[64];
9391
9392
0
            start_offset = offset;
9393
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, tep_tree,
9394
0
                                              offset, hf_tep_2_2_initiator_ticket, ett_tep_2_2_initiator_ticket, NULL);
9395
9396
0
            if (!packet->processed && rekey_data)
9397
0
            {
9398
0
                int i;
9399
9400
                /* Produce a (possibly empty) list of potential keys based on our
9401
                * initiator secrets based on identity. These will be validated
9402
                * later on.
9403
                */
9404
0
                for (i = 0; i < globals.global_security->identity_data_count; i++)
9405
0
                {
9406
0
                    dof_identity_data *identity = globals.global_security->identity_data + i;
9407
0
                    gcry_cipher_hd_t rijndael_handle;
9408
0
                    int j;
9409
9410
0
                    if (identity->domain_length != rekey_data->domain_length)
9411
0
                        continue;
9412
0
                    if (memcmp(identity->domain, rekey_data->domain, identity->domain_length) != 0)
9413
0
                        continue;
9414
0
                    if (identity->identity_length != rekey_data->i_identity_length)
9415
0
                        continue;
9416
0
                    if (memcmp(identity->identity, rekey_data->i_identity, identity->identity_length) != 0)
9417
0
                        continue;
9418
9419
0
                    tvb_memcpy(tvb, ticket, start_offset, 64);
9420
9421
0
                    if (!gcry_cipher_open(&rijndael_handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0)) {
9422
0
                        if (!gcry_cipher_setkey(rijndael_handle, identity->secret, 32)) {
9423
0
                            gcry_cipher_encrypt(rijndael_handle, ticket, 16, NULL, 0);
9424
0
                            gcry_cipher_encrypt(rijndael_handle, ticket + 16, 16, NULL, 0);
9425
0
                        }
9426
0
                        gcry_cipher_close(rijndael_handle);
9427
0
                    }
9428
9429
0
                    for (j = 0; j < 32; j++)
9430
0
                        ticket[j + 32] = ticket[j + 32] ^ ticket[j];
9431
9432
                    /* Add the key to the list - ep memory. */
9433
0
                    {
9434
0
                        identity_key *key = (identity_key *)wmem_alloc0(wmem_file_scope(), sizeof(*key));
9435
0
                        key->session_key = (uint8_t *)wmem_alloc0(wmem_file_scope(), 32);
9436
0
                        memcpy(key->session_key, ticket + 32, 32);
9437
0
                        key->next = identity_key_list;
9438
0
                        identity_key_list = key;
9439
0
                    }
9440
0
                }
9441
0
            }
9442
0
        }
9443
9444
        /* Ticket Confirmation */
9445
0
        {
9446
0
            if (!packet->processed)
9447
0
                tvb_memcpy(tvb, confirmation, offset, sizeof(confirmation));
9448
0
            proto_tree_add_item(tep_tree, hf_tep_2_2_ticket_confirmation, tvb, offset, 32, ENC_NA);
9449
0
            offset += 32;
9450
0
        }
9451
9452
        /* Add a field to show the session key that has been learned. */
9453
0
        if (rekey_data->key_data && rekey_data->key_data->session_key && tep_tree)
9454
0
        {
9455
0
            ti = proto_tree_add_bytes_with_length(tree, hf_tep_session_key, tvb, 0, 0, rekey_data->key_data->session_key, 32);
9456
0
            proto_item_set_generated(ti);
9457
0
        }
9458
9459
        /* Responder Initialization - present based on whether the command was a rekey */
9460
0
        {
9461
9462
0
            if (rekey_data && rekey_data->is_rekey)
9463
0
            {
9464
0
                int block_length;
9465
0
                tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
9466
0
                ti = proto_tree_add_item(tep_tree, hf_tep_2_2_responder_initialization, tvb, offset, 0, ENC_NA);
9467
0
                ti = proto_item_add_subtree(ti, ett_tep_2_2_responder_initialization);
9468
0
                block_length = dissect_2008_4_tep_2_2_1(start, pinfo, ti, &ssid, data);
9469
0
                proto_item_set_len(ti, block_length);
9470
0
                offset += block_length;
9471
9472
0
                if (!packet->processed)
9473
0
                {
9474
0
                    S_length = block_length;
9475
0
                    S = (uint8_t *)wmem_alloc0(wmem_file_scope(), S_length);
9476
0
                    tvb_memcpy(start, S, 0, S_length);
9477
0
                }
9478
9479
                /* TEP can create new sessions when not used inside an existing secure
9480
                * session. Each session can use an SSID, present in TEP.2.2.1.
9481
                * Note that in this case there may be no existing session, and so
9482
                * we need to "backpedal" and create one.
9483
                */
9484
0
                if (packet->decrypted_buffer == NULL && !packet->processed)
9485
0
                {
9486
#if 0
9487
                    if (api_data->session)
9488
                    tep_session = (tep_session_data*)dof_session_get_proto_data((dof_session_data*)api_data->session, proto_tep);
9489
                    if (!tep_session && api_data->session)
9490
                    {
9491
                        tep_session = (tep_session_data*)se_alloc0(sizeof(*tep_session));
9492
                        dof_session_add_proto_data((dof_session_data*)api_data->session, proto_tep, tep_session);
9493
                    }
9494
9495
                    tep_session->pending_rekey = cmd;
9496
                    tep_session->pending_confirm = packet;
9497
#endif
9498
0
                }
9499
0
            }
9500
0
        }
9501
9502
        /* Responder Block */
9503
0
        {
9504
0
            dof_2008_16_security_6_2 response;
9505
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_2, tvb, pinfo, tep_tree,
9506
0
                                              offset, hf_tep_2_2_responder_block, ett_tep_2_2_responder_block, &response);
9507
0
            if (!packet->processed)
9508
0
            {
9509
0
                tvbuff_t *rnonce = response.r_nonce;
9510
0
                tvbuff_t *ridentity = response.r_identity;
9511
9512
0
                rekey_data->r_nonce_length = tvb_reported_length(rnonce);
9513
0
                rekey_data->r_nonce = (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data->r_nonce_length);
9514
0
                tvb_memcpy(rnonce, rekey_data->r_nonce, 0, rekey_data->r_nonce_length);
9515
9516
0
                rekey_data->r_identity_length = tvb_reported_length(ridentity);
9517
0
                rekey_data->r_identity = (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data->r_identity_length);
9518
0
                tvb_memcpy(ridentity, rekey_data->r_identity, 0, rekey_data->r_identity_length);
9519
0
            }
9520
0
        }
9521
9522
        /* Authentication Initialization */
9523
0
        {
9524
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_3, tvb, pinfo, tep_tree,
9525
0
                                              offset, hf_tep_2_2_authenticator_initialization, ett_tep_2_2_authenticator_initialization, NULL);
9526
0
        }
9527
9528
9529
        /* The request was accepted, and so a new secure session exists. We define the session,
9530
        * add it to the list of secure sessions for the unsecure session, and EPP will do the
9531
        * rest.
9532
        */
9533
0
        if (packet->decrypted_buffer == NULL)
9534
0
        {
9535
            /* This triggers the creation of the corresponding secure DPS session if it is not already
9536
            * created. This allows information to be stored in that session even though no packets
9537
            * have used it yet. There is a problem, however, because at this point we do not know
9538
            * the SSID that (may) be associated with this session.
9539
            */
9540
0
            {
9541
0
                dof_session_data *dof_session = api_data->session;
9542
9543
0
                dof_secure_session = dof_session->secure_sessions;
9544
0
                while (dof_secure_session != NULL)
9545
0
                {
9546
                    /* Determine matching session. The session list already is scoped by transport and DPS
9547
                    * session, so the only thing remaining is the domain and secure session ID.
9548
                    */
9549
0
                    if ((dof_secure_session->ssid == ssid) &&
9550
0
                        (dof_secure_session->domain_length == rekey_data->domain_length) &&
9551
0
                        (memcmp(dof_secure_session->domain, rekey_data->domain, rekey_data->domain_length) == 0))
9552
0
                        break;
9553
9554
0
                    dof_secure_session = dof_secure_session->next;
9555
0
                }
9556
9557
0
                if (!dof_secure_session)
9558
0
                {
9559
0
                    dof_session = wmem_new0(wmem_file_scope(), dof_session_data);
9560
0
                    dof_session->session_id = globals.next_session++;
9561
0
                    dof_session->dof_id = api_data->session->dof_id;
9562
9563
0
                    dof_secure_session = wmem_new0(wmem_file_scope(), dof_secure_session_data);
9564
0
                    dof_secure_session->ssid = ssid;
9565
0
                    dof_secure_session->domain_length = rekey_data->domain_length;
9566
0
                    dof_secure_session->domain = rekey_data->domain;
9567
0
                    dof_secure_session->original_session_id = api_data->session->session_id;
9568
0
                    dof_secure_session->parent = dof_session;
9569
0
                    dof_secure_session->is_2_node = true;
9570
0
                    dof_secure_session->next = api_data->session->secure_sessions;
9571
0
                    api_data->session->secure_sessions = dof_secure_session;
9572
9573
0
                    if (!dof_secure_session->session_security_data_last)
9574
0
                        dof_secure_session->session_security_data = rekey_data->key_data;
9575
0
                    else
9576
0
                        dof_secure_session->session_security_data_last->next = rekey_data->key_data;
9577
9578
0
                    dof_secure_session->session_security_data_last = rekey_data->key_data;
9579
0
                }
9580
0
            }
9581
0
        }
9582
9583
        /* This PDU indicates the beginning of security for the responder. The next PDU
9584
        * sent will be encrypted with these settings. This means that we must determine
9585
        * the security settings and set them in the session.
9586
        */
9587
0
        if (!packet->processed && rekey_data->is_rekey)
9588
0
        {
9589
0
            int i;
9590
0
            uint8_t *session_key = NULL;
9591
9592
            /* We have everything that we need. Determine the session secret if we can. */
9593
9594
            /* Check any keys determined above by initiator identity. */
9595
0
            while (session_key == NULL && identity_key_list)
9596
0
            {
9597
0
                if (validate_session_key(rekey_data, S_length, S, confirmation, identity_key_list->session_key))
9598
0
                {
9599
0
                    session_key = (uint8_t *)wmem_alloc0(wmem_file_scope(), 32);
9600
0
                    memcpy(session_key, identity_key_list->session_key, 32);
9601
0
                }
9602
9603
0
                identity_key_list = identity_key_list->next;
9604
0
            }
9605
9606
            /* For each key in the global configuration, see if we can validate the confirmation. */
9607
0
            for (i = 0; session_key == NULL && i < globals.global_security->session_key_count; i++)
9608
0
            {
9609
0
                if (validate_session_key(rekey_data, S_length, S, confirmation, globals.global_security->session_key[i].session_key))
9610
0
                    session_key = globals.global_security->session_key[i].session_key;
9611
0
            }
9612
9613
9614
            /* Whether or not this can be decrypted, the security mode information
9615
            * should be kept with the session.
9616
            */
9617
0
            {
9618
0
                rekey_data->key_data->r_valid = packet->dof_frame;
9619
0
                rekey_data->key_data->i_valid = UINT32_MAX;
9620
0
                rekey_data->key_data->session_key = session_key;
9621
0
                rekey_data->key_data->security_mode = rekey_data->security_mode;
9622
0
                rekey_data->key_data->security_mode_data_length = rekey_data->security_mode_data_length;
9623
0
                rekey_data->key_data->security_mode_data = rekey_data->security_mode_data;
9624
9625
0
                if (session_key && dof_secure_session)
9626
0
                {
9627
                    /* Look up the field-dissector table, and determine if it is registered. */
9628
0
                    dissector_table_t field_dissector = find_dissector_table("dof.secmode");
9629
0
                    if (field_dissector != NULL)
9630
0
                    {
9631
0
                        dissector_handle_t field_handle = dissector_get_uint_handle(field_dissector, rekey_data->key_data->security_mode);
9632
0
                        if (field_handle != NULL)
9633
0
                        {
9634
0
                            dof_secmode_api_data setup_data;
9635
9636
0
                            setup_data.context = INITIALIZE;
9637
0
                            setup_data.security_mode_offset = 0;
9638
0
                            setup_data.dof_api = api_data;
9639
0
                            setup_data.secure_session = dof_secure_session;
9640
0
                            setup_data.session_key_data = rekey_data->key_data;
9641
9642
0
                            call_dissector_only(field_handle, NULL, pinfo, NULL, &setup_data);
9643
0
                        }
9644
0
                    }
9645
0
                }
9646
0
            }
9647
0
        }
9648
0
    }
9649
0
        break;
9650
9651
0
    case TEP_PDU_CONFIRM:
9652
0
    {
9653
        /* C is set, K is clear. */
9654
        /* Ticket Confirmation */
9655
0
        proto_tree_add_item(tep_tree, hf_tep_2_1_ticket_confirmation, tvb, offset, 32, ENC_NA);
9656
0
        offset += 32;
9657
9658
0
        if (!packet->processed && api_data->session && packet->opid_first && packet->opid_first->opid_data)
9659
0
        {
9660
0
            dof_session_key_exchange_data *sk_data;
9661
9662
0
            rekey_data = (tep_rekey_data *)packet->opid_first->opid_data;
9663
0
            sk_data = rekey_data->key_data;
9664
9665
            /* TODO: Error if not found or if already set. */
9666
0
            if (sk_data)
9667
0
                sk_data->i_valid = packet->dof_frame;
9668
0
        }
9669
0
    }
9670
0
        break;
9671
9672
0
    case TEP_PDU_END_SESSION:
9673
0
    case TEP_PDU_SESSION_ENDING:
9674
0
        break;
9675
9676
0
    case TEP_PDU_REJECT:
9677
0
    {
9678
        /* Error Code */
9679
0
        proto_tree_add_item(tep_tree, hf_tep_reject_code, tvb, offset, 1, ENC_NA);
9680
0
        offset += 1;
9681
9682
        /* Error Description */
9683
0
        if (tvb_captured_length(tvb) > offset)
9684
0
            proto_tree_add_item(tep_tree, hf_tep_reject_data, tvb, offset, -1, ENC_NA);
9685
0
    }
9686
0
        break;
9687
9688
1
    default:
9689
1
        break;
9690
2
    }
9691
1
    return offset;
9692
2
}
9693
9694
static int dissect_trp_dsp(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
9695
0
{
9696
    /* We are handed a buffer that starts with our protocol id. Any options follow that. */
9697
0
    int offset = 0;
9698
9699
    /* We don't care except for the treeview. */
9700
0
    if (!tree)
9701
0
        return 0;
9702
9703
    /* Compute the version and flags, masking off other bits. */
9704
0
    offset += 4; /* Skip the type and protocol. */
9705
9706
0
    proto_tree_add_item(tree, hf_trp_dsp_option, tvb, 0, -1, ENC_NA);
9707
0
    return offset;
9708
0
}
9709
9710
static int dissect_trp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
9711
129
{
9712
129
    dof_api_data *api_data = (dof_api_data *)data;
9713
129
    dof_packet_data *packet_data;
9714
129
    unsigned offset = 0;
9715
129
    uint8_t opcode;
9716
129
    uint16_t app;
9717
129
    int app_len;
9718
129
    proto_item *ti;
9719
129
    proto_tree *trp_tree;
9720
129
    trp_packet_data *trp_data;
9721
9722
    /* Make entries in Protocol column and Info column on summary display */
9723
129
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "TRP ");
9724
9725
    /* Create the protocol tree. */
9726
129
    offset = 0;
9727
129
    ti = proto_tree_add_item(tree, proto_trp, tvb, offset, -1, ENC_NA);
9728
129
    trp_tree = proto_item_add_subtree(ti, ett_trp);
9729
9730
    /* Add the APPID. */
9731
129
    offset = read_c2(tvb, offset, &app, &app_len);
9732
129
    ti = proto_tree_add_uint(trp_tree, hf_2008_1_app_version, tvb, 0, app_len, app);
9733
129
    validate_c2(pinfo, ti, app, app_len);
9734
9735
129
    if (api_data == NULL)
9736
0
    {
9737
0
        expert_add_info_format(pinfo, ti, &ei_malformed, "api_data == NULL");
9738
0
        return offset;
9739
0
    }
9740
9741
129
    packet_data = api_data->packet;
9742
129
    if (packet_data == NULL)
9743
0
    {
9744
0
        expert_add_info_format(pinfo, ti, &ei_malformed, "api_data == NULL");
9745
0
        return offset;
9746
0
    }
9747
9748
129
    trp_data = (trp_packet_data *)dof_packet_get_proto_data(packet_data, proto_trp);
9749
9750
129
    if (offset == tvb_captured_length(tvb))
9751
0
    {
9752
0
        col_append_str(pinfo->cinfo, COL_INFO, "TRP [nop]");
9753
0
        expert_add_info(pinfo, trp_tree, &ei_implicit_no_op);
9754
9755
0
        return offset;
9756
0
    }
9757
9758
    /* Retrieve the opcode. */
9759
129
    opcode = tvb_get_uint8(tvb, offset);
9760
129
    if (!packet_data->is_command)
9761
61
        opcode |= TRP_RESPONSE;
9762
9763
129
    col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(pinfo->pool, opcode, trp_opcode_strings, "Unknown Opcode (%d)"));
9764
9765
    /* Opcode */
9766
129
    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);
9767
129
    offset += 1;
9768
9769
129
    switch (opcode)
9770
129
    {
9771
1
    case TRP_RSP_REJECT:
9772
1
    {
9773
        /* Error Code */
9774
1
        proto_tree_add_item(trp_tree, hf_trp_errorcode, tvb, offset, 1, ENC_NA);
9775
1
        offset += 1;
9776
1
    }
9777
1
        break;
9778
9779
1
    case TRP_CMD_REQUEST_KEK:
9780
1
    {
9781
1
        uint8_t *domain_buf = NULL;
9782
1
        uint8_t domain_length = 0;
9783
1
        int start_offset;
9784
9785
1
        if (trp_data && trp_data->identity_length)
9786
0
        {
9787
0
            expert_add_info(pinfo, ti, &ei_trp_initiator_id_known);
9788
0
        }
9789
9790
        /* Domain - Security.7 */
9791
1
        start_offset = offset;
9792
1
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree, offset, hf_domain, ett_domain, NULL);
9793
1
        if (!packet_data->processed)
9794
1
        {
9795
1
            domain_length = offset - start_offset;
9796
1
            domain_buf = (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length);
9797
1
            tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
9798
1
        }
9799
9800
        /* Initiator Block - TRP.4.1.1 */
9801
1
        {
9802
1
            dof_2008_16_security_4 response;
9803
1
            trp_packet_data *trp_pkt_data = NULL;
9804
9805
1
            start_offset = offset;
9806
9807
            /* Initiator Key Request - Security.4 */
9808
1
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_4, tvb, pinfo, trp_tree,
9809
1
                                              offset, hf_initiator_request, ett_initiator_request, &response);
9810
1
            if (!packet_data->processed)
9811
0
            {
9812
0
                tvbuff_t *identity = response.identity;
9813
0
                uint8_t identity_length = tvb_reported_length(identity);
9814
0
                uint8_t *identity_buf = (uint8_t *)wmem_alloc0(pinfo->pool, identity_length);
9815
0
                int i;
9816
9817
                /* Get the buffer. */
9818
0
                tvb_memcpy(identity, identity_buf, 0, identity_length);
9819
9820
                /* Check to see if there is a matching identity. */
9821
0
                for (i = 0; i < globals.global_security->identity_data_count; i++)
9822
0
                {
9823
0
                    dof_identity_data *gidentity = globals.global_security->identity_data + i;
9824
9825
0
                    if (domain_length != gidentity->domain_length ||
9826
0
                        memcmp(domain_buf, gidentity->domain, domain_length) != 0)
9827
0
                        continue;
9828
9829
0
                    if (identity_length == gidentity->identity_length &&
9830
0
                        memcmp(identity_buf, gidentity->identity, identity_length) == 0)
9831
0
                    {
9832
0
                        trp_pkt_data = wmem_new0(wmem_file_scope(), trp_packet_data);
9833
0
                        dof_packet_add_proto_data(packet_data, proto_trp, trp_pkt_data);
9834
9835
0
                        trp_pkt_data->domain_length = domain_length;
9836
0
                        trp_pkt_data->domain = (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length);
9837
0
                        memcpy(trp_pkt_data->domain, domain_buf, domain_length);
9838
9839
0
                        trp_pkt_data->identity_length = identity_length;
9840
0
                        trp_pkt_data->identity = (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length);
9841
0
                        memcpy(trp_pkt_data->identity, identity_buf, identity_length);
9842
9843
0
                        trp_pkt_data->secret = gidentity->secret;
9844
0
                    }
9845
0
                }
9846
0
            }
9847
9848
            /* Group Identifier - Security.8 */
9849
1
            {
9850
1
                int gid_start = offset;
9851
1
                offset = dof_dissect_pdu_as_field(dissect_2008_16_security_8, tvb, pinfo, trp_tree,
9852
1
                                                  offset, hf_group_identifier, ett_group_identifier, NULL);
9853
9854
1
                if (trp_pkt_data)
9855
0
                {
9856
0
                    trp_pkt_data->group_length = offset - gid_start;
9857
0
                    trp_pkt_data->group = (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pkt_data->group_length);
9858
0
                    tvb_memcpy(tvb, trp_pkt_data->group, gid_start, trp_pkt_data->group_length);
9859
0
                }
9860
1
            }
9861
9862
1
            if (trp_pkt_data)
9863
0
            {
9864
                /* We need to store the entire block_I for later use. */
9865
0
                trp_pkt_data->block_I_length = offset - start_offset;
9866
0
                trp_pkt_data->block_I = (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pkt_data->block_I_length);
9867
0
                tvb_memcpy(tvb, trp_pkt_data->block_I, start_offset, trp_pkt_data->block_I_length);
9868
0
            }
9869
1
        }
9870
1
    }
9871
1
        break;
9872
9873
93
    case TRP_RSP_REQUEST_KEK:
9874
93
    {
9875
93
        int start_offset;
9876
93
        uint32_t ssid;
9877
93
        uint8_t *mode;
9878
93
        uint8_t mode_length;
9879
93
        uint8_t *block_A;
9880
93
        uint8_t block_A_length;
9881
9882
93
        if (trp_data && trp_data->kek_known)
9883
0
        {
9884
0
            expert_add_info(pinfo, ti, &ei_trp_kek_discovered);
9885
0
        }
9886
9887
        /* Initiator Ticket - Security.5 */
9888
93
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, trp_tree,
9889
93
                                          offset, hf_initiator_ticket, ett_initiator_ticket, NULL);
9890
9891
        /* Initialization Block - TRP.4.2.1 */
9892
        /* A BLOCK */
9893
93
        {
9894
93
            start_offset = offset;
9895
9896
            /* THB */
9897
93
            {
9898
93
                proto_tree_add_item(trp_tree, hf_thb, tvb, offset, 1, ENC_NA);
9899
93
                offset += 1;
9900
93
            }
9901
9902
            /* TMIN */
9903
93
            {
9904
93
                proto_tree_add_item(trp_tree, hf_tmin, tvb, offset, 1, ENC_NA);
9905
93
                offset += 1;
9906
93
            }
9907
9908
            /* TMAX */
9909
93
            {
9910
93
                proto_tree_add_item(trp_tree, hf_tmax, tvb, offset, 1, ENC_NA);
9911
93
                offset += 1;
9912
93
            }
9913
9914
            /* Epoch */
9915
93
            {
9916
93
                proto_tree_add_item(trp_tree, hf_trp_epoch, tvb, offset, 2, ENC_BIG_ENDIAN);
9917
93
                offset += 2;
9918
93
            }
9919
9920
            /* SIDg - Type.4 */
9921
93
            {
9922
93
                offset = dof_dissect_pdu_as_field(dissect_2009_11_type_4, tvb, pinfo, trp_tree,
9923
93
                                                  offset, hf_sidg, ett_sidg, NULL);
9924
93
            }
9925
9926
            /* Initiator Node Security Scope - Security.10 */
9927
93
            {
9928
93
                offset = dof_dissect_pdu_as_field(dissect_2008_16_security_10, tvb, pinfo, trp_tree,
9929
93
                                                  offset, hf_security_scope, ett_security_scope, NULL);
9930
93
            }
9931
9932
            /* Security Mode - Security.13 */
9933
93
            {
9934
93
                int mode_start = offset;
9935
93
                offset = dof_dissect_pdu_as_field(dissect_2008_16_security_13, tvb, pinfo, trp_tree,
9936
93
                                                  offset, hf_security_mode, ett_security_mode, NULL);
9937
93
                if (!packet_data->processed)
9938
69
                {
9939
69
                    mode_length = offset - mode_start;
9940
69
                    mode = (uint8_t *)wmem_alloc0(pinfo->pool, mode_length);
9941
69
                    tvb_memcpy(tvb, mode, mode_start, mode_length);
9942
69
                }
9943
93
            }
9944
9945
            /* State Identifier - Type.3 */
9946
93
            {
9947
93
                int s_offset = offset;
9948
93
                int ssid_len;
9949
93
                proto_item *pi;
9950
93
                offset = read_c4(tvb, offset, &ssid, &ssid_len);
9951
93
                ssid |= AS_ASSIGNED_SSID;   /* TRP SSID are *always* assigned by the AS. */
9952
93
                pi = proto_tree_add_uint_format(trp_tree, hf_ssid, tvb, s_offset, offset - s_offset, ssid, "SSID: %u", ssid);
9953
93
                validate_c4(pinfo, pi, ssid, ssid_len);
9954
93
            }
9955
9956
            /* PG - Security.2 */
9957
93
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_2, tvb, pinfo, trp_tree,
9958
93
                                              offset, hf_responder_pg, ett_responder_pg, NULL);
9959
9960
            /* Group Validation - Security.11 */
9961
93
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_11, tvb, pinfo, trp_tree,
9962
93
                                              offset, hf_responder_validation, ett_responder_validation, NULL);
9963
9964
            /* Initiator Validation - Security.11 */
9965
93
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_11, tvb, pinfo, trp_tree,
9966
93
                                              offset, hf_initiator_validation, ett_initiator_validation, NULL);
9967
9968
93
            block_A_length = offset - start_offset;
9969
93
            block_A = (uint8_t *)wmem_alloc0(pinfo->pool, block_A_length);
9970
93
            tvb_memcpy(tvb, block_A, start_offset, block_A_length);
9971
93
        }
9972
9973
        /* Determine the KEK, if possible. This requires that either the initiator node's secret
9974
        * is known or that the group has been configured. In either case this requires knowledge
9975
        * from the matching command, including the domain, identity, and group information.
9976
        */
9977
93
        if (packet_data->opid_first && !packet_data->processed)
9978
10
        {
9979
#if 0
9980
            trp_packet_data* cmd_data = (trp_packet_data*)dof_packet_get_proto_data(packet_data->opid_first, proto_trp);
9981
            uint8_t mac[32];
9982
            extern struct BlockCipher BlockCipher_AES_256;
9983
            struct BlockCipher* cipher = &BlockCipher_AES_256;
9984
            uint8_t* ekey = (uint8_t*)ep_alloc(cipher->keyStateSize);
9985
9986
            int i;
9987
9988
            if (cmd_data)
9989
            {
9990
                uint8_t kek[32];
9991
9992
                tvb_memcpy(tvb, mac, mac_offset, 32);
9993
                tvb_memcpy(tvb, kek, mac_offset + 32, 32);
9994
9995
                if (cipher != NULL)
9996
                {
9997
                    cipher->GenerateKeyState(ekey, cmd_data->secret);
9998
                    cipher->Encrypt(ekey, mac);
9999
                    cipher->Encrypt(ekey, mac + 16);
10000
                }
10001
10002
                for (i = 0; i < 32; i++)
10003
                kek[i] ^= mac[i];
10004
10005
                {
10006
                    OALSecureHMACContext ctx;
10007
                    OALSecureHMACDigest digest;
10008
10009
                    OALSecureHMAC_Start(&ctx, cmd_data->secret);
10010
                    OALSecureHMAC_Digest(&ctx, cmd_data->domain_length, cmd_data->domain);
10011
                    OALSecureHMAC_Digest(&ctx, cmd_data->block_I_length, cmd_data->block_I);
10012
                    OALSecureHMAC_Digest(&ctx, block_A_length, block_A);
10013
                    OALSecureHMAC_Digest(&ctx, 32, kek);
10014
                    OALSecureHMAC_Finish(&ctx, digest);
10015
10016
                    tvb_memcpy(tvb, mac, mac_offset, 32);
10017
                    if (memcmp(mac, digest, 32) == 0)
10018
                    {
10019
                        dof_learned_group_data* group = globals.learned_group_data;
10020
                        dof_learned_group_auth_data *auth = NULL;
10021
10022
                        /* The KEK has been discovered, flag this for output on the PDU. */
10023
                        if (!trp_data)
10024
                        {
10025
                            trp_data = wmem_alloc0(wmem_file_scope(), sizeof(trp_packet_data));
10026
                            dof_packet_add_proto_data(packet_data, proto_trp, trp_data);
10027
                        }
10028
10029
                        trp_data->kek_known = true;
10030
10031
                        while (group)
10032
                        {
10033
                            if ((cmd_data->domain_length == group->domain_length) &&
10034
                                (memcmp(cmd_data->domain, group->domain, group->domain_length) == 0) &&
10035
                                (cmd_data->group_length == group->group_length) &&
10036
                                (memcmp(cmd_data->group, group->group, group->group_length) == 0) &&
10037
                                (ssid == group->ssid))
10038
                            break;
10039
10040
                            group = group->next;
10041
                        }
10042
10043
                        if (group == NULL)
10044
                        {
10045
                            group = wmem_alloc0(wmem_file_scope, sizeof(dof_learned_group_data));
10046
                            group->domain_length = cmd_data->domain_length;
10047
                            group->domain = cmd_data->domain;
10048
                            group->group_length = cmd_data->group_length;
10049
                            group->group = cmd_data->group;
10050
                            group->ssid = ssid;
10051
                            group->next = globals.learned_group_data;
10052
                            globals.learned_group_data = group;
10053
                        }
10054
10055
                        auth = group->keys;
10056
10057
                        while (auth)
10058
                        {
10059
                            if (epoch == auth->epoch)
10060
                            break;
10061
10062
                            auth = auth->next;
10063
                        }
10064
10065
                        if (auth == NULL)
10066
                        {
10067
                            auth = wmem_alloc0(wmem_file_scope(), sizeof(dof_learned_group_auth_data));
10068
                            auth->epoch = epoch;
10069
                            auth->next = group->keys;
10070
                            group->keys = auth;
10071
10072
                            auth->kek = (uint8_t*)wmem_alloc0(wmem_file_scope(), 32);
10073
                            memcpy(auth->kek, kek, 32);
10074
10075
                            auth->mode_length = mode_length;
10076
                            auth->mode = (uint8_t*)wmem_alloc0(wmem_file_scope(), mode_length);
10077
                            memcpy(auth->mode, mode, mode_length);
10078
10079
                            auth->security_mode = (mode[1] * 256) | mode[2];
10080
                            auth->parent = group;
10081
                        }
10082
                    }
10083
                }
10084
            }
10085
#endif
10086
10
        }
10087
93
    }
10088
93
        break;
10089
10090
1
    case TRP_CMD_REQUEST_RANDOM:
10091
1
    {
10092
1
        uint8_t *domain_buf = NULL;
10093
1
        uint8_t domain_length = 0;
10094
1
        int start_offset;
10095
10096
1
        if (trp_data && trp_data->identity_length)
10097
0
        {
10098
0
            expert_add_info(pinfo, ti, &ei_trp_initiator_id_known);
10099
0
        }
10100
10101
        /* Domain - Security.7 */
10102
1
        start_offset = offset;
10103
1
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree,
10104
1
                                          offset, hf_domain, ett_domain, NULL);
10105
1
        if (!packet_data->processed)
10106
1
        {
10107
1
            domain_length = offset - start_offset;
10108
1
            domain_buf = (uint8_t *)wmem_alloc0(pinfo->pool, domain_length);
10109
1
            tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
10110
1
        }
10111
10112
        /* Initiator Block - TRP.6.1.1 */
10113
1
        {
10114
1
            dof_2008_16_security_4 response;
10115
1
            trp_packet_data *trp_pkt_data = NULL;
10116
10117
1
            start_offset = offset;
10118
10119
            /* Initiator Key Request - Security.4 */
10120
1
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_4, tvb, pinfo, trp_tree,
10121
1
                                              offset, hf_initiator_request, ett_initiator_request, &response);
10122
1
            if (!packet_data->processed)
10123
0
            {
10124
0
                tvbuff_t *identity = response.identity;
10125
0
                uint8_t identity_length = tvb_reported_length(identity);
10126
0
                uint8_t *identity_buf = (uint8_t *)wmem_alloc0(pinfo->pool, identity_length);
10127
0
                int i;
10128
10129
                /* Get the buffer. */
10130
0
                tvb_memcpy(identity, identity_buf, 0, identity_length);
10131
10132
                /* Check to see if there is a matching identity. */
10133
0
                for (i = 0; i < globals.global_security->identity_data_count; i++)
10134
0
                {
10135
0
                    dof_identity_data *gidentity = globals.global_security->identity_data + i;
10136
10137
0
                    if (domain_length != gidentity->domain_length ||
10138
0
                        memcmp(domain_buf, gidentity->domain, domain_length) != 0)
10139
0
                        continue;
10140
10141
0
                    if (identity_length == gidentity->identity_length &&
10142
0
                        memcmp(identity_buf, gidentity->identity, identity_length) == 0)
10143
0
                    {
10144
0
                        trp_pkt_data = wmem_new0(wmem_file_scope(), trp_packet_data);
10145
0
                        dof_packet_add_proto_data(packet_data, proto_trp, trp_pkt_data);
10146
10147
0
                        trp_pkt_data->domain_length = domain_length;
10148
0
                        trp_pkt_data->domain = (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length);
10149
0
                        memcpy(trp_pkt_data->domain, domain_buf, domain_length);
10150
10151
0
                        trp_pkt_data->identity_length = identity_length;
10152
0
                        trp_pkt_data->identity = (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length);
10153
0
                        memcpy(trp_pkt_data->identity, identity_buf, identity_length);
10154
10155
0
                        trp_pkt_data->secret = gidentity->secret;
10156
0
                    }
10157
0
                }
10158
0
            }
10159
10160
1
            if (trp_pkt_data)
10161
0
            {
10162
                /* We need to store the entire block_I for later use. */
10163
0
                trp_pkt_data->block_I_length = offset - start_offset;
10164
0
                trp_pkt_data->block_I = (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pkt_data->block_I_length);
10165
0
                tvb_memcpy(tvb, trp_pkt_data->block_I, start_offset, trp_pkt_data->block_I_length);
10166
0
            }
10167
1
        }
10168
1
    }
10169
1
        break;
10170
10171
1
    case TRP_RSP_REQUEST_RANDOM:
10172
1
    {
10173
        /* Initiator Ticket - Security.5 */
10174
1
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, trp_tree,
10175
1
                                          offset, hf_initiator_ticket, ett_initiator_ticket, NULL);
10176
1
    }
10177
1
        break;
10178
10179
14
    case TRP_CMD_REQUEST_SECURITY_SCOPES:
10180
14
    {
10181
14
        uint8_t *domain_buf = NULL;
10182
14
        uint8_t domain_length = 0;
10183
14
        int start_offset;
10184
10185
14
        if (trp_data && trp_data->identity_length)
10186
0
        {
10187
0
            expert_add_info(pinfo, ti, &ei_trp_initiator_id_known);
10188
0
        }
10189
10190
        /* Domain - Security.7 */
10191
14
        start_offset = offset;
10192
14
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree,
10193
14
                                          offset, hf_domain, ett_domain, NULL);
10194
14
        if (!packet_data->processed)
10195
14
        {
10196
14
            domain_length = offset - start_offset;
10197
14
            domain_buf = (uint8_t *)wmem_alloc0(pinfo->pool, domain_length);
10198
14
            tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
10199
14
        }
10200
10201
        /* Initiator Block - TRP.5.1.1 */
10202
14
        {
10203
14
            dof_2008_16_security_4 response;
10204
14
            trp_packet_data *trp_pk_data = NULL;
10205
10206
14
            start_offset = offset;
10207
10208
            /* Initiator Duration Request */
10209
14
            proto_tree_add_item(trp_tree, hf_trp_duration, tvb, offset, 1, ENC_NA);
10210
14
            offset += 1;
10211
10212
            /* Initiator Key Request - Security.4 */
10213
14
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_4, tvb, pinfo, trp_tree,
10214
14
                                              offset, hf_initiator_request, ett_initiator_request, &response);
10215
14
            if (!packet_data->processed)
10216
5
            {
10217
5
                tvbuff_t *identity = response.identity;
10218
5
                uint8_t identity_length = tvb_reported_length(identity);
10219
5
                uint8_t *identity_buf = (uint8_t *)wmem_alloc0(pinfo->pool, identity_length);
10220
5
                int i;
10221
10222
                /* Get the buffer. */
10223
5
                tvb_memcpy(identity, identity_buf, 0, identity_length);
10224
10225
                /* Check to see if there is a matching identity. */
10226
5
                for (i = 0; i < globals.global_security->identity_data_count; i++)
10227
0
                {
10228
0
                    dof_identity_data *gidentity = globals.global_security->identity_data + i;
10229
10230
0
                    if (domain_length != gidentity->domain_length ||
10231
0
                        memcmp(domain_buf, gidentity->domain, domain_length) != 0)
10232
0
                        continue;
10233
10234
0
                    if (identity_length == gidentity->identity_length &&
10235
0
                        memcmp(identity_buf, gidentity->identity, identity_length) == 0)
10236
0
                    {
10237
0
                        trp_pk_data = wmem_new0(wmem_file_scope(), trp_packet_data);
10238
0
                        dof_packet_add_proto_data(packet_data, proto_trp, trp_pk_data);
10239
10240
0
                        trp_pk_data->domain_length = domain_length;
10241
0
                        trp_pk_data->domain = (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length);
10242
0
                        memcpy(trp_pk_data->domain, domain_buf, domain_length);
10243
10244
0
                        trp_pk_data->identity_length = identity_length;
10245
0
                        trp_pk_data->identity = (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length);
10246
0
                        memcpy(trp_pk_data->identity, identity_buf, identity_length);
10247
10248
0
                        trp_pk_data->secret = gidentity->secret;
10249
0
                    }
10250
0
                }
10251
5
            }
10252
10253
            /* Node - Security.8 */
10254
14
            {
10255
14
                int gid_start = offset;
10256
14
                offset = dof_dissect_pdu_as_field(dissect_2008_16_security_8, tvb, pinfo, trp_tree,
10257
14
                                                  offset, hf_node_identifier, ett_node_identifier, NULL);
10258
10259
14
                if (trp_pk_data)
10260
0
                {
10261
0
                    trp_pk_data->group_length = offset - gid_start;
10262
0
                    trp_pk_data->group = (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pk_data->group_length);
10263
0
                    tvb_memcpy(tvb, trp_pk_data->group, gid_start, trp_pk_data->group_length);
10264
0
                }
10265
14
            }
10266
10267
14
            if (trp_pk_data)
10268
0
            {
10269
                /* We need to store the entire block_I for later use. */
10270
0
                trp_pk_data->block_I_length = offset - start_offset;
10271
0
                trp_pk_data->block_I = (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pk_data->block_I_length);
10272
0
                tvb_memcpy(tvb, trp_pk_data->block_I, start_offset, trp_pk_data->block_I_length);
10273
0
            }
10274
14
        }
10275
14
    }
10276
14
        break;
10277
10278
15
    case TRP_RSP_REQUEST_SECURITY_SCOPES:
10279
15
    {
10280
15
        int start_offset;
10281
15
        uint8_t *block_A;
10282
15
        uint8_t block_A_length;
10283
10284
        /* Initiator Ticket - Security.5 */
10285
15
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, trp_tree,
10286
15
                                          offset, hf_initiator_ticket, ett_initiator_ticket, NULL);
10287
10288
        /* Initialization Block - TRP.5.2.1 */
10289
        /* A BLOCK */
10290
15
        {
10291
15
            start_offset = offset;
10292
10293
            /* Initiator Duration Request */
10294
15
            proto_tree_add_item(trp_tree, hf_trp_duration, tvb, offset, 1, ENC_NA);
10295
15
            offset += 1;
10296
10297
            /* Initiator Node Security Scope - Security.10 */
10298
15
            {
10299
15
                offset = dof_dissect_pdu_as_field(dissect_2008_16_security_10, tvb, pinfo, trp_tree,
10300
15
                                                  offset, hf_security_scope, ett_security_scope, NULL);
10301
15
            }
10302
10303
            /* Validation - Security.11 */
10304
15
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_11, tvb, pinfo, trp_tree,
10305
15
                                              offset, hf_initiator_validation, ett_initiator_validation, NULL);
10306
10307
15
            block_A_length = offset - start_offset;
10308
15
            block_A = (uint8_t *)wmem_alloc0(pinfo->pool, block_A_length);
10309
15
            tvb_memcpy(tvb, block_A, start_offset, block_A_length);
10310
15
        }
10311
15
    }
10312
15
        break;
10313
10314
0
    case TRP_CMD_RESOLVE_CREDENTIAL:
10315
0
    {
10316
0
        uint8_t *domain_buf = NULL;
10317
0
        uint8_t domain_length = 0;
10318
0
        int start_offset;
10319
10320
        /* Domain - Security.7 */
10321
0
        start_offset = offset;
10322
0
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree,
10323
0
                                          offset, hf_domain, ett_domain, NULL);
10324
0
        if (!packet_data->processed)
10325
0
        {
10326
0
            domain_length = offset - start_offset;
10327
0
            domain_buf = (uint8_t *)wmem_alloc0(pinfo->pool, domain_length);
10328
0
            tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
10329
0
        }
10330
10331
        /* Identity Resolution - Security.3.2 */
10332
0
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_3_2, tvb, pinfo, trp_tree,
10333
0
                                          offset, hf_identity_resolution, ett_identity_resolution, NULL);
10334
0
    }
10335
0
        break;
10336
10337
0
    case TRP_RSP_RESOLVE_CREDENTIAL:
10338
0
    {
10339
        /* Identity Resolution - Security.3.2 */
10340
0
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_3_2, tvb, pinfo, trp_tree,
10341
0
                                          offset, hf_identity_resolution, ett_identity_resolution, NULL);
10342
0
    }
10343
0
        break;
10344
10345
1
    case TRP_CMD_REQUEST_SESSION:
10346
1
    {
10347
1
        uint8_t *domain_buf = NULL;
10348
1
        uint8_t domain_length = 0;
10349
1
        int start_offset;
10350
10351
1
        if (trp_data && trp_data->identity_length)
10352
0
        {
10353
0
            expert_add_info(pinfo, ti, &ei_trp_initiator_id_known);
10354
0
        }
10355
10356
        /* Domain - Security.7 */
10357
1
        start_offset = offset;
10358
1
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree,
10359
1
                                          offset, hf_domain, ett_domain, NULL);
10360
1
        if (!packet_data->processed)
10361
1
        {
10362
1
            domain_length = offset - start_offset;
10363
1
            domain_buf = (uint8_t *)wmem_alloc0(pinfo->pool, domain_length);
10364
1
            tvb_memcpy(tvb, domain_buf, start_offset, domain_length);
10365
1
        }
10366
10367
        /* Responder Block - Security.6.2 */
10368
1
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_2, tvb, pinfo, trp_tree,
10369
1
                                          offset, hf_responder_request, ett_responder_request, NULL);
10370
10371
        /* Initiator Block - Security.6.1 */
10372
1
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_1, tvb, pinfo, trp_tree,
10373
1
                                          offset, hf_initiator_request, ett_initiator_request, NULL);
10374
1
    }
10375
1
        break;
10376
10377
0
    case TRP_RSP_REQUEST_SESSION:
10378
0
    {
10379
0
        int start_offset;
10380
0
        uint8_t *block_A;
10381
0
        uint8_t block_A_length;
10382
10383
        /* Responder Ticket - Security.5 */
10384
0
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, trp_tree,
10385
0
                                          offset, hf_responder_ticket, ett_responder_ticket, NULL);
10386
10387
        /* Initiator Ticket - Security.5 */
10388
0
        offset = dof_dissect_pdu_as_field(dissect_2008_16_security_5, tvb, pinfo, trp_tree,
10389
0
                                          offset, hf_initiator_ticket, ett_initiator_ticket, NULL);
10390
10391
10392
        /* Initialization Block - Security.6.3 */
10393
        /* A BLOCK */
10394
0
        {
10395
0
            start_offset = offset;
10396
10397
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_6_3, tvb, pinfo, trp_tree,
10398
0
                                              offset, hf_authentication_block, ett_authentication_block, NULL);
10399
10400
0
            block_A_length = offset - start_offset;
10401
0
            block_A = (uint8_t *)wmem_alloc0(pinfo->pool, block_A_length);
10402
0
            tvb_memcpy(tvb, block_A, start_offset, block_A_length);
10403
0
        }
10404
0
    }
10405
0
        break;
10406
10407
0
    case TRP_CMD_VALIDATE_CREDENTIAL:
10408
0
        {
10409
0
            tvbuff_t *data_tvb;
10410
10411
            /* Domain - Security.7 */
10412
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_7, tvb, pinfo, trp_tree,
10413
0
                                              offset, hf_domain, ett_domain, NULL);
10414
10415
0
            offset = dof_dissect_pdu_as_field(dissect_2008_16_security_3_1, tvb, pinfo, trp_tree,
10416
0
                                              offset, hf_identity_resolution, ett_identity_resolution, NULL);
10417
0
            data_tvb = tvb_new_subset_remaining(tvb, offset);
10418
0
            call_data_dissector(data_tvb, pinfo, trp_tree);
10419
0
        }
10420
0
        break;
10421
10422
0
    case TRP_RSP_VALIDATE_CREDENTIAL:
10423
0
    {
10424
0
        tvbuff_t *data_tvb = tvb_new_subset_remaining(tvb, offset);
10425
0
        call_data_dissector(data_tvb, pinfo, trp_tree);
10426
0
    }
10427
0
       break;
10428
129
    }
10429
10430
20
    return offset;
10431
129
}
10432
10433
/* Initialize Core Tunnel Functionality */
10434
static void dof_tun_register(void)
10435
15
{
10436
15
    static hf_register_info hf[] =
10437
15
    {
10438
15
        { &hf_2012_1_tunnel_1_version,
10439
15
            { "Version", "dof.2012_1.tunnel_1.version", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
10440
15
        },
10441
15
        { &hf_2012_1_tunnel_1_length,
10442
15
            { "Length", "dof.2012_1.tunnel_1.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
10443
15
        },
10444
15
    };
10445
10446
15
    static int *ett[] = {
10447
15
        &ett_2012_1_tunnel,
10448
15
    };
10449
10450
15
    proto_2012_1_tunnel = proto_register_protocol(TUNNEL_PROTOCOL_STACK, "DTPS", "dtps");
10451
15
    proto_register_field_array(proto_2012_1_tunnel, hf, array_length(hf));
10452
15
    proto_register_subtree_array(ett, array_length(ett));
10453
10454
15
    register_dissector_with_description("dof.tunnel", TUNNEL_PROTOCOL_STACK, dissect_tunnel_common, proto_2012_1_tunnel);
10455
15
    dof_tun_app_dissectors = register_dissector_table("dof.tunnel.app", "DOF Tunnel Version", proto_2012_1_tunnel, FT_UINT8, BASE_DEC);
10456
15
}
10457
10458
static void dof_tun_reset(void)
10459
15
{
10460
15
}
10461
10462
static void dof_tun_cleanup(void)
10463
0
{
10464
0
}
10465
10466
/* The registration hand-off routine */
10467
static void dof_tun_handoff(void)
10468
15
{
10469
15
    static dissector_handle_t tcp_handle;
10470
10471
15
    register_dissector_with_description("dof.app", TUNNEL_APPLICATION_PROTOCOL, dissect_tun_app_common, proto_2008_1_app);
10472
10473
15
    tcp_handle = create_dissector_handle(dissect_tunnel_tcp, proto_2012_1_tunnel);
10474
10475
15
    dissector_add_uint_with_preference("tcp.port", DOF_TUN_NON_SEC_TCP_PORT, tcp_handle);
10476
15
}
10477
10478
/* Main DOF Registration Support */
10479
10480
static void dof_reset(void)
10481
15
{
10482
15
    globals.next_session = 1;
10483
15
    globals.next_transport_session = 1;
10484
15
    globals.dof_packet_head = globals.dof_packet_tail = NULL;
10485
15
    globals.global_security = &global_security;
10486
15
    globals.learned_group_data = NULL;
10487
15
    globals.decrypt_all_packets = decrypt_all_packets;
10488
15
    globals.track_operations = track_operations;
10489
15
    globals.track_operations_window = track_operations_window;
10490
10491
15
    init_addr_port_tables();
10492
10493
    /* Reset the packet counter. */
10494
15
    next_dof_frame = 1;
10495
10496
    /* Load the template values for different groups. */
10497
15
    {
10498
15
        secmode_field_t *list = secmode_list;
10499
15
        unsigned i;
10500
10501
15
        global_security.group_data = g_new0(dof_group_data, num_secmode_list);
10502
15
        global_security.group_data_count = num_secmode_list;
10503
15
        for (i = 0; i < num_secmode_list; i++)
10504
0
        {
10505
0
            uint8_t kek_len;
10506
0
            dof_group_data *group_data = global_security.group_data + i;
10507
0
            parse_hex_string(list[i].domain, &(group_data->domain), &(group_data->domain_length));
10508
0
            parse_hex_string(list[i].identity, &(group_data->identity), &(group_data->identity_length));
10509
0
            parse_hex_string(list[i].kek, &(group_data->kek), &kek_len);
10510
0
        }
10511
15
    }
10512
10513
    /* Load the template values for different secrets. */
10514
15
    {
10515
15
        seckey_field_t *list = seckey_list;
10516
15
        unsigned i;
10517
10518
        /* Clear existing. */
10519
15
        for (i = 0; i < global_security.session_key_count; i++)
10520
0
        {
10521
0
            dof_session_key_data *session_data = &global_security.session_key[i];
10522
0
            g_free(session_data->session_key);
10523
0
        }
10524
10525
15
        g_free(global_security.session_key);
10526
15
        global_security.session_key = NULL;
10527
15
        global_security.session_key_count = 0;
10528
10529
15
        global_security.session_key = g_new0(dof_session_key_data, num_seckey_list);
10530
15
        global_security.session_key_count = num_seckey_list;
10531
15
        for (i = 0; i < num_seckey_list; i++)
10532
0
        {
10533
0
            uint8_t key_len;
10534
0
            dof_session_key_data *session_data = global_security.session_key + i;
10535
0
            parse_hex_string(list[i].key, &(session_data->session_key), &key_len);
10536
0
        }
10537
15
    }
10538
10539
    /* Load the template values for different identities. */
10540
15
    {
10541
15
        identsecret_field_t *list = identsecret_list;
10542
15
        unsigned i;
10543
10544
        /* Clear existing. */
10545
15
        for (i = 0; i < global_security.identity_data_count; i++)
10546
0
        {
10547
0
            dof_identity_data *identity_data = &global_security.identity_data[i];
10548
0
            g_free(identity_data->domain);
10549
0
            g_free(identity_data->identity);
10550
0
            g_free(identity_data->secret);
10551
0
        }
10552
10553
15
        g_free(global_security.identity_data);
10554
15
        global_security.identity_data = NULL;
10555
15
        global_security.identity_data_count = 0;
10556
10557
15
        global_security.identity_data = g_new0(dof_identity_data, num_identsecret_list);
10558
15
        global_security.identity_data_count = num_identsecret_list;
10559
15
        for (i = 0; i < num_identsecret_list; i++)
10560
0
        {
10561
0
            uint8_t key_len;
10562
0
            uint32_t size;
10563
10564
0
            dof_identity_data *identity_data = global_security.identity_data + i;
10565
0
            if (VALIDHEX(list[i].domain[0]))
10566
0
            {
10567
0
                parse_hex_string(list[i].domain, &(identity_data->domain), &(identity_data->domain_length));
10568
0
            }
10569
0
            else
10570
0
            {
10571
0
                size = (uint32_t)strlen(list[i].domain);
10572
0
                dof_oid_new_standard_string(list[i].domain, &size, &(identity_data->domain));
10573
0
                identity_data->domain_length = size;
10574
0
            }
10575
10576
0
            if (VALIDHEX(list[i].identity[0]))
10577
0
            {
10578
0
                parse_hex_string(list[i].identity, &(identity_data->identity), &(identity_data->identity_length));
10579
0
            }
10580
0
            else
10581
0
            {
10582
0
                size = (uint32_t)strlen(list[i].identity);
10583
0
                dof_oid_new_standard_string(list[i].identity, &size, &(identity_data->identity));
10584
0
                identity_data->identity_length = size;
10585
0
            }
10586
10587
0
            parse_hex_string(list[i].secret, &(identity_data->secret), &key_len);
10588
0
        }
10589
15
    }
10590
15
}
10591
10592
static void dof_cleanup(void)
10593
0
{
10594
0
    unsigned i;
10595
10596
    /* Clear existing. */
10597
0
    for (i = 0; i < global_security.group_data_count; i++)
10598
0
    {
10599
0
        dof_group_data *group_data = &global_security.group_data[i];
10600
0
        g_free(group_data->domain);
10601
0
        g_free(group_data->identity);
10602
0
        g_free(group_data->kek);
10603
0
    }
10604
10605
0
    g_free(global_security.group_data);
10606
0
    global_security.group_data = NULL;
10607
0
    global_security.group_data_count = 0;
10608
10609
0
}
10610
10611
/**
10612
 * Initialize Core DPS Functionality
10613
 */
10614
static void dof_register(void)
10615
15
{
10616
15
    static hf_register_info hf[] =
10617
15
    {
10618
15
        { &hf_security_1_permission_type,
10619
15
            { "Permission Type", "dof.2008.16.security.1.desired-duration", FT_UINT16, BASE_DEC, VALS(dof_2008_16_permission_type), 0, NULL, HFILL } },
10620
10621
15
        { &hf_security_1_length,
10622
15
            { "Length", "dof.2008.16.security.1.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
10623
10624
15
        { &hf_security_1_data,
10625
15
            { "Data", "dof.2008.16.security.1.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
10626
10627
        /* Security.2 */
10628
15
        { &hf_security_2_count,
10629
15
            { "Count", "dof.2008.16.security.2.count", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
10630
10631
15
        { &hf_security_2_permission,
10632
15
            { "Permission", "dof.2008.16.security.2.permission", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10633
10634
        /* Security.3.1 */
10635
15
        { &hf_security_3_1_credential_type,
10636
15
            { "Credential Type", "dof.2008.16.security.3.1.credential_type", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
10637
10638
15
        { &hf_security_3_1_stage,
10639
15
            { "Stage", "dof.2008.16.security.3.1.stage", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
10640
10641
15
        { &hf_security_3_1_security_node_identifier,
10642
15
            { "Security Node Identifier", "dof.2008.16.security.3.1.security_node_identifier", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10643
10644
        /* Security 3.2 */
10645
15
        { &hf_security_3_2_credential_type,
10646
15
            { "Credential Type", "dof.2008.16.security.3.2.credential_type", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
10647
10648
15
        { &hf_security_3_2_stage,
10649
15
            { "Stage", "dof.2008.16.security.3.2.stage", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
10650
10651
15
        { &hf_security_3_2_length,
10652
15
            { "Length", "dof.2008.16.security.3.2.length", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
10653
10654
15
        { &hf_security_3_2_public_data,
10655
15
            { "Public Data", "dof.2008.16.security.3.2.public_data", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10656
10657
        /* Security.4 */
10658
15
        { &hf_security_4_l,
10659
15
            { "L", "dof.2008.16.security.4.l", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL } },
10660
10661
15
        { &hf_security_4_f,
10662
15
            { "F", "dof.2008.16.security.4.f", FT_UINT8, BASE_DEC, NULL, 0x40, NULL, HFILL } },
10663
10664
15
        { &hf_security_4_ln,
10665
15
            { "Ln", "dof.2008.16.security.4.ln", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL } },
10666
10667
15
        { &hf_security_4_identity,
10668
15
            { "Identity", "dof.2008.16.security.4.identity", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10669
10670
15
        { &hf_security_4_nonce,
10671
15
            { "Nonce", "dof.2008.16.security.4.nonce", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
10672
10673
15
        { &hf_security_4_permission_set,
10674
15
            { "Permission Set", "dof.2008.16.security.4.permission_set", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10675
10676
        /* Security.5 */
10677
15
        { &hf_security_5_mac,
10678
15
            { "MAC", "dof.2008.16.security.5.mac", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
10679
10680
15
        { &hf_security_5_key,
10681
15
            { "KEY", "dof.2008.16.security.5.key", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
10682
10683
        /* Security.6.1 */
10684
15
        { &hf_security_6_1_desired_duration,
10685
15
            { "Desired Duration", "dof.2008.16.security.6.1.desired_duration", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
10686
10687
15
        { &hf_security_6_1_desired_security_mode,
10688
15
            { "Desired Security Mode", "dof.2008.16.security.6.1.desired_security_mode", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10689
10690
15
        { &hf_security_6_1_initiator_request,
10691
15
            { "Initiator Request", "dof.2008.16.security.6.1.initiator_request", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10692
10693
        /* Security.6.2 */
10694
15
        { &hf_security_6_2_responder_request,
10695
15
            { "Responder Request", "dof.2008.16.security.6.2.responder_request", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10696
10697
        /* Security.6.3 */
10698
15
        { &hf_security_6_3_granted_duration,
10699
15
            { "Granted Duration", "dof.2008.16.security.6.3.granted_duration", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
10700
10701
15
        { &hf_security_6_3_session_security_scope,
10702
15
            { "Session Security Scope", "dof.2008.16.security.6.3.session_security_scope", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10703
10704
15
        { &hf_security_6_3_initiator_validation,
10705
15
            { "Initiator Validation", "dof.2008.16.security.6.3.initiator_validation", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10706
10707
15
        { &hf_security_6_3_responder_validation,
10708
15
            { "Responder Validation", "dof.2008.16.security.6.3.responder_validation", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10709
10710
        /* Security.9 */
10711
15
        { &hf_security_9_length,
10712
15
            { "Length", "dof.2008.16.security.9.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
10713
10714
15
        { &hf_security_9_initial_state,
10715
15
            { "Initial State", "dof.2008.16.security.9.initial_state", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
10716
10717
        /* Security.10 */
10718
15
        { &hf_security_10_count,
10719
15
            { "Count", "dof.2008.16.security.10.count", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
10720
10721
15
        { &hf_security_10_permission_group_identifier,
10722
15
            { "Permission Group Identifier", "dof.2008.16.security.10.permission_group_identifier", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
10723
10724
        /* Security.11 */
10725
15
        { &hf_security_11_count,
10726
15
            { "Count", "dof.2008.16.security.11.count", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
10727
10728
15
        { &hf_security_11_permission_security_scope,
10729
15
            { "Permission Security Scope", "dof.2008.16.security.11.permission_security_scope", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
10730
10731
        /* Security.12 */
10732
15
        { &hf_security_12_m,
10733
15
            { "M", "dof.2008.16.security.12.m", FT_UINT8, BASE_DEC, VALS(dof_2008_16_security_12_m), 0xC0, NULL, HFILL } },
10734
10735
15
        { &hf_security_12_count,
10736
15
            { "Count", "dof.2008.16.security.12.count", FT_UINT8, BASE_DEC, NULL, 0x3F, NULL, HFILL } },
10737
10738
15
        { &hf_security_12_permission_group_identifier,
10739
15
            { "Permission Group Identifier", "dof.2008.16.security.12.permission_group_identifier", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
10740
10741
15
        { &hf_2008_1_dof_session_transport,
10742
15
            { "Transport Session", "dof.transport_session", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
10743
15
        },
10744
15
        { &hf_2008_1_dof_session,
10745
15
            { "DPS Session", "dof.session", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
10746
15
        },
10747
15
        { &hf_2008_1_dof_frame,
10748
15
            { "DPS Frame", "dof.frame", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
10749
15
        },
10750
15
        { &hf_2008_1_dof_is_2_node,
10751
15
            { "DPS Is 2 Node", "dof.is_2_node", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
10752
15
        },
10753
15
        { &hf_2008_1_dof_is_streaming,
10754
15
            { "DPS Is Streaming", "dof.is_streaming", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
10755
15
        },
10756
15
        { &hf_2008_1_dof_is_from_client,
10757
15
            { "DPS Is From Client", "dof.is_from_client", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
10758
15
        }
10759
15
    };
10760
10761
15
    static int *ett[] = {
10762
        /* Security.2 */
10763
15
        &ett_security_2_permission,
10764
15
        &ett_security_3_1_security_node_identifier,
10765
10766
        /* Security.11 */
10767
15
        &ett_security_11_permission_security_scope,
10768
10769
15
        &ett_security_6_1_desired_security_mode,
10770
15
        &ett_security_6_1_initiator_request,
10771
10772
15
        &ett_security_6_2_responder_request,
10773
15
        &ett_security_6_3_session_security_scope,
10774
15
        &ett_security_6_3_initiator_validation,
10775
15
        &ett_security_6_3_responder_validation,
10776
10777
15
        &ett_security_4_identity,
10778
15
        &ett_security_4_permission_set,
10779
10780
15
        &ett_2008_1_dof,
10781
15
    };
10782
10783
15
    static ei_register_info ei[] =
10784
15
    {
10785
#if 0
10786
        { &ei_undecoded, { "dof.undecoded", PI_UNDECODED, PI_WARN, "DOF: Some protocol octets were not decoded", EXPFILL } },
10787
#endif
10788
15
        { &ei_malformed, { "dof.malformed", PI_MALFORMED, PI_ERROR, "Malformed:", EXPFILL } },
10789
15
        { &ei_implicit_no_op, { "dof.implicit_no_op", PI_PROTOCOL, PI_COMMENT, "Implicit No-op", EXPFILL } },
10790
15
        { &ei_c2_c3_c4_format, { "dof.c2_c3_c4_format", PI_MALFORMED, PI_WARN, "DOF: Cx IE format", EXPFILL } },
10791
15
        { &ei_security_3_1_invalid_stage, { "dof.security.3.1.invalid_stage", PI_MALFORMED, PI_ERROR, "DPS: Security.3.1: Stage invalid.", EXPFILL } },
10792
15
        { &ei_security_4_invalid_bit, { "dof.security.4.invalid_bit", PI_MALFORMED, PI_WARN, "DPS: Security.4: Reserved bit set.", EXPFILL } },
10793
15
        { &ei_security_13_out_of_range, { "dof.security.13.out_of_range", PI_MALFORMED, PI_ERROR, "DPS: Security.13: Attribute Data out of range.", EXPFILL } },
10794
15
    };
10795
10796
    /* Security mode of operation templates. */
10797
15
    static uat_field_t secmode_uat_fields[] = {
10798
15
        UAT_FLD_CSTRING(secmode_list, domain, "Domain", "The domain, coded as hex digits of PDU Security.7."),
10799
15
        UAT_FLD_CSTRING(secmode_list, identity, "Group ID", "The group identifier, coded as hex digits of PDU Security.8."),
10800
15
        UAT_FLD_CSTRING(secmode_list, kek, "KEK", "The KEK, coded as hex digits representing the KEK (256-bit)."),
10801
15
        UAT_END_FIELDS
10802
15
    };
10803
10804
    /* Security keys. */
10805
15
    static uat_field_t seckey_uat_fields[] = {
10806
15
        UAT_FLD_CSTRING(seckey_list, key, "Session Key", "The session key to try to use, coded as hex digits representing the key (256-bit)."),
10807
15
        UAT_END_FIELDS
10808
15
    };
10809
10810
    /* Identity secrets. */
10811
15
    static uat_field_t identsecret_uat_fields[] = {
10812
15
        UAT_FLD_CSTRING(identsecret_list, domain, "Domain", "The domain, coded as hex digits of PDU Security.7."),
10813
15
        UAT_FLD_CSTRING(identsecret_list, identity, "Identity", "The group identifier, coded as hex digits of PDU Security.8."),
10814
15
        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)."),
10815
15
        UAT_END_FIELDS
10816
15
    };
10817
10818
15
    module_t *dof_module;
10819
15
    uat_t *secmode_uat;
10820
15
    uat_t *seckey_uat;
10821
15
    uat_t *identsecret_uat;
10822
15
    expert_module_t *expert_security;
10823
10824
15
    dsp_option_dissectors = register_dissector_table("dof.dsp.options", "DSP Protocol Options", proto_2008_1_dsp, FT_UINT32, BASE_DEC);
10825
15
    dof_sec_dissectors = register_dissector_table("dof.secmode", "DOF Security Mode of Operation", proto_2008_1_dof, FT_UINT16, BASE_DEC);
10826
15
    register_dissector_table("dof.2008.1", "DOF Common PDU", proto_2008_1_dof, FT_STRING, BASE_DEC);
10827
10828
15
    proto_2008_1_dof = proto_register_protocol(DOF_PROTOCOL_STACK, "DOF", "dof");
10829
10830
15
    proto_2008_1_dof_tcp = proto_register_protocol(DOF_PROTOCOL_STACK" TCP", "DOF-TCP", "dof-tcp");
10831
15
    proto_2008_1_dof_udp = proto_register_protocol(DOF_PROTOCOL_STACK" UDP", "DOF-UDP", "dof-udp");
10832
10833
15
    proto_register_field_array(proto_2008_1_dof, hf, array_length(hf));
10834
15
    proto_register_subtree_array(ett, array_length(ett));
10835
10836
15
    expert_security = expert_register_protocol(proto_2008_1_dof);
10837
15
    expert_register_field_array(expert_security, ei, array_length(ei));
10838
10839
15
    dof_module = prefs_register_protocol(proto_2008_1_dof, dof_reset);
10840
15
    secmode_uat = uat_new("DPS Security Mode Templates",
10841
15
                          sizeof(secmode_field_t),
10842
15
                          "custom_dof_secmode_list",
10843
15
                          true,
10844
15
                          &secmode_list,
10845
15
                          &num_secmode_list,
10846
15
                          (UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS),
10847
15
                          NULL,
10848
15
                          secmode_list_copy_cb,
10849
15
                          secmode_list_update_cb,
10850
15
                          secmode_list_free_cb,
10851
15
                          secmode_list_post_update_cb,
10852
15
                          NULL,
10853
15
                          secmode_uat_fields
10854
15
                          );
10855
10856
15
    seckey_uat = uat_new("DPS Session Keys",
10857
15
                         sizeof(seckey_field_t),
10858
15
                         "custom_dof_seckey_list",
10859
15
                         true,
10860
15
                         &seckey_list,
10861
15
                         &num_seckey_list,
10862
15
                         (UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS),
10863
15
                         NULL,
10864
15
                         seckey_list_copy_cb,
10865
15
                         seckey_list_update_cb,
10866
15
                         seckey_list_free_cb,
10867
15
                         seckey_list_post_update_cb,
10868
15
                         NULL,
10869
15
                         seckey_uat_fields
10870
15
                         );
10871
10872
15
    identsecret_uat = uat_new("DPS Identity Secrets",
10873
15
                              sizeof(identsecret_field_t),
10874
15
                              "custom_dof_identsecret_list",
10875
15
                              true,
10876
15
                              &identsecret_list,
10877
15
                              &num_identsecret_list,
10878
15
                              (UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS),
10879
15
                              NULL,
10880
15
                              identsecret_list_copy_cb,
10881
15
                              identsecret_list_update_cb,
10882
15
                              identsecret_list_free_cb,
10883
15
                              identsecret_list_post_update_cb,
10884
15
                              NULL,
10885
15
                              identsecret_uat_fields
10886
15
                              );
10887
10888
15
    prefs_register_bool_preference(dof_module, "custom_dof_decrypt_all",
10889
15
                                   "Attempt to decrypt all packets",
10890
15
                                   "Specifies that decryption should be attempted on all packets, even if the session initialization wasn't captured.",
10891
15
                                   &decrypt_all_packets);
10892
10893
15
    prefs_register_bool_preference(dof_module, "custom_dof_track_operations",
10894
15
                                   "Track DPS operations",
10895
15
                                   "Specifies that operations should be tracked across multiple packets, providing summary lists. This takes time and memory.",
10896
15
                                   &track_operations);
10897
10898
15
    prefs_register_uint_preference(dof_module, "custom_dof_track_operations_window",
10899
15
                                   "Track DPS window",
10900
15
                                   "Limits the number of operations shown before and after the current operations",
10901
15
                                   10, &track_operations_window);
10902
10903
15
    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.");
10904
10905
15
    prefs_register_uat_preference(dof_module, "custom_dof_secmode_list", "DPS Security Mode Templates",
10906
15
                                  "A table of security modes and initialization data that will be tried if no security mode is found.",
10907
15
                                  secmode_uat);
10908
10909
15
    prefs_register_uat_preference(dof_module, "custom_dof_seckey_list", "DPS Session Keys",
10910
15
                                  "A table of session keys to attempt if none is known.",
10911
15
                                  seckey_uat);
10912
10913
15
    prefs_register_uat_preference(dof_module, "custom_dof_identsecret_list", "DPS Identity Secrets",
10914
15
                                  "A table of secrets for different identities.",
10915
15
                                  identsecret_uat);
10916
15
}
10917
10918
static void dof_handoff(void)
10919
15
{
10920
15
    static dissector_handle_t tcp_handle;
10921
10922
15
    dof_oid_handle = register_dissector_with_description("dof.oid", DOF_OBJECT_IDENTIFIER, dissect_2009_11_type_4, oid_proto);
10923
10924
15
    tcp_handle = create_dissector_handle(dissect_dof_tcp, proto_2008_1_dof);
10925
15
    dof_udp_handle = create_dissector_handle(dissect_dof_udp, proto_2008_1_dof);
10926
10927
15
    dissector_add_uint_with_preference("tcp.port", DOF_P2P_NEG_SEC_TCP_PORT, tcp_handle);
10928
15
    dissector_add_uint_range_with_preference("udp.port", DOF_NEG_SEC_UDP_PORT_RANGE, dof_udp_handle);
10929
15
}
10930
10931
/* OID Registration Support */
10932
10933
static void oid_reset(void)
10934
15
{
10935
15
}
10936
10937
static void oid_cleanup(void)
10938
0
{
10939
0
}
10940
10941
/* Initialize OID */
10942
static void oid_register(void)
10943
15
{
10944
15
    static hf_register_info hf[] = {
10945
15
        { &hf_oid_class,
10946
15
            { "Class", "dof.oid.class", FT_UINT32, BASE_DEC, NULL, 0, "DPS Object Identifier Class", HFILL }
10947
15
        },
10948
15
        { &hf_oid_header,
10949
15
            { "Header", "dof.oid.header", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
10950
15
        },
10951
15
        { &hf_oid_attribute,
10952
15
            { "Attribute", "dof.oid.attribute", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL }
10953
15
        },
10954
15
        { &hf_oid_length,
10955
15
            { "Length", "dof.oid.length", FT_UINT8, BASE_DEC, NULL, 0x3F, NULL, HFILL }
10956
15
        },
10957
15
        { &hf_oid_data,
10958
15
            { "Data", "dof.oid.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
10959
15
        },
10960
15
        { &hf_oid_all_attribute_data,
10961
15
            { "Attribute Data", "dof.oid.attribute-data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
10962
15
        },
10963
15
        { &hf_oid_attribute_header,
10964
15
            { "Header", "dof.attribute.header", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
10965
15
        },
10966
15
        { &hf_oid_attribute_attribute,
10967
15
            { "Attribute", "dof.attribute.attribute", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL }
10968
15
        },
10969
15
        { &hf_oid_attribute_id,
10970
15
            { "ID", "dof.attribute.id", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL }
10971
15
        },
10972
15
        { &hf_oid_attribute_length,
10973
15
            { "Length", "dof.attribute.length", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
10974
15
        },
10975
15
        { &hf_oid_attribute_data,
10976
15
            { "Data", "dof.attribute.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
10977
15
        },
10978
15
        { &hf_oid_attribute_oid,
10979
15
            { "OID", "dof.attribute.oid", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
10980
15
        },
10981
15
    };
10982
10983
15
    static int *ett[] = {
10984
15
        &ett_oid,
10985
15
        &ett_oid_header,
10986
15
        &ett_oid_attribute,
10987
15
        &ett_oid_attribute_header,
10988
15
        &ett_oid_attribute_oid,
10989
15
    };
10990
10991
15
    static ei_register_info ei[] =
10992
15
    {
10993
15
        { &ei_type_4_header_zero, { "dof.oid.header_zero", PI_MALFORMED, PI_ERROR, "DOF Violation: Type.4: Header bit mandated 0.", EXPFILL } },
10994
15
    };
10995
10996
15
    if (oid_proto == -1)
10997
15
    {
10998
15
        expert_module_t *expert_oid;
10999
11000
15
        oid_proto = proto_register_protocol(DOF_OBJECT_IDENTIFIER, "DPS.OID", "dof.oid");
11001
15
        proto_register_field_array(oid_proto, hf, array_length(hf));
11002
15
        proto_register_subtree_array(ett, array_length(ett));
11003
15
        expert_oid = expert_register_protocol(oid_proto);
11004
15
        expert_register_field_array(expert_oid, ei, array_length(ei));
11005
15
    }
11006
15
}
11007
11008
static void oid_handoff(void)
11009
15
{
11010
15
}
11011
11012
/* DNP Registration Support */
11013
11014
static unsigned dof_ns_session_key_hash_fn(const void *key)
11015
409
{
11016
409
    const dof_ns_session_key *session_key = (const dof_ns_session_key *)key;
11017
409
    unsigned result = 0;
11018
11019
409
    result += g_int_hash(&session_key->transport_session_id);
11020
409
    result += g_int_hash(&session_key->client);
11021
409
    result += g_int_hash(&session_key->server);
11022
11023
409
    return result;
11024
409
}
11025
11026
static gboolean dof_ns_session_key_equal_fn(const void *key1, const void *key2)
11027
297
{
11028
297
    const dof_ns_session_key *session_key_ptr1 = (const dof_ns_session_key *)key1;
11029
297
    const dof_ns_session_key *session_key_ptr2 = (const dof_ns_session_key *)key2;
11030
11031
297
    if (session_key_ptr1->transport_session_id != session_key_ptr2->transport_session_id)
11032
2
        return FALSE;
11033
11034
295
    if (session_key_ptr1->client != session_key_ptr2->client)
11035
0
        return FALSE;
11036
11037
295
    if (session_key_ptr1->server != session_key_ptr2->server)
11038
0
        return FALSE;
11039
11040
295
    return TRUE;
11041
295
}
11042
11043
static void dof_dnp_reset(void)
11044
15
{
11045
15
    dof_ns_session_lookup = g_hash_table_new_full(dof_ns_session_key_hash_fn, dof_ns_session_key_equal_fn, g_free, NULL);
11046
15
}
11047
11048
static void dof_dnp_cleanup(void)
11049
0
{
11050
0
    g_hash_table_destroy(dof_ns_session_lookup);
11051
0
    dof_ns_session_lookup = NULL;
11052
0
}
11053
11054
static void dof_register_dnp_0(void)
11055
15
{
11056
15
    static hf_register_info hf[] =
11057
15
    {
11058
15
        { &hf_2008_1_dnp_0_1_1_padding,
11059
15
            { "Padding", "dof.dnp.v0.padding", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
11060
15
        },
11061
15
        { &hf_2008_1_dnp_0_1_1_version,
11062
15
            { "Version", "dof.dnp.v0.version", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
11063
15
        },
11064
15
    };
11065
11066
15
    if (proto_2008_1_dnp_0 <= 0)
11067
15
    {
11068
15
        proto_2008_1_dnp_0 = proto_register_protocol(DOF_NETWORK_PROTOCOL " V0", "DPS.DNP.V0", "dof.dnp.v0");
11069
11070
15
        proto_register_field_array(proto_2008_1_dnp_0, hf, array_length(hf));
11071
15
    }
11072
15
}
11073
11074
/**
11075
 * The registration hand-off routine
11076
 */
11077
static void dof_reg_handoff_dnp_0(void)
11078
15
{
11079
15
    dissector_handle_t dnp_handle;
11080
15
    dnp_handle = create_dissector_handle(dissect_dnp_0, proto_2008_1_dnp_0);
11081
11082
15
    dissector_add_uint("dof.dnp", 0, dnp_handle);
11083
15
}
11084
11085
static void dof_register_dnp_1(void)
11086
15
{
11087
15
    expert_module_t *expert_dnp;
11088
11089
15
    static hf_register_info hf[] =
11090
15
    {
11091
15
        { &hf_2009_9_dnp_1_flags,
11092
15
            { "Flags", "dof.2009_9.dnp_1.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
11093
15
        },
11094
15
        { &hf_2009_9_dnp_1_flag_length,
11095
15
            { "Length Size", "dof.2009_9.dnp_1.flags.lengthsize", FT_UINT8, BASE_DEC, NULL, 0x03, NULL, HFILL }
11096
15
        },
11097
15
        { &hf_2009_9_dnp_1_flag_srcport,
11098
15
            { "Source Port", "dof.2009_9.dnp_1.flags.srcport", FT_UINT8, BASE_DEC, NULL, 0x04, NULL, HFILL }
11099
15
        },
11100
15
        { &hf_2009_9_dnp_1_flag_dstport,
11101
15
            { "Destination Port", "dof.2009_9.dnp_1.flags.dstport", FT_UINT8, BASE_DEC, NULL, 0x08, NULL, HFILL }
11102
15
        },
11103
11104
15
        { &hf_2009_9_dnp_1_length,
11105
15
            { "Length", "dof.2009_9.dnp_1.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
11106
15
        },
11107
15
        { &hf_2009_9_dnp_1_srcport,
11108
15
            { "Source Port", "dof.2009_9.dnp_1.srcport", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
11109
15
        },
11110
15
        { &hf_2009_9_dnp_1_dstport,
11111
15
            { "Destination Port", "dof.2009_9.dnp_1.dstport", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
11112
15
        },
11113
15
    };
11114
11115
15
    static int *ett[] =
11116
15
    {
11117
15
        &ett_2009_9_dnp_1_flags,
11118
15
    };
11119
11120
15
    static ei_register_info ei[] =
11121
15
    {
11122
15
        { &ei_dof_10_flags_zero, { "dof.dnp.v1.flags_zero", PI_UNDECODED, PI_ERROR, "DPS-10: Reserved flag bits must be zero.", EXPFILL } },
11123
#if 0
11124
        { &ei_dof_13_length_specified, { "dof.dnp.v1.length_specified", PI_UNDECODED, PI_ERROR, "DPS-13: Length must be specified on a connection.", EXPFILL } },
11125
#endif
11126
15
    };
11127
11128
15
    if (proto_2009_9_dnp_1 <= 0)
11129
15
    {
11130
15
        proto_2009_9_dnp_1 = proto_register_protocol(DOF_NETWORK_PROTOCOL " V1", "DOF.DNP.V1", "dof.dnp.v1");
11131
11132
15
        proto_register_field_array(proto_2009_9_dnp_1, hf, array_length(hf));
11133
15
        proto_register_subtree_array(ett, array_length(ett));
11134
11135
15
        expert_dnp = expert_register_protocol(proto_2009_9_dnp_1);
11136
15
        expert_register_field_array(expert_dnp, ei, array_length(ei));
11137
15
    }
11138
15
}
11139
11140
/**
11141
 * The registration hand-off routine
11142
 */
11143
static void dof_reg_handoff_dnp_1(void)
11144
15
{
11145
15
    dissector_handle_t dnp_handle, dnp_frame_handle;
11146
15
    dnp_handle = create_dissector_handle(dissect_dnp_1, proto_2009_9_dnp_1);
11147
15
    dnp_frame_handle = create_dissector_handle(determine_packet_length_1, proto_2009_9_dnp_1);
11148
11149
15
    dissector_add_uint("dof.dnp", 1, dnp_handle);
11150
15
    dissector_add_uint("dof.dnp.frame", 1, dnp_frame_handle);
11151
15
}
11152
11153
static void dof_dnp_handoff(void)
11154
15
{
11155
15
    dof_reg_handoff_dnp_0();
11156
15
    dof_reg_handoff_dnp_1();
11157
15
}
11158
11159
/**
11160
 * Initialize Core DNP Functionality
11161
 */
11162
static void dof_dnp_register(void)
11163
15
{
11164
15
    static hf_register_info hf[] =
11165
15
    {
11166
15
        { &hf_2008_1_dnp_1_flag,
11167
15
            { "Flag", "dof.2008_1.dnp_1.flag", FT_BOOLEAN, 8, TFS(&tfs_present_not_present), 0x80, NULL, HFILL }
11168
15
        },
11169
15
        { &hf_2008_1_dnp_1_version,
11170
15
            { "Version", "dof.2008_1.dnp_1.version", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL }
11171
15
        },
11172
15
    };
11173
11174
15
    static int *ett[] =
11175
15
    {
11176
15
        &ett_2008_1_dnp,
11177
15
        &ett_2008_1_dnp_header,
11178
15
    };
11179
11180
15
    proto_2008_1_dnp = proto_register_protocol(DOF_NETWORK_PROTOCOL, "DPS.DNP", "dof.dnp");
11181
11182
15
    proto_register_field_array(proto_2008_1_dnp, hf, array_length(hf));
11183
15
    proto_register_subtree_array(ett, array_length(ett));
11184
15
    dnp_dissectors = register_dissector_table("dof.dnp", "DOF DNP Version", proto_2008_1_dnp, FT_UINT8, BASE_DEC);
11185
15
    dnp_framing_dissectors = register_dissector_table("dof.dnp.frame", "DOF DNP Framing", proto_2008_1_dnp, FT_UINT8, BASE_DEC);
11186
11187
15
    dof_register_dnp_0();
11188
15
    dof_register_dnp_1();
11189
15
}
11190
11191
/* DPP Registration Support */
11192
11193
/**
11194
 * This routine is called each time the system is reset (file load, capture)
11195
 * and so it should take care of freeing any of our persistent stuff.
11196
 */
11197
static void dof_dpp_reset(void)
11198
15
{
11199
15
    dpp_reset_opid_support();
11200
15
    dpp_reset_sid_support();
11201
15
}
11202
11203
static void dof_dpp_cleanup(void)
11204
0
{
11205
0
}
11206
11207
static void dof_register_dpp_0(void)
11208
15
{
11209
15
    static hf_register_info hf[] =
11210
15
    {
11211
15
        { &hf_2008_1_dpp_0_1_1_version,
11212
15
            { "Version", "dof.dpp.v0.version", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
11213
15
        },
11214
15
    };
11215
11216
15
    if (proto_2008_1_dpp_0 <= 0)
11217
15
    {
11218
15
        proto_2008_1_dpp_0 = proto_register_protocol(DOF_PRESENTATION_PROTOCOL " V0", "DPS.DPP.V0", "dof.dpp.v0");
11219
11220
15
        proto_register_field_array(proto_2008_1_dpp_0, hf, array_length(hf));
11221
15
    }
11222
15
}
11223
11224
/**
11225
 * The registration hand-off routine
11226
 */
11227
static void dof_reg_handoff_dpp_0(void)
11228
15
{
11229
15
    dissector_handle_t dpp_handle;
11230
15
    dpp_handle = create_dissector_handle(dissect_dpp_0, proto_2008_1_dpp_0);
11231
11232
15
    dissector_add_uint("dof.dpp", 0, dpp_handle);
11233
15
}
11234
11235
static void dof_register_dpp_2(void)
11236
15
{
11237
15
    expert_module_t *expert_dpp;
11238
11239
15
    static hf_register_info hf[] =
11240
15
    {
11241
15
        { &hf_2009_12_dpp_2_1_flags,
11242
15
            { "Flags", "dof.dpp.v2.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
11243
15
        },
11244
15
        { &hf_2009_12_dpp_2_1_flag_security,
11245
15
            { "Secure", "dof.dpp.v2.flags.security", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }
11246
15
        },
11247
15
        { &hf_2009_12_dpp_2_1_flag_opid,
11248
15
            { "Operation ID Type", "dof.dpp.v2.flags.opidtype", FT_UINT8, BASE_DEC, VALS(strings_2009_12_dpp_opid_types), 0x60, NULL, HFILL } },
11249
15
        { &hf_2009_12_dpp_2_1_flag_cmdrsp,
11250
15
            { "Command/Response", "dof.dpp.v2.flags.cmdrsp", FT_BOOLEAN, 8, TFS(&tfs_response_command), 0x10, NULL, HFILL } },
11251
15
        { &hf_2009_12_dpp_2_1_flag_seq,
11252
15
            { "Sequence", "dof.dpp.v2.flags.sequence", FT_BOOLEAN, 8, TFS(&tfs_present_not_present), 0x04, NULL, HFILL } },
11253
15
        { &hf_2009_12_dpp_2_1_flag_retry,
11254
15
            { "Retry", "dof.dpp.v2.flags.retry", FT_BOOLEAN, 8, TFS(&tfs_present_not_present), 0x02, NULL, HFILL } },
11255
11256
15
        { &hf_2009_12_dpp_2_3_sec_flags,
11257
15
            { "Flags", "dof.dpp.v2.security.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
11258
15
        { &hf_2009_12_dpp_2_3_sec_flag_secure,
11259
15
            { "Security Mode Header", "dof.dpp.v2.security.flags.securitymodeheader", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL } },
11260
15
        { &hf_2009_12_dpp_2_3_sec_flag_rdid,
11261
15
            { "Remote Domain ID", "dof.dpp.v2.security.flags.rdid", FT_UINT8, BASE_DEC, NULL, 0x08, NULL, HFILL } },
11262
15
        { &hf_2009_12_dpp_2_3_sec_flag_partition,
11263
15
            { "Partition Present", "dof.dpp.v2.security.flags.partition", FT_UINT8, BASE_DEC, NULL, 0x04, NULL, HFILL } },
11264
15
        { &hf_2009_12_dpp_2_3_sec_flag_ssid,
11265
15
            { "SSID Present", "dof.dpp.v2.security.flags.ssid", FT_UINT8, BASE_DEC, NULL, 0x01, NULL, HFILL } },
11266
15
        { &hf_2009_12_dpp_2_3_sec_flag_as,
11267
15
            { "AS Present", "dof.dpp.v2.security.flags.as", FT_UINT8, BASE_DEC, NULL, 0x02, NULL, HFILL } },
11268
15
        { &hf_2009_12_dpp_2_3_sec_ssid,
11269
15
            { "Security State Identifier", "dof.dpp.v2.security.ssid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11270
15
        { &hf_2009_12_dpp_2_3_sec_rdid,
11271
15
            { "Remote Domain Identifier", "dof.dpp.v2.security.rdid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11272
15
        { &hf_2009_12_dpp_2_3_sec_remote_partition,
11273
15
            { "Remote Security Scope", "dof.dpp.v2.security.remote-scope", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11274
15
        { &hf_2009_12_dpp_2_3_sec_partition,
11275
15
            { "Security Scope", "dof.dpp.v2.security.scope", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11276
11277
15
        { &hf_2009_12_dpp_2_1_opcnt,
11278
15
            { "Operation Count", "dof.dpp.v2.opcnt", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11279
15
        { &hf_2009_12_dpp_2_1_seq,
11280
15
            { "Sequence", "dof.dpp.v2.sequence", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11281
15
        { &hf_2009_12_dpp_2_1_retry,
11282
15
            { "Retry", "dof.dpp.v2.retry", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11283
15
        { &hf_2009_12_dpp_2_1_delay,
11284
15
            { "Delay", "dof.dpp.v2.delay", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11285
15
    };
11286
11287
15
    static hf_register_info shf[] =
11288
15
    {
11289
15
        { &hf_2009_12_dpp_2_14_opcode,
11290
15
            { "Opcode", "dof.dpp.v2s.opcode", FT_UINT8, BASE_DEC, VALS(strings_2009_12_dpp_common_opcodes), 0x0, NULL, HFILL } },
11291
15
    };
11292
11293
15
    static int *ett[] =
11294
15
    {
11295
15
        &ett_2009_12_dpp_2_1_flags,
11296
15
        &ett_2009_12_dpp_2_opid,
11297
15
        &ett_2009_12_dpp_2_opid_history,
11298
15
        &ett_2009_12_dpp_2_3_security,
11299
15
        &ett_2009_12_dpp_2_3_sec_flags,
11300
15
        &ett_2009_12_dpp_2_3_sec_remote_partition,
11301
15
        &ett_2009_12_dpp_2_3_sec_partition,
11302
15
    };
11303
11304
15
    static ei_register_info ei[] =
11305
15
    {
11306
15
        { &ei_dpp2_dof_10_flags_zero, { "dof.dpp.v2.flags_zero", PI_UNDECODED, PI_ERROR, "DPPv2: Reserved flag bits must be zero.", EXPFILL } },
11307
15
        { &ei_dpp_default_flags, { "dof.dpp.v2.flags_included", PI_COMMENTS_GROUP, PI_NOTE, "Default flag value is included explicitly.", EXPFILL } },
11308
15
        { &ei_dpp_explicit_sender_sid_included, { "dof.dpp.v2.sender_sid_included", PI_PROTOCOL, PI_NOTE, "Explicit SID could be optimized, same as sender.", EXPFILL } },
11309
15
        { &ei_dpp_explicit_receiver_sid_included, { "dof.dpp.v2.receiver_sid_included", PI_PROTOCOL, PI_NOTE, "Explicit SID could be optimized, same as receiver.", EXPFILL } },
11310
15
        { &ei_dpp_no_security_context, { "dof.dpp.v2.no_context", PI_UNDECODED, PI_WARN, "No security context to enable packet decryption.", EXPFILL } },
11311
15
    };
11312
11313
15
    static int *sett[] =
11314
15
    {
11315
15
        &ett_2009_12_dpp_common,
11316
15
    };
11317
11318
15
    if (proto_2009_12_dpp <= 0)
11319
15
    {
11320
15
        proto_2009_12_dpp = proto_register_protocol(DOF_PRESENTATION_PROTOCOL " V2", "DPS.DPP.V2", "dof.dpp.v2");
11321
15
        proto_register_field_array(proto_2009_12_dpp, hf, array_length(hf));
11322
15
        proto_register_subtree_array(ett, array_length(ett));
11323
15
    }
11324
11325
15
    if (proto_2009_12_dpp_common <= 0)
11326
15
    {
11327
15
        proto_2009_12_dpp_common = proto_register_protocol(DOF_PRESENTATION_PROTOCOL " V2 Support", "DPS.DPP.V2S", "dof.dpp.v2s");
11328
11329
15
        proto_register_field_array(proto_2009_12_dpp, shf, array_length(shf));
11330
15
        proto_register_subtree_array(sett, array_length(sett));
11331
11332
15
        expert_dpp = expert_register_protocol(proto_2009_12_dpp);
11333
15
        expert_register_field_array(expert_dpp, ei, array_length(ei));
11334
15
    }
11335
15
}
11336
11337
/**
11338
 * The registration hand-off routine
11339
 */
11340
static void dof_reg_handoff_dpp_2(void)
11341
15
{
11342
15
    dissector_handle_t dpp_handle;
11343
15
    dpp_handle = create_dissector_handle(dissect_dpp_2, proto_2009_12_dpp);
11344
15
    dissector_add_uint("dof.dpp", 2, dpp_handle);
11345
15
}
11346
11347
/**
11348
 * Initialize Core DPP Functionality
11349
 */
11350
static void dof_dpp_register(void)
11351
15
{
11352
15
    static hf_register_info hf[] =
11353
15
    {
11354
15
        { &hf_2008_1_dpp_sid_num,
11355
15
            { "SID ID", "dof.dpp.v2.sid-id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
11356
15
        },
11357
15
        { &hf_2008_1_dpp_sid_str,
11358
15
            { "SID", "dof.dpp.v2.sid", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
11359
15
        },
11360
15
        { &hf_2008_1_dpp_rid_num,
11361
15
            { "RID ID", "dof.dpp.v2.rid-id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
11362
15
        },
11363
15
        { &hf_2008_1_dpp_rid_str,
11364
15
            { "RID", "dof.dpp.v2.rid", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
11365
15
        },
11366
15
        { &hf_2008_1_dpp_first_command,
11367
15
            { "First Operation", "dof.dpp.v2.first-operation", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11368
15
        { &hf_2008_1_dpp_last_command,
11369
15
            { "Last Operation", "dof.dpp.v2.last-operation", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11370
15
        { &hf_2008_1_dpp_first_response,
11371
15
            { "First Response", "dof.dpp.v2.first-response", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11372
15
        { &hf_2008_1_dpp_last_response,
11373
15
            { "Last Response", "dof.dpp.v2.last-response", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11374
15
        { &hf_2008_1_dpp_related_frame,
11375
15
            { "Related Frame", "dof.dpp.v2.related-frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11376
15
        { &hf_2008_1_dpp_1_flag,
11377
15
            { "Flags", "dof.dpp.flag", FT_BOOLEAN, 8, TFS(&tfs_present_not_present), 0x80, NULL, HFILL }
11378
15
        },
11379
15
        { &hf_2008_1_dpp_1_version,
11380
15
            { "Version", "dof.dpp.version", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL }
11381
15
        },
11382
15
    };
11383
11384
15
    static int *ett[] =
11385
15
    {
11386
15
        &ett_2008_1_dpp,
11387
15
        &ett_2008_1_dpp_1_header,
11388
15
    };
11389
11390
15
    static ei_register_info ei[] =
11391
15
    {
11392
15
        { &ei_dof_6_timeout, { "dof.dpp.timeout", PI_PROTOCOL, PI_ERROR, "DOF Violation: DPS.6: Negotiation not complete within 10 seconds.", EXPFILL } },
11393
15
    };
11394
11395
15
    if (proto_2008_1_dpp <= 0)
11396
15
    {
11397
15
        expert_module_t *expert_dpp;
11398
11399
15
        proto_2008_1_dpp = proto_register_protocol(DOF_PRESENTATION_PROTOCOL, "DPS.DPP", "dof.dpp");
11400
11401
15
        proto_register_field_array(proto_2008_1_dpp, hf, array_length(hf));
11402
15
        proto_register_subtree_array(ett, array_length(ett));
11403
15
        dof_dpp_dissectors = register_dissector_table("dof.dpp", "DOF DPP Version", proto_2008_1_dpp, FT_UINT8, BASE_DEC);
11404
11405
15
        expert_dpp = expert_register_protocol(proto_2008_1_dpp);
11406
15
        expert_register_field_array(expert_dpp, ei, array_length(ei));
11407
15
    }
11408
11409
15
    dof_register_dpp_0();
11410
15
    dof_register_dpp_2();
11411
15
}
11412
11413
static void dof_dpp_handoff(void)
11414
15
{
11415
15
    dof_reg_handoff_dpp_0();
11416
15
    dof_reg_handoff_dpp_2();
11417
15
}
11418
11419
/* General Application Registration Support */
11420
11421
static void app_reset(void)
11422
15
{
11423
15
}
11424
11425
static void app_cleanup(void)
11426
0
{
11427
0
}
11428
11429
/**
11430
 * Initialize Core DPP Functionality
11431
 */
11432
static void app_register(void)
11433
15
{
11434
15
    if (proto_2008_1_app <= 0)
11435
15
    {
11436
15
        proto_2008_1_app = proto_register_protocol(DOF_APPLICATION_PROTOCOL, "DPS.APP", "dof.app");
11437
15
        app_dissectors = register_dissector_table("dof.app", "DOF APP Version", proto_2008_1_app, FT_UINT16, BASE_DEC);
11438
15
    }
11439
15
}
11440
11441
static void app_handoff(void)
11442
15
{
11443
15
}
11444
11445
/* DSP Registration Support */
11446
11447
static void dof_dsp_reset(void)
11448
15
{
11449
15
}
11450
11451
static void dof_dsp_cleanup(void)
11452
0
{
11453
0
}
11454
11455
static void dof_register_dsp_0(void)
11456
15
{
11457
15
    static hf_register_info hf[] =
11458
15
    {
11459
15
        { &hf_2008_1_app_version,
11460
15
            { "APPID", "dof.app.v0.appid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }
11461
15
        },
11462
11463
15
        { &hf_2008_1_dsp_12_opcode,
11464
15
            { "Opcode", "dof.dsp.opcode", FT_UINT8, BASE_DEC, VALS(strings_2008_1_dsp_opcodes), 0x0, NULL, HFILL } },
11465
11466
15
        { &hf_2008_1_dsp_attribute_code,
11467
15
            { "Attribute Code", "dof.dsp.avp.attribute-code", FT_UINT8, BASE_DEC, VALS(strings_2008_1_dsp_attribute_codes), 0x00, NULL, HFILL } },
11468
11469
15
        { &hf_2008_1_dsp_attribute_data,
11470
15
            { "Attribute Data", "dof.dsp.avp.attribute-data", FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL } },
11471
11472
15
        { &hf_2008_1_dsp_value_length,
11473
15
            { "Value Length", "dof.dsp.avp.value-length", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
11474
11475
15
        { &hf_2008_1_dsp_value_data,
11476
15
            { "Value Data", "dof.dsp.avp.value-data", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11477
15
    };
11478
11479
15
    static int *ett[] =
11480
15
    {
11481
15
        &ett_2008_1_dsp_12,
11482
15
        &ett_2008_1_dsp_12_options,
11483
15
        &ett_2008_1_dsp_12_option,
11484
15
    };
11485
11486
15
    proto_2008_1_dsp = proto_register_protocol("DOF Session Protocol", "DOF.ESP", "dof.esp");
11487
11488
15
    proto_register_field_array(proto_2008_1_dsp, hf, array_length(hf));
11489
15
    proto_register_subtree_array(ett, array_length(ett));
11490
15
}
11491
11492
/**
11493
 * The registration hand-off routine
11494
 */
11495
static void dof_reg_handoff_dsp_0(void)
11496
15
{
11497
15
    dissector_handle_t dsp_handle = create_dissector_handle(dissect_dsp, proto_2008_1_dsp);
11498
15
    dissector_add_uint("dof.app", 0, dsp_handle);
11499
15
}
11500
11501
static void dof_dsp_register(void)
11502
15
{
11503
15
    dof_register_dsp_0();
11504
15
}
11505
11506
static void dof_dsp_handoff(void)
11507
15
{
11508
15
    dof_reg_handoff_dsp_0();
11509
15
}
11510
11511
/* CCM Registration Support */
11512
11513
static void dof_ccm_reset(void)
11514
15
{
11515
15
}
11516
11517
static void dof_ccm_cleanup(void)
11518
0
{
11519
0
}
11520
11521
static void dof_register_ccm_24577(void)
11522
15
{
11523
15
    expert_module_t *expert_ccm;
11524
11525
15
    static hf_register_info hfdsp[] =
11526
15
    {
11527
15
        { &hf_ccm_dsp_option,
11528
15
            { "CCM Security Mode", "dof.ccm.dsp_opt", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11529
15
        { &hf_ccm_dsp_strength_count,
11530
15
            { "CCM Strength Count", "dof.ccm.strength-count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11531
15
        { &hf_ccm_dsp_strength,
11532
15
            { "CCM Strength", "dof.ccm.strength", FT_UINT8, BASE_DEC, VALS(ccm_strengths), 0x0, NULL, HFILL } },
11533
15
        { &hf_ccm_dsp_e_flag,
11534
15
            { "CCM Minimum Encrypt", "dof.ccm.encrypt.min", FT_BOOLEAN, 8, TFS(&tfs_encrypt_do_not_encrypt), 0x80, NULL, HFILL } },
11535
15
        { &hf_ccm_dsp_m_flag,
11536
15
            { "CCM Maximum Encrypt", "dof.ccm.encrypt.max", FT_BOOLEAN, 8, TFS(&tfs_encrypt_do_not_encrypt), 0x40, NULL, HFILL } },
11537
15
        { &hf_ccm_dsp_tmax,
11538
15
            { "CCM Maximum MAC", "dof.ccm.mac.max", FT_UINT8, BASE_DEC, NULL, 0x38, NULL, HFILL } },
11539
15
        { &hf_ccm_dsp_tmin,
11540
15
            { "CCM Minimum MAC", "dof.ccm.mac.min", FT_UINT8, BASE_DEC, NULL, 0x07, NULL, HFILL } },
11541
15
    };
11542
11543
15
    static hf_register_info hf[] =
11544
15
    {
11545
15
        { &hf_ccm_opcode,
11546
15
            { "Opcode", "dof.ccm.opcode", FT_UINT8, BASE_DEC, VALS(ccm_opcode_strings), 0x0, NULL, HFILL } },
11547
15
    };
11548
11549
15
    static int *ett[] =
11550
15
    {
11551
15
        &ett_ccm_dsp_option,
11552
15
        &ett_ccm_dsp,
11553
15
        &ett_ccm,
11554
15
    };
11555
11556
15
    static hf_register_info hfheader[] =
11557
15
    {
11558
15
        { &hf_epp_v1_ccm_flags,
11559
15
            { "Flags", "dof.epp.v1.ccm.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
11560
15
        { &hf_epp_v1_ccm_flags_manager,
11561
15
            { "Manager", "dof.epp.v1.ccm.flags.manager", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL } },
11562
15
        { &hf_epp_v1_ccm_flags_period,
11563
15
            { "Period", "dof.epp.v1.ccm.flags.period", FT_UINT8, BASE_DEC, NULL, 0x70, NULL, HFILL } },
11564
15
        { &hf_epp_v1_ccm_flags_target,
11565
15
            { "Target", "dof.epp.v1.ccm.flags.target", FT_UINT8, BASE_DEC, NULL, 0x08, NULL, HFILL } },
11566
15
        { &hf_epp_v1_ccm_flags_next_nid,
11567
15
            { "Next Node Identifier", "dof.epp.v1.ccm.flags.next-nid", FT_UINT8, BASE_DEC, NULL, 0x02, NULL, HFILL } },
11568
15
        { &hf_epp_v1_ccm_flags_packet,
11569
15
            { "Packet", "dof.epp.v1.ccm.flags.packet", FT_UINT8, BASE_DEC, NULL, 0x01, NULL, HFILL } },
11570
15
        { &hf_epp_v1_ccm_nid,
11571
15
            { "Node ID", "dof.epp.v1.ccm.nodeid", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
11572
15
        { &hf_epp_v1_ccm_slot,
11573
15
            { "Slot", "dof.epp.v1.ccm.slot", FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL } },
11574
15
        { &hf_epp_v1_ccm_pn,
11575
15
            { "Packet", "dof.epp.v1.ccm.packet", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
11576
15
        { &hf_epp_v1_ccm_tnid,
11577
15
            { "Target Node ID", "dof.epp.v1.ccm.target", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
11578
15
        { &hf_epp_v1_ccm_nnid,
11579
15
            { "Next Node ID", "dof.epp.v1.ccm.nnid", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
11580
15
    };
11581
11582
15
    static int *ettheader[] =
11583
15
    {
11584
15
        &ett_epp_v1_ccm_flags,
11585
15
        &ett_header,
11586
15
    };
11587
11588
15
    static ei_register_info ei[] =
11589
15
    {
11590
15
        { &ei_decode_failure, { "dof.ccm.decode_failure", PI_UNDECODED, PI_WARN, "Failure to decrypt packet.", EXPFILL } },
11591
15
    };
11592
11593
    /* No Configuration options to register? */
11594
11595
15
    proto_ccm_app = proto_register_protocol("DOF CCM Security Mode App", "DOF.CCM.APP", "dof.ccm.app");
11596
15
    proto_ccm = proto_register_protocol("DOF CCM Security Mode of Operation", "DOF.CCM", "dof.ccm");
11597
15
    proto_ccm_dsp = proto_register_protocol("DOF CCM Security Mode DSP Options", "DOF.CCM.DSP", "dof.ccm.dsp");
11598
11599
15
    proto_register_field_array(proto_ccm_app, hf, array_length(hf));
11600
15
    proto_register_field_array(proto_ccm_dsp, hfdsp, array_length(hfdsp));
11601
15
    proto_register_subtree_array(ett, array_length(ett));
11602
11603
15
    proto_register_field_array(proto_ccm, hfheader, array_length(hfheader));
11604
15
    proto_register_subtree_array(ettheader, array_length(ettheader));
11605
11606
15
    expert_ccm = expert_register_protocol(proto_ccm);
11607
15
    expert_register_field_array(expert_ccm, ei, array_length(ei));
11608
15
}
11609
11610
/**
11611
 * The registration hand-off routine
11612
 */
11613
static void dof_reg_handoff_ccm_24577(void)
11614
15
{
11615
15
    static dissector_handle_t ccm_app_handle;
11616
15
    static dissector_handle_t dsp_handle;
11617
15
    static dissector_handle_t ccm_handle;
11618
11619
15
    ccm_app_handle = create_dissector_handle(dissect_ccm_app, proto_ccm_app);
11620
15
    dsp_handle = create_dissector_handle(dissect_ccm_dsp, proto_ccm_dsp);
11621
15
    ccm_handle = create_dissector_handle(dissect_ccm, proto_ccm);
11622
11623
15
    dissector_add_uint("dof.app", DOF_PROTOCOL_CCM, ccm_app_handle);
11624
15
    dissector_add_uint("dof.dsp.options", DSP_CCM_FAMILY | DOF_PROTOCOL_CCM, dsp_handle);
11625
15
    dissector_add_uint("dof.secmode", DOF_PROTOCOL_CCM, ccm_handle);
11626
15
}
11627
11628
static void dof_ccm_register(void)
11629
15
{
11630
15
    dof_register_ccm_24577();
11631
15
}
11632
11633
static void dof_ccm_handoff(void)
11634
15
{
11635
15
    dof_reg_handoff_ccm_24577();
11636
15
}
11637
11638
/* OAP Registration Support */
11639
11640
static void dof_oap_reset(void)
11641
15
{
11642
    /* The value is not allocated, so does not need to be freed. */
11643
15
    oap_1_alias_to_binding = g_hash_table_new_full(oap_1_alias_hash_func, oap_1_alias_equal_func, NULL, NULL);
11644
15
}
11645
11646
static void dof_oap_cleanup(void)
11647
0
{
11648
0
    g_hash_table_destroy(oap_1_alias_to_binding);
11649
0
    oap_1_alias_to_binding = NULL;
11650
0
}
11651
11652
static void dof_register_oap_1(void)
11653
15
{
11654
15
    expert_module_t *expert_oap;
11655
11656
15
    static hf_register_info hfdsp[] =
11657
15
    {
11658
15
        { &hf_oap_1_dsp_option,
11659
15
            { "Object Access Protocol", "dof.oap.dsp_opt", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11660
15
    };
11661
11662
15
    static hf_register_info hf[] =
11663
15
    {
11664
15
        { &hf_oap_1_opcode,
11665
15
            { "Opcode", "dof.oap.opcode", FT_UINT8, BASE_DEC, VALS(oap_opcode_strings), 0x1F, NULL, HFILL } },
11666
11667
15
        { &hf_oap_1_alias_size,
11668
15
            { "Alias Length", "dof.oap.aliaslen", FT_UINT8, BASE_DEC, NULL, 0xC0, NULL, HFILL } },
11669
11670
15
        { &hf_oap_1_flags,
11671
15
            { "Flags", "dof.oap.flags", FT_UINT8, BASE_DEC, NULL, 0x20, NULL, HFILL } },
11672
11673
15
        { &hf_oap_1_exception_internal_flag,
11674
15
            { "Internal Exception", "dof.oap.exception.internal", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL } },
11675
11676
15
        { &hf_oap_1_exception_final_flag,
11677
15
            { "Final Exception", "dof.oap.exception.final", FT_UINT8, BASE_DEC, NULL, 0x40, NULL, HFILL } },
11678
11679
15
        { &hf_oap_1_exception_provider_flag,
11680
15
            { "Exception Provider", "dof.oap.exception.provider", FT_UINT8, BASE_DEC, NULL, 0x20, NULL, HFILL } },
11681
11682
15
        { &hf_oap_1_cmdcontrol,
11683
15
            { "Command Control", "dof.oap.cmdcontrol", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
11684
11685
15
        { &hf_oap_1_cmdcontrol_cache_flag,
11686
15
            { "Cache Delay Flag", "dof.oap.cmdcontrol.flag.cache", FT_UINT8, BASE_HEX, NULL, 0x40, NULL, HFILL } },
11687
11688
15
        { &hf_oap_1_cmdcontrol_cache,
11689
15
            { "Cache Delay", "dof.oap.cmdcontrol.cache", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL } },
11690
11691
15
        { &hf_oap_1_cmdcontrol_verbosity_flag,
11692
15
            { "Verbosity Flag", "dof.oap.cmdcontrol.flag.verbosity", FT_UINT8, BASE_HEX, NULL, 0x30, NULL, HFILL } },
11693
11694
15
        { &hf_oap_1_cmdcontrol_noexecute_flag,
11695
15
            { "No Execute Flag", "dof.oap.cmdcontrol.flag.noexecute", FT_UINT8, BASE_HEX, NULL, 0x08, NULL, HFILL } },
11696
11697
15
        { &hf_oap_1_cmdcontrol_ack_flag,
11698
15
            { "Ack List Flag", "dof.oap.cmdcontrol.flag.ack", FT_UINT8, BASE_HEX, NULL, 0x04, NULL, HFILL } },
11699
11700
15
        { &hf_oap_1_cmdcontrol_ackcnt,
11701
15
            { "Ack List Count", "dof.oap.cmdcontrol.ackcnt", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL } },
11702
11703
15
        { &hf_oap_1_cmdcontrol_ack,
11704
15
            { "Ack", "dof.oap.cmdcontrol.ack", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11705
11706
15
        { &hf_oap_1_cmdcontrol_delay_flag,
11707
15
            { "Execution Delay Flag", "dof.oap.cmdcontrol.flag.delay", FT_UINT8, BASE_HEX, NULL, 0x02, NULL, HFILL } },
11708
11709
15
        { &hf_oap_1_cmdcontrol_heuristic_flag,
11710
15
            { "Heuristic Flag", "dof.oap.cmdcontrol.flag.heuristic", FT_UINT8, BASE_HEX, NULL, 0x01, NULL, HFILL } },
11711
11712
15
        { &hf_oap_1_cmdcontrol_heuristic,
11713
15
            { "Heuristic", "dof.oap.cmdcontrol.heuristic", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL } },
11714
11715
15
        { &hf_oap_1_providerid,
11716
15
            { "Provider ID", "dof.oap.provider-id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11717
11718
15
        { &hf_oap_1_objectid,
11719
15
            { "Object ID", "dof.oap.object-id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11720
11721
15
        { &hf_oap_1_interfaceid,
11722
15
            { "Interface ID", "dof.oap.interface-id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11723
11724
15
        { &hf_oap_1_itemid,
11725
15
            { "Item ID", "dof.oap.item-id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11726
11727
#if 0 /* not used yet */
11728
        { &hf_oap_1_distance,
11729
            { "Distance", "dof.oap.distance", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11730
#endif
11731
11732
15
        { &hf_oap_1_alias,
11733
15
            { "Alias", "dof.oap.alias", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11734
11735
15
        { &hf_oap_1_alias_frame,
11736
15
            { "Alias Frame", "dof.oap.alias-frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11737
11738
#if 0 /* not used yet */
11739
        { &hf_oap_1_opinfo_start_frame,
11740
            { "Command Frame", "dof.oap.command-frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11741
11742
        { &hf_oap_1_opinfo_end_frame,
11743
            { "Response Frame", "dof.oap.response-frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11744
11745
        { &hf_oap_1_opinfo_timeout,
11746
            { "Operation Timeout", "dof.oap.opid.timeout", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11747
#endif
11748
11749
15
        { &hf_oap_1_subscription_delta,
11750
15
            { "Minimum Delta", "dof.oap.subscription.min-delta", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11751
11752
15
        { &hf_oap_1_update_sequence,
11753
15
            { "Sequence", "dof.oap.sequence", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
11754
11755
15
        { &hf_oap_1_value_list,
11756
15
            { "OAP Value List", "dof.oap.value_list", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11757
15
    };
11758
11759
15
    static int *ett[] =
11760
15
    {
11761
15
        &ett_oap_1_dsp,
11762
15
        &ett_oap_1_dsp_options,
11763
15
        &ett_oap_1,
11764
15
        &ett_oap_1_opinfo,
11765
15
        &ett_oap_1_cmdcontrol,
11766
15
        &ett_oap_1_cmdcontrol_flags,
11767
15
        &ett_oap_1_cmdcontrol_ack,
11768
15
        &ett_oap_1_alias,
11769
15
        &ett_oap_1_objectid,
11770
15
        &ett_oap_1_1_providerid,
11771
15
    };
11772
11773
15
    static ei_register_info ei[] =
11774
15
    {
11775
15
        { &ei_oap_no_session, { "dof.oap.no_session", PI_PROTOCOL, PI_ERROR, "Session not found", EXPFILL } },
11776
15
    };
11777
11778
15
    proto_oap_1 = proto_register_protocol("DOF Object Access Protocol", "DOF.OAP", "dof.oap");
11779
15
    proto_oap_1_dsp = proto_register_protocol("DOF Object Access Protocol DSP Options", "DOF.OAP.DSP", "dof.oap.dsp");
11780
11781
15
    proto_register_field_array(proto_oap_1, hf, array_length(hf));
11782
15
    proto_register_field_array(proto_oap_1_dsp, hfdsp, array_length(hfdsp));
11783
15
    proto_register_subtree_array(ett, array_length(ett));
11784
11785
15
    expert_oap = expert_register_protocol(proto_oap_1);
11786
15
    expert_register_field_array(expert_oap, ei, array_length(ei));
11787
15
}
11788
11789
/**
11790
 * The registration hand-off routine
11791
 */
11792
static void dof_reg_handoff_oap_1(void)
11793
15
{
11794
15
    dissector_handle_t oap_handle = create_dissector_handle(dissect_oap, proto_oap_1);
11795
15
    dissector_handle_t dsp_handle = create_dissector_handle(dissect_oap_dsp, proto_oap_1_dsp);
11796
11797
15
    dissector_add_uint("dof.app", DOF_PROTOCOL_OAP_1, oap_handle);
11798
15
    dissector_add_uint("dof.dsp.options", DSP_OAP_FAMILY | DOF_PROTOCOL_OAP_1, dsp_handle);
11799
15
}
11800
11801
static void dof_oap_register(void)
11802
15
{
11803
15
    dof_register_oap_1();
11804
15
}
11805
11806
static void dof_oap_handoff(void)
11807
15
{
11808
15
    dof_reg_handoff_oap_1();
11809
15
}
11810
11811
/* SGMP Registration Support */
11812
11813
static void dof_register_sgmp_130(void);
11814
static void dof_reg_handoff_sgmp_130(void);
11815
11816
static void dof_sgmp_reset(void)
11817
15
{
11818
15
}
11819
11820
static void dof_sgmp_cleanup(void)
11821
0
{
11822
0
}
11823
11824
static void dof_register_sgmp_130(void)
11825
15
{
11826
15
    static hf_register_info hf[] =
11827
15
    {
11828
15
        { &hf_opcode,
11829
15
            { "Opcode", "dof.sgmp.v1.opcode", FT_UINT8, BASE_DEC, VALS(sgmp_opcode_strings), 0x0, NULL, HFILL } },
11830
11831
15
        { &hf_sgmp_domain,
11832
15
            { "Domain", "dof.sgmp.v1.domain", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
11833
11834
15
        { &hf_sgmp_epoch,
11835
15
            { "Epoch", "dof.sgmp.v1.epoch", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
11836
11837
15
        { &hf_initiator_block,
11838
15
            { "Initiator Block", "dof.sgmp.v1.initiator-block", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
11839
11840
15
        { &hf_sgmp_security_scope,
11841
15
            { "Security Scope", "dof.sgmp.v1.security-scope", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
11842
11843
15
        { &hf_initial_state,
11844
15
            { "Initial State", "dof.sgmp.v1.initial-state", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
11845
11846
15
        { &hf_latest_version,
11847
15
            { "Latest SGMP Version", "dof.sgmp.v1.latest-sgmp-version", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
11848
11849
15
        { &hf_desire,
11850
15
            { "Desire", "dof.sgmp.v1.desire", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
11851
11852
15
        { &hf_ticket,
11853
15
            { "Ticket", "dof.sgmp.v1.ticket", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
11854
11855
15
        { &hf_sgmp_tmin,
11856
15
            { "TMIN", "dof.sgmp.v1.tmin", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
11857
11858
15
        { &hf_tie_breaker,
11859
15
            { "Tie Breaker", "dof.sgmp.v1.tie-breaker", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL } },
11860
11861
15
        { &hf_delay,
11862
15
            { "Delay", "dof.sgmp.v1.delay", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
11863
11864
15
        { &hf_key,
11865
15
            { "Key", "dof.sgmp.v1.key", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
11866
15
    };
11867
11868
15
    static int *ett[] =
11869
15
    {
11870
15
        &ett_sgmp,
11871
15
        &ett_sgmp_domain,
11872
15
        &ett_initiator_block,
11873
15
        &ett_sgmp_security_scope,
11874
15
        &ett_initial_state,
11875
15
        &ett_ticket,
11876
15
    };
11877
11878
15
    proto_sgmp = proto_register_protocol("DOF Secure Group Management Protocol", "DOF.SGMP", "dof.sgmp");
11879
11880
15
    proto_register_field_array(proto_sgmp, hf, array_length(hf));
11881
15
    proto_register_subtree_array(ett, array_length(ett));
11882
15
}
11883
11884
/**
11885
 * The registration hand-off routine
11886
 */
11887
static void dof_reg_handoff_sgmp_130(void)
11888
15
{
11889
15
    dissector_handle_t sgmp_handle = create_dissector_handle(dissect_sgmp, proto_sgmp);
11890
11891
15
    dissector_add_uint("dof.app", DOF_PROTOCOL_SGMP, sgmp_handle);
11892
15
}
11893
11894
static void dof_sgmp_register(void)
11895
15
{
11896
15
    dof_register_sgmp_130();
11897
15
}
11898
11899
static void dof_sgmp_handoff(void)
11900
15
{
11901
15
    dof_reg_handoff_sgmp_130();
11902
15
}
11903
11904
/* TEP Registration Support */
11905
11906
static void dof_tep_reset(void)
11907
15
{
11908
15
}
11909
11910
static void dof_tep_cleanup(void)
11911
0
{
11912
0
}
11913
11914
static void dof_register_tep_128(void)
11915
15
{
11916
15
    static hf_register_info hfdsp[] =
11917
15
    {
11918
15
        { &hf_dsp_option,
11919
15
            { "Ticket Exchange Protocol Version 1", "dof.tep1.dsp_opt", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11920
15
    };
11921
11922
15
    static hf_register_info hf[] =
11923
15
    {
11924
15
        { &hf_tep_operation,
11925
15
            { "Operation", "dof.tep1.operation", FT_UINT8, BASE_DEC, VALS(tep_opcode_strings), 0x00, NULL, HFILL } },
11926
11927
15
        { &hf_tep_operation_type,
11928
15
            { "Operation Type", "dof.tep1.operation_type", FT_BOOLEAN, 8, TFS(&tep_optype_vals), TEP_OPCODE_RSP, NULL, HFILL } },
11929
11930
15
        { &hf_tep_opcode,
11931
15
            { "Opcode", "dof.tep1.opcode", FT_UINT8, BASE_DEC, VALS(tep_opcode_strings), 0x0F, NULL, HFILL } },
11932
11933
15
        { &hf_tep_k,
11934
15
            { "K", "dof.tep1.k", FT_UINT8, BASE_DEC, NULL, 0x10, NULL, HFILL } },
11935
11936
15
        { &hf_tep_c,
11937
15
            { "C", "dof.tep1.c", FT_UINT8, BASE_DEC, NULL, 0x20, NULL, HFILL } },
11938
11939
15
        { &hf_tep_reject_code,
11940
15
            { "Code", "dof.tep1.reject.code", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
11941
11942
15
        { &hf_tep_reject_data,
11943
15
            { "Data", "dof.tep1.reject.data", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11944
11945
        /* TEP.2.1 */
11946
15
        { &hf_tep_2_1_domain,
11947
15
            { "Domain", "dof.2008.4.tep1.2.1.domain", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
11948
11949
15
        { &hf_tep_2_1_initiator_block,
11950
15
            { "Initiator Block", "dof.2008.4.tep1.2.1.initiator_block", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11951
11952
15
        { &hf_tep_2_1_ticket_confirmation,
11953
15
            { "Ticket Confirmation", "dof.2008.4.tep1.2.1.ticket_confirmation", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11954
11955
        /* TEP.2.2 */
11956
15
        { &hf_tep_2_2_initiator_ticket,
11957
15
            { "Initiator Ticket", "dof.2008.4.tep1.2.2.initiator_ticket", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11958
11959
15
        { &hf_tep_2_2_ticket_confirmation,
11960
15
            { "Ticket Confirmation", "dof.2008.4.tep1.2.2.ticket_confirmation", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11961
11962
15
        { &hf_tep_2_2_responder_initialization,
11963
15
            { "Responder Initialization", "dof.2008.4.tep1.2.2.responder_initialization", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11964
11965
15
        { &hf_tep_2_2_responder_block,
11966
15
            { "Responder Block", "dof.2008.4.tep1.2.2.responder_block", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11967
11968
15
        { &hf_tep_2_2_authenticator_initialization,
11969
15
            { "Authenticator Initialization", "dof.2008.4.tep1.2.2.authenticator_initialization", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11970
11971
        /* TEP.2.2.1 */
11972
15
        { &hf_tep_2_2_1_state_identifier,
11973
15
            { "State Identifier", "dof.2008.4.tep1.2.2.1.state_identifier", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
11974
11975
15
        { &hf_tep_2_2_1_initial_state,
11976
15
            { "Initial State", "dof.2008.4.tep1.2.2.1.initial_state", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
11977
11978
15
        { &hf_tep_session_key,
11979
15
            { "Session Key", "dof.session_key", FT_BYTES, SEP_COLON, NULL, 0x00, NULL, HFILL } },
11980
15
    };
11981
11982
15
    static int *ett[] =
11983
15
    {
11984
15
        &ett_tep_dsp,
11985
15
        &ett_tep_dsp_options,
11986
15
        &ett_tep,
11987
15
        &ett_tep_operation,
11988
11989
15
        &ett_tep_2_1_domain,
11990
15
        &ett_tep_2_1_initiator_block,
11991
11992
15
        &ett_tep_2_2_initiator_ticket,
11993
15
        &ett_tep_2_2_responder_initialization,
11994
15
        &ett_tep_2_2_responder_block,
11995
15
        &ett_tep_2_2_authenticator_initialization,
11996
11997
15
        &ett_tep_2_2_1_initial_state,
11998
15
    };
11999
12000
    /* module_t *tep_module;*/
12001
12002
    /* No Configuration options to register? */
12003
12004
15
    proto_tep = proto_register_protocol("DOF Ticket Exchange Protocol Version 1", "DOF.TEP1", "dof.tep1");
12005
12006
15
    proto_tep_dsp = proto_register_protocol("DOF Ticket Exchange Protocol DSP Options", "DOF.TEP1.DSP", "dof.tep1.dsp");
12007
12008
15
    proto_register_field_array(proto_tep, hf, array_length(hf));
12009
15
    proto_register_field_array(proto_tep_dsp, hfdsp, array_length(hfdsp));
12010
15
    proto_register_subtree_array(ett, array_length(ett));
12011
12012
    /* tep_module = prefs_register_protocol( proto_tep, NULL );*/
12013
15
}
12014
12015
/**
12016
 * The registration hand-off routine
12017
 */
12018
static void dof_reg_handoff_tep_128(void)
12019
15
{
12020
15
    dissector_handle_t tep_handle = create_dissector_handle(dissect_tep, proto_tep);
12021
15
    dissector_handle_t dsp_handle = create_dissector_handle(dissect_tep_dsp, proto_tep_dsp);
12022
12023
15
    dissector_add_uint("dof.app", DOF_PROTOCOL_TEP, tep_handle);
12024
15
    dissector_add_uint("dof.dsp.options", DSP_TEP_FAMILY | DOF_PROTOCOL_TEP, dsp_handle);
12025
15
}
12026
12027
static void dof_tep_register(void)
12028
15
{
12029
15
    dof_register_tep_128();
12030
15
}
12031
12032
static void dof_tep_handoff(void)
12033
15
{
12034
15
    dof_reg_handoff_tep_128();
12035
15
}
12036
12037
/* TRP Registration Support */
12038
12039
static void dof_trp_reset(void)
12040
15
{
12041
15
}
12042
12043
static void dof_trp_cleanup(void)
12044
0
{
12045
0
}
12046
12047
static void dof_register_trp_129(void)
12048
15
{
12049
15
    expert_module_t *expert_trp;
12050
12051
15
    static hf_register_info hfdsp[] =
12052
15
    {
12053
15
        { &hf_trp_dsp_option,
12054
15
            { "Ticket Request Protocol", "dof.trp.dsp_opt", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12055
15
    };
12056
12057
15
    static hf_register_info hf[] =
12058
15
    {
12059
15
        { &hf_trp_opcode,
12060
15
            { "Opcode", "dof.trp.opcode", FT_UINT8, BASE_DEC, VALS(trp_opcode_strings), 0x0, NULL, HFILL } },
12061
12062
15
        { &hf_domain,
12063
15
            { "Domain", "dof.trp.domain", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12064
12065
15
        { &hf_identity_resolution,
12066
15
            { "Identity Resolution", "dof.trp.identity_resolution", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12067
12068
15
        { &hf_initiator_request,
12069
15
            { "Initiator Request", "dof.trp.initiator_request", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12070
12071
15
        { &hf_responder_request,
12072
15
            { "Responder Request", "dof.trp.responder_request", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12073
12074
15
        { &hf_initiator_ticket,
12075
15
            { "Initiator Ticket", "dof.trp.initiator_ticket", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12076
12077
15
        { &hf_responder_ticket,
12078
15
            { "Responder Ticket", "dof.trp.responder_ticket", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12079
12080
15
        { &hf_authentication_block,
12081
15
            { "Authentication Block", "dof.trp.authentication_block", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12082
12083
15
        { &hf_group_identifier,
12084
15
            { "Group Identifier", "dof.trp.group_identifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12085
12086
15
        { &hf_node_identifier,
12087
15
            { "Node Identifier", "dof.trp.node_identifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12088
12089
15
        { &hf_thb,
12090
15
            { "Thb", "dof.trp.thb", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
12091
12092
15
        { &hf_tmin,
12093
15
            { "Tmin", "dof.trp.tmin", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
12094
12095
15
        { &hf_tmax,
12096
15
            { "Tmax", "dof.trp.tmax", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
12097
12098
15
        { &hf_trp_epoch,
12099
15
            { "Epoch", "dof.trp.epoch", FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL } },
12100
12101
15
        { &hf_sidg,
12102
15
            { "SIDg", "dof.trp.sid_g", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12103
12104
15
        { &hf_security_scope,
12105
15
            { "Security Scope", "dof.trp.security_scope", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12106
12107
15
        { &hf_security_mode,
12108
15
            { "Security Mode", "dof.trp.security_mode", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12109
12110
15
        { &hf_ssid,
12111
15
            { "SSID", "dof.trp.ssid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
12112
12113
#if 0 /* not used yet */
12114
        { &hf_initiator_pg,
12115
            { "Initiator Permissions", "dof.trp.initiator_pg", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12116
#endif
12117
12118
15
        { &hf_initiator_validation,
12119
15
            { "Initiator Validation", "dof.trp.initiator_validation", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12120
12121
15
        { &hf_responder_pg,
12122
15
            { "Responder Permissions", "dof.trp.responder_pg", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12123
12124
15
        { &hf_responder_validation,
12125
15
            { "Responder Validation", "dof.trp.responder_validation", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12126
12127
15
        { &hf_trp_errorcode,
12128
15
            { "Error Code", "dof.trp.errorcode", FT_UINT8, BASE_DEC, VALS(trp_error_strings), 0x0, NULL, HFILL } },
12129
12130
15
        { &hf_trp_duration,
12131
15
            { "Duration", "dof.trp.duration", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
12132
12133
#if 0 /* not used yet */
12134
        { &hf_trp_rnonce,
12135
            { "Requestor Nonce", "dof.trp.rnonce", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12136
12137
        { &hf_trp_pnonce,
12138
            { "Provider Nonce", "dof.trp.pnonce", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12139
12140
        { &hf_trp_reqid,
12141
            { "Requestor ID", "dof.trp.reqid", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12142
12143
        { &hf_trp_provid,
12144
            { "Provider ID", "dof.trp.provid", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12145
12146
        { &hf_trp_perm_count,
12147
            { "Permission Count", "dof.trp.perm.count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
12148
12149
        { &hf_trp_perm_type,
12150
            { "Permission Type", "dof.trp.perm.type", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
12151
12152
        { &hf_trp_perm_rflags,
12153
            { "Requestor SRP Flags", "dof.trp.rflags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
12154
12155
        { &hf_trp_perm_rcache,
12156
            { "Requestor SRP Cache", "dof.trp.rcache", FT_BOOLEAN, 8, NULL, 0x2, NULL, HFILL } },
12157
12158
        { &hf_trp_perm_rsrp,
12159
            { "Requestor SRP", "dof.trp.rsrp", FT_BOOLEAN, 8, NULL, 0x1, NULL, HFILL } },
12160
12161
        { &hf_trp_perm_rsrp_a,
12162
            { "Requestor SRP A", "dof.trp.rsrp.a", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12163
12164
        { &hf_trp_perm_rsrp_u,
12165
            { "Requestor SRP u", "dof.trp.rsrp.u", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12166
12167
        { &hf_trp_perm_pflags,
12168
            { "Provider SRP Flags", "dof.trp.pflags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
12169
12170
        { &hf_trp_perm_pcache,
12171
            { "Provider SRP Cache", "dof.trp.pcache", FT_BOOLEAN, 8, NULL, 0x2, NULL, HFILL } },
12172
12173
        { &hf_trp_perm_psrp,
12174
            { "Provider SRP", "dof.trp.psrp", FT_BOOLEAN, 8, NULL, 0x1, NULL, HFILL } },
12175
12176
        { &hf_trp_perm_psrp_a,
12177
            { "Provider SRP A", "dof.trp.psrp.a", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12178
12179
        { &hf_trp_perm_psrp_u,
12180
            { "Provider SRP u", "dof.trp.psrp.u", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12181
12182
        { &hf_trp_perm_psrp_b,
12183
            { "Provider SRP B", "dof.trp.psrp.b", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12184
12185
        { &hf_trp_perm_psrp_s,
12186
            { "Provider SRP S", "dof.trp.psrp.s", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12187
12188
        { &hf_trp_confirmation,
12189
            { "Confirmation", "dof.trp.confirmation", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12190
12191
        { &hf_trp_perm_pke,
12192
            { "Provider Key Expression", "dof.trp.pke", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12193
12194
        { &hf_trp_perm_pka,
12195
            { "Provider Key Authenticator", "dof.trp.pka", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12196
#endif
12197
15
    };
12198
12199
15
    static int *ett[] =
12200
15
    {
12201
15
        &ett_trp_dsp,
12202
15
        &ett_trp,
12203
15
        &ett_domain,
12204
15
        &ett_identity_resolution,
12205
15
        &ett_initiator_request,
12206
15
        &ett_initiator_ticket,
12207
15
        &ett_responder_request,
12208
15
        &ett_responder_ticket,
12209
15
        &ett_authentication_block,
12210
15
        &ett_group_identifier,
12211
15
        &ett_node_identifier,
12212
15
        &ett_sidg,
12213
15
        &ett_security_scope,
12214
15
        &ett_security_mode,
12215
15
        &ett_initiator_pg,
12216
15
        &ett_initiator_validation,
12217
15
        &ett_responder_pg,
12218
15
        &ett_responder_validation,
12219
15
        &ett_trp_permset,
12220
15
        &ett_srp_flags,
12221
15
        &ett_trp_ticket,
12222
15
    };
12223
12224
15
    static ei_register_info ei[] =
12225
15
    {
12226
15
        { &ei_trp_initiator_id_known, { "dof.trp.initiator_id_known", PI_PROTOCOL, PI_COMMENT, "Initiator identity known", EXPFILL } },
12227
15
        { &ei_trp_kek_discovered, { "dof.trp.kek_discovered", PI_PROTOCOL, PI_COMMENT, "KEK discovered", EXPFILL } },
12228
15
    };
12229
12230
    /* No Configuration options to register? */
12231
12232
15
    proto_trp = proto_register_protocol("DOF Ticket Request Protocol", "DOF.TRP", "dof.trp");
12233
12234
15
    proto_trp_dsp = proto_register_protocol("DOF Ticket Request Protocol DSP Options", "DOF.TRP.DSP", "dof.trp.dsp");
12235
12236
15
    proto_register_field_array(proto_trp, hf, array_length(hf));
12237
15
    proto_register_field_array(proto_trp_dsp, hfdsp, array_length(hfdsp));
12238
15
    proto_register_subtree_array(ett, array_length(ett));
12239
15
    expert_trp = expert_register_protocol(proto_trp);
12240
15
    expert_register_field_array(expert_trp, ei, array_length(ei));
12241
15
}
12242
12243
/**
12244
 * The registration hand-off routine
12245
 */
12246
static void dof_reg_handoff_trp_129(void)
12247
15
{
12248
15
    dissector_handle_t trp_handle = create_dissector_handle(dissect_trp, proto_trp);
12249
15
    dissector_handle_t dsp_handle = create_dissector_handle(dissect_trp_dsp, proto_trp_dsp);
12250
12251
15
    dissector_add_uint("dof.app", DOF_PROTOCOL_TRP, trp_handle);
12252
15
    dissector_add_uint("dof.dsp.options", DSP_TRP_FAMILY | DOF_PROTOCOL_TRP, dsp_handle);
12253
15
}
12254
12255
static void dof_trp_register(void)
12256
15
{
12257
15
    dof_register_trp_129();
12258
15
}
12259
12260
static void dof_trp_handoff(void)
12261
15
{
12262
15
    dof_reg_handoff_trp_129();
12263
15
}
12264
12265
/* Wireshark Dissector Registration Proper */
12266
12267
/**
12268
 * This is called only during reset (file load, reload, etc.).
12269
 */
12270
static void dof_reset_routine(void)
12271
15
{
12272
15
    dof_tun_reset();
12273
15
    dof_reset();
12274
15
    oid_reset();
12275
15
    dof_dnp_reset();
12276
15
    dof_dpp_reset();
12277
15
    app_reset();
12278
15
    dof_dsp_reset();
12279
15
    dof_ccm_reset();
12280
15
    dof_oap_reset();
12281
15
    dof_sgmp_reset();
12282
15
    dof_tep_reset();
12283
15
    dof_trp_reset();
12284
15
}
12285
12286
static void dof_cleanup_routine(void)
12287
0
{
12288
0
    dof_tun_cleanup();
12289
0
    dof_cleanup();
12290
0
    oid_cleanup();
12291
0
    dof_dnp_cleanup();
12292
0
    dof_dpp_cleanup();
12293
0
    app_cleanup();
12294
0
    dof_dsp_cleanup();
12295
0
    dof_ccm_cleanup();
12296
0
    dof_oap_cleanup();
12297
0
    dof_sgmp_cleanup();
12298
0
    dof_tep_cleanup();
12299
0
    dof_trp_cleanup();
12300
0
}
12301
12302
static void
12303
dof_shutdown_routine(void)
12304
0
{
12305
0
    unsigned i;
12306
12307
0
    for (i = 0; i < global_security.identity_data_count; i++) {
12308
0
        g_free(global_security.identity_data[i].identity);
12309
0
        g_free(global_security.identity_data[i].domain);
12310
0
        g_free(global_security.identity_data[i].secret);
12311
0
    }
12312
0
    g_free(global_security.identity_data);
12313
12314
0
    for (i = 0; i < global_security.group_data_count; i++) {
12315
0
        g_free(global_security.group_data[i].domain);
12316
0
        g_free(global_security.group_data[i].identity);
12317
0
        g_free(global_security.group_data[i].kek);
12318
0
    }
12319
12320
0
    if (addr_port_to_id)
12321
0
        g_hash_table_destroy(addr_port_to_id);
12322
0
    if (dpp_opid_to_packet_data)
12323
0
        g_hash_table_destroy(dpp_opid_to_packet_data);
12324
0
    if (node_key_to_sid_id)
12325
0
        g_hash_table_destroy(node_key_to_sid_id);
12326
0
    if (sid_buffer_to_sid_id)
12327
0
        g_hash_table_destroy(sid_buffer_to_sid_id);
12328
0
    if (sid_id_to_sid_buffer)
12329
0
        g_hash_table_destroy(sid_id_to_sid_buffer);
12330
0
}
12331
12332
/**
12333
 * This is the first entry point into the dissector, called on program launch.
12334
 */
12335
void proto_register_dof(void)
12336
15
{
12337
15
    dof_tun_register();
12338
15
    dof_register();
12339
15
    oid_register();
12340
15
    dof_dnp_register();
12341
15
    dof_dpp_register();
12342
15
    app_register();
12343
15
    dof_dsp_register();
12344
15
    dof_ccm_register();
12345
15
    dof_oap_register();
12346
15
    dof_sgmp_register();
12347
15
    dof_tep_register();
12348
15
    dof_trp_register();
12349
12350
15
    register_init_routine(&dof_reset_routine);
12351
15
    register_cleanup_routine(&dof_cleanup_routine);
12352
15
    register_shutdown_routine(&dof_shutdown_routine);
12353
15
}
12354
12355
/**
12356
 * This routine is called after initialization and whenever the preferences are changed.
12357
 */
12358
void proto_reg_handoff_dof(void)
12359
15
{
12360
15
    dof_tun_handoff();
12361
15
    dof_handoff();
12362
15
    oid_handoff();
12363
15
    dof_dnp_handoff();
12364
15
    dof_dpp_handoff();
12365
15
    app_handoff();
12366
15
    dof_dsp_handoff();
12367
15
    dof_ccm_handoff();
12368
15
    dof_oap_handoff();
12369
15
    dof_sgmp_handoff();
12370
15
    dof_tep_handoff();
12371
15
    dof_trp_handoff();
12372
15
}
12373
12374
/**
12375
 * Protocol-specific data attached to a conversation_t structure - protocol
12376
 * index and opaque pointer.
12377
 */
12378
typedef struct _dof_proto_data {
12379
    int     proto;
12380
    void    *proto_data;
12381
} dof_proto_data;
12382
12383
static int p_compare(const void *a, const void *b)
12384
0
{
12385
0
    const dof_proto_data *ap = (const dof_proto_data *)a;
12386
0
    const dof_proto_data *bp = (const dof_proto_data *)b;
12387
12388
0
    if (ap->proto > bp->proto)
12389
0
        return 1;
12390
0
    else if (ap->proto == bp->proto)
12391
0
        return 0;
12392
0
    else
12393
0
        return -1;
12394
0
}
12395
12396
#if 0 /* TODO not used yet */
12397
static void dof_session_add_proto_data(wmem_allocator_t* allocator, dof_session_data *session, int proto, void *proto_data)
12398
{
12399
    dof_proto_data *p1 = wmem_new0(allocator, dof_proto_data);
12400
12401
    p1->proto = proto;
12402
    p1->proto_data = proto_data;
12403
12404
    /* Add it to the list of items for this conversation. */
12405
12406
    session->data_list = g_slist_insert_sorted(session->data_list, (void * *)p1, p_compare);
12407
}
12408
12409
static void *dof_session_get_proto_data(dof_session_data *session, int proto)
12410
{
12411
    dof_proto_data temp, *p1;
12412
    GSList *item;
12413
12414
    temp.proto = proto;
12415
    temp.proto_data = NULL;
12416
12417
    item = g_slist_find_custom(session->data_list, (void * *)&temp,
12418
                               p_compare);
12419
12420
    if (item != NULL)
12421
    {
12422
        p1 = (dof_proto_data *)item->data;
12423
        return p1->proto_data;
12424
    }
12425
12426
    return NULL;
12427
}
12428
12429
static void dof_session_delete_proto_data(dof_session_data *session, int proto)
12430
{
12431
    dof_proto_data temp;
12432
    GSList *item;
12433
12434
    temp.proto = proto;
12435
    temp.proto_data = NULL;
12436
12437
    item = g_slist_find_custom(session->data_list, (void * *)&temp,
12438
                               p_compare);
12439
12440
    while (item)
12441
    {
12442
        session->data_list = g_slist_remove(session->data_list, item->data);
12443
        item = item->next;
12444
    }
12445
}
12446
#endif
12447
12448
static void dof_packet_add_proto_data(dof_packet_data *packet, int proto, void *proto_data)
12449
107
{
12450
107
    dof_proto_data *p1 = wmem_new0(wmem_file_scope(), dof_proto_data);
12451
12452
107
    p1->proto = proto;
12453
107
    p1->proto_data = proto_data;
12454
12455
    /* Add it to the list of items for this conversation. */
12456
12457
107
    wmem_list_insert_sorted(packet->data_list, (void * *)p1, p_compare);
12458
107
}
12459
12460
static void *dof_packet_get_proto_data(dof_packet_data *packet, int proto)
12461
236
{
12462
236
    dof_proto_data temp, *p1;
12463
236
    wmem_list_frame_t *item;
12464
12465
236
    temp.proto = proto;
12466
236
    temp.proto_data = NULL;
12467
12468
236
    item = wmem_list_find_custom(packet->data_list, (void * *)&temp,
12469
236
                               p_compare);
12470
12471
236
    if (item != NULL)
12472
0
    {
12473
0
        p1 = (dof_proto_data *)wmem_list_frame_data(item);
12474
0
        return p1->proto_data;
12475
0
    }
12476
12477
236
    return NULL;
12478
236
}
12479
12480
static int dof_dissect_pdu_as_field(dissector_t dissector, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, int item, int ett, void *result)
12481
1.84k
{
12482
1.84k
    int block_length;
12483
1.84k
    tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
12484
1.84k
    proto_tree *my_tree;
12485
1.84k
    proto_item *ti = proto_tree_add_item(tree, item, tvb, offset, -1, ENC_NA);
12486
1.84k
    my_tree = proto_item_add_subtree(ti, ett);
12487
1.84k
    block_length = dof_dissect_pdu(dissector, start, pinfo, my_tree, result);
12488
1.84k
    return offset + block_length;
12489
1.84k
}
12490
12491
static int dof_dissect_pdu(dissector_t dissector, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *result)
12492
1.84k
{
12493
1.84k
    int len = dissector(tvb, pinfo, tree, result);
12494
1.84k
    proto_item_set_len(proto_tree_get_parent(tree), len);
12495
12496
1.84k
    return len;
12497
1.84k
}
12498
12499
static int dof_dissect_dnp_length(tvbuff_t *tvb, packet_info *pinfo, uint8_t version, int *offset)
12500
0
{
12501
0
    dissector_handle_t dp;
12502
12503
0
    dp = dissector_get_uint_handle(dnp_framing_dissectors, version);
12504
0
    if (!dp)
12505
0
        return -1;
12506
12507
0
    return call_dissector_only(dp, tvb, pinfo, NULL, offset);
12508
0
}
12509
12510
/*
12511
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
12512
 *
12513
 * Local variables:
12514
 * c-basic-offset: 4
12515
 * tab-width: 8
12516
 * indent-tabs-mode: nil
12517
 * End:
12518
 *
12519
 * vi: set shiftwidth=4 tabstop=8 expandtab:
12520
 * :indentSize=4:tabSize=8:noTabs=true:
12521
 */