Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-pana.c
Line
Count
Source
1
/* packet-pana.c
2
 * Routines for Protocol for carrying Authentication for Network Access dissection
3
 * Copyright 2006, Peter Racz <racz@ifi.unizh.ch>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
/* This protocol implements PANA as of the IETF RFC 5191.
12
 * (Note: This dissector was updated to reflect
13
 * draft-ietf-pana-pana-18 which is a workitem of the ietf workgroup
14
 * internet area/pana. I believe draft-18 then became RFC 5191).
15
 */
16
17
#include "config.h"
18
19
#include <epan/packet.h>
20
#include <epan/conversation.h>
21
#include <epan/tfs.h>
22
23
#include <wsutil/array.h>
24
#include <wsutil/ws_padding_to.h>
25
26
void proto_register_pana(void);
27
void proto_reg_handoff_pana(void);
28
29
static dissector_handle_t pana_handle;
30
31
#if 0
32
#define PANA_UDP_PORT 3001
33
#endif
34
35
0
#define MIN_AVP_SIZE 8
36
37
15
#define PANA_FLAG_R 0x8000
38
15
#define PANA_FLAG_S 0x4000
39
15
#define PANA_FLAG_C 0x2000
40
15
#define PANA_FLAG_A 0x1000
41
15
#define PANA_FLAG_P 0x0800
42
15
#define PANA_FLAG_I 0x0400
43
#if 0
44
#define PANA_FLAG_RES6  0x0200
45
#define PANA_FLAG_RES7  0x0100
46
#define PANA_FLAG_RES8  0x0080
47
#define PANA_FLAG_RES9  0x0040
48
#define PANA_FLAG_RES10 0x0020
49
#define PANA_FLAG_RES11 0x0010
50
#define PANA_FLAG_RES12 0x0008
51
#define PANA_FLAG_RES13 0x0004
52
#define PANA_FLAG_RES14 0x0002
53
#define PANA_FLAG_RES15 0x0001
54
#endif
55
4
#define PANA_FLAG_RESERVED 0x03ff
56
57
15
#define PANA_AVP_FLAG_V 0x8000
58
#if 0
59
#define PANA_AVP_FLAG_RES1  0x4000
60
#define PANA_AVP_FLAG_RES2  0x2000
61
#define PANA_AVP_FLAG_RES3  0x1000
62
#define PANA_AVP_FLAG_RES4  0x0800
63
#define PANA_AVP_FLAG_RES5  0x0400
64
#define PANA_AVP_FLAG_RES6  0x0200
65
#define PANA_AVP_FLAG_RES7  0x0100
66
#define PANA_AVP_FLAG_RES8  0x0080
67
#define PANA_AVP_FLAG_RES9  0x0040
68
#define PANA_AVP_FLAG_RES10 0x0020
69
#define PANA_AVP_FLAG_RES11 0x0010
70
#define PANA_AVP_FLAG_RES12 0x0008
71
#define PANA_AVP_FLAG_RES13 0x0004
72
#define PANA_AVP_FLAG_RES14 0x0002
73
#define PANA_AVP_FLAG_RES15 0x0001
74
#endif
75
0
#define PANA_AVP_FLAG_RESERVED 0x7fff
76
77
static dissector_handle_t eap_handle;
78
79
/* Initialize the protocol and registered fields */
80
static int proto_pana;
81
static int hf_pana_reserved_type;
82
static int hf_pana_length_type;
83
static int hf_pana_msg_type;
84
static int hf_pana_session_id;
85
static int hf_pana_seqnumber;
86
static int hf_pana_response_in;
87
static int hf_pana_response_to;
88
static int hf_pana_response_time;
89
90
static int hf_pana_flags;
91
static int hf_pana_flag_r;
92
static int hf_pana_flag_s;
93
static int hf_pana_flag_c;
94
static int hf_pana_flag_a;
95
static int hf_pana_flag_p;
96
static int hf_pana_flag_i;
97
static int hf_pana_avp_code;
98
static int hf_pana_avp_data_length;
99
static int hf_pana_avp_flags;
100
static int hf_pana_avp_flag_v;
101
static int hf_pana_avp_reserved;
102
static int hf_pana_avp_vendorid;
103
104
static int hf_pana_avp_data_uint64;
105
static int hf_pana_avp_data_int64;
106
static int hf_pana_avp_data_uint32;
107
static int hf_pana_avp_data_int32;
108
static int hf_pana_avp_data_bytes;
109
static int hf_pana_avp_data_string;
110
static int hf_pana_avp_data_enumerated;
111
112
2
#define MSG_TYPE_MAX 5
113
static const value_string msg_type_names[] = {
114
        { 1, "PANA-Client-Initiation" },
115
        { 2, "PANA-Auth" },
116
        { 3, "PANA-Termination" },
117
        { 4, "PANA-Notification" },
118
        { 5, "PANA-Relay" },
119
        { 0, NULL }
120
};
121
122
static const value_string msg_subtype_names[] = {
123
        { 0x0000, "Answer" },
124
        { 0x8000, "Request" },
125
        { 0, NULL }
126
};
127
128
0
#define AVP_CODE_MAX 13
129
static const value_string avp_code_names[] = {
130
        { 1, "AUTH AVP" },
131
        { 2, "EAP-Payload AVP" },
132
        { 3, "Integrity-Algorithm AVP" },
133
        { 4, "Key-Id AVP" },
134
        { 5, "Nonce AVP" },
135
        { 6, "PRF-Algorithm AVP" },
136
        { 7, "Result-Code" },
137
        { 8, "Session-Lifetime" },
138
        { 9, "Termination-Cause" },
139
        { 10, "PaC-Information" },
140
        { 11, "Relayed-Message" },
141
        { 12, "Encryption-Encap" },
142
        { 13, "Encryption-Algorithm" },
143
        { 0, NULL }
144
};
145
146
#if 0
147
static const value_string avp_resultcode_names[] = {
148
        { 0, "PANA_SUCCESS" },
149
        { 1, "PANA_AUTHENTICATION_REJECTED" },
150
        { 2, "PANA_AUTHORIZATION_REJECTED" },
151
        { 0, NULL }
152
};
153
#endif
154
155
typedef enum {
156
        PANA_OCTET_STRING = 1,
157
        PANA_INTEGER32,
158
        PANA_INTEGER64,
159
        PANA_UNSIGNED32,
160
        PANA_UNSIGNED64,
161
        PANA_FLOAT32,
162
        PANA_FLOAT64,
163
        PANA_FLOAT128,
164
        PANA_GROUPED,
165
        PANA_ENUMERATED,
166
        PANA_UTF8STRING,
167
        PANA_EAP,
168
        PANA_RESULT_CODE,
169
        PANA_ENCAPSULATED
170
} pana_avp_types;
171
172
static const value_string avp_type_names[]={
173
        { PANA_OCTET_STRING,    "OctetString" },
174
        { PANA_INTEGER32,       "Integer32" },
175
        { PANA_INTEGER64,       "Integer64" },
176
        { PANA_UNSIGNED32,      "Unsigned32" },
177
        { PANA_UNSIGNED64,      "Unsigned64" },
178
        { PANA_FLOAT32,         "Float32" },
179
        { PANA_FLOAT64,         "Float64" },
180
        { PANA_FLOAT128,        "Float128" },
181
        { PANA_GROUPED,         "Grouped" },
182
        { PANA_ENUMERATED,      "Enumerated" },
183
        { PANA_UTF8STRING,      "UTF8String" },
184
        { PANA_EAP,             "OctetString" },
185
        { PANA_RESULT_CODE,     "Unsigned32" },
186
        { PANA_ENCAPSULATED,    "Encapsulated" },
187
        { 0, NULL }
188
};
189
190
191
/* Initialize the subtree pointers */
192
static int ett_pana;
193
static int ett_pana_flags;
194
static int ett_pana_avp;
195
static int ett_pana_avp_info;
196
static int ett_pana_avp_flags;
197
198
199
typedef struct _pana_transaction_t {
200
        uint32_t req_frame;
201
        uint32_t rep_frame;
202
        nstime_t req_time;
203
} pana_transaction_t;
204
205
typedef struct _pana_conv_info_t {
206
        wmem_map_t *pdus;
207
} pana_conv_info_t;
208
209
static void
210
dissect_pana_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
211
212
/*
213
 * Function for the PANA flags dissector.
214
 */
215
static void
216
dissect_pana_flags(proto_tree *parent_tree, tvbuff_t *tvb, int offset, uint16_t flags)
217
0
{
218
0
        static int * const flag_fields[] = {
219
0
            &hf_pana_flag_r,
220
0
            &hf_pana_flag_s,
221
0
            &hf_pana_flag_c,
222
0
            &hf_pana_flag_a,
223
0
            &hf_pana_flag_p,
224
0
            &hf_pana_flag_i,
225
0
            NULL,
226
0
        };
227
228
0
        proto_tree_add_bitmask_value_with_flags(parent_tree, tvb, offset, hf_pana_flags,
229
0
                                                ett_pana_flags, flag_fields, flags, BMT_NO_TFS|BMT_NO_FALSE);
230
0
}
231
232
233
/*
234
 * Function for AVP flags dissector.
235
 */
236
static void
237
dissect_pana_avp_flags(proto_tree *parent_tree, tvbuff_t *tvb, int offset, uint16_t flags)
238
0
{
239
0
        static int * const flag_fields[] = {
240
0
            &hf_pana_avp_flag_v,
241
0
            NULL,
242
0
        };
243
244
0
        proto_tree_add_bitmask_value_with_flags(parent_tree, tvb, offset, hf_pana_avp_flags,
245
0
                                                ett_pana_avp_flags, flag_fields, flags, BMT_NO_TFS|BMT_NO_FALSE);
246
0
}
247
248
249
/*
250
 * Map AVP code to AVP type
251
 */
252
static pana_avp_types
253
pana_avp_get_type(uint16_t avp_code, uint32_t vendor_id)
254
0
{
255
256
0
        if(vendor_id == 0) {
257
0
                switch(avp_code) {
258
0
                        case 1:  return PANA_OCTET_STRING;       /* AUTH AVP */
259
0
                        case 2:  return PANA_EAP;                /* EAP-Payload AVP */
260
0
                        case 3:  return PANA_UNSIGNED32;         /* Integrity-Algorithm AVP */
261
0
                        case 4:  return PANA_INTEGER32;          /* Key-Id AVP */
262
0
                        case 5:  return PANA_OCTET_STRING;       /* Nonce AVP */
263
0
                        case 6:  return PANA_UNSIGNED32;         /* PRF-Algorithm AVP */
264
0
                        case 7:  return PANA_RESULT_CODE;        /* Result-Code AVP */
265
0
                        case 8:  return PANA_UNSIGNED32;         /* Session-Lifetime AVP */
266
0
                        case 9:  return PANA_ENUMERATED;         /* Termination-Cause AVP */
267
0
                        case 10: return PANA_OCTET_STRING;       /* PaC-Information AVP */
268
0
                        case 11: return PANA_ENCAPSULATED;       /* Relayed-Message AVP */
269
0
                        case 12: return PANA_OCTET_STRING;       /* Encryption-Encap AVP */
270
0
                        case 13: return PANA_UNSIGNED32;         /* Encryption-Algorithm AVP */
271
0
                        default: return PANA_OCTET_STRING;
272
0
                }
273
0
        } else {
274
0
                return PANA_OCTET_STRING;
275
0
        }
276
277
0
}
278
279
280
/*
281
 * Function for AVP dissector.
282
 */
283
static void
284
// NOLINTNEXTLINE(misc-no-recursion)
285
dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
286
0
{
287
288
0
        int     offset;
289
0
        uint16_t avp_code;
290
0
        uint16_t avp_flags;
291
0
        uint32_t avp_length;
292
0
        uint16_t avp_type;
293
0
        uint32_t vendor_id;
294
0
        uint32_t avp_hdr_length;
295
0
        uint32_t avp_data_length, result_code;
296
0
        uint32_t padding;
297
298
0
        int32_t buffer_length;
299
300
0
        tvbuff_t   *group_tvb;
301
0
        tvbuff_t   *eap_tvb;
302
0
        tvbuff_t   *encap_tvb;
303
0
        proto_tree *single_avp_tree;
304
0
        proto_tree *avp_eap_tree;
305
0
        proto_tree *avp_encap_tree;
306
307
0
        offset = 0;
308
0
        buffer_length = tvb_reported_length(tvb);
309
310
        /* Go through all AVPs */
311
0
        while (buffer_length > 0) {
312
0
                avp_code        = tvb_get_ntohs(tvb, offset);
313
0
                avp_flags       = tvb_get_ntohs(tvb, offset + 2);
314
0
                avp_data_length = tvb_get_ntohs(tvb, offset + 4);
315
316
                /* Check AVP flags for vendor specific AVP */
317
0
                if (avp_flags & PANA_AVP_FLAG_V) {
318
0
                        vendor_id      = tvb_get_ntohl(tvb, 8);
319
0
                        avp_hdr_length = 12;
320
0
                } else {
321
0
                        vendor_id = 0;
322
0
                        avp_hdr_length = 8;
323
0
                }
324
325
0
                avp_length = avp_hdr_length + avp_data_length;
326
327
                /* Check AVP type */
328
0
                avp_type = pana_avp_get_type(avp_code, vendor_id);
329
330
331
                /* Check padding */
332
0
                padding = WS_PADDING_TO_4(avp_length);
333
334
0
                single_avp_tree = proto_tree_add_subtree_format(avp_tree, tvb, offset, avp_length + padding,
335
0
                                                                ett_pana_avp_info, NULL, "%s (%s) length: %d bytes (%d padded bytes)",
336
0
                                                                val_to_str(pinfo->pool, avp_code, avp_code_names, "Unknown (%d)"),
337
0
                                                                val_to_str(pinfo->pool, avp_type, avp_type_names, "Unknown (%d)"),
338
0
                                                                avp_length,
339
0
                                                                avp_length + padding);
340
341
                /* AVP Code */
342
0
                proto_tree_add_uint_format_value(single_avp_tree, hf_pana_avp_code, tvb,
343
0
                                                 offset, 2, avp_code, "%s (%u)",
344
0
                                                 val_to_str(pinfo->pool, avp_code, avp_code_names, "Unknown (%d)"),
345
0
                                                 avp_code);
346
0
                offset += 2;
347
348
                /* AVP Flags */
349
0
                dissect_pana_avp_flags(single_avp_tree, tvb, offset, avp_flags);
350
0
                offset += 2;
351
352
                /* AVP Length */
353
0
                proto_tree_add_item(single_avp_tree, hf_pana_avp_data_length, tvb, offset, 2, ENC_BIG_ENDIAN);
354
0
                offset += 2;
355
356
                /* Reserved */
357
0
                proto_tree_add_item(single_avp_tree, hf_pana_avp_reserved, tvb, offset, 2, ENC_NA);
358
0
                offset += 2;
359
360
0
                if (avp_flags & PANA_AVP_FLAG_V) {
361
                        /* Vendor ID */
362
0
                        proto_tree_add_item(single_avp_tree, hf_pana_avp_vendorid, tvb, offset, 4, ENC_BIG_ENDIAN);
363
0
                        offset += 4;
364
0
                }
365
0
                if (! (avp_flags & PANA_AVP_FLAG_V)) {
366
                        /* AVP Value */
367
0
                        switch(avp_type) {
368
0
                                case PANA_GROUPED: {
369
0
                                        proto_tree *avp_group_tree;
370
0
                                        avp_group_tree = proto_tree_add_subtree(single_avp_tree,
371
0
                                                                                tvb, offset, avp_data_length,
372
0
                                                                                ett_pana_avp, NULL, "Grouped AVP");
373
0
                                        group_tvb = tvb_new_subset_length(tvb, offset, avp_data_length);
374
                                        // We recurse here, but we'll run out of packet before we run out of stack.
375
0
                                        dissect_avps(group_tvb, pinfo, avp_group_tree);
376
0
                                        break;
377
0
                                }
378
0
                                case PANA_UTF8STRING: {
379
0
                                        proto_tree_add_item(single_avp_tree, hf_pana_avp_data_string, tvb,
380
0
                                                                     offset, avp_data_length, ENC_UTF_8);
381
0
                                        break;
382
0
                                }
383
0
                                case PANA_OCTET_STRING: {
384
0
                                        proto_tree_add_item(single_avp_tree, hf_pana_avp_data_bytes, tvb,
385
0
                                                            offset, avp_data_length, ENC_NA);
386
0
                                        break;
387
0
                                }
388
0
                                case PANA_INTEGER32: {
389
0
                                        proto_tree_add_item(single_avp_tree, hf_pana_avp_data_int32, tvb,
390
0
                                                            offset, 4, ENC_BIG_ENDIAN);
391
0
                                        break;
392
0
                                }
393
0
                                case PANA_UNSIGNED32: {
394
0
                                        proto_tree_add_item(single_avp_tree, hf_pana_avp_data_uint32, tvb,
395
0
                                                            offset, 4, ENC_BIG_ENDIAN);
396
0
                                        break;
397
0
                                }
398
0
                                case PANA_INTEGER64: {
399
0
                                        proto_tree_add_item(single_avp_tree, hf_pana_avp_data_int64, tvb,
400
0
                                                            offset, 8, ENC_BIG_ENDIAN);
401
0
                                        break;
402
0
                                }
403
0
                                case PANA_UNSIGNED64: {
404
0
                                        proto_tree_add_item(single_avp_tree, hf_pana_avp_data_uint64, tvb,
405
0
                                                            offset, 8, ENC_BIG_ENDIAN);
406
0
                                        break;
407
0
                                }
408
0
                                case PANA_ENUMERATED: {
409
0
                                        proto_tree_add_item(single_avp_tree, hf_pana_avp_data_enumerated, tvb,
410
0
                                                            offset, 4, ENC_BIG_ENDIAN);
411
0
                                        break;
412
0
                                }
413
0
                                case PANA_RESULT_CODE: {
414
0
                                        result_code = tvb_get_ntohl(tvb, offset);
415
0
                                        proto_tree_add_uint_format(single_avp_tree, hf_pana_avp_code, tvb, offset, avp_data_length,
416
0
                                                                   result_code, "Value: %d (%s)",
417
0
                                                                   result_code,
418
0
                                                                   val_to_str(pinfo->pool, result_code, avp_code_names, "Unknown (%d)"));
419
0
                                        break;
420
0
                                }
421
0
                                case PANA_EAP: {
422
0
                                        avp_eap_tree = proto_tree_add_subtree(single_avp_tree,
423
0
                                                                              tvb, offset, avp_data_length,
424
0
                                                                              ett_pana_avp, NULL, "AVP Value (EAP packet)");
425
0
                                        eap_tvb = tvb_new_subset_length(tvb, offset, avp_data_length);
426
0
                                        DISSECTOR_ASSERT_HINT(eap_handle, "EAP Dissector not available");
427
0
                                        call_dissector(eap_handle, eap_tvb, pinfo, avp_eap_tree);
428
0
                                        break;
429
0
                                }
430
0
                                case PANA_ENCAPSULATED: {
431
0
                                        avp_encap_tree = proto_tree_add_subtree(single_avp_tree,
432
0
                                                                                tvb, offset, avp_data_length,
433
0
                                                                                ett_pana_avp, NULL, "AVP Value (PANA packet)");
434
0
                                        encap_tvb = tvb_new_subset_length(tvb, offset, avp_data_length);
435
                                        // We recurse here, but we'll run out of packet before we run out of stack.
436
0
                                        dissect_pana_pdu(encap_tvb, pinfo, avp_encap_tree);
437
0
                                        break;
438
0
                                }
439
0
                        }
440
0
                }
441
0
                offset += avp_data_length + padding;
442
443
                /* Update the buffer length */
444
0
                buffer_length -=  avp_length + padding;
445
0
        }
446
447
0
}
448
449
450
/*
451
 * Function for the PANA PDU dissector.
452
 */
453
static void
454
// NOLINTNEXTLINE(misc-no-recursion)
455
dissect_pana_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
456
0
{
457
458
0
        proto_tree        *pana_tree = NULL;
459
0
        uint16_t           flags;
460
0
        uint16_t           msg_type;
461
0
        uint32_t           msg_length;
462
0
        uint32_t           avp_length;
463
0
        uint32_t           seq_num;
464
0
        conversation_t     *conversation;
465
0
        pana_conv_info_t   *pana_info;
466
0
        pana_transaction_t *pana_trans;
467
0
        unsigned offset = 0;
468
469
0
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "PANA");
470
0
        col_clear(pinfo->cinfo,   COL_INFO);
471
472
        /* Get message length, type and flags */
473
0
        msg_length = tvb_get_ntohs(tvb, 2);
474
0
        flags      = tvb_get_ntohs(tvb, 4);
475
0
        msg_type   = tvb_get_ntohs(tvb, 6);
476
0
        seq_num    = tvb_get_ntohl(tvb, 12);
477
0
        avp_length = msg_length - 16;
478
479
0
        col_add_fstr(pinfo->cinfo, COL_INFO, "Type %s-%s",
480
0
                     val_to_str(pinfo->pool, msg_type, msg_type_names, "Unknown (%d)"),
481
0
                     val_to_str(pinfo->pool, flags & PANA_FLAG_R, msg_subtype_names, "Unknown (%d)"));
482
483
        /* Make the protocol tree */
484
0
        if (tree) {
485
0
                proto_item *ti;
486
0
                ti = proto_tree_add_item(tree, proto_pana, tvb, 0, -1, ENC_NA);
487
0
                pana_tree = proto_item_add_subtree(ti, ett_pana);
488
0
        }
489
490
491
        /*
492
         * We need to track some state for this protocol on a per conversation
493
         * basis so we can do neat things like request/response tracking
494
         */
495
0
        conversation = find_or_create_conversation(pinfo);
496
497
        /*
498
         * Do we already have a state structure for this conv
499
         */
500
0
        pana_info = (pana_conv_info_t *)conversation_get_proto_data(conversation, proto_pana);
501
0
        if (!pana_info) {
502
                /* No.  Attach that information to the conversation, and add
503
                 * it to the list of information structures.
504
                 */
505
0
                pana_info = wmem_new(wmem_file_scope(), pana_conv_info_t);
506
0
                pana_info->pdus=wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
507
508
0
                conversation_add_proto_data(conversation, proto_pana, pana_info);
509
0
        }
510
511
0
        if(!pinfo->fd->visited){
512
0
                if(flags&PANA_FLAG_R){
513
                        /* This is a request */
514
0
                        pana_trans=wmem_new(wmem_file_scope(), pana_transaction_t);
515
0
                        pana_trans->req_frame=pinfo->num;
516
0
                        pana_trans->rep_frame=0;
517
0
                        pana_trans->req_time=pinfo->abs_ts;
518
0
                        wmem_map_insert(pana_info->pdus, GUINT_TO_POINTER(seq_num), (void *)pana_trans);
519
0
                } else {
520
0
                        pana_trans=(pana_transaction_t *)wmem_map_lookup(pana_info->pdus, GUINT_TO_POINTER(seq_num));
521
0
                        if(pana_trans){
522
0
                                pana_trans->rep_frame=pinfo->num;
523
0
                        }
524
0
                }
525
0
        } else {
526
0
                pana_trans=(pana_transaction_t *)wmem_map_lookup(pana_info->pdus, GUINT_TO_POINTER(seq_num));
527
0
        }
528
529
0
        if(!pana_trans){
530
                /* create a "fake" pana_trans structure */
531
0
                pana_trans=wmem_new(pinfo->pool, pana_transaction_t);
532
0
                pana_trans->req_frame=0;
533
0
                pana_trans->rep_frame=0;
534
0
                pana_trans->req_time=pinfo->abs_ts;
535
0
        }
536
537
        /* print state tracking in the tree */
538
0
        if(flags&PANA_FLAG_R){
539
                /* This is a request */
540
0
                if(pana_trans->rep_frame){
541
0
                        proto_item *it;
542
543
0
                        it=proto_tree_add_uint(pana_tree, hf_pana_response_in, tvb, 0, 0, pana_trans->rep_frame);
544
0
                        proto_item_set_generated(it);
545
0
                }
546
0
        } else {
547
                /* This is a reply */
548
0
                if(pana_trans->req_frame){
549
0
                        proto_item *it;
550
0
                        nstime_t ns;
551
552
0
                        it=proto_tree_add_uint(pana_tree, hf_pana_response_to, tvb, 0, 0, pana_trans->req_frame);
553
0
                        proto_item_set_generated(it);
554
555
0
                        nstime_delta(&ns, &pinfo->abs_ts, &pana_trans->req_time);
556
0
                        it=proto_tree_add_time(pana_tree, hf_pana_response_time, tvb, 0, 0, &ns);
557
0
                        proto_item_set_generated(it);
558
0
                }
559
0
        }
560
561
        /* Reserved field */
562
0
        proto_tree_add_item(pana_tree, hf_pana_reserved_type, tvb, offset, 2, ENC_NA);
563
0
        offset += 2;
564
565
        /* Length */
566
0
        proto_tree_add_item(pana_tree, hf_pana_length_type, tvb, offset, 2, ENC_BIG_ENDIAN);
567
0
        offset += 2;
568
569
        /* Flags */
570
0
        dissect_pana_flags(pana_tree, tvb, offset, flags);
571
0
        offset += 2;
572
573
        /* Message Type */
574
0
        proto_tree_add_uint_format_value(pana_tree, hf_pana_msg_type, tvb,
575
0
                                         offset, 2, msg_type, "%s-%s (%d)",
576
0
                                         val_to_str(pinfo->pool, msg_type, msg_type_names, "Unknown (%d)"),
577
0
                                         val_to_str(pinfo->pool, flags & PANA_FLAG_R, msg_subtype_names, "Unknown (%d)"),
578
0
                                         msg_type);
579
0
        offset += 2;
580
581
        /* Session ID */
582
0
        proto_tree_add_item(pana_tree, hf_pana_session_id, tvb, offset, 4, ENC_BIG_ENDIAN);
583
0
        offset += 4;
584
585
        /* Sequence Number */
586
0
        proto_tree_add_item(pana_tree, hf_pana_seqnumber, tvb, offset, 4, ENC_BIG_ENDIAN);
587
0
        offset += 4;
588
589
        /* AVPs */
590
0
        if(avp_length != 0){
591
0
                tvbuff_t   *avp_tvb;
592
0
                proto_tree *avp_tree;
593
0
                avp_tvb  = tvb_new_subset_length(tvb, offset, avp_length);
594
0
                avp_tree = proto_tree_add_subtree(pana_tree, tvb, offset, avp_length, ett_pana_avp, NULL, "Attribute Value Pairs");
595
596
0
                dissect_avps(avp_tvb, pinfo, avp_tree);
597
0
        }
598
599
0
}
600
601
602
/*
603
 * Function for the PANA dissector.
604
 *
605
 * Called directly as a non-heuristic dissecotr or called by the heuristic
606
 * dissector.
607
 */
608
static int
609
dissect_pana(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
610
1.43k
{
611
612
1.43k
        uint16_t pana_res;
613
1.43k
        uint32_t msg_length;
614
1.43k
        uint16_t flags;
615
1.43k
        uint32_t buffer_length;
616
1.43k
        uint16_t msg_type;
617
1.43k
        uint32_t avp_length;
618
619
        /* Get actual buffer length */
620
1.43k
        buffer_length = tvb_captured_length(tvb);
621
622
        /* Check minimum buffer length */
623
1.43k
        if(buffer_length < 12) {
624
511
                return 0;
625
511
        }
626
627
        /* Check minimum packet length */
628
920
        msg_length = tvb_get_ntohs(tvb, 2);
629
920
        if(msg_length < 16) {
630
145
                return 0;
631
145
        }
632
633
        /* Check the packet length */
634
775
        if(msg_length != tvb_reported_length(tvb)) {
635
770
                return 0;
636
770
        }
637
638
        /* check that the reserved field is zero */
639
5
        pana_res   = tvb_get_ntohs(tvb, 0);
640
5
        if (pana_res != 0) {
641
1
                return 0;
642
1
        }
643
644
        /* verify that none of the reserved bits are set */
645
4
        flags      = tvb_get_ntohs(tvb, 4);
646
4
        if (flags & PANA_FLAG_RESERVED) {
647
2
                return 0;
648
2
        }
649
650
        /* verify that we recognize the message type */
651
2
        msg_type   = tvb_get_ntohs(tvb, 6);
652
2
        if ((msg_type > MSG_TYPE_MAX) || (msg_type == 0)) {
653
2
                return 0;
654
2
        }
655
656
0
        avp_length = msg_length - 16;
657
658
        /* For bug 1908: check the length of the first AVP, too */
659
660
0
        if (avp_length != 0) {
661
0
                uint32_t avp_offset;
662
0
                uint16_t avp_code;
663
0
                uint32_t first_avp_length;
664
0
                uint16_t avp_flags;
665
666
0
                if (avp_length < MIN_AVP_SIZE) {
667
0
                        return 0;
668
0
                }
669
0
                avp_offset = 16;
670
                /* Make sure no exceptions since we're just doing a preliminary heuristic check */
671
0
                if ((avp_offset + 8) > buffer_length ) {
672
0
                        return 0;
673
0
                }
674
0
                avp_code  = tvb_get_ntohs(tvb, avp_offset);
675
0
                if ((avp_code == 0) || (avp_code > AVP_CODE_MAX)) {
676
0
                        return 0;
677
0
                }
678
0
                avp_flags = tvb_get_ntohs(tvb, avp_offset + 2);
679
0
                if (avp_flags & PANA_AVP_FLAG_RESERVED) {
680
0
                        return 0;
681
0
                }
682
                /* check whether is the V (vendor) flag on or not */
683
0
                if (avp_flags & PANA_AVP_FLAG_V) {
684
0
                        first_avp_length = 12;
685
0
                } else {
686
0
                        first_avp_length = 8;
687
0
                }
688
689
0
                first_avp_length += tvb_get_ntohs(tvb, avp_offset + 4);
690
691
0
                if (first_avp_length > avp_length) {
692
0
                        return 0;
693
0
                }
694
0
        }
695
696
0
        dissect_pana_pdu(tvb, pinfo, tree);
697
698
0
        return tvb_reported_length(tvb);
699
700
0
}
701
702
static bool
703
dissect_pana_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
704
1.43k
{
705
1.43k
    return dissect_pana(tvb, pinfo, tree, data) != 0;
706
1.43k
}
707
708
/*
709
 * Register the protocol with Wireshark
710
 */
711
void
712
proto_register_pana(void)
713
15
{
714
715
15
        static hf_register_info hf[] = {
716
15
                { &hf_pana_response_in,
717
15
                  { "Response In", "pana.response_in",
718
15
                    FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
719
15
                    "The response to this PANA request is in this frame", HFILL }
720
15
                },
721
15
                { &hf_pana_response_to,
722
15
                  { "Request In", "pana.response_to",
723
15
                    FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
724
15
                    "This is a response to the PANA request in this frame", HFILL }
725
15
                },
726
15
                { &hf_pana_response_time,
727
15
                  { "Response Time", "pana.response_time",
728
15
                    FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
729
15
                    "The time between the Call and the Reply", HFILL }
730
15
                },
731
15
                { &hf_pana_reserved_type,
732
15
                  { "PANA Reserved", "pana.reserved",
733
15
                    FT_BYTES, BASE_NONE, NULL, 0x0,
734
15
                    NULL, HFILL }
735
15
                },
736
15
                { &hf_pana_length_type,
737
15
                  { "PANA Message Length", "pana.length",
738
15
                    FT_UINT16, BASE_DEC, NULL, 0x0,
739
15
                    NULL, HFILL }
740
15
                },
741
742
743
15
                { &hf_pana_flags,
744
15
                  { "Flags", "pana.flags",
745
15
                    FT_UINT8, BASE_HEX, NULL, 0x0,
746
15
                    NULL, HFILL }
747
15
                },
748
15
                { &hf_pana_flag_r,
749
15
                  { "Request", "pana.flags.r",
750
15
                    FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_R,
751
15
                    NULL, HFILL }
752
15
                },
753
15
                { &hf_pana_flag_s,
754
15
                  { "Start", "pana.flags.s",
755
15
                    FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_S,
756
15
                    NULL, HFILL }
757
15
                },
758
15
                { &hf_pana_flag_c,
759
15
                  { "Complete","pana.flags.c",
760
15
                    FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_C,
761
15
                    NULL, HFILL }
762
15
                },
763
15
                { &hf_pana_flag_a,
764
15
                  { "Auth","pana.flags.a",
765
15
                    FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_A,
766
15
                    NULL, HFILL }
767
15
                },
768
15
                { &hf_pana_flag_p,
769
15
                  { "Ping","pana.flags.p",
770
15
                    FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_P,
771
15
                    NULL, HFILL }
772
15
                },
773
15
                { &hf_pana_flag_i,
774
15
                  { "IP Reconfig","pana.flags.i",
775
15
                    FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_I,
776
15
                    NULL, HFILL }
777
15
                },
778
779
15
                { &hf_pana_msg_type,
780
15
                  { "PANA Message Type", "pana.type",
781
15
                    FT_UINT16, BASE_DEC, NULL, 0x0,
782
15
                    NULL, HFILL }
783
15
                },
784
15
                { &hf_pana_session_id,
785
15
                  { "PANA Session ID", "pana.sid",
786
15
                    FT_UINT32, BASE_HEX, NULL, 0x0,
787
15
                    NULL, HFILL }
788
15
                },
789
15
                { &hf_pana_seqnumber,
790
15
                  { "PANA Sequence Number", "pana.seq",
791
15
                    FT_UINT32, BASE_HEX, NULL, 0x0,
792
15
                    NULL, HFILL }
793
15
                },
794
795
796
15
                { &hf_pana_avp_code,
797
15
                  { "AVP Code", "pana.avp.code",
798
15
                    FT_UINT16, BASE_DEC, NULL, 0x0,
799
15
                    NULL, HFILL }
800
15
                },
801
15
                { &hf_pana_avp_data_length,
802
15
                  { "AVP Data Length", "pana.avp.data_length",
803
15
                    FT_UINT16, BASE_DEC, NULL, 0x0,
804
15
                    NULL, HFILL }
805
15
                },
806
15
                { &hf_pana_avp_flags,
807
15
                  { "AVP Flags", "pana.avp.flags",
808
15
                    FT_UINT16, BASE_HEX, NULL, 0x0,
809
15
                    NULL, HFILL }
810
15
                },
811
15
                { &hf_pana_avp_flag_v,
812
15
                  { "Vendor", "pana.avp.flags.v",
813
15
                    FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_AVP_FLAG_V,
814
15
                    NULL, HFILL }
815
15
                },
816
15
                { &hf_pana_avp_reserved,
817
15
                  { "AVP Reserved", "pana.avp.reserved",
818
15
                    FT_BYTES, BASE_NONE, NULL, 0x0,
819
15
                    NULL, HFILL }
820
15
                },
821
15
                { &hf_pana_avp_vendorid,
822
15
                  { "AVP Vendor ID", "pana.avp.vendorid",
823
15
                    FT_UINT32, BASE_HEX, NULL, 0x0,
824
15
                    NULL, HFILL }
825
15
                },
826
827
828
15
                { &hf_pana_avp_data_uint64,
829
15
                  { "Value", "pana.avp.data.uint64",
830
15
                    FT_UINT64, BASE_HEX, NULL, 0x0,
831
15
                    NULL, HFILL }
832
15
                },
833
15
                { &hf_pana_avp_data_int64,
834
15
                  { "Value", "pana.avp.data.int64",
835
15
                    FT_INT64, BASE_DEC, NULL, 0x0,
836
15
                    NULL, HFILL }
837
15
                },
838
15
                { &hf_pana_avp_data_uint32,
839
15
                  { "Value", "pana.avp.data.uint32",
840
15
                    FT_UINT32, BASE_HEX, NULL, 0x0,
841
15
                    NULL, HFILL }
842
15
                },
843
15
                { &hf_pana_avp_data_int32,
844
15
                  { "Value", "pana.avp.data.int32",
845
15
                    FT_INT32, BASE_DEC, NULL, 0x0,
846
15
                    NULL, HFILL }
847
15
                },
848
15
                { &hf_pana_avp_data_bytes,
849
15
                  { "Value", "pana.avp.data.bytes",
850
15
                    FT_BYTES, BASE_NONE, NULL, 0x0,
851
15
                    NULL, HFILL }
852
15
                },
853
15
                { &hf_pana_avp_data_string,
854
15
                  { "UTF8String", "pana.avp.data.string",
855
15
                    FT_STRING, BASE_NONE, NULL, 0x0,
856
15
                    NULL, HFILL }
857
15
                },
858
15
                { &hf_pana_avp_data_enumerated,
859
15
                  { "Value", "pana.avp.data.enum",
860
15
                    FT_INT32, BASE_DEC, NULL, 0x0,
861
15
                    NULL, HFILL }
862
15
                }
863
864
15
        };
865
866
        /* Setup protocol subtree array */
867
15
        static int *ett[] = {
868
15
                &ett_pana,
869
15
                &ett_pana_flags,
870
15
                &ett_pana_avp,
871
15
                &ett_pana_avp_info,
872
15
                &ett_pana_avp_flags
873
15
        };
874
875
        /* Register the protocol name and description */
876
15
        proto_pana = proto_register_protocol("Protocol for carrying Authentication for Network Access", "PANA", "pana");
877
878
        /* Required function calls to register the header fields and subtrees used */
879
15
        proto_register_field_array(proto_pana, hf, array_length(hf));
880
15
        proto_register_subtree_array(ett, array_length(ett));
881
882
        /* Register the dissector handle */
883
15
        pana_handle = register_dissector("pana", dissect_pana, proto_pana);
884
15
}
885
886
887
void
888
proto_reg_handoff_pana(void)
889
15
{
890
15
        heur_dissector_add("udp", dissect_pana_heur, "PANA over UDP", "pana_udp", proto_pana, HEURISTIC_ENABLE);
891
892
15
        dissector_add_for_decode_as_with_preference("udp.port", pana_handle);
893
894
15
        eap_handle = find_dissector_add_dependency("eap", proto_pana);
895
896
15
}
897
898
/*
899
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
900
 *
901
 * Local variables:
902
 * c-basic-offset: 8
903
 * tab-width: 8
904
 * indent-tabs-mode: nil
905
 * End:
906
 *
907
 * vi: set shiftwidth=8 tabstop=8 expandtab:
908
 * :indentSize=8:tabSize=8:noTabs=true:
909
 */