Define some fcns & vars as static...
[metze/wireshark/wip.git] / epan / dissectors / packet-diameter.c
1 /* packet-diameter.c
2  * Routines for Diameter packet disassembly
3  *
4  * $Id$
5  *
6  * Copyright (c) 2001 by David Frascone <dave@frascone.com>
7  * Copyright (c) 2007 by Luis E. Garcia Ontanon <luis@ontanon.org>
8  *
9  * Support for Request-Answer tracking and Tapping
10  * introduced by Abhik Sarkar
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  * References:
30  * 2004-03-11
31  * http://www.ietf.org/rfc/rfc3588.txt
32  * http://www.iana.org/assignments/radius-types
33  * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-cc-03.txt
34  * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-nasreq-14.txt
35  * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-mobileip-16.txt
36  * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-sip-app-01.txt
37  * http://www.ietf.org/html.charters/aaa-charter.html
38  * http://www.iana.org/assignments/address-family-numbers
39  * http://www.iana.org/assignments/enterprise-numbers
40  * http://www.iana.org/assignments/aaa-parameters
41 */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <errno.h>
51 #include <ctype.h>
52 #include <time.h>
53 #include <glib.h>
54 #include <epan/filesystem.h>
55 #include <epan/packet.h>
56 #include <epan/prefs.h>
57 #include <epan/sminmpec.h>
58 #include <epan/emem.h>
59 #include <epan/expert.h>
60 #include <epan/conversation.h>
61 #include <epan/tap.h>
62 #include <epan/diam_dict.h>
63 #include "packet-tcp.h"
64 #include "packet-ntp.h"
65 #include "packet-diameter.h"
66
67 #define SCTP_PORT_DIAMETER      3868
68
69 /* Diameter Header Flags */
70 /*                                      RPETrrrrCCCCCCCCCCCCCCCCCCCCCCCC  */
71 #define DIAM_FLAGS_R 0x80
72 #define DIAM_FLAGS_P 0x40
73 #define DIAM_FLAGS_E 0x20
74 #define DIAM_FLAGS_T 0x10
75 #define DIAM_FLAGS_RESERVED4 0x08
76 #define DIAM_FLAGS_RESERVED5 0x04
77 #define DIAM_FLAGS_RESERVED6 0x02
78 #define DIAM_FLAGS_RESERVED7 0x01
79 #define DIAM_FLAGS_RESERVED  0x0f
80
81 #define DIAM_LENGTH_MASK  0x00ffffffl
82 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
83 #define DIAM_GET_FLAGS(dh)                ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
84 #define DIAM_GET_VERSION(dh)              ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
85 #define DIAM_GET_COMMAND(dh)              (dh.flagsCmdCode & DIAM_COMMAND_MASK)
86 #define DIAM_GET_LENGTH(dh)               (dh.versionLength & DIAM_LENGTH_MASK)
87
88 /* Diameter AVP Flags */
89 #define AVP_FLAGS_P 0x20
90 #define AVP_FLAGS_V 0x80
91 #define AVP_FLAGS_M 0x40
92 #define AVP_FLAGS_RESERVED3 0x10
93 #define AVP_FLAGS_RESERVED4 0x08
94 #define AVP_FLAGS_RESERVED5 0x04
95 #define AVP_FLAGS_RESERVED6 0x02
96 #define AVP_FLAGS_RESERVED7 0x01
97 #define AVP_FLAGS_RESERVED 0x1f          /* 00011111  -- V M P X X X X X */
98
99 #define DIAMETER_V16 16
100 #define DIAMETER_RFC 1
101
102 typedef struct _diam_ctx_t {
103         proto_tree* tree;
104         packet_info* pinfo;
105         emem_tree_t* avps;
106         gboolean version_rfc;
107 } diam_ctx_t;
108
109 typedef struct _diam_avp_t diam_avp_t;
110 typedef struct _avp_type_t avp_type_t;
111
112 typedef const char* (*diam_avp_dissector_t)(diam_ctx_t*, diam_avp_t*, tvbuff_t*);
113
114
115 typedef struct _diam_vnd_t {
116         guint32 code;
117         GArray* vs_avps;
118         value_string_ext* vs_avps_ext;
119         GArray* vs_cmds;
120 } diam_vnd_t;
121
122 struct _diam_avp_t {
123         guint32 code;
124         const diam_vnd_t* vendor;
125         diam_avp_dissector_t dissector_v16;
126         diam_avp_dissector_t dissector_rfc;
127
128         gint ett;
129         int hf_value;
130         void* type_data;
131 };
132
133 #define VND_AVP_VS(v) ((value_string*)(void*)((v)->vs_avps->data))
134 #define VND_CMD_VS(v) ((value_string*)(void*)((v)->vs_cmds->data))
135
136 typedef struct _diam_dictionary_t {
137         emem_tree_t* avps;
138         emem_tree_t* vnds;
139         value_string* applications;
140         value_string* commands;
141 } diam_dictionary_t;
142
143 typedef diam_avp_t* (*avp_constructor_t)(const avp_type_t*, guint32, const diam_vnd_t*, const char*,  const value_string*, void*);
144
145 struct _avp_type_t {
146         const char* name;
147         diam_avp_dissector_t v16;
148         diam_avp_dissector_t rfc;
149         enum ftenum ft;
150         base_display_e base;
151         avp_constructor_t build;
152 };
153
154 struct _build_dict {
155         GArray* hf;
156         GPtrArray* ett;
157         GHashTable* types;
158         GHashTable* avps;
159 };
160
161
162 typedef struct _address_avp_t {
163         gint ett;
164         int hf_address_type;
165         int hf_ipv4;
166         int hf_ipv6;
167         int hf_other;
168 } address_avp_t;
169
170 typedef enum {
171         REASEMBLE_NEVER = 0,
172         REASEMBLE_AT_END,
173         REASEMBLE_BY_LENGTH
174 } avp_reassemble_mode_t;
175
176 typedef struct _proto_avp_t {
177         char* name;
178         dissector_handle_t handle;
179         avp_reassemble_mode_t reassemble_mode;
180 } proto_avp_t;
181
182 static const char* simple_avp(diam_ctx_t*, diam_avp_t*, tvbuff_t*);
183
184 static const value_string no_vs[] = {{0, NULL} };
185 static GArray no_garr = { (void*)no_vs, 1 };
186 static value_string_ext no_vs_avps_ext = { (value_string_match_t) match_strval_ext_init, 0, (void*)no_vs};
187 static diam_vnd_t unknown_vendor = { 0xffffffff, &no_garr, &no_vs_avps_ext,  &no_garr };
188 static diam_vnd_t no_vnd = { 0, NULL, NULL, NULL };
189 static diam_avp_t unknown_avp = {0, &unknown_vendor, simple_avp, simple_avp, -1, -1, NULL };
190 static GArray* all_cmds;
191 static diam_dictionary_t dictionary = { NULL, NULL, NULL, NULL };
192 static struct _build_dict build_dict;
193 static const value_string* vnd_short_vs;
194 static dissector_handle_t data_handle;
195 static dissector_handle_t eap_handle;
196
197 static const value_string diameter_avp_data_addrfamily_vals[]= {
198         {1,"IPv4"},
199         {2,"IPv6"},
200         {3,"NSAP"},
201         {4,"HDLC"},
202         {5,"BBN"},
203         {6,"IEEE-802"},
204         {7,"E-163"},
205         {8,"E-164"},
206         {9,"F-69"},
207         {10,"X-121"},
208         {11,"IPX"},
209         {12,"Appletalk"},
210         {13,"Decnet4"},
211         {14,"Vines"},
212         {15,"E-164-NSAP"},
213         {16,"DNS"},
214         {17,"DistinguishedName"},
215         {18,"AS"},
216         {19,"XTPoIPv4"},
217         {20,"XTPoIPv6"},
218         {21,"XTPNative"},
219         {22,"FibrePortName"},
220         {23,"FibreNodeName"},
221         {24,"GWID"},
222         {0,NULL}
223 };
224
225 static int proto_diameter = -1;
226 static int hf_diameter_length = -1;
227 static int hf_diameter_code = -1;
228 static int hf_diameter_hopbyhopid =-1;
229 static int hf_diameter_endtoendid =-1;
230 static int hf_diameter_version = -1;
231 static int hf_diameter_vendor_id = -1;
232 static int hf_diameter_application_id = -1;
233 static int hf_diameter_flags = -1;
234 static int hf_diameter_flags_request = -1;
235 static int hf_diameter_flags_proxyable = -1;
236 static int hf_diameter_flags_error = -1;
237 static int hf_diameter_flags_T          = -1;
238 static int hf_diameter_flags_reserved4 = -1;
239 static int hf_diameter_flags_reserved5 = -1;
240 static int hf_diameter_flags_reserved6 = -1;
241 static int hf_diameter_flags_reserved7 = -1;
242
243 static int hf_diameter_avp = -1;
244 static int hf_diameter_avp_len = -1;
245 static int hf_diameter_avp_code = -1;
246 static int hf_diameter_avp_flags = -1;
247 static int hf_diameter_avp_flags_vendor_specific = -1;
248 static int hf_diameter_avp_flags_mandatory = -1;
249 static int hf_diameter_avp_flags_protected = -1;
250 static int hf_diameter_avp_flags_reserved3 = -1;
251 static int hf_diameter_avp_flags_reserved4 = -1;
252 static int hf_diameter_avp_flags_reserved5 = -1;
253 static int hf_diameter_avp_flags_reserved6 = -1;
254 static int hf_diameter_avp_flags_reserved7 = -1;
255 static int hf_diameter_avp_vendor_id = -1;
256 static int hf_diameter_avp_data_wrong_length = -1;
257
258 static int hf_diameter_answer_in = -1;
259 static int hf_diameter_answer_to = -1;
260 static int hf_diameter_answer_time = -1;
261
262 static gint ett_diameter = -1;
263 static gint ett_diameter_flags = -1;
264 static gint ett_diameter_avp_flags = -1;
265 static gint ett_diameter_avpinfo = -1;
266 static gint ett_unknown = -1;
267 static gint ett_err = -1;
268
269 /* Tap for Diameter */
270 static int diameter_tap = -1;
271
272 /* For conversations */
273
274
275 static guint gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
276
277 static dissector_handle_t diameter_tcp_handle;
278 static range_t *global_diameter_tcp_port_range;
279 #define DEFAULT_DIAMETER_PORT_RANGE "3868"
280
281 /* desegmentation of Diameter over TCP */
282 static gboolean gbl_diameter_desegment = TRUE;
283
284 /* Dissector tables */
285 static dissector_table_t diameter_dissector_table;
286 static dissector_table_t diameter_3gpp_avp_dissector_table;
287 static dissector_table_t diameter_ericsson_avp_dissector_table;
288
289 static const char* avpflags_str[] = {
290         "---",
291         "--P",
292         "-M-",
293         "-MP",
294         "V--",
295         "V-P",
296         "VM-",
297         "VMP",
298 };
299
300 static gint
301 compare_avps (gconstpointer  a, gconstpointer  b)
302 {
303         value_string* vsa = (value_string*)a;
304         value_string* vsb = (value_string*)b;
305
306         if(vsa->value > vsb->value)
307                 return 1;
308         if(vsa->value < vsb->value)
309                 return -1;
310
311         return 0;
312 }
313
314 /* Special decoding of some AVP:s */
315
316 static int
317 dissect_diameter_vedor_id(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_)
318 {
319
320         int offset = 0;
321
322         proto_tree_add_item(tree, hf_diameter_vendor_id, tvb, 0, 4, FALSE);
323
324         offset++;
325         return offset;
326
327 }
328
329 static int
330 dissect_diameter_eap_payload(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_) {
331         gboolean save_writable;
332
333         /* Ensure the packet is displayed as Diameter, not EAP */
334         save_writable = col_get_writable(pinfo->cinfo);
335         col_set_writable(pinfo->cinfo, FALSE);
336
337         call_dissector(eap_handle, tvb, pinfo, tree);
338
339         col_set_writable(pinfo->cinfo, save_writable);
340         return tvb_length(tvb);
341 }
342
343 /* Dissect an AVP at offset */
344 static int
345 dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
346 {
347         guint32 code = tvb_get_ntohl(tvb,offset);
348         guint32 len = tvb_get_ntohl(tvb,offset+4);
349         guint32 vendor_flag = len & 0x80000000;
350         guint32 flags_bits_idx = (len & 0xE0000000) >> 29;
351         guint32 flags_bits = (len & 0xFF000000) >> 24;
352         guint32 vendorid = vendor_flag ? tvb_get_ntohl(tvb,offset+8) : 0 ;
353         emem_tree_key_t k[] = {
354                 {1,&code},
355                 {1,&vendorid},
356                 {0,NULL}
357         };
358         diam_avp_t* a = emem_tree_lookup32_array(dictionary.avps,k);
359         proto_item *pi, *avp_item;
360         proto_tree *avp_tree, *save_tree;
361         tvbuff_t* subtvb;
362         const diam_vnd_t* vendor;
363         value_string* vendor_avp_vs;
364         const char* code_str;
365         const char* avp_str;
366 #if 0
367         gint i = 0;
368 #endif
369         len &= 0x00ffffff;
370
371         if (!a) {
372                 a = &unknown_avp;
373
374                 if (vendor_flag) {
375                         if (! (vendor = emem_tree_lookup32(dictionary.vnds,vendorid) ))
376                                 vendor = &unknown_vendor;
377                 } else {
378                         vendor = &no_vnd;
379                 }
380         } else {
381                 vendor = a->vendor;
382         }
383
384         if(vendor->vs_avps_ext->vals == NULL){
385                 g_array_sort(vendor->vs_avps, compare_avps);
386                 /* Get dictionary of AVPs matching found vendor */
387                 vendor_avp_vs = VND_AVP_VS(vendor);
388                 vendor->vs_avps_ext->vals = vendor_avp_vs;
389 #if 0
390                 Debug code
391                 while(vendor_avp_vs[i].strptr!=NULL){
392                         g_warning("%u %s",vendor_avp_vs[i].value,vendor_avp_vs[i].strptr);
393                         i++;
394                 }
395 #endif
396         }else{
397                 /* Get dictionary of AVPs matching found vendor */
398                 vendor_avp_vs = VND_AVP_VS(vendor);
399         }
400
401         /* Add root of tree for this AVP */
402         avp_item = proto_tree_add_item(c->tree,hf_diameter_avp,tvb,offset,len,FALSE);
403         avp_tree = proto_item_add_subtree(avp_item,a->ett);
404
405         pi = proto_tree_add_item(avp_tree,hf_diameter_avp_code,tvb,offset,4,FALSE);
406         code_str = val_to_str_ext(code, vendor->vs_avps_ext, "Unknown");
407         proto_item_append_text(pi," %s", code_str);
408
409         /* Code */
410         if (a == &unknown_avp) {
411                 proto_tree* tu = proto_item_add_subtree(pi,ett_unknown);
412                 proto_item* iu = proto_tree_add_text(tu,tvb,offset,4,"Unknown AVP, "
413                                                      "if you know what this is you can add it to dictionary.xml");
414                 expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN,
415                                        "Unknown AVP %u (vendor=%s)", code,
416                                        val_to_str(vendorid, vnd_short_vs, "Unknown"));
417                 PROTO_ITEM_SET_GENERATED(iu);
418         }
419
420         offset += 4;
421
422         proto_item_set_text(avp_item,"AVP: %s(%u) l=%u f=%s", code_str, code, len, avpflags_str[flags_bits_idx]);
423
424         /* Flags */
425         pi = proto_tree_add_item(avp_tree,hf_diameter_avp_flags,tvb,offset,1,FALSE);
426         {
427                 proto_tree* flags_tree = proto_item_add_subtree(pi,ett_diameter_avp_flags);
428                 proto_tree_add_item(flags_tree,hf_diameter_avp_flags_vendor_specific,tvb,offset,1,FALSE);
429                 proto_tree_add_item(flags_tree,hf_diameter_avp_flags_mandatory,tvb,offset,1,FALSE);
430                 proto_tree_add_item(flags_tree,hf_diameter_avp_flags_protected,tvb,offset,1,FALSE);
431                 pi = proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved3,tvb,offset,1,FALSE);
432                 if(flags_bits & 0x10) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN);
433                 pi = proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved4,tvb,offset,1,FALSE);
434                 if(flags_bits & 0x08) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN);
435                 pi = proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved5,tvb,offset,1,FALSE);
436                 if(flags_bits & 0x04) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN);
437                 proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved6,tvb,offset,1,FALSE);
438                 if(flags_bits & 0x02) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN);
439                 proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved7,tvb,offset,1,FALSE);
440                 if(flags_bits & 0x01) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN);
441         }
442         offset += 1;
443
444         /* Length */
445         proto_tree_add_item(avp_tree,hf_diameter_avp_len,tvb,offset,3,FALSE);
446         offset += 3;
447
448         /* Vendor flag */
449         if (vendor_flag) {
450                 proto_item_append_text(avp_item," vnd=%s", val_to_str(vendorid, vnd_short_vs, "%d"));
451                 pi = proto_tree_add_item(avp_tree,hf_diameter_avp_vendor_id,tvb,offset,4,FALSE);
452                 if (vendor == &unknown_vendor) {
453                         proto_tree* tu = proto_item_add_subtree(pi,ett_unknown);
454                         proto_item* iu = proto_tree_add_text(tu,tvb,offset,4,"Unknown Vendor, "
455                                                              "if you know whose this is you can add it to dictionary.xml");
456                         expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, "Unknown Vendor");
457                         PROTO_ITEM_SET_GENERATED(iu);
458                 }
459                 offset += 4;
460         }
461
462         if ( len == (guint32)(vendor_flag ? 12 : 8) ) {
463                 /* Data is empty so return now */
464                 proto_item* iu = proto_tree_add_text(avp_tree,tvb,offset,0,"No data");
465                 expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, "Data is empty");
466                 PROTO_ITEM_SET_GENERATED(iu);
467                 return len;
468         }
469
470         subtvb = tvb_new_subset(tvb,offset,len-(8+(vendor_flag?4:0)),len-(8+(vendor_flag?4:0)));
471
472         save_tree = c->tree;
473         c->tree = avp_tree;
474         if (c->version_rfc) {
475                 avp_str = a->dissector_rfc(c,a,subtvb);
476         } else {
477                 avp_str = a->dissector_v16(c,a,subtvb);
478         }
479         c->tree = save_tree;
480
481         if (avp_str) proto_item_append_text(avp_item," val=%s", avp_str);
482
483         /* Call subdissectors for AVP:s */
484         switch (vendorid){
485         case 0:
486                 dissector_try_port(diameter_dissector_table, code, subtvb, c->pinfo, avp_tree);
487                 break;
488         case VENDOR_ERICSSON:
489                 dissector_try_port(diameter_ericsson_avp_dissector_table, code, subtvb, c->pinfo, avp_tree);
490                 break;
491         case VENDOR_THE3GPP:
492                 dissector_try_port(diameter_3gpp_avp_dissector_table, code, subtvb, c->pinfo, avp_tree);
493                 break;
494         default:
495                 break;
496         }
497         /* Debug
498         proto_tree_add_text(avp_tree, subtvb, 0, -1, "AVP %u data, Vendor Id %u ",code,vendorid);
499         */
500
501         return len;
502 }
503
504 static const char*
505 address_rfc_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
506 {
507         char* label = ep_alloc(ITEM_LABEL_LENGTH+1);
508         address_avp_t* t = a->type_data;
509         proto_item* pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),FALSE);
510         proto_tree* pt = proto_item_add_subtree(pi,t->ett);
511         guint32 addr_type = tvb_get_ntohs(tvb,0);
512         guint32 len = tvb_length_remaining(tvb,2);
513
514         proto_tree_add_item(pt,t->hf_address_type,tvb,0,2,FALSE);
515         switch (addr_type ) {
516                 case 1:
517                         if (len != 4) {
518                                 pi = proto_tree_add_text(pt,tvb,2,len,"Wrong length for IPv4 Address: %d instead of 4",len);
519                                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_WARN, "Wrong length for IPv4 Address");
520                                 return "[Malformed]";
521                         }
522                         pi = proto_tree_add_item(pt,t->hf_ipv4,tvb,2,4,FALSE);
523                         break;
524                 case 2:
525                         if (len != 16) {
526                                 pi = proto_tree_add_text(pt,tvb,2,len,"Wrong length for IPv6 Address: %d instead of 16",len);
527                                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_WARN, "Wrong length for IPv6 Address");
528                                 return "[Malformed]";
529                         }
530                         pi = proto_tree_add_item(pt,t->hf_ipv6,tvb,2,16,FALSE);
531                         break;
532                 default:
533                         pi = proto_tree_add_item(pt,t->hf_other,tvb,2,-1,FALSE);
534                         pt = proto_item_add_subtree(pi,t->ett);
535                         break;
536         }
537
538         proto_item_fill_label(PITEM_FINFO(pi), label);
539         label = strstr(label,": ")+2;
540         return label;
541 }
542
543 static const char*
544 proto_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
545 {
546         proto_avp_t* t = a->type_data;
547
548         col_set_writable(c->pinfo->cinfo, FALSE);
549
550         if (!t->handle) {
551                 t->handle = find_dissector(t->name);
552                 if(!t->handle) t->handle = data_handle;
553         }
554
555         call_dissector(t->handle, tvb, c->pinfo, c->tree);
556
557         return "";
558 }
559
560 static const char*
561 time_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
562 {
563         int len = tvb_length(tvb);
564         guint8 ntptime[8] = {0,0,0,0,0,0,0,0};
565         const char* label;
566         proto_item* pi;
567
568         if ( len != 4 ) {
569                 proto_item* pi_local = proto_tree_add_text(c->tree, tvb, 0, 4,
570                                                            "Error! AVP value MUST be 4 bytes");
571                 expert_add_info_format(c->pinfo, pi_local, PI_MALFORMED, PI_NOTE,
572                                        "Bad Timestamp Length (%u)", len);
573                 return "[Malformed]";
574         }
575
576         pi = proto_tree_add_item(c->tree, (a->hf_value), tvb, 0, 4, FALSE);
577         tvb_memcpy(tvb,ntptime,0,4);
578         label = ntp_fmt_ts(ntptime);
579         proto_item_append_text(pi,"  %s",label);
580         return label;
581 }
582
583 static const char*
584 address_v16_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
585 {
586         char* label = ep_alloc(ITEM_LABEL_LENGTH+1);
587         address_avp_t* t = a->type_data;
588         proto_item* pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),FALSE);
589         proto_tree* pt = proto_item_add_subtree(pi,t->ett);
590         guint32 len = tvb_length(tvb);
591
592         switch (len) {
593                 case 4:
594                         pi = proto_tree_add_item(pt,t->hf_ipv4,tvb,0,4,FALSE);
595                         break;
596                 case 16:
597                         pi = proto_tree_add_item(pt,t->hf_ipv6,tvb,0,16,FALSE);
598                         break;
599                 default:
600                         pi = proto_tree_add_item(pt,t->hf_other,tvb,0,len,FALSE);
601                         pt = proto_item_add_subtree(pi,t->ett);
602                         expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE,
603                                                "Bad Address Length (%u)", len);
604
605                         break;
606         }
607
608         proto_item_fill_label(PITEM_FINFO(pi), label);
609         label = strstr(label,": ")+2;
610         return label;
611 }
612
613 static const char*
614 simple_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
615 {
616         char* label = ep_alloc(ITEM_LABEL_LENGTH+1);
617         proto_item* pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),FALSE);
618         proto_item_fill_label(PITEM_FINFO(pi), label);
619         label = strstr(label,": ")+2;
620         return label;
621 }
622
623 static const char*
624 unsigned32_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
625 {
626         char* label = ep_alloc(ITEM_LABEL_LENGTH+1);
627         proto_item* pi;
628
629         /* Verify length before adding */
630         gint length = tvb_length_remaining(tvb,0);
631         if (length == 4) {
632                 pi= proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length_remaining(tvb,0),FALSE);
633                 proto_item_fill_label(PITEM_FINFO(pi), label);
634                 label = strstr(label,": ")+2;
635         }
636         else {
637                 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
638                                                  tvb, 0, length,
639                                                  tvb_get_ptr(tvb, 0, length),
640                                                 "Error!  Bad Integer32 Length");
641                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE,
642                                        "Bad Integer32 Length (%u)", length);
643                 PROTO_ITEM_SET_GENERATED(pi);
644         }
645         return label;
646 }
647
648 static const char*
649 grouped_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
650 {
651         int offset = 0;
652         int len = tvb_length(tvb);
653         proto_item* pi = proto_tree_add_item(c->tree, a->hf_value, tvb , 0 , -1, FALSE);
654         proto_tree* pt = c->tree;
655
656         c->tree = proto_item_add_subtree(pi,a->ett);
657
658         while (offset < len) {
659                 offset += dissect_diameter_avp(c, tvb, offset);
660                 offset +=  (offset % 4) ? 4 - (offset % 4) : 0 ;
661         }
662
663         c->tree = pt;
664
665         return NULL;
666 }
667
668 static const char* msgflags_str[] = {
669         "----", "---T", "--E-", "--ET",
670         "-P--", "-P-T", "-PE-", "-PET",
671         "R---", "R--T", "R-E-", "R-ET",
672         "RP--", "RP-T", "RPE-", "RPET"
673 };
674
675 static void
676 dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
677 {
678         guint32 first_word  = tvb_get_ntohl(tvb,0);
679         guint32 version = (first_word & 0xff000000) >> 24;
680         guint32 flags_bits = (tvb_get_ntohl(tvb,4) & 0xff000000) >> 24;
681         int packet_len = first_word & 0x00ffffff;
682         proto_item *pi, *cmd_item, *app_item, *version_item;
683         proto_tree* diam_tree;
684         diam_ctx_t* c = ep_alloc0(sizeof(diam_ctx_t));
685         int offset;
686         value_string* cmd_vs;
687         const char* cmd_str;
688         guint32 cmd = tvb_get_ntoh24(tvb,5);
689         guint32 fourth = tvb_get_ntohl(tvb,8);
690         guint32 hop_by_hop_id = 0;
691         conversation_t *conversation;
692         diameter_conv_info_t *diameter_conv_info;
693         diameter_req_ans_pair_t *diameter_pair;
694         proto_item *it;
695         nstime_t ns;
696
697         col_set_str(pinfo->cinfo, COL_PROTOCOL, "DIAMETER");
698
699         pi = proto_tree_add_item(tree,proto_diameter,tvb,0,-1,FALSE);
700         diam_tree = proto_item_add_subtree(pi,ett_diameter);
701
702         c->tree = diam_tree;
703         c->pinfo = pinfo;
704
705         version_item = proto_tree_add_item(diam_tree,hf_diameter_version,tvb,0,1,FALSE);
706         proto_tree_add_item(diam_tree,hf_diameter_length,tvb,1,3,FALSE);
707
708         pi = proto_tree_add_item(diam_tree,hf_diameter_flags,tvb,4,1,FALSE);
709         {
710                 proto_tree* pt = proto_item_add_subtree(pi,ett_diameter_flags);
711                 proto_tree_add_item(pt,hf_diameter_flags_request,tvb,4,1,FALSE);
712                 proto_tree_add_item(pt,hf_diameter_flags_proxyable,tvb,4,1,FALSE);
713                 proto_tree_add_item(pt,hf_diameter_flags_error,tvb,4,1,FALSE);
714                 proto_tree_add_item(pt,hf_diameter_flags_T,tvb,4,1,FALSE);
715                 proto_tree_add_item(pt,hf_diameter_flags_reserved4,tvb,4,1,FALSE);
716                 if(flags_bits & 0x08) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN);
717                 pi = proto_tree_add_item(pt,hf_diameter_flags_reserved5,tvb,4,1,FALSE);
718                 if(flags_bits & 0x04) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN);
719                 pi = proto_tree_add_item(pt,hf_diameter_flags_reserved6,tvb,4,1,FALSE);
720                 if(flags_bits & 0x02) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN);
721                 pi = proto_tree_add_item(pt,hf_diameter_flags_reserved7,tvb,4,1,FALSE);
722                 if(flags_bits & 0x01) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN);
723         }
724
725         cmd_item = proto_tree_add_item(diam_tree,hf_diameter_code,tvb,5,3,FALSE);
726
727         switch (version) {
728                 case DIAMETER_V16: {
729                         guint32 vendorid = tvb_get_ntohl(tvb,8);
730                         diam_vnd_t* vendor;
731
732                         if (! ( vendor = emem_tree_lookup32(dictionary.vnds,vendorid) ) ) {
733                                 vendor = &unknown_vendor;
734                         }
735
736                         cmd_vs = VND_CMD_VS(vendor);
737                         proto_tree_add_item(diam_tree, hf_diameter_vendor_id,tvb,8,4,FALSE);
738
739                         c->version_rfc = FALSE;
740                         break;
741                 }
742                 case DIAMETER_RFC: {
743                         cmd_vs = (value_string*)(void*)all_cmds->data;
744                         app_item = proto_tree_add_item(diam_tree, hf_diameter_application_id,tvb,8,4,FALSE);
745                         if (strcmp(val_to_str(tvb_get_ntohl(tvb, 8), dictionary.applications,
746                                                   "Unknown"), "Unknown") == 0) {
747                                 proto_tree* tu = proto_item_add_subtree(app_item,ett_unknown);
748                                 proto_item* iu = proto_tree_add_text(tu,tvb, 8 ,4,"Unknown Application Id, "
749                                                                      "if you know what this is you can add it to dictionary.xml");
750                                 expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN,
751                                                        "Unknown Application Id (%u)",
752                                                        tvb_get_ntohl(tvb, 8));
753                                 PROTO_ITEM_SET_GENERATED(iu);
754                         }
755
756
757                         c->version_rfc = TRUE;
758                         break;
759                 }
760                 default:
761                 {
762                         proto_tree* pt = proto_item_add_subtree(version_item,ett_err);
763                         proto_item* pi_local = proto_tree_add_text(pt,tvb,0,1,"Unknown Diameter Version (decoding as RFC 3588)");
764                         expert_add_info_format(pinfo, pi_local, PI_UNDECODED, PI_WARN, "Unknown Diameter Version");
765                         PROTO_ITEM_SET_GENERATED(pi);
766                         c->version_rfc = TRUE;
767                         cmd_vs = VND_CMD_VS(&no_vnd);
768                         break;
769                 }
770         }
771         cmd_str = val_to_str(cmd, cmd_vs, "Unknown");
772
773         col_add_fstr(pinfo->cinfo, COL_INFO,
774                          "cmd=%s%s(%d) flags=%s %s=%s(%d) h2h=%x e2e=%x",
775                          cmd_str,
776                          ((flags_bits>>4)&0x08) ? "Request" : "Answer",
777                          cmd,
778                          msgflags_str[((flags_bits>>4)&0x0f)],
779                          c->version_rfc ? "appl" : "vend",
780                          val_to_str(fourth, c->version_rfc ? dictionary.applications : vnd_short_vs, "Unknown"),
781                          fourth,
782                          tvb_get_ntohl(tvb,12),
783                          tvb_get_ntohl(tvb,16));
784
785         /* Append name to command item, warn if unknown */
786         proto_item_append_text(cmd_item," %s", cmd_str);
787         if (strcmp(cmd_str, "Unknown") == 0) {
788                 proto_tree* tu = proto_item_add_subtree(cmd_item,ett_unknown);
789                 proto_item* iu = proto_tree_add_text(tu,tvb, 5 ,3,"Unknown command, "
790                                                      "if you know what this is you can add it to dictionary.xml");
791                 expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, "Unknown command (%u)", cmd);
792                 PROTO_ITEM_SET_GENERATED(iu);
793         }
794
795
796         hop_by_hop_id = tvb_get_ntohl(tvb, 12);
797         proto_tree_add_item(diam_tree,hf_diameter_hopbyhopid,tvb,12,4,FALSE);
798         proto_tree_add_item(diam_tree,hf_diameter_endtoendid,tvb,16,4,FALSE);
799
800         /* Conversation tracking stuff */
801         /*
802          * FIXME: Looking at epan/conversation.c it seems unlike that this will work properly in
803          * multi-homed SCTP connections. This will probably need to be fixed at some point.
804          */
805
806         conversation = find_or_create_conversation(pinfo);
807
808         diameter_conv_info = conversation_get_proto_data(conversation, proto_diameter);
809         if (!diameter_conv_info) {
810                 diameter_conv_info =  se_alloc(sizeof(diameter_conv_info_t));
811                 diameter_conv_info->pdus = se_tree_create_non_persistent(
812                                         EMEM_TREE_TYPE_RED_BLACK, "diameter_pdus");
813
814                 conversation_add_proto_data(conversation, proto_diameter, diameter_conv_info);
815         }
816
817         if (!pinfo->fd->flags.visited) {
818                 if (flags_bits & 0x80) {
819                         /* This is a request */
820                         diameter_pair = se_alloc(sizeof(diameter_req_ans_pair_t));
821                         diameter_pair->hop_by_hop_id = hop_by_hop_id;
822                         diameter_pair->cmd_code = cmd;
823                         diameter_pair->result_code = 0;
824                         diameter_pair->cmd_str = cmd_str;
825                         diameter_pair->req_frame = pinfo->fd->num;
826                         diameter_pair->ans_frame = 0;
827                         diameter_pair->req_time = pinfo->fd->abs_ts;
828                         se_tree_insert32(diameter_conv_info->pdus, hop_by_hop_id, (void *)diameter_pair);
829                 } else {
830                         diameter_pair = se_tree_lookup32(diameter_conv_info->pdus, hop_by_hop_id);
831                         if (diameter_pair) {
832                                 diameter_pair->ans_frame = pinfo->fd->num;
833                         }
834                 }
835         } else {
836                 diameter_pair = se_tree_lookup32(diameter_conv_info->pdus, hop_by_hop_id);
837         }
838
839         if (!diameter_pair) {
840                 /* create a "fake" diameter_pair structure */
841                 diameter_pair = ep_alloc(sizeof(diameter_req_ans_pair_t));
842                 diameter_pair->hop_by_hop_id = hop_by_hop_id;
843                 diameter_pair->cmd_code = cmd;
844                 diameter_pair->result_code = 0;
845                 diameter_pair->cmd_str = cmd_str;
846                 diameter_pair->req_frame = 0;
847                 diameter_pair->ans_frame = 0;
848                 diameter_pair->req_time = pinfo->fd->abs_ts;
849         }
850         diameter_pair->processing_request=(flags_bits & 0x80)!=0;
851
852         if (!tree) return;
853
854         /* print state tracking info in the tree */
855         if (flags_bits & 0x80) {
856                 /* This is a request */
857                 if (diameter_pair->ans_frame) {
858                         it = proto_tree_add_uint(diam_tree, hf_diameter_answer_in,
859                                         tvb, 0, 0, diameter_pair->ans_frame);
860                         PROTO_ITEM_SET_GENERATED(it);
861                 }
862         } else {
863                 /* This is an answer */
864                 if (diameter_pair->req_frame) {
865                         it = proto_tree_add_uint(diam_tree, hf_diameter_answer_to,
866                                         tvb, 0, 0, diameter_pair->req_frame);
867                         PROTO_ITEM_SET_GENERATED(it);
868
869                         nstime_delta(&ns, &pinfo->fd->abs_ts, &diameter_pair->req_time);
870                         diameter_pair->srt_time = ns;
871                         it = proto_tree_add_time(diam_tree, hf_diameter_answer_time, tvb, 0, 0, &ns);
872                         PROTO_ITEM_SET_GENERATED(it);
873                         /* TODO: Populate result_code in tap record from AVP 268 */
874                 }
875         }
876
877         offset = 20;
878
879         /* Dissect AVPs until the end of the packet is reached */
880         while (offset < packet_len) {
881                 offset += dissect_diameter_avp(c, tvb, offset);
882
883                 /* Skip to next 4-byte boundary */
884                 offset +=  (offset % 4) ? 4 - (offset % 4) : 0 ;
885         }
886
887
888         /* Handle requests for which no answers were found and
889          * anawers for which no requests were found in the tap listener.
890          * In case if you don't need unpaired requests/answers use:
891          * if(diameter_pair->processing_request || !diameter_pair->req_frame)
892          *   return;
893          */
894         tap_queue_packet(diameter_tap, pinfo, diameter_pair);
895 }
896
897 static guint
898 get_diameter_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
899 {
900         /* Get the length of the Diameter packet. */
901         return tvb_get_ntoh24(tvb, offset + 1);
902 }
903
904 static gboolean
905 check_diameter(tvbuff_t *tvb)
906 {
907         if (tvb_length(tvb) < 1)
908                 return FALSE;   /* not enough bytes to check the version */
909
910         if (tvb_get_guint8(tvb, 0) != 1)
911                 return FALSE;   /* not version 1 */
912
913                   /*
914                    * XXX - fetch length and make sure it's at least MIN_DIAMETER_SIZE?
915                    * Fetch flags and check that none of the DIAM_FLAGS_RESERVED bits
916                    * are set?
917                    */
918         return TRUE;
919 }
920
921 /************************************************/
922 /* Main dissection function                     */
923 static int
924 dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
925 {
926         if (!check_diameter(tvb))
927                 return 0;
928         dissect_diameter_common(tvb, pinfo, tree);
929         return tvb_length(tvb);
930 }
931
932 static void
933 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
934 {
935         tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4,
936                          get_diameter_pdu_len, dissect_diameter_common);
937 } /* dissect_diameter_tcp */
938
939
940 static char*
941 alnumerize(char* name)
942 {
943         char* r = name;
944         char* w = name;
945         char c;
946
947         for (;(c = *r); r++) {
948                 if (isalnum((unsigned char)c) || c == '_' || c == '-' || c == '.') {
949                         *(w++) = c;
950                 }
951         }
952
953         *w = '\0';
954
955         return name;
956 }
957
958
959 static guint
960 reginfo(int* hf_ptr, const char* name, const char* abbr, const char* desc,
961         enum ftenum ft, base_display_e base, const value_string* vs,
962         guint32 mask)
963 {
964         hf_register_info hf = { hf_ptr, {
965                                 name ? g_strdup(name) : g_strdup(abbr),
966                                 g_strdup(abbr),
967                                 ft,
968                                 base,
969                                 VALS(vs),
970                                 mask,
971                                 g_strdup(desc),
972                                 HFILL }};
973
974         g_array_append_vals(build_dict.hf,&hf,1);
975         return build_dict.hf->len - 1;
976 }
977
978 static void
979 basic_avp_reginfo(diam_avp_t* a, const char* name, enum ftenum ft,
980                   base_display_e base, const value_string* vs)
981 {
982         hf_register_info hf[] = { { &(a->hf_value),
983                                   { NULL, NULL, ft, base, VALS(vs), 0x0,
984                                   a->vendor->code ?
985                                   g_strdup_printf("vendor=%d code=%d", a->vendor->code, a->code)
986                                   : g_strdup_printf("code=%d", a->code),
987                                   HFILL }}
988         };
989         gint* ettp = &(a->ett);
990
991         hf->hfinfo.name = g_strdup_printf("%s",name);
992         hf->hfinfo.abbrev = alnumerize(g_strdup_printf("diameter.%s",name));
993
994         g_array_append_vals(build_dict.hf,hf,1);
995         g_ptr_array_add(build_dict.ett,ettp);
996 }
997
998 static diam_avp_t*
999 build_address_avp(const avp_type_t* type _U_, guint32 code,
1000                   const diam_vnd_t* vendor, const char* name,
1001                   const value_string* vs _U_, void* data _U_)
1002 {
1003         diam_avp_t* a = g_malloc0(sizeof(diam_avp_t));
1004         address_avp_t* t = g_malloc(sizeof(address_avp_t));
1005         gint* ettp = &(t->ett);
1006
1007         a->code = code;
1008         a->vendor = vendor;
1009 /*
1010 It seems like the radius AVP:s 1-255 will use the defs from RADIUS in which case:
1011 http://www.ietf.org/rfc/rfc2865.txt?number=2865
1012 Address
1013
1014       The Address field is four octets.  The value 0xFFFFFFFF indicates
1015       that the NAS Should allow the user to select an address (e.g.
1016       Negotiated).  The value 0xFFFFFFFE indicates that the NAS should
1017       select an address for the user (e.g. Assigned from a pool of
1018       addresses kept by the NAS).  Other valid values indicate that the
1019       NAS should use that value as the user's IP address.
1020 Where as in Diameter:
1021 RFC3588
1022    Address
1023       The Address format is derived from the OctetString AVP Base
1024       Format.  It is a discriminated union, representing, for example a
1025       32-bit (IPv4) [IPV4] or 128-bit (IPv6) [IPV6] address, most
1026       significant octet first.  The first two octets of the Address
1027       AVP represents the AddressType, which contains an Address Family
1028       defined in [IANAADFAM].  The AddressType is used to discriminate
1029       the content and format of the remaining octets.
1030
1031 */
1032         a->dissector_v16 = address_v16_avp;
1033         if (code<256) {
1034                 a->dissector_rfc = address_v16_avp;
1035         } else {
1036                 a->dissector_rfc = address_rfc_avp;
1037         }
1038         a->ett = -1;
1039         a->hf_value = -1;
1040         a->type_data = t;
1041
1042         t->ett = -1;
1043         t->hf_address_type = -1;
1044         t->hf_ipv4 = -1;
1045         t->hf_ipv6 = -1;
1046         t->hf_other = -1;
1047
1048         basic_avp_reginfo(a,name,FT_BYTES,BASE_NONE,NULL);
1049
1050         reginfo(&(t->hf_address_type), ep_strdup_printf("%s Address Family",name),
1051                 alnumerize(ep_strdup_printf("diameter.%s.addr_family",name)),
1052                 NULL, FT_UINT16, BASE_DEC, diameter_avp_data_addrfamily_vals, 0);
1053
1054         reginfo(&(t->hf_ipv4), ep_strdup_printf("%s Address",name),
1055                 alnumerize(ep_strdup_printf("diameter.%s",name)),
1056                 NULL, FT_IPv4, BASE_NONE, NULL, 0);
1057
1058         reginfo(&(t->hf_ipv6), ep_strdup_printf("%s Address",name),
1059                 alnumerize(ep_strdup_printf("diameter.%s",name)),
1060                 NULL, FT_IPv6, BASE_NONE, NULL, 0);
1061
1062         reginfo(&(t->hf_other), ep_strdup_printf("%s Address",name),
1063                 alnumerize(ep_strdup_printf("diameter.%s",name)),
1064                 NULL, FT_BYTES, BASE_NONE, NULL, 0);
1065
1066         g_ptr_array_add(build_dict.ett,ettp);
1067
1068         return a;
1069 }
1070
1071 static diam_avp_t*
1072 build_proto_avp(const avp_type_t* type _U_, guint32 code,
1073                 const diam_vnd_t* vendor, const char* name _U_,
1074                 const value_string* vs _U_, void* data)
1075 {
1076         diam_avp_t* a = g_malloc0(sizeof(diam_avp_t));
1077         proto_avp_t* t = g_malloc0(sizeof(proto_avp_t));
1078         gint* ettp = &(a->ett);
1079
1080         a->code = code;
1081         a->vendor = vendor;
1082         a->dissector_v16 = proto_avp;
1083         a->dissector_rfc = proto_avp;
1084         a->ett = -1;
1085         a->hf_value = -2;
1086         a->type_data = t;
1087
1088         t->name = data;
1089         t->handle = NULL;
1090         t->reassemble_mode = 0;
1091
1092         g_ptr_array_add(build_dict.ett,ettp);
1093
1094         return a;
1095 }
1096
1097 static diam_avp_t*
1098 build_simple_avp(const avp_type_t* type, guint32 code, const diam_vnd_t* vendor,
1099                 const char* name, const value_string* vs, void* data _U_)
1100 {
1101         diam_avp_t* a;
1102
1103         /*
1104          * Only 32-bit or shorter integral types can have a list of values.
1105          */
1106         if (vs != NULL) {
1107                 switch (type->ft) {
1108
1109                 case FT_UINT8:
1110                 case FT_UINT16:
1111                 case FT_UINT32:
1112                 case FT_INT8:
1113                 case FT_INT16:
1114                 case FT_INT32:
1115                         break;
1116
1117                 default:
1118                         fprintf(stderr,"Diameter Dictionary: AVP %s has a list of values but isn't of a 32-bit or shorter integral type\n",
1119                                 name);
1120                         return NULL;
1121                 }
1122         }
1123
1124         a = g_malloc0(sizeof(diam_avp_t));
1125         a->code = code;
1126         a->vendor = vendor;
1127         a->dissector_v16 = type->v16;
1128         a->dissector_rfc = type->rfc;
1129         a->ett = -1;
1130         a->hf_value = -1;
1131
1132         basic_avp_reginfo(a,name,type->ft,type->base,vs);
1133
1134         return a;
1135 }
1136
1137
1138
1139 static const avp_type_t basic_types[] = {
1140         {"octetstring"                          , simple_avp    , simple_avp    , FT_BYTES                      , BASE_NONE     , build_simple_avp  },
1141         {"utf8string"                           , simple_avp    , simple_avp    , FT_STRING                     , BASE_NONE     , build_simple_avp  },
1142         {"grouped"                              , grouped_avp   , grouped_avp   , FT_BYTES                      , BASE_NONE     , build_simple_avp  },
1143         {"integer32"                            , simple_avp    , simple_avp    , FT_INT32                      , BASE_DEC      , build_simple_avp  },
1144         {"unsigned32"                           , unsigned32_avp, unsigned32_avp, FT_UINT32                     , BASE_DEC      , build_simple_avp  },
1145         {"integer64"                            , simple_avp    , simple_avp    , FT_INT64                      , BASE_DEC      , build_simple_avp  },
1146         {"unsigned64"                           , simple_avp    , simple_avp    , FT_UINT64                     , BASE_DEC      , build_simple_avp  },
1147         {"float32"                              , simple_avp    , simple_avp    , FT_FLOAT                      , BASE_NONE     , build_simple_avp  },
1148         {"float64"                              , simple_avp    , simple_avp    , FT_DOUBLE                     , BASE_NONE     , build_simple_avp  },
1149         {"ipaddress"                            ,  NULL         , NULL          , FT_NONE                       , BASE_NONE     , build_address_avp },
1150         {"diameteruri"                          , simple_avp    , simple_avp    , FT_STRING                     , BASE_NONE     , build_simple_avp  },
1151         {"diameteridentity"                     , simple_avp    , simple_avp    , FT_STRING                     , BASE_NONE     , build_simple_avp  },
1152         {"ipfilterrule"                         , simple_avp    , simple_avp    , FT_STRING                     , BASE_NONE     , build_simple_avp  },
1153         {"qosfilterrule"                        , simple_avp    , simple_avp    , FT_STRING                     , BASE_NONE     , build_simple_avp  },
1154         {"time"                                 , time_avp      , time_avp      , FT_UINT32                     , BASE_DEC      , build_simple_avp  },
1155         {NULL, NULL, NULL, FT_NONE, BASE_NONE, NULL }
1156 };
1157
1158
1159
1160 /*
1161  * This is like g_str_hash() (as of GLib 2.4.8), but it maps all
1162  * upper-case ASCII characters to their ASCII lower-case equivalents.
1163  * We can't use g_strdown(), as that doesn't do an ASCII mapping;
1164  * in Turkish locales, for example, there are two lower-case "i"s
1165  * and two upper-case "I"s, with and without dots - the ones with
1166  * dots map between each other, as do the ones without dots, so "I"
1167  * doesn't map to "i".
1168  */
1169 static guint
1170 strcase_hash(gconstpointer key)
1171 {
1172         const char *p = key;
1173         guint h = *p;
1174         char c;
1175
1176         if (h) {
1177                 if (h >= 'A' && h <= 'Z')
1178                         h = h - 'A' + 'a';
1179                 for (p += 1; *p != '\0'; p++) {
1180                         c = *p;
1181                         if (c >= 'A' && c <= 'Z')
1182                                 c = c - 'A' + 'a';
1183                         h = (h << 5) - h + c;
1184                 }
1185         }
1186
1187         return h;
1188 }
1189
1190 /*
1191  * Again, use g_ascii_strcasecmp(), not strcasecmp(), so that only ASCII
1192  * letters are mapped, and they're mapped to the lower-case ASCII
1193  * equivalents.
1194  */
1195 static gboolean
1196 strcase_equal(gconstpointer ka, gconstpointer kb)
1197 {
1198         const char* a = ka;
1199         const char* b = kb;
1200         return g_ascii_strcasecmp(a,b) == 0;
1201 }
1202
1203
1204 static int
1205 dictionary_load(void)
1206 {
1207         ddict_t* d;
1208         ddict_application_t* p;
1209         ddict_vendor_t* v;
1210         ddict_cmd_t* c;
1211         ddict_typedefn_t* t;
1212         ddict_avp_t* a;
1213         gboolean do_debug_parser = getenv("WIRESHARK_DEBUG_DIAM_DICT_PARSER") ? TRUE : FALSE;
1214         gboolean do_dump_dict = getenv("WIRESHARK_DUMP_DIAM_DICT") ? TRUE : FALSE;
1215         char* dir = ep_strdup_printf("%s" G_DIR_SEPARATOR_S "diameter" G_DIR_SEPARATOR_S, get_datafile_dir());
1216         const avp_type_t* type;
1217         const avp_type_t* octetstring = &basic_types[0];
1218         diam_avp_t* avp;
1219         GHashTable* vendors = g_hash_table_new(strcase_hash,strcase_equal);
1220         diam_vnd_t* vnd;
1221         GArray* vnd_shrt_arr = g_array_new(TRUE,TRUE,sizeof(value_string));
1222
1223         build_dict.hf = g_array_new(FALSE,TRUE,sizeof(hf_register_info));
1224         build_dict.ett = g_ptr_array_new();
1225         build_dict.types = g_hash_table_new(strcase_hash,strcase_equal);
1226         build_dict.avps = g_hash_table_new(strcase_hash,strcase_equal);
1227
1228         dictionary.vnds = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"diameter_vnds");
1229         dictionary.avps = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"diameter_avps");
1230
1231         no_vnd.vs_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
1232         no_vnd.vs_avps = g_array_new(TRUE,TRUE,sizeof(value_string));
1233         no_vnd.vs_avps_ext = g_malloc0(sizeof(value_string_ext));
1234         no_vnd.vs_avps_ext->match = (value_string_match_t) match_strval_ext_init;
1235         no_vnd.vs_avps_ext->length = 0;
1236
1237         all_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
1238
1239         pe_tree_insert32(dictionary.vnds,0,&no_vnd);
1240         g_hash_table_insert(vendors,(gchar *)"None",&no_vnd);
1241
1242         /* initialize the types hash with the known basic types */
1243         for (type = basic_types; type->name; type++) {
1244                 g_hash_table_insert(build_dict.types,(gchar *)type->name,(void*)type);
1245         }
1246
1247         /* load the dictionary */
1248         d = ddict_scan(dir,"dictionary.xml",do_debug_parser);
1249         if (d == NULL) {
1250                 return 0;
1251         }
1252
1253         if (do_dump_dict) ddict_print(stdout, d);
1254
1255         /* populate the types */
1256         for (t = d->typedefns; t; t = t->next) {
1257                 const avp_type_t* parent = NULL;
1258                 /* try to get the parent type */
1259
1260                 if (g_hash_table_lookup(build_dict.types,t->name))
1261                         continue;
1262
1263                 if (t->parent) {
1264                         parent = g_hash_table_lookup(build_dict.types,t->parent);
1265                 }
1266
1267                 if (!parent) parent = octetstring;
1268
1269                 /* insert the parent type for this type */
1270                 g_hash_table_insert(build_dict.types,t->name,(void*)parent);
1271         }
1272
1273         /* populate the applications */
1274         if ((p = d->applications)) {
1275                 GArray* arr = g_array_new(TRUE,TRUE,sizeof(value_string));
1276
1277                 for (; p; p = p->next) {
1278                         value_string item = {p->code,p->name};
1279                         g_array_append_val(arr,item);
1280                 }
1281
1282                 dictionary.applications = (void*)arr->data;
1283                 g_array_free(arr,FALSE);
1284         }
1285
1286         if ((v = d->vendors)) {
1287                 for ( ; v; v = v->next) {
1288                         value_string item = {v->code,v->name};
1289
1290                         if (g_hash_table_lookup(vendors,v->name))
1291                                 continue;
1292
1293                         g_array_append_val(vnd_shrt_arr,item);
1294
1295                         vnd = g_malloc(sizeof(diam_vnd_t));
1296                         vnd->code = v->code;
1297                         vnd->vs_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
1298                         vnd->vs_avps = g_array_new(TRUE,TRUE,sizeof(value_string));
1299                         vnd->vs_avps_ext = g_malloc0(sizeof(value_string_ext));
1300                         vnd->vs_avps_ext->match = (value_string_match_t) match_strval_ext_init;
1301                         vnd->vs_avps_ext->length= 0;
1302                         pe_tree_insert32(dictionary.vnds,vnd->code,vnd);
1303                         g_hash_table_insert(vendors,v->name,vnd);
1304                 }
1305         }
1306
1307         vnd_short_vs = (void*)vnd_shrt_arr->data;
1308         g_array_free(vnd_shrt_arr,FALSE);
1309
1310         if ((c = d->cmds)) {
1311                 for (; c; c = c->next) {
1312                         if ((vnd = g_hash_table_lookup(vendors,c->vendor))) {
1313                                 value_string item = {c->code,c->name};
1314                                 g_array_append_val(vnd->vs_cmds,item);
1315                                 /* Also add to all_cmds as used by RFC version */
1316                                 g_array_append_val(all_cmds,item);
1317                         } else {
1318                                 fprintf(stderr,"Diameter Dictionary: No Vendor: %s",c->vendor);
1319                         }
1320                 }
1321         }
1322
1323
1324         for (a = d->avps; a; a = a->next) {
1325                 ddict_enum_t* e;
1326                 value_string* vs = NULL;
1327                 const char* vend = a->vendor ? a->vendor : "None";
1328                 ddict_xmlpi_t* x;
1329                 void* avp_data = NULL;
1330
1331                 if ((vnd = g_hash_table_lookup(vendors,vend))) {
1332                         value_string vndvs = {a->code,a->name};
1333                         g_array_append_val(vnd->vs_avps,vndvs);
1334                         vnd->vs_avps_ext->length++;
1335                 } else {
1336                         fprintf(stderr,"Diameter Dictionary: No Vendor: %s",vend);
1337                         vnd = &unknown_vendor;
1338                 }
1339
1340                 if ((e = a->enums)) {
1341                         GArray* arr = g_array_new(TRUE,TRUE,sizeof(value_string));
1342
1343                         for (; e; e = e->next) {
1344                                 value_string item = {e->code,e->name};
1345                                 g_array_append_val(arr,item);
1346                         }
1347                         vs = (void*)arr->data;
1348                 }
1349
1350                 type = NULL;
1351
1352                 for( x = d->xmlpis; x; x = x->next ) {
1353                         if ( (strcase_equal(x->name,"avp-proto") && strcase_equal(x->key,a->name))
1354                                  || (a->type && strcase_equal(x->name,"type-proto") && strcase_equal(x->key,a->type))
1355                                  ) {
1356                                 static avp_type_t proto_type = {"proto", proto_avp, proto_avp, FT_UINT32, BASE_NONE, build_proto_avp};
1357                                 type =  &proto_type;
1358
1359                                 avp_data = x->value;
1360                                 break;
1361                         }
1362                 }
1363
1364                 if ( (!type) && a->type )
1365                         type = g_hash_table_lookup(build_dict.types,a->type);
1366
1367                 if (!type) type = octetstring;
1368
1369                 avp = type->build( type, a->code, vnd, a->name, vs, avp_data);
1370                 if (avp != NULL) {
1371                         g_hash_table_insert(build_dict.avps, a->name, avp);
1372
1373                         {
1374                                 emem_tree_key_t k[] = {
1375                                         { 1, &(a->code) },
1376                                         { 1, &(vnd->code) },
1377                                         { 0 , NULL }
1378                                 };
1379                                 pe_tree_insert32_array(dictionary.avps,k,avp);
1380                         }
1381                 }
1382         }
1383         g_hash_table_destroy(build_dict.types);
1384         g_hash_table_destroy(build_dict.avps);
1385         g_hash_table_destroy(vendors);
1386
1387         return 1;
1388 }
1389
1390 static void
1391 range_delete_callback(guint32 port)
1392 {
1393         dissector_delete("tcp.port", port, diameter_tcp_handle);
1394 }
1395
1396 static void
1397 range_add_callback(guint32 port)
1398 {
1399         dissector_add("tcp.port", port, diameter_tcp_handle);
1400 }
1401
1402 /* registration with the filtering engine */
1403
1404 void proto_reg_handoff_diameter(void);
1405
1406 void
1407 proto_register_diameter(void)
1408 {
1409         module_t *diameter_module;
1410         guint i, ett_length;
1411
1412         hf_register_info hf_base[] = {
1413         { &hf_diameter_version,
1414                   { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1415                           NULL, HFILL }},
1416         { &hf_diameter_length,
1417                   { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1418                           NULL, HFILL }},
1419         { &hf_diameter_flags,
1420                   { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1421                           NULL, HFILL }},
1422         { &hf_diameter_flags_request,
1423                   { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_R,
1424                           NULL, HFILL }},
1425         { &hf_diameter_flags_proxyable,
1426                   { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_P,
1427                           NULL, HFILL }},
1428         { &hf_diameter_flags_error,
1429                   { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_E,
1430                           NULL, HFILL }},
1431         { &hf_diameter_flags_T,
1432                   { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN, 8, TFS(&tfs_set_notset),DIAM_FLAGS_T,
1433                           NULL, HFILL }},
1434         { &hf_diameter_flags_reserved4,
1435                   { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1436                           DIAM_FLAGS_RESERVED4, NULL, HFILL }},
1437         { &hf_diameter_flags_reserved5,
1438                   { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1439                           DIAM_FLAGS_RESERVED5, NULL, HFILL }},
1440         { &hf_diameter_flags_reserved6,
1441                   { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1442                           DIAM_FLAGS_RESERVED6, NULL, HFILL }},
1443         { &hf_diameter_flags_reserved7,
1444                   { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1445                           DIAM_FLAGS_RESERVED7, NULL, HFILL }},
1446         { &hf_diameter_vendor_id,
1447                   { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC|BASE_EXT_STRING, &sminmpec_values_ext,
1448                           0x0,NULL, HFILL }},
1449         { &hf_diameter_application_id,
1450                   { "ApplicationId",    "diameter.applicationId", FT_UINT32, BASE_DEC, dictionary.applications,
1451                           0x0,NULL, HFILL }},
1452         { &hf_diameter_hopbyhopid,
1453                   { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1454                           BASE_HEX, NULL, 0x0, NULL, HFILL }},
1455         { &hf_diameter_endtoendid,
1456                   { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
1457                           BASE_HEX, NULL, 0x0, NULL, HFILL }},
1458         { &hf_diameter_avp,
1459                   { "AVP","diameter.avp", FT_BYTES, BASE_NONE,
1460                           NULL, 0x0, NULL, HFILL }},
1461         { &hf_diameter_avp_len,
1462                   { "AVP Length","diameter.avp.len", FT_UINT24, BASE_DEC,
1463                           NULL, 0x0, NULL, HFILL }},
1464         { &hf_diameter_avp_flags,
1465                   { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1466                           NULL, 0x0, NULL, HFILL }},
1467         { &hf_diameter_avp_flags_vendor_specific,
1468                   { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_V,
1469                           NULL, HFILL }},
1470         { &hf_diameter_avp_flags_mandatory,
1471                   { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_M,
1472                           NULL, HFILL }},
1473         { &hf_diameter_avp_flags_protected,
1474                   { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_P,
1475                           NULL, HFILL }},
1476         { &hf_diameter_avp_flags_reserved3,
1477                   { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1478                           AVP_FLAGS_RESERVED3,  NULL, HFILL }},
1479         { &hf_diameter_avp_flags_reserved4,
1480                   { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1481                           AVP_FLAGS_RESERVED4,  NULL, HFILL }},
1482         { &hf_diameter_avp_flags_reserved5,
1483                   { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1484                           AVP_FLAGS_RESERVED5,  NULL, HFILL }},
1485         { &hf_diameter_avp_flags_reserved6,
1486                   { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1487                           AVP_FLAGS_RESERVED6,  NULL, HFILL }},
1488         { &hf_diameter_avp_flags_reserved7,
1489                   { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1490                           AVP_FLAGS_RESERVED7,  NULL, HFILL }},
1491         { &hf_diameter_avp_vendor_id,
1492                   { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC|BASE_EXT_STRING,
1493                           &sminmpec_values_ext, 0x0, NULL, HFILL }},
1494         { &(unknown_avp.hf_value),
1495                   { "Value","diameter.avp.unknown", FT_BYTES, BASE_NONE,
1496                           NULL, 0x0, NULL, HFILL }},
1497         { &hf_diameter_avp_data_wrong_length,
1498                   { "Data","diameter.avp.invalid-data", FT_BYTES, BASE_NONE,
1499                     NULL, 0x0, NULL, HFILL }},
1500         { &hf_diameter_code,
1501                   { "Command Code", "diameter.cmd.code", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
1502         { &hf_diameter_avp_code,
1503                   { "AVP Code", "diameter.avp.code", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
1504         { &hf_diameter_answer_in,
1505                 { "Answer In", "diameter.answer_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1506                 "The answer to this diameter request is in this frame", HFILL }},
1507         { &hf_diameter_answer_to,
1508                 { "Request In", "diameter.answer_to", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1509                 "This is an answer to the diameter request in this frame", HFILL }},
1510         { &hf_diameter_answer_time,
1511                 { "Response Time", "diameter.resp_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1512                 "The time between the request and the answer", HFILL }},
1513
1514         };
1515
1516         gint *ett_base[] = {
1517                 &ett_diameter,
1518                 &ett_diameter_flags,
1519                 &ett_diameter_avp_flags,
1520                 &ett_diameter_avpinfo,
1521                 &ett_unknown,
1522                 &ett_err,
1523                 &(unknown_avp.ett)
1524         };
1525
1526         dictionary_load();
1527
1528         g_array_append_vals(build_dict.hf, hf_base, array_length(hf_base));
1529         ett_length = array_length(ett_base);
1530         for (i = 0; i < ett_length; i++)
1531         {
1532                 g_ptr_array_add(build_dict.ett, ett_base[i]);
1533         }
1534
1535         proto_diameter = proto_register_protocol ("Diameter Protocol", "DIAMETER", "diameter");
1536
1537         proto_register_field_array(proto_diameter, (hf_register_info*)(void*)build_dict.hf->data, build_dict.hf->len);
1538         proto_register_subtree_array((gint**)build_dict.ett->pdata, build_dict.ett->len);
1539
1540         g_array_free(build_dict.hf,FALSE);
1541         g_ptr_array_free(build_dict.ett,TRUE);
1542
1543         /* Allow dissector to find be found by name. */
1544         new_register_dissector("diameter", dissect_diameter, proto_diameter);
1545
1546         /* Register dissector table(s) to do sub dissection of AVP:s ( OctetStrings) */
1547         diameter_dissector_table = register_dissector_table("diameter.base", "DIAMETER_BASE_AVPS", FT_UINT32, BASE_DEC);
1548         diameter_3gpp_avp_dissector_table = register_dissector_table("diameter.3gpp", "DIAMETER_3GPP_AVPS", FT_UINT32, BASE_DEC);
1549         diameter_ericsson_avp_dissector_table = register_dissector_table("diameter.ericsson", "DIAMETER_ERICSSON_AVPS", FT_UINT32, BASE_DEC);
1550
1551         /* Set default TCP ports */
1552         range_convert_str(&global_diameter_tcp_port_range, DEFAULT_DIAMETER_PORT_RANGE, MAX_UDP_PORT);
1553
1554         /* Register configuration options for ports */
1555         diameter_module = prefs_register_protocol(proto_diameter,
1556                                                   proto_reg_handoff_diameter);
1557
1558         prefs_register_range_preference(diameter_module, "tcp.ports", "Diameter TCP ports",
1559                                         "TCP ports to be decoded as Diameter (default: "
1560                                         DEFAULT_DIAMETER_PORT_RANGE ")",
1561                                         &global_diameter_tcp_port_range, MAX_UDP_PORT);
1562
1563         prefs_register_uint_preference(diameter_module, "sctp.port",
1564                                        "Diameter SCTP Port",
1565                                        "Set the SCTP port for Diameter messages",
1566                                        10,
1567                                        &gbl_diameterSctpPort);
1568
1569         /* Desegmentation */
1570         prefs_register_bool_preference(diameter_module, "desegment",
1571                                        "Reassemble Diameter messages\nspanning multiple TCP segments",
1572                                        "Whether the Diameter dissector should reassemble messages spanning multiple TCP segments."
1573                                        " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1574                                        &gbl_diameter_desegment);
1575
1576         /*  Register some preferences we no longer support, so we can report
1577          *  them as obsolete rather than just illegal.
1578          */
1579         prefs_register_obsolete_preference(diameter_module, "version");
1580         prefs_register_obsolete_preference(diameter_module, "udp.port");
1581         prefs_register_obsolete_preference(diameter_module, "tcp.port");
1582         prefs_register_obsolete_preference(diameter_module, "command_in_header");
1583         prefs_register_obsolete_preference(diameter_module, "dictionary.name");
1584         prefs_register_obsolete_preference(diameter_module, "dictionary.use");
1585         prefs_register_obsolete_preference(diameter_module, "allow_zero_as_app_id");
1586         prefs_register_obsolete_preference(diameter_module, "suppress_console_output");
1587
1588         /* Register tap */
1589         diameter_tap = register_tap("diameter");
1590
1591 } /* proto_register_diameter */
1592
1593 void
1594 proto_reg_handoff_diameter(void)
1595 {
1596         static gboolean Initialized=FALSE;
1597         static guint SctpPort;
1598         static dissector_handle_t diameter_handle;
1599         static range_t *diameter_tcp_port_range;
1600
1601         if (!Initialized) {
1602                 diameter_handle = find_dissector("diameter");
1603                 diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
1604                                                               proto_diameter);
1605                 data_handle = find_dissector("data");
1606                 eap_handle = find_dissector("eap");
1607                 /* Register special decoding for some AVP:s */
1608                 /* AVP Code: 266 Vendor-Id */
1609                 dissector_add("diameter.base", 266,
1610                                 new_create_dissector_handle(dissect_diameter_vedor_id, proto_diameter));
1611                 /* AVP Code: 462 EAP-Payload */
1612                 dissector_add("diameter.base", 462,
1613                         new_create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
1614                 /* AVP Code: 463 EAP-Reissued-Payload */
1615                 dissector_add("diameter.base", 463,
1616                         new_create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
1617
1618                 Initialized=TRUE;
1619         } else {
1620                 range_foreach(diameter_tcp_port_range, range_delete_callback);
1621                 g_free(diameter_tcp_port_range);
1622                 dissector_delete("sctp.port", SctpPort, diameter_handle);
1623         }
1624
1625         /* set port for future deletes */
1626         diameter_tcp_port_range = range_copy(global_diameter_tcp_port_range);
1627         range_foreach(diameter_tcp_port_range, range_add_callback);
1628
1629         SctpPort=gbl_diameterSctpPort;
1630         dissector_add("sctp.port", gbl_diameterSctpPort, diameter_handle);
1631 }
1632