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