Coverage Report

Created: 2026-01-02 06:13

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