Make the UDP port preference a range.
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 #include "config.h"
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <ctype.h>
50
51 #include <glib.h>
52
53 #include <epan/packet.h>
54 #include <epan/filesystem.h>
55 #include <epan/prefs.h>
56 #include <epan/sminmpec.h>
57 #include <epan/emem.h>
58 #include <epan/wmem/wmem.h>
59 #include <epan/expert.h>
60 #include <epan/conversation.h>
61 #include <epan/tap.h>
62 #include <epan/exported_pdu.h>
63 #include <epan/diam_dict.h>
64 #include <epan/sctpppids.h>
65 #include <epan/show_exception.h>
66 #include "packet-tcp.h"
67 #include "packet-diameter.h"
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 static gint exported_pdu_tap = -1;
103
104 /* Conversation Info */
105 typedef struct _diameter_conv_info_t {
106         emem_tree_t *pdus_tree;
107 } diameter_conv_info_t;
108
109 typedef struct _diam_ctx_t {
110         proto_tree *tree;
111         packet_info *pinfo;
112         emem_tree_t *avps;
113         gboolean version_rfc;
114 } diam_ctx_t;
115
116 typedef struct _diam_avp_t diam_avp_t;
117 typedef struct _avp_type_t avp_type_t;
118
119 typedef const char *(*diam_avp_dissector_t)(diam_ctx_t *, diam_avp_t *, tvbuff_t *);
120
121
122 typedef struct _diam_vnd_t {
123         guint32 code;
124         GArray *vs_avps;
125         value_string_ext *vs_avps_ext;
126         GArray *vs_cmds;
127 } diam_vnd_t;
128
129 struct _diam_avp_t {
130         guint32 code;
131         const diam_vnd_t *vendor;
132         diam_avp_dissector_t dissector_v16;
133         diam_avp_dissector_t dissector_rfc;
134
135         gint ett;
136         int hf_value;
137         void *type_data;
138 };
139
140 #define VND_AVP_VS(v)      ((value_string *)(void *)((v)->vs_avps->data))
141 #define VND_AVP_VS_LEN(v)  ((v)->vs_avps->len)
142 #define VND_CMD_VS(v)      ((value_string *)(void *)((v)->vs_cmds->data))
143
144 typedef struct _diam_dictionary_t {
145         emem_tree_t *avps;
146         emem_tree_t *vnds;
147         value_string *applications;
148         value_string *commands;
149 } diam_dictionary_t;
150
151 typedef diam_avp_t *(*avp_constructor_t)(const avp_type_t *, guint32, const diam_vnd_t *, const char *,  const value_string *, void *);
152
153 struct _avp_type_t {
154         const char *name;
155         diam_avp_dissector_t v16;
156         diam_avp_dissector_t rfc;
157         enum ftenum ft;
158         int base;
159         avp_constructor_t build;
160 };
161
162 struct _build_dict {
163         wmem_array_t *hf;
164         GPtrArray    *ett;
165         GHashTable   *types;
166         GHashTable   *avps;
167 };
168
169
170 typedef struct _address_avp_t {
171         gint ett;
172         int hf_address_type;
173         int hf_ipv4;
174         int hf_ipv6;
175         int hf_other;
176 } address_avp_t;
177
178 typedef enum {
179         REASEMBLE_NEVER = 0,
180         REASEMBLE_AT_END,
181         REASEMBLE_BY_LENGTH
182 } avp_reassemble_mode_t;
183
184 typedef struct _proto_avp_t {
185         char *name;
186         dissector_handle_t handle;
187         avp_reassemble_mode_t reassemble_mode;
188 } proto_avp_t;
189
190 static const char *simple_avp(diam_ctx_t *, diam_avp_t *, tvbuff_t *);
191
192 static diam_vnd_t unknown_vendor = { 0xffffffff, NULL, NULL, NULL };
193 static diam_vnd_t no_vnd = { 0, NULL, NULL, NULL };
194 static diam_avp_t unknown_avp = {0, &unknown_vendor, simple_avp, simple_avp, -1, -1, NULL };
195 static GArray *all_cmds;
196 static diam_dictionary_t dictionary = { NULL, NULL, NULL, NULL };
197 static struct _build_dict build_dict;
198 static const value_string *vnd_short_vs;
199 static dissector_handle_t data_handle;
200 static dissector_handle_t eap_handle;
201
202 static const value_string diameter_avp_data_addrfamily_vals[]= {
203         {1,"IPv4"},
204         {2,"IPv6"},
205         {3,"NSAP"},
206         {4,"HDLC"},
207         {5,"BBN"},
208         {6,"IEEE-802"},
209         {7,"E-163"},
210         {8,"E-164"},
211         {9,"F-69"},
212         {10,"X-121"},
213         {11,"IPX"},
214         {12,"Appletalk"},
215         {13,"Decnet4"},
216         {14,"Vines"},
217         {15,"E-164-NSAP"},
218         {16,"DNS"},
219         {17,"DistinguishedName"},
220         {18,"AS"},
221         {19,"XTPoIPv4"},
222         {20,"XTPoIPv6"},
223         {21,"XTPNative"},
224         {22,"FibrePortName"},
225         {23,"FibreNodeName"},
226         {24,"GWID"},
227         {0,NULL}
228 };
229 static value_string_ext diameter_avp_data_addrfamily_vals_ext = VALUE_STRING_EXT_INIT(diameter_avp_data_addrfamily_vals);
230
231 static int proto_diameter = -1;
232 static int hf_diameter_length = -1;
233 static int hf_diameter_code = -1;
234 static int hf_diameter_hopbyhopid =-1;
235 static int hf_diameter_endtoendid =-1;
236 static int hf_diameter_version = -1;
237 static int hf_diameter_vendor_id = -1;
238 static int hf_diameter_application_id = -1;
239 static int hf_diameter_flags = -1;
240 static int hf_diameter_flags_request = -1;
241 static int hf_diameter_flags_proxyable = -1;
242 static int hf_diameter_flags_error = -1;
243 static int hf_diameter_flags_T          = -1;
244 static int hf_diameter_flags_reserved4 = -1;
245 static int hf_diameter_flags_reserved5 = -1;
246 static int hf_diameter_flags_reserved6 = -1;
247 static int hf_diameter_flags_reserved7 = -1;
248
249 static int hf_diameter_avp = -1;
250 static int hf_diameter_avp_len = -1;
251 static int hf_diameter_avp_code = -1;
252 static int hf_diameter_avp_flags = -1;
253 static int hf_diameter_avp_flags_vendor_specific = -1;
254 static int hf_diameter_avp_flags_mandatory = -1;
255 static int hf_diameter_avp_flags_protected = -1;
256 static int hf_diameter_avp_flags_reserved3 = -1;
257 static int hf_diameter_avp_flags_reserved4 = -1;
258 static int hf_diameter_avp_flags_reserved5 = -1;
259 static int hf_diameter_avp_flags_reserved6 = -1;
260 static int hf_diameter_avp_flags_reserved7 = -1;
261 static int hf_diameter_avp_vendor_id = -1;
262 static int hf_diameter_avp_data_wrong_length = -1;
263 static int hf_diameter_avp_pad = -1;
264
265 static int hf_diameter_answer_in = -1;
266 static int hf_diameter_answer_to = -1;
267 static int hf_diameter_answer_time = -1;
268
269 /* AVPs with special/extra decoding */
270 static int hf_framed_ipv6_prefix_reserved = -1;
271 static int hf_framed_ipv6_prefix_length = -1;
272 static int hf_framed_ipv6_prefix_bytes = -1;
273 static int hf_framed_ipv6_prefix_ipv6 = -1;
274
275 static gint ett_diameter = -1;
276 static gint ett_diameter_flags = -1;
277 static gint ett_diameter_avp_flags = -1;
278 static gint ett_diameter_avpinfo = -1;
279 static gint ett_unknown = -1;
280 static gint ett_err = -1;
281
282
283 static expert_field ei_diameter_reserved_bit_set = EI_INIT;
284
285 /* Tap for Diameter */
286 static int diameter_tap = -1;
287
288 /* For conversations */
289
290 static dissector_handle_t diameter_udp_handle;
291 static dissector_handle_t diameter_tcp_handle;
292 static dissector_handle_t diameter_sctp_handle;
293 static range_t *global_diameter_tcp_port_range;
294 static range_t *global_diameter_sctp_port_range;
295 static range_t *global_diameter_udp_port_range;
296 /* This is used for TCP and SCTP */
297 #define DEFAULT_DIAMETER_PORT_RANGE "3868"
298
299 /* desegmentation of Diameter over TCP */
300 static gboolean gbl_diameter_desegment = TRUE;
301
302 /* Dissector tables */
303 static dissector_table_t diameter_dissector_table;
304 static dissector_table_t diameter_3gpp_avp_dissector_table;
305 static dissector_table_t diameter_ericsson_avp_dissector_table;
306
307 static const char *avpflags_str[] = {
308         "---",
309         "--P",
310         "-M-",
311         "-MP",
312         "V--",
313         "V-P",
314         "VM-",
315         "VMP",
316 };
317
318 static void
319 export_diameter_pdu(packet_info *pinfo, tvbuff_t *tvb)
320 {
321   exp_pdu_data_t *exp_pdu_data;
322   guint32 tags_bit_field;
323
324   tags_bit_field = EXP_PDU_TAG_IP_SRC_BIT + EXP_PDU_TAG_IP_DST_BIT + EXP_PDU_TAG_SRC_PORT_BIT+
325           EXP_PDU_TAG_DST_PORT_BIT + EXP_PDU_TAG_ORIG_FNO_BIT;
326
327   exp_pdu_data = load_export_pdu_tags(pinfo, "diameter", -1, tags_bit_field);
328
329   exp_pdu_data->tvb_length = tvb_length(tvb);
330   exp_pdu_data->pdu_tvb = tvb;
331
332   tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
333
334 }
335
336 static int
337 compare_avps(const void *a, const void *b)
338 {
339         const value_string *vsa = (const value_string *)a;
340         const value_string *vsb = (const value_string *)b;
341
342         if(vsa->value > vsb->value)
343                 return 1;
344         if(vsa->value < vsb->value)
345                 return -1;
346
347         return 0;
348 }
349
350 /* Special decoding of some AVPs */
351
352 static int
353 dissect_diameter_vendor_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
354 {
355         int offset = 0;
356
357         proto_tree_add_item(tree, hf_diameter_vendor_id, tvb, 0, 4, ENC_BIG_ENDIAN);
358
359         offset++;
360         return offset;
361 }
362
363 static int
364 dissect_diameter_eap_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
365 {
366         gboolean save_writable;
367
368         /* Ensure the packet is displayed as Diameter, not EAP */
369         save_writable = col_get_writable(pinfo->cinfo);
370         col_set_writable(pinfo->cinfo, FALSE);
371
372         call_dissector(eap_handle, tvb, pinfo, tree);
373
374         col_set_writable(pinfo->cinfo, save_writable);
375         return tvb_length(tvb);
376 }
377
378 /* From RFC 3162 section 2.3 */
379 static int
380 dissect_diameter_base_framed_ipv6_prefix(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
381 {
382         guint8 prefix_len, prefix_len_bytes;
383
384         proto_tree_add_item(tree, hf_framed_ipv6_prefix_reserved, tvb, 0, 1, ENC_BIG_ENDIAN);
385         proto_tree_add_item(tree, hf_framed_ipv6_prefix_length, tvb, 1, 1, ENC_BIG_ENDIAN);
386
387         prefix_len = tvb_get_guint8(tvb, 1);
388         prefix_len_bytes = prefix_len / 8;
389         if (prefix_len % 8)
390                 prefix_len_bytes++;
391
392         proto_tree_add_item(tree, hf_framed_ipv6_prefix_bytes, tvb, 2, prefix_len_bytes, ENC_NA);
393
394         /* If we have a fully IPv6 address, display it as such */
395         if (prefix_len_bytes == 16)
396                 proto_tree_add_item(tree, hf_framed_ipv6_prefix_ipv6, tvb, 2, prefix_len_bytes, ENC_NA);
397
398         return(prefix_len_bytes+2);
399 }
400
401 /* Call subdissectors for AVPs.
402  * This is a separate function to avoid having any local variables that might
403  * get clobbered by the exception longjmp() (without having to declare the
404  * variables as volatile and deal with casting them).
405  */
406 static void
407 call_avp_subdissector(guint32 vendorid, guint32 code, tvbuff_t *subtvb, packet_info *pinfo, proto_tree *avp_tree)
408 {
409         TRY {
410                 switch (vendorid) {
411                 case 0:
412                         dissector_try_uint(diameter_dissector_table, code, subtvb, pinfo, avp_tree);
413                         break;
414                 case VENDOR_ERICSSON:
415                         dissector_try_uint(diameter_ericsson_avp_dissector_table, code, subtvb, pinfo, avp_tree);
416                         break;
417                 case VENDOR_THE3GPP:
418                         dissector_try_uint(diameter_3gpp_avp_dissector_table, code, subtvb, pinfo, avp_tree);
419                         break;
420                 default:
421                         break;
422                 }
423
424                 /* Debug
425                 proto_tree_add_text(avp_tree, subtvb, 0, -1, "AVP %u data, Vendor Id %u ",code,vendorid);
426                 */
427         }
428         CATCH_NONFATAL_ERRORS {
429                 show_exception(subtvb, pinfo, avp_tree, EXCEPT_CODE, GET_MESSAGE);
430         }
431         ENDTRY;
432 }
433
434 /* Dissect an AVP at offset */
435 static int
436 dissect_diameter_avp(diam_ctx_t *c, tvbuff_t *tvb, int offset)
437 {
438         guint32 code           = tvb_get_ntohl(tvb,offset);
439         guint32 len            = tvb_get_ntohl(tvb,offset+4);
440         guint32 vendor_flag    = len & 0x80000000;
441         guint32 flags_bits_idx = (len & 0xE0000000) >> 29;
442         guint32 flags_bits     = (len & 0xFF000000) >> 24;
443         guint32 vendorid       = vendor_flag ? tvb_get_ntohl(tvb,offset+8) : 0 ;
444         emem_tree_key_t k[]    = {
445                 {1,&code},
446                 {1,&vendorid},
447                 {0,NULL}
448         };
449         diam_avp_t *a          = (diam_avp_t *)emem_tree_lookup32_array(dictionary.avps,k);
450         proto_item *pi, *avp_item;
451         proto_tree *avp_tree, *save_tree;
452         tvbuff_t *subtvb;
453         diam_vnd_t *vendor;
454         const char *code_str;
455         const char *avp_str;
456         guint8 pad_len;
457
458         len &= 0x00ffffff;
459         pad_len =  (len % 4) ? 4 - (len % 4) : 0 ;
460
461         if (!a) {
462                 a = &unknown_avp;
463
464                 if (vendor_flag) {
465                         if (! (vendor = (diam_vnd_t *)emem_tree_lookup32(dictionary.vnds,vendorid) ))
466                                 vendor = &unknown_vendor;
467                 } else {
468                         vendor = &no_vnd;
469                 }
470         } else {
471                 vendor = (diam_vnd_t *)a->vendor;
472         }
473
474         if(vendor->vs_avps_ext == NULL) {
475                 g_array_sort(vendor->vs_avps, compare_avps);
476                 vendor->vs_avps_ext = value_string_ext_new(VND_AVP_VS(vendor), VND_AVP_VS_LEN(vendor)+1,
477                                                            g_strdup_printf("diameter_vendor_%s",val_to_str_ext_const(vendorid, &sminmpec_values_ext, "Unknown")));
478 #if 0
479                 { /* Debug code */
480                         value_string *vendor_avp_vs=VALUE_STRING_EXT_VS_P(vendor->vs_avps_ext);
481                         gint i = 0;
482                         while(vendor_avp_vs[i].strptr!=NULL) {
483                                 g_warning("%u %s",vendor_avp_vs[i].value,vendor_avp_vs[i].strptr);
484                                 i++;
485                         }
486                 }
487 #endif
488         }
489
490         /* Add root of tree for this AVP */
491         avp_item = proto_tree_add_item(c->tree, hf_diameter_avp, tvb, offset, len + pad_len, ENC_NA);
492         avp_tree = proto_item_add_subtree(avp_item, a->ett);
493
494         pi = proto_tree_add_item(avp_tree,hf_diameter_avp_code,tvb,offset,4,ENC_BIG_ENDIAN);
495         code_str = val_to_str_ext_const(code, vendor->vs_avps_ext, "Unknown");
496         proto_item_append_text(pi," %s", code_str);
497
498         /* Code */
499         if (a == &unknown_avp) {
500                 proto_tree *tu = proto_item_add_subtree(pi,ett_unknown);
501                 pi = proto_tree_add_text(tu,tvb,offset,4,"Unknown AVP, "
502                                          "if you know what this is you can add it to dictionary.xml");
503                 expert_add_info_format(c->pinfo, pi, PI_UNDECODED, PI_WARN,
504                                        "Unknown AVP %u (vendor=%s)", code,
505                                        val_to_str_ext_const(vendorid, &sminmpec_values_ext, "Unknown"));
506                 PROTO_ITEM_SET_GENERATED(pi);
507         }
508
509         offset += 4;
510
511         proto_item_set_text(avp_item,"AVP: %s(%u) l=%u f=%s", code_str, code, len, avpflags_str[flags_bits_idx]);
512
513         /* Flags */
514         pi = proto_tree_add_item(avp_tree,hf_diameter_avp_flags,tvb,offset,1,ENC_BIG_ENDIAN);
515         {
516                 proto_tree *flags_tree = proto_item_add_subtree(pi,ett_diameter_avp_flags);
517                 proto_tree_add_item(flags_tree,hf_diameter_avp_flags_vendor_specific,tvb,offset,1,ENC_BIG_ENDIAN);
518                 proto_tree_add_item(flags_tree,hf_diameter_avp_flags_mandatory,tvb,offset,1,ENC_BIG_ENDIAN);
519                 proto_tree_add_item(flags_tree,hf_diameter_avp_flags_protected,tvb,offset,1,ENC_BIG_ENDIAN);
520                 pi = proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved3,tvb,offset,1,ENC_BIG_ENDIAN);
521                 if(flags_bits & 0x10) expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
522                 pi = proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved4,tvb,offset,1,ENC_BIG_ENDIAN);
523                 if(flags_bits & 0x08) expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
524                 pi = proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved5,tvb,offset,1,ENC_BIG_ENDIAN);
525                 if(flags_bits & 0x04) expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
526                 proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved6,tvb,offset,1,ENC_BIG_ENDIAN);
527                 if(flags_bits & 0x02) expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
528                 proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved7,tvb,offset,1,ENC_BIG_ENDIAN);
529                 if(flags_bits & 0x01) expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
530         }
531         offset += 1;
532
533         /* Length */
534         proto_tree_add_item(avp_tree,hf_diameter_avp_len,tvb,offset,3,ENC_BIG_ENDIAN);
535         offset += 3;
536
537         /* Vendor flag */
538         if (vendor_flag) {
539                 proto_item_append_text(avp_item," vnd=%s", val_to_str(vendorid, vnd_short_vs, "%d"));
540                 pi = proto_tree_add_item(avp_tree,hf_diameter_avp_vendor_id,tvb,offset,4,ENC_BIG_ENDIAN);
541                 if (vendor == &unknown_vendor) {
542                         proto_tree *tu = proto_item_add_subtree(pi,ett_unknown);
543                         pi = proto_tree_add_text(tu,tvb,offset,4,"Unknown Vendor, "
544                                              "if you know whose this is you can add it to dictionary.xml");
545                         expert_add_info_format(c->pinfo, pi, PI_UNDECODED, PI_WARN, "Unknown Vendor");
546                         PROTO_ITEM_SET_GENERATED(pi);
547                 }
548                 offset += 4;
549         }
550
551         if ( len == (guint32)(vendor_flag ? 12 : 8) ) {
552                 /* Data is empty so return now */
553                 pi = proto_tree_add_text(avp_tree,tvb,offset,0,"No data");
554                 expert_add_info_format(c->pinfo, pi, PI_UNDECODED, PI_WARN, "Data is empty");
555                 PROTO_ITEM_SET_GENERATED(pi);
556                 /* pad_len is always 0 in this case, but kept here for consistency */
557                 return len+pad_len;
558         }
559
560         subtvb = tvb_new_subset(tvb,offset,len-(8+(vendor_flag?4:0)),len-(8+(vendor_flag?4:0)));
561         offset += len-(8+(vendor_flag?4:0));
562
563         save_tree = c->tree;
564         c->tree = avp_tree;
565         if (c->version_rfc) {
566                 avp_str = a->dissector_rfc(c,a,subtvb);
567         } else {
568                 avp_str = a->dissector_v16(c,a,subtvb);
569         }
570         c->tree = save_tree;
571
572         if (avp_str) proto_item_append_text(avp_item," val=%s", avp_str);
573
574         call_avp_subdissector(vendorid, code, subtvb, c->pinfo, avp_tree);
575
576         if (pad_len) {
577                 guint8 i;
578
579                 pi = proto_tree_add_item(avp_tree, hf_diameter_avp_pad, tvb, offset, pad_len, ENC_NA);
580                 for (i=0; i < pad_len; i++) {
581                         if (tvb_get_guint8(tvb, offset++) != 0) {
582                                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE, "Padding is non-zero");
583                                 break;
584                         }
585                 }
586         }
587
588         return len+pad_len;
589 }
590
591 static const char *
592 address_rfc_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
593 {
594         char *label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
595         address_avp_t *t = (address_avp_t *)a->type_data;
596         proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_BIG_ENDIAN);
597         proto_tree *pt = proto_item_add_subtree(pi,t->ett);
598         guint32 addr_type = tvb_get_ntohs(tvb,0);
599         gint len = tvb_length_remaining(tvb,2);
600
601         proto_tree_add_item(pt,t->hf_address_type,tvb,0,2,ENC_NA);
602         switch (addr_type ) {
603                 case 1:
604                         if (len != 4) {
605                                 pi = proto_tree_add_text(pt,tvb,2,len,"Wrong length for IPv4 Address: %d instead of 4",len);
606                                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_WARN, "Wrong length for IPv4 Address");
607                                 return "[Malformed]";
608                         }
609                         pi = proto_tree_add_item(pt,t->hf_ipv4,tvb,2,4,ENC_BIG_ENDIAN);
610                         break;
611                 case 2:
612                         if (len != 16) {
613                                 pi = proto_tree_add_text(pt,tvb,2,len,"Wrong length for IPv6 Address: %d instead of 16",len);
614                                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_WARN, "Wrong length for IPv6 Address");
615                                 return "[Malformed]";
616                         }
617                         pi = proto_tree_add_item(pt,t->hf_ipv6,tvb,2,16,ENC_NA);
618                         break;
619                 default:
620                         pi = proto_tree_add_item(pt,t->hf_other,tvb,2,-1,ENC_BIG_ENDIAN);
621                         break;
622         }
623
624         proto_item_fill_label(PITEM_FINFO(pi), label);
625         label = strstr(label,": ")+2;
626         return label;
627 }
628
629 static const char *
630 proto_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
631 {
632         proto_avp_t *t = (proto_avp_t *)a->type_data;
633
634         col_set_writable(c->pinfo->cinfo, FALSE);
635
636         if (!t->handle) {
637                 t->handle = find_dissector(t->name);
638                 if(!t->handle) t->handle = data_handle;
639         }
640
641         TRY {
642                 call_dissector(t->handle, tvb, c->pinfo, c->tree);
643         }
644         CATCH_NONFATAL_ERRORS {
645                 show_exception(tvb, c->pinfo, c->tree, EXCEPT_CODE, GET_MESSAGE);
646         }
647         ENDTRY;
648
649         return "";
650 }
651
652 static const char *
653 time_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
654 {
655         int len = tvb_length(tvb);
656         char *label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
657         proto_item *pi;
658
659         if ( len != 4 ) {
660                 pi = proto_tree_add_text(c->tree, tvb, 0, 4, "Error! AVP value MUST be 4 bytes");
661                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE,
662                                        "Bad Timestamp Length (%u)", len);
663                 return "[Malformed]";
664         }
665
666         pi = proto_tree_add_item(c->tree, (a->hf_value), tvb, 0, 4, ENC_TIME_NTP|ENC_BIG_ENDIAN);
667         proto_item_fill_label(PITEM_FINFO(pi), label);
668         label = strstr(label,": ")+2;
669         return label;
670 }
671
672 static const char *
673 address_v16_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
674 {
675         char *label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
676         address_avp_t *t = (address_avp_t *)a->type_data;
677         proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_BIG_ENDIAN);
678         proto_tree *pt = proto_item_add_subtree(pi,t->ett);
679         guint32 len = tvb_length(tvb);
680
681         switch (len) {
682                 case 4:
683                         pi = proto_tree_add_item(pt,t->hf_ipv4,tvb,0,4,ENC_BIG_ENDIAN);
684                         break;
685                 case 16:
686                         pi = proto_tree_add_item(pt,t->hf_ipv6,tvb,0,16,ENC_NA);
687                         break;
688                 default:
689                         pi = proto_tree_add_item(pt,t->hf_other,tvb,0,len,ENC_BIG_ENDIAN);
690                         expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE,
691                                                "Bad Address Length (%u)", len);
692
693                         break;
694         }
695
696         proto_item_fill_label(PITEM_FINFO(pi), label);
697         label = strstr(label,": ")+2;
698         return label;
699 }
700
701 static const char *
702 simple_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
703 {
704         char *label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
705         proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_BIG_ENDIAN);
706         proto_item_fill_label(PITEM_FINFO(pi), label);
707         label = strstr(label,": ")+2;
708         return label;
709 }
710
711 static const char *
712 utf8_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
713 {
714         char *label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
715         proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_UTF_8|ENC_BIG_ENDIAN);
716         proto_item_fill_label(PITEM_FINFO(pi), label);
717         label = strstr(label,": ")+2;
718         return label;
719 }
720
721 static const char *
722 integer32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
723 {
724         char *label;
725         proto_item *pi;
726
727         /* Verify length before adding */
728         gint length = tvb_length_remaining(tvb,0);
729         if (length == 4) {
730                 pi= proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length_remaining(tvb,0),ENC_BIG_ENDIAN);
731                 label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
732                 proto_item_fill_label(PITEM_FINFO(pi), label);
733                 label = strstr(label,": ")+2;
734         }
735         else {
736                 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
737                                                  tvb, 0, length, NULL,
738                                                 "Error!  Bad Integer32 Length");
739                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE,
740                                        "Bad Integer32 Length (%u)", length);
741                 PROTO_ITEM_SET_GENERATED(pi);
742                 label = NULL;
743         }
744         return label;
745 }
746
747 static const char *
748 integer64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
749 {
750         char *label;
751         proto_item *pi;
752
753         /* Verify length before adding */
754         gint length = tvb_length_remaining(tvb,0);
755         if (length == 8) {
756                 pi= proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length_remaining(tvb,0),ENC_BIG_ENDIAN);
757                 label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
758                 proto_item_fill_label(PITEM_FINFO(pi), label);
759                 label = strstr(label,": ")+2;
760         }
761         else {
762                 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
763                                                  tvb, 0, length, NULL,
764                                                 "Error!  Bad Integer64 Length");
765                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE,
766                                        "Bad Integer64 Length (%u)", length);
767                 PROTO_ITEM_SET_GENERATED(pi);
768                 label = NULL;
769         }
770         return label;
771 }
772
773 static const char *
774 unsigned32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
775 {
776         char *label;
777         proto_item *pi;
778
779         /* Verify length before adding */
780         gint length = tvb_length_remaining(tvb,0);
781         if (length == 4) {
782                 pi= proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length_remaining(tvb,0),ENC_BIG_ENDIAN);
783                 label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
784                 proto_item_fill_label(PITEM_FINFO(pi), label);
785                 label = strstr(label,": ")+2;
786         }
787         else {
788                 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
789                                                  tvb, 0, length, NULL,
790                                                 "Error!  Bad Unsigned32 Length");
791                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE,
792                                        "Bad Unsigned32 Length (%u)", length);
793                 PROTO_ITEM_SET_GENERATED(pi);
794                 label = NULL;
795         }
796         return label;
797 }
798
799 static const char *
800 unsigned64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
801 {
802         char *label;
803         proto_item *pi;
804
805         /* Verify length before adding */
806         gint length = tvb_length_remaining(tvb,0);
807         if (length == 8) {
808                 pi= proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length_remaining(tvb,0),ENC_BIG_ENDIAN);
809                 label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
810                 proto_item_fill_label(PITEM_FINFO(pi), label);
811                 label = strstr(label,": ")+2;
812         }
813         else {
814                 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
815                                                  tvb, 0, length, NULL,
816                                                 "Error!  Bad Unsigned64 Length");
817                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE,
818                                        "Bad Unsigned64 Length (%u)", length);
819                 PROTO_ITEM_SET_GENERATED(pi);
820                 label = NULL;
821         }
822         return label;
823 }
824
825 static const char *
826 float32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
827 {
828         char *label;
829         proto_item *pi;
830
831         /* Verify length before adding */
832         gint length = tvb_length_remaining(tvb,0);
833         if (length == 4) {
834                 pi= proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length_remaining(tvb,0),ENC_BIG_ENDIAN);
835                 label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
836                 proto_item_fill_label(PITEM_FINFO(pi), label);
837                 label = strstr(label,": ")+2;
838         }
839         else {
840                 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
841                                                  tvb, 0, length, NULL,
842                                                 "Error!  Bad Float32 Length");
843                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE,
844                                        "Bad Float32 Length (%u)", length);
845                 PROTO_ITEM_SET_GENERATED(pi);
846                 label = NULL;
847         }
848         return label;
849 }
850
851 static const char *
852 float64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
853 {
854         char *label;
855         proto_item *pi;
856
857         /* Verify length before adding */
858         gint length = tvb_length_remaining(tvb,0);
859         if (length == 8) {
860                 pi= proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length_remaining(tvb,0),ENC_BIG_ENDIAN);
861                 label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
862                 proto_item_fill_label(PITEM_FINFO(pi), label);
863                 label = strstr(label,": ")+2;
864         }
865         else {
866                 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
867                                                  tvb, 0, length, NULL,
868                                                 "Error!  Bad Float64 Length");
869                 expert_add_info_format(c->pinfo, pi, PI_MALFORMED, PI_NOTE,
870                                        "Bad Float64 Length (%u)", length);
871                 PROTO_ITEM_SET_GENERATED(pi);
872                 label = NULL;
873         }
874         return label;
875 }
876
877 static const char *
878 grouped_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
879 {
880         int offset = 0;
881         int len = tvb_length(tvb);
882         proto_item *pi = proto_tree_add_item(c->tree, a->hf_value, tvb , 0 , -1, ENC_BIG_ENDIAN);
883         proto_tree *pt = c->tree;
884
885         c->tree = proto_item_add_subtree(pi,a->ett);
886
887         while (offset < len) {
888                 offset += dissect_diameter_avp(c, tvb, offset);
889         }
890
891         c->tree = pt;
892
893         return NULL;
894 }
895
896 static const char *msgflags_str[] = {
897         "----", "---T", "--E-", "--ET",
898         "-P--", "-P-T", "-PE-", "-PET",
899         "R---", "R--T", "R-E-", "R-ET",
900         "RP--", "RP-T", "RPE-", "RPET"
901 };
902
903 static void
904 dissect_diameter_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
905 {
906         guint32 first_word  = tvb_get_ntohl(tvb,0);
907         guint32 version = (first_word & 0xff000000) >> 24;
908         guint32 flags_bits = (tvb_get_ntohl(tvb,4) & 0xff000000) >> 24;
909         int packet_len = first_word & 0x00ffffff;
910         proto_item *pi, *cmd_item, *app_item, *version_item;
911         proto_tree *diam_tree;
912         diam_ctx_t *c = (diam_ctx_t *)ep_alloc0(sizeof(diam_ctx_t));
913         int offset;
914         value_string *cmd_vs;
915         const char *cmd_str;
916         guint32 cmd = tvb_get_ntoh24(tvb,5);
917         guint32 hop_by_hop_id, end_to_end_id;
918         conversation_t *conversation;
919         diameter_conv_info_t *diameter_conv_info;
920         diameter_req_ans_pair_t *diameter_pair = NULL;
921         emem_tree_t *pdus_tree;
922         proto_item *it;
923         nstime_t ns;
924         void *pd_save;
925         diam_sub_dis_t *diam_sub_dis_inf = ep_new0(diam_sub_dis_t);
926
927
928         diam_sub_dis_inf->application_id = tvb_get_ntohl(tvb,8);
929
930         pd_save = pinfo->private_data;
931         col_set_str(pinfo->cinfo, COL_PROTOCOL, "DIAMETER");
932
933         pi = proto_tree_add_item(tree,proto_diameter,tvb,0,-1,ENC_NA);
934         diam_tree = proto_item_add_subtree(pi,ett_diameter);
935
936         c->tree = diam_tree;
937         c->pinfo = pinfo;
938
939         version_item = proto_tree_add_item(diam_tree,hf_diameter_version,tvb,0,1,ENC_BIG_ENDIAN);
940         proto_tree_add_item(diam_tree,hf_diameter_length,tvb,1,3,ENC_BIG_ENDIAN);
941
942         pi = proto_tree_add_item(diam_tree,hf_diameter_flags,tvb,4,1,ENC_BIG_ENDIAN);
943         {
944                 proto_tree *pt = proto_item_add_subtree(pi,ett_diameter_flags);
945                 proto_tree_add_item(pt,hf_diameter_flags_request,tvb,4,1,ENC_BIG_ENDIAN);
946                 proto_tree_add_item(pt,hf_diameter_flags_proxyable,tvb,4,1,ENC_BIG_ENDIAN);
947                 proto_tree_add_item(pt,hf_diameter_flags_error,tvb,4,1,ENC_BIG_ENDIAN);
948                 proto_tree_add_item(pt,hf_diameter_flags_T,tvb,4,1,ENC_BIG_ENDIAN);
949                 proto_tree_add_item(pt,hf_diameter_flags_reserved4,tvb,4,1,ENC_BIG_ENDIAN);
950                 if(flags_bits & 0x08) expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
951                 pi = proto_tree_add_item(pt,hf_diameter_flags_reserved5,tvb,4,1,ENC_BIG_ENDIAN);
952                 if(flags_bits & 0x04) expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
953                 pi = proto_tree_add_item(pt,hf_diameter_flags_reserved6,tvb,4,1,ENC_BIG_ENDIAN);
954                 if(flags_bits & 0x02) expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
955                 pi = proto_tree_add_item(pt,hf_diameter_flags_reserved7,tvb,4,1,ENC_BIG_ENDIAN);
956                 if(flags_bits & 0x01) expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
957         }
958
959         cmd_item = proto_tree_add_item(diam_tree,hf_diameter_code,tvb,5,3,ENC_BIG_ENDIAN);
960
961         switch (version) {
962                 case DIAMETER_V16: {
963                         guint32 vendorid = tvb_get_ntohl(tvb,8);
964                         diam_vnd_t *vendor;
965
966                         if (! ( vendor = (diam_vnd_t *)emem_tree_lookup32(dictionary.vnds,vendorid) ) ) {
967                                 vendor = &unknown_vendor;
968                         }
969
970                         cmd_vs = VND_CMD_VS(vendor);
971                         proto_tree_add_item(diam_tree, hf_diameter_vendor_id,tvb,8,4,ENC_BIG_ENDIAN);
972
973                         c->version_rfc = FALSE;
974                         break;
975                 }
976                 case DIAMETER_RFC: {
977
978                         cmd_vs = (value_string *)(void *)all_cmds->data;
979
980                         app_item = proto_tree_add_item(diam_tree, hf_diameter_application_id, tvb, 8, 4, ENC_BIG_ENDIAN);
981                         /* Store the application id to be used by subdissectors */
982                         pinfo->private_data = diam_sub_dis_inf;
983
984                         if (try_val_to_str(diam_sub_dis_inf->application_id, dictionary.applications) == NULL) {
985                                 proto_tree *tu = proto_item_add_subtree(app_item,ett_unknown);
986                                 proto_item *iu = proto_tree_add_text(tu, tvb, 8, 4, "Unknown Application Id, "
987                                                                      "if you know what this is you can add it to dictionary.xml");
988                                 expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN,
989                                                        "Unknown Application Id (%u)", diam_sub_dis_inf->application_id);
990                                 PROTO_ITEM_SET_GENERATED(iu);
991                         }
992
993                         c->version_rfc = TRUE;
994                         break;
995                 }
996                 default:
997                 {
998                         proto_tree *pt = proto_item_add_subtree(version_item,ett_err);
999                         proto_item *pi_local = proto_tree_add_text(pt,tvb,0,1,"Unknown Diameter Version (decoding as RFC 3588)");
1000                         expert_add_info_format(pinfo, pi_local, PI_UNDECODED, PI_WARN, "Unknown Diameter Version");
1001                         PROTO_ITEM_SET_GENERATED(pi);
1002                         c->version_rfc = TRUE;
1003                         cmd_vs = VND_CMD_VS(&no_vnd);
1004                         break;
1005                 }
1006         }
1007         cmd_str = val_to_str_const(cmd, cmd_vs, "Unknown");
1008
1009         col_add_fstr(pinfo->cinfo, COL_INFO,
1010                          "cmd=%s%s(%d) flags=%s %s=%s(%d) h2h=%x e2e=%x",
1011                          cmd_str,
1012                          ((flags_bits>>4)&0x08) ? " Request" : " Answer",
1013                          cmd,
1014                          msgflags_str[((flags_bits>>4)&0x0f)],
1015                          c->version_rfc ? "appl" : "vend",
1016                          val_to_str_const(diam_sub_dis_inf->application_id, c->version_rfc ? dictionary.applications : vnd_short_vs, "Unknown"),
1017                          diam_sub_dis_inf->application_id,
1018                          tvb_get_ntohl(tvb,12),
1019                          tvb_get_ntohl(tvb,16));
1020
1021         col_append_str(pinfo->cinfo, COL_INFO, " | ");
1022         col_set_fence(pinfo->cinfo, COL_INFO);
1023
1024         /* Append name to command item, warn if unknown */
1025         proto_item_append_text(cmd_item," %s", cmd_str);
1026         if (strcmp(cmd_str, "Unknown") == 0) {
1027                 proto_tree *tu = proto_item_add_subtree(cmd_item,ett_unknown);
1028                 proto_item *iu = proto_tree_add_text(tu,tvb, 5 ,3,"Unknown command, "
1029                                                      "if you know what this is you can add it to dictionary.xml");
1030                 expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, "Unknown command (%u)", cmd);
1031                 PROTO_ITEM_SET_GENERATED(iu);
1032         }
1033
1034
1035         hop_by_hop_id = tvb_get_ntohl(tvb, 12);
1036         proto_tree_add_item(diam_tree,hf_diameter_hopbyhopid,tvb,12,4,ENC_BIG_ENDIAN);
1037         end_to_end_id = tvb_get_ntohl(tvb, 16);
1038         proto_tree_add_item(diam_tree,hf_diameter_endtoendid,tvb,16,4,ENC_BIG_ENDIAN);
1039
1040         /* Conversation tracking stuff */
1041         /*
1042          * FIXME: Looking at epan/conversation.c it seems unlike that this will work properly in
1043          * multi-homed SCTP connections. This will probably need to be fixed at some point.
1044          */
1045
1046         conversation = find_or_create_conversation(pinfo);
1047
1048         diameter_conv_info = (diameter_conv_info_t *)conversation_get_proto_data(conversation, proto_diameter);
1049         if (!diameter_conv_info) {
1050                 diameter_conv_info = (diameter_conv_info_t *)se_alloc(sizeof(diameter_conv_info_t));
1051                 diameter_conv_info->pdus_tree = se_tree_create_non_persistent(
1052                                         EMEM_TREE_TYPE_RED_BLACK, "diameter_pdu_trees");
1053
1054                 conversation_add_proto_data(conversation, proto_diameter, diameter_conv_info);
1055         }
1056
1057         /* pdus_tree is an se_tree keyed by frame number (in order to handle hop-by-hop collisions */
1058         pdus_tree = (emem_tree_t *)se_tree_lookup32(diameter_conv_info->pdus_tree, hop_by_hop_id);
1059
1060         if (pdus_tree == NULL && (flags_bits & DIAM_FLAGS_R)) {
1061                 /* This is the first request we've seen with this hop-by-hop id */
1062                 pdus_tree = se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "diameter_pdus");
1063                 se_tree_insert32(diameter_conv_info->pdus_tree, hop_by_hop_id, pdus_tree);
1064         }
1065
1066         if (pdus_tree) {
1067                 if (!pinfo->fd->flags.visited) {
1068                         if (flags_bits & DIAM_FLAGS_R) {
1069                                 /* This is a request */
1070                                 diameter_pair = (diameter_req_ans_pair_t *)se_alloc(sizeof(diameter_req_ans_pair_t));
1071                                 diameter_pair->hop_by_hop_id = hop_by_hop_id;
1072                                 diameter_pair->end_to_end_id = end_to_end_id;
1073                                 diameter_pair->cmd_code = cmd;
1074                                 diameter_pair->result_code = 0;
1075                                 diameter_pair->cmd_str = cmd_str;
1076                                 diameter_pair->req_frame = PINFO_FD_NUM(pinfo);
1077                                 diameter_pair->ans_frame = 0;
1078                                 diameter_pair->req_time = pinfo->fd->abs_ts;
1079                                 se_tree_insert32(pdus_tree, PINFO_FD_NUM(pinfo), (void *)diameter_pair);
1080                         } else {
1081                                 /* Look for a request which occurs earlier in the trace than this answer. */
1082                                 diameter_pair = (diameter_req_ans_pair_t *)se_tree_lookup32_le(pdus_tree, PINFO_FD_NUM(pinfo));
1083
1084                                 /* Verify the end-to-end-id matches before declaring a match */
1085                                 if (diameter_pair && diameter_pair->end_to_end_id == end_to_end_id) {
1086                                         diameter_pair->ans_frame = PINFO_FD_NUM(pinfo);
1087                                 }
1088                         }
1089                 } else {
1090                         /* Look for a request which occurs earlier in the trace than this answer. */
1091                         diameter_pair = (diameter_req_ans_pair_t *)se_tree_lookup32_le(pdus_tree, PINFO_FD_NUM(pinfo));
1092
1093                         /* If the end-to-end ID doesn't match then this is not the request we were
1094                          * looking for.
1095                          */
1096                         if (diameter_pair && diameter_pair->end_to_end_id != end_to_end_id)
1097                                 diameter_pair = NULL;
1098                 }
1099         }
1100
1101         if (!diameter_pair) {
1102                 /* create a "fake" diameter_pair structure */
1103                 diameter_pair = (diameter_req_ans_pair_t *)ep_alloc(sizeof(diameter_req_ans_pair_t));
1104                 diameter_pair->hop_by_hop_id = hop_by_hop_id;
1105                 diameter_pair->cmd_code = cmd;
1106                 diameter_pair->result_code = 0;
1107                 diameter_pair->cmd_str = cmd_str;
1108                 diameter_pair->req_frame = 0;
1109                 diameter_pair->ans_frame = 0;
1110                 diameter_pair->req_time = pinfo->fd->abs_ts;
1111         }
1112         diameter_pair->processing_request=(flags_bits & DIAM_FLAGS_R)!=0;
1113
1114         if (tree){
1115                 /* print state tracking info in the tree */
1116                 if (flags_bits & DIAM_FLAGS_R) {
1117                         /* This is a request */
1118                         if (diameter_pair->ans_frame) {
1119                                 it = proto_tree_add_uint(diam_tree, hf_diameter_answer_in,
1120                                                 tvb, 0, 0, diameter_pair->ans_frame);
1121                                 PROTO_ITEM_SET_GENERATED(it);
1122                         }
1123                 } else {
1124                         /* This is an answer */
1125                         if (diameter_pair->req_frame) {
1126                                 it = proto_tree_add_uint(diam_tree, hf_diameter_answer_to,
1127                                                 tvb, 0, 0, diameter_pair->req_frame);
1128                                 PROTO_ITEM_SET_GENERATED(it);
1129
1130                                 nstime_delta(&ns, &pinfo->fd->abs_ts, &diameter_pair->req_time);
1131                                 diameter_pair->srt_time = ns;
1132                                 it = proto_tree_add_time(diam_tree, hf_diameter_answer_time, tvb, 0, 0, &ns);
1133                                 PROTO_ITEM_SET_GENERATED(it);
1134                                 /* TODO: Populate result_code in tap record from AVP 268 */
1135                         }
1136                 }
1137
1138                 offset = 20;
1139
1140                 /* Dissect AVPs until the end of the packet is reached */
1141                 while (offset < packet_len) {
1142                         offset += dissect_diameter_avp(c, tvb, offset);
1143                 }
1144
1145                 /* Handle requests for which no answers were found and
1146                  * anawers for which no requests were found in the tap listener.
1147                  * In case if you don't need unpaired requests/answers use:
1148                  * if(diameter_pair->processing_request || !diameter_pair->req_frame)
1149                  *   return;
1150                  */
1151                 tap_queue_packet(diameter_tap, pinfo, diameter_pair);
1152         }
1153
1154         if(have_tap_listener(exported_pdu_tap)){
1155                 export_diameter_pdu(pinfo,tvb);
1156         }
1157
1158         pinfo->private_data = pd_save;
1159 }
1160
1161 static guint
1162 get_diameter_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
1163 {
1164         /* Get the length of the Diameter packet. */
1165         return tvb_get_ntoh24(tvb, offset + 1);
1166 }
1167
1168 static gboolean
1169 check_diameter(tvbuff_t *tvb)
1170 {
1171         if (tvb_length(tvb) < 1)
1172                 return FALSE;   /* not enough bytes to check the version */
1173
1174         if (tvb_get_guint8(tvb, 0) != 1)
1175                 return FALSE;   /* not version 1 */
1176
1177                   /*
1178                    * XXX - fetch length and make sure it's at least MIN_DIAMETER_SIZE?
1179                    * Fetch flags and check that none of the DIAM_FLAGS_RESERVED bits
1180                    * are set?
1181                    */
1182         return TRUE;
1183 }
1184
1185 /************************************************/
1186 /* Main dissection function                     */
1187 static int
1188 dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1189 {
1190         if (!check_diameter(tvb))
1191                 return 0;
1192         dissect_diameter_common(tvb, pinfo, tree);
1193         return tvb_length(tvb);
1194 }
1195
1196 static void
1197 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1198 {
1199         /* Check if we have the start of a PDU or if this is segment */
1200         if (!check_diameter(tvb)) {
1201                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DIAMETER");
1202                 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
1203                 call_dissector(data_handle, tvb, pinfo, tree);
1204         } else {
1205                 tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4,
1206                                  get_diameter_pdu_len, dissect_diameter_common);
1207         }
1208 }
1209
1210
1211 static char *
1212 alnumerize(char *name)
1213 {
1214         char *r = name;
1215         char *w = name;
1216         char c;
1217
1218         for (;(c = *r); r++) {
1219                 if (isalnum((unsigned char)c) || c == '_' || c == '-' || c == '.') {
1220                         *(w++) = c;
1221                 }
1222         }
1223
1224         *w = '\0';
1225
1226         return name;
1227 }
1228
1229
1230 static guint
1231 reginfo(int *hf_ptr, const char *name, const char *abbr, const char *desc,
1232         enum ftenum ft, base_display_e base, value_string_ext *vs_ext,
1233         guint32 mask)
1234 {
1235         hf_register_info hf = { hf_ptr, {
1236                                 name ? wmem_strdup(wmem_epan_scope(), name) : wmem_strdup(wmem_epan_scope(), abbr),
1237                                 wmem_strdup(wmem_epan_scope(), abbr),
1238                                 ft,
1239                                 base,
1240                                 NULL,
1241                                 mask,
1242                                 wmem_strdup(wmem_epan_scope(), desc),
1243                                 HFILL }};
1244
1245         if(vs_ext) {
1246                 hf.hfinfo.strings = vs_ext;
1247         }
1248
1249         wmem_array_append_one(build_dict.hf,hf);
1250         return wmem_array_get_count(build_dict.hf);
1251 }
1252
1253 static void
1254 basic_avp_reginfo(diam_avp_t *a, const char *name, enum ftenum ft,
1255                   base_display_e base, value_string_ext *vs_ext)
1256 {
1257         hf_register_info hf[] = { { &(a->hf_value),
1258                                   { NULL, NULL, ft, base, NULL, 0x0,
1259                                   a->vendor->code ?
1260                                   wmem_strdup_printf(wmem_epan_scope(), "vendor=%d code=%d", a->vendor->code, a->code)
1261                                   : wmem_strdup_printf(wmem_epan_scope(), "code=%d", a->code),
1262                                   HFILL }}
1263         };
1264         gint *ettp = &(a->ett);
1265
1266         hf->hfinfo.name = wmem_strdup_printf(wmem_epan_scope(), "%s",name);
1267         hf->hfinfo.abbrev = alnumerize(wmem_strdup_printf(wmem_epan_scope(), "diameter.%s",name));
1268         if(vs_ext) {
1269                 hf->hfinfo.strings = vs_ext;
1270         }
1271
1272         wmem_array_append(build_dict.hf,hf,1);
1273         g_ptr_array_add(build_dict.ett,ettp);
1274 }
1275
1276 static diam_avp_t *
1277 build_address_avp(const avp_type_t *type _U_, guint32 code,
1278                   const diam_vnd_t *vendor, const char *name,
1279                   const value_string *vs _U_, void *data _U_)
1280 {
1281         diam_avp_t *a = (diam_avp_t *)g_malloc0(sizeof(diam_avp_t));
1282         address_avp_t *t = (address_avp_t *)g_malloc(sizeof(address_avp_t));
1283         gint *ettp = &(t->ett);
1284
1285         a->code = code;
1286         a->vendor = vendor;
1287 /*
1288  * It seems like the radius AVPs 1-255 will use the defs from RADIUS in which case:
1289  * http://www.ietf.org/rfc/rfc2865.txt?number=2865
1290  * Address
1291  *    The Address field is four octets.  The value 0xFFFFFFFF indicates
1292  *    that the NAS Should allow the user to select an address (e.g.
1293  *    Negotiated).  The value 0xFFFFFFFE indicates that the NAS should
1294  *    select an address for the user (e.g. Assigned from a pool of
1295  *    addresses kept by the NAS).  Other valid values indicate that the
1296  *    NAS should use that value as the user's IP address.
1297  *
1298  * Where as in Diameter:
1299  * RFC3588
1300  * Address
1301  *    The Address format is derived from the OctetString AVP Base
1302  *    Format.  It is a discriminated union, representing, for example a
1303  *    32-bit (IPv4) [IPV4] or 128-bit (IPv6) [IPV6] address, most
1304  *    significant octet first.  The first two octets of the Address
1305  *    AVP represents the AddressType, which contains an Address Family
1306  *    defined in [IANAADFAM].  The AddressType is used to discriminate
1307  *    the content and format of the remaining octets.
1308  */
1309         a->dissector_v16 = address_v16_avp;
1310         if (code<256) {
1311                 a->dissector_rfc = address_v16_avp;
1312         } else {
1313                 a->dissector_rfc = address_rfc_avp;
1314         }
1315         a->ett = -1;
1316         a->hf_value = -1;
1317         a->type_data = t;
1318
1319         t->ett = -1;
1320         t->hf_address_type = -1;
1321         t->hf_ipv4 = -1;
1322         t->hf_ipv6 = -1;
1323         t->hf_other = -1;
1324
1325         basic_avp_reginfo(a,name,FT_BYTES,BASE_NONE,NULL);
1326
1327         reginfo(&(t->hf_address_type), ep_strdup_printf("%s Address Family",name),
1328                 alnumerize(ep_strdup_printf("diameter.%s.addr_family",name)),
1329                 NULL, FT_UINT16, (base_display_e)(BASE_DEC|BASE_EXT_STRING), &diameter_avp_data_addrfamily_vals_ext, 0);
1330
1331         reginfo(&(t->hf_ipv4), ep_strdup_printf("%s Address",name),
1332                 alnumerize(ep_strdup_printf("diameter.%s.IPv4",name)),
1333                 NULL, FT_IPv4, BASE_NONE, NULL, 0);
1334
1335         reginfo(&(t->hf_ipv6), ep_strdup_printf("%s Address",name),
1336                 alnumerize(ep_strdup_printf("diameter.%s.IPv6",name)),
1337                 NULL, FT_IPv6, BASE_NONE, NULL, 0);
1338
1339         reginfo(&(t->hf_other), ep_strdup_printf("%s Address",name),
1340                 alnumerize(ep_strdup_printf("diameter.%s.Bytes",name)),
1341                 NULL, FT_BYTES, BASE_NONE, NULL, 0);
1342
1343         g_ptr_array_add(build_dict.ett,ettp);
1344
1345         return a;
1346 }
1347
1348 static diam_avp_t *
1349 build_proto_avp(const avp_type_t *type _U_, guint32 code,
1350                 const diam_vnd_t *vendor, const char *name _U_,
1351                 const value_string *vs _U_, void *data)
1352 {
1353         diam_avp_t *a = (diam_avp_t *)g_malloc0(sizeof(diam_avp_t));
1354         proto_avp_t *t = (proto_avp_t *)g_malloc0(sizeof(proto_avp_t));
1355         gint *ettp = &(a->ett);
1356
1357         a->code = code;
1358         a->vendor = vendor;
1359         a->dissector_v16 = proto_avp;
1360         a->dissector_rfc = proto_avp;
1361         a->ett = -1;
1362         a->hf_value = -2;
1363         a->type_data = t;
1364
1365         t->name = (char *)data;
1366         t->handle = NULL;
1367         t->reassemble_mode = REASEMBLE_NEVER;
1368
1369         g_ptr_array_add(build_dict.ett,ettp);
1370
1371         return a;
1372 }
1373
1374 static diam_avp_t *
1375 build_simple_avp(const avp_type_t *type, guint32 code, const diam_vnd_t *vendor,
1376                  const char *name, const value_string *vs, void *data _U_)
1377 {
1378         diam_avp_t *a;
1379         value_string_ext *vs_ext = NULL;
1380         base_display_e base;
1381         guint i = 0;
1382
1383         /*
1384          * Only 32-bit or shorter integral types can have a list of values.
1385          */
1386         base = (base_display_e)type->base;
1387         if (vs != NULL) {
1388                 switch (type->ft) {
1389
1390                 case FT_UINT8:
1391                 case FT_UINT16:
1392                 case FT_UINT32:
1393                 case FT_INT8:
1394                 case FT_INT16:
1395                 case FT_INT32:
1396                         break;
1397
1398                 default:
1399                         fprintf(stderr,"Diameter Dictionary: AVP '%s' has a list of values but isn't of a 32-bit or shorter integral type\n",
1400                                 name);
1401                         return NULL;
1402                 }
1403                 while (vs[i].strptr) {
1404                   i++;
1405                 }
1406                 vs_ext = value_string_ext_new((value_string *)vs, i+1, wmem_strdup_printf(wmem_epan_scope(), "%s_vals_ext",name));
1407                 base = (base_display_e)(base|BASE_EXT_STRING);
1408         }
1409
1410         a = (diam_avp_t *)wmem_alloc0(wmem_epan_scope(), sizeof(diam_avp_t));
1411         a->code = code;
1412         a->vendor = vendor;
1413         a->dissector_v16 = type->v16;
1414         a->dissector_rfc = type->rfc;
1415         a->ett = -1;
1416         a->hf_value = -1;
1417
1418         basic_avp_reginfo(a,name,type->ft,base,vs_ext);
1419
1420         return a;
1421 }
1422
1423
1424
1425 static const avp_type_t basic_types[] = {
1426         {"octetstring"          , simple_avp            , simple_avp    , FT_BYTES              , BASE_NONE             , build_simple_avp  },
1427         {"utf8string"           , utf8_avp              , utf8_avp      , FT_STRING             , BASE_NONE             , build_simple_avp  },
1428         {"grouped"              , grouped_avp           , grouped_avp   , FT_BYTES              , BASE_NONE             , build_simple_avp  },
1429         {"integer32"            , integer32_avp         , integer32_avp , FT_INT32              , BASE_DEC              , build_simple_avp  },
1430         {"unsigned32"           , unsigned32_avp        , unsigned32_avp, FT_UINT32             , BASE_DEC              , build_simple_avp  },
1431         {"integer64"            , integer64_avp         , integer64_avp , FT_INT64              , BASE_DEC              , build_simple_avp  },
1432         {"unsigned64"           , unsigned64_avp        , unsigned64_avp, FT_UINT64             , BASE_DEC              , build_simple_avp  },
1433         {"float32"              , float32_avp           , float32_avp   , FT_FLOAT              , BASE_NONE             , build_simple_avp  },
1434         {"float64"              , float64_avp           , float64_avp   , FT_DOUBLE             , BASE_NONE             , build_simple_avp  },
1435         {"ipaddress"            , NULL                  , NULL          , FT_NONE               , BASE_NONE             , build_address_avp },
1436         {"diameteruri"          , utf8_avp              , utf8_avp      , FT_STRING             , BASE_NONE             , build_simple_avp  },
1437         {"diameteridentity"     , utf8_avp              , utf8_avp      , FT_STRING             , BASE_NONE             , build_simple_avp  },
1438         {"ipfilterrule"         , utf8_avp              , utf8_avp      , FT_STRING             , BASE_NONE             , build_simple_avp  },
1439         {"qosfilterrule"        , utf8_avp              , utf8_avp      , FT_STRING             , BASE_NONE             , build_simple_avp  },
1440         {"time"                 , time_avp              , time_avp      , FT_ABSOLUTE_TIME      , ABSOLUTE_TIME_UTC     , build_simple_avp  },
1441         {NULL, NULL, NULL, FT_NONE, BASE_NONE, NULL }
1442 };
1443
1444
1445
1446 /*
1447  * This is like g_str_hash() (as of GLib 2.4.8), but it maps all
1448  * upper-case ASCII characters to their ASCII lower-case equivalents.
1449  * We can't use g_strdown(), as that doesn't do an ASCII mapping;
1450  * in Turkish locales, for example, there are two lower-case "i"s
1451  * and two upper-case "I"s, with and without dots - the ones with
1452  * dots map between each other, as do the ones without dots, so "I"
1453  * doesn't map to "i".
1454  */
1455 static guint
1456 strcase_hash(gconstpointer key)
1457 {
1458         const char *p = (const char *)key;
1459         guint h = *p;
1460         char c;
1461
1462         if (h) {
1463                 if (h >= 'A' && h <= 'Z')
1464                         h = h - 'A' + 'a';
1465                 for (p += 1; *p != '\0'; p++) {
1466                         c = *p;
1467                         if (c >= 'A' && c <= 'Z')
1468                                 c = c - 'A' + 'a';
1469                         h = (h << 5) - h + c;
1470                 }
1471         }
1472
1473         return h;
1474 }
1475
1476 /*
1477  * Again, use g_ascii_strcasecmp(), not strcasecmp(), so that only ASCII
1478  * letters are mapped, and they're mapped to the lower-case ASCII
1479  * equivalents.
1480  */
1481 static gboolean
1482 strcase_equal(gconstpointer ka, gconstpointer kb)
1483 {
1484         const char *a = (const char *)ka;
1485         const char *b = (const char *)kb;
1486         return g_ascii_strcasecmp(a,b) == 0;
1487 }
1488
1489
1490 /* Note: Dynamic "value string arrays" (e.g., vs_cmds, vs_avps, ...) are constructed using */
1491 /*       "zero-terminated" GArrays so that they will have the same form as standard        */
1492 /*       value_string arrays created at compile time. Since the last entry in a            */
1493 /*       value_string array must be {0, NULL}, we are assuming that NULL == 0 (hackish).   */
1494
1495 static int
1496 dictionary_load(void)
1497 {
1498         ddict_t *d;
1499         ddict_application_t *p;
1500         ddict_vendor_t *v;
1501         ddict_cmd_t *c;
1502         ddict_typedefn_t *t;
1503         ddict_avp_t *a;
1504         gboolean do_debug_parser = getenv("WIRESHARK_DEBUG_DIAM_DICT_PARSER") ? TRUE : FALSE;
1505         gboolean do_dump_dict = getenv("WIRESHARK_DUMP_DIAM_DICT") ? TRUE : FALSE;
1506         char *dir = ep_strdup_printf("%s" G_DIR_SEPARATOR_S "diameter" G_DIR_SEPARATOR_S, get_datafile_dir());
1507         const avp_type_t *type;
1508         const avp_type_t *octetstring = &basic_types[0];
1509         diam_avp_t *avp;
1510         GHashTable *vendors = g_hash_table_new(strcase_hash,strcase_equal);
1511         diam_vnd_t *vnd;
1512         GArray *vnd_shrt_arr = g_array_new(TRUE,TRUE,sizeof(value_string));
1513
1514         build_dict.hf = wmem_array_new(wmem_epan_scope(),sizeof(hf_register_info));
1515         build_dict.ett = g_ptr_array_new();
1516         build_dict.types = g_hash_table_new(strcase_hash,strcase_equal);
1517         build_dict.avps = g_hash_table_new(strcase_hash,strcase_equal);
1518
1519         dictionary.vnds = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"diameter_vnds");
1520         dictionary.avps = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"diameter_avps");
1521
1522         unknown_vendor.vs_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
1523         unknown_vendor.vs_avps = g_array_new(TRUE,TRUE,sizeof(value_string));
1524         no_vnd.vs_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
1525         no_vnd.vs_avps = g_array_new(TRUE,TRUE,sizeof(value_string));
1526
1527         all_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
1528
1529         pe_tree_insert32(dictionary.vnds,0,&no_vnd);
1530         g_hash_table_insert(vendors,(gchar *)"None",&no_vnd);
1531
1532         /* initialize the types hash with the known basic types */
1533         for (type = basic_types; type->name; type++) {
1534                 g_hash_table_insert(build_dict.types,(gchar *)type->name,(void *)type);
1535         }
1536
1537         /* load the dictionary */
1538         d = ddict_scan(dir,"dictionary.xml",do_debug_parser);
1539         if (d == NULL) {
1540                 return 0;
1541         }
1542
1543         if (do_dump_dict) ddict_print(stdout, d);
1544
1545         /* populate the types */
1546         for (t = d->typedefns; t; t = t->next) {
1547                 const avp_type_t *parent = NULL;
1548                 /* try to get the parent type */
1549
1550                 if (t->name == NULL) {
1551                         fprintf(stderr,"Diameter Dictionary: Invalid Type (empty name): parent==%s\n",
1552                                 t->parent ? t->parent : "(null)");
1553                         continue;
1554                 }
1555
1556
1557                 if (g_hash_table_lookup(build_dict.types,t->name))
1558                         continue;
1559
1560                 if (t->parent) {
1561                         parent = (avp_type_t *)g_hash_table_lookup(build_dict.types,t->parent);
1562                 }
1563
1564                 if (!parent) parent = octetstring;
1565
1566                 /* insert the parent type for this type */
1567                 g_hash_table_insert(build_dict.types,t->name,(void *)parent);
1568         }
1569
1570         /* populate the applications */
1571         if ((p = d->applications)) {
1572                 GArray *arr = g_array_new(TRUE,TRUE,sizeof(value_string));
1573
1574                 for (; p; p = p->next) {
1575                         value_string item = {p->code,p->name};
1576                         g_array_append_val(arr,item);
1577                 }
1578
1579                 dictionary.applications = (value_string *)arr->data;
1580                 g_array_free(arr,FALSE);
1581         }
1582
1583         if ((v = d->vendors)) {
1584                 for ( ; v; v = v->next) {
1585                         value_string item = {v->code,v->name};
1586
1587                         if (v->name == NULL) {
1588                                 fprintf(stderr,"Diameter Dictionary: Invalid Vendor (empty name): code==%d\n",v->code);
1589                                 continue;
1590                         }
1591
1592                         if (g_hash_table_lookup(vendors,v->name))
1593                                 continue;
1594
1595                         g_array_append_val(vnd_shrt_arr,item);
1596
1597                         vnd = (diam_vnd_t *)g_malloc(sizeof(diam_vnd_t));
1598                         vnd->code = v->code;
1599                         vnd->vs_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
1600                         vnd->vs_avps = g_array_new(TRUE,TRUE,sizeof(value_string));
1601                         vnd->vs_avps_ext = NULL;
1602                         pe_tree_insert32(dictionary.vnds,vnd->code,vnd);
1603                         g_hash_table_insert(vendors,v->name,vnd);
1604                 }
1605         }
1606
1607         vnd_short_vs = (value_string *)vnd_shrt_arr->data;
1608         g_array_free(vnd_shrt_arr,FALSE);
1609
1610         if ((c = d->cmds)) {
1611                 for (; c; c = c->next) {
1612                         if (c->vendor == NULL) {
1613                                 fprintf(stderr,"Diameter Dictionary: Invalid Vendor (empty name) for command %s\n",
1614                                         c->name ? c->name : "(null)");
1615                                 continue;
1616                         }
1617
1618                         if ((vnd = (diam_vnd_t *)g_hash_table_lookup(vendors,c->vendor))) {
1619                                 value_string item = {c->code,c->name};
1620                                 g_array_append_val(vnd->vs_cmds,item);
1621                                 /* Also add to all_cmds as used by RFC version */
1622                                 g_array_append_val(all_cmds,item);
1623                         } else {
1624                                 fprintf(stderr,"Diameter Dictionary: No Vendor: %s\n",c->vendor);
1625                         }
1626                 }
1627         }
1628
1629
1630         for (a = d->avps; a; a = a->next) {
1631                 ddict_enum_t *e;
1632                 value_string *vs = NULL;
1633                 const char *vend = a->vendor ? a->vendor : "None";
1634                 ddict_xmlpi_t *x;
1635                 void *avp_data = NULL;
1636
1637                 if (a->name == NULL) {
1638                         fprintf(stderr,"Diameter Dictionary: Invalid AVP (empty name)\n");
1639                         continue;
1640                 }
1641
1642                 if ((vnd = (diam_vnd_t *)g_hash_table_lookup(vendors,vend))) {
1643                         value_string vndvs = {a->code,a->name};
1644                         g_array_append_val(vnd->vs_avps,vndvs);
1645                 } else {
1646                         fprintf(stderr,"Diameter Dictionary: No Vendor: %s\n",vend);
1647                         vnd = &unknown_vendor;
1648                 }
1649
1650                 if ((e = a->enums)) {
1651                         wmem_array_t *arr = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
1652                         value_string term = {0, NULL};
1653
1654                         for (; e; e = e->next) {
1655                                 value_string item = {e->code,e->name};
1656                                 wmem_array_append_one(arr,item);
1657                         }
1658                         wmem_array_sort(arr, compare_avps);
1659                         wmem_array_append_one(arr,term);
1660                         vs = (value_string *)wmem_array_get_raw(arr);
1661                 }
1662
1663                 type = NULL;
1664
1665                 for( x = d->xmlpis; x; x = x->next ) {
1666                         if ( (strcase_equal(x->name,"avp-proto") && strcase_equal(x->key,a->name))
1667                                  || (a->type && strcase_equal(x->name,"type-proto") && strcase_equal(x->key,a->type))
1668                                  ) {
1669                                 static avp_type_t proto_type = {"proto", proto_avp, proto_avp, FT_UINT32, BASE_HEX, build_proto_avp};
1670                                 type =  &proto_type;
1671
1672                                 avp_data = x->value;
1673                                 break;
1674                         }
1675                 }
1676
1677                 if ( (!type) && a->type )
1678                         type = (avp_type_t *)g_hash_table_lookup(build_dict.types,a->type);
1679
1680                 if (!type) type = octetstring;
1681
1682                 avp = type->build( type, a->code, vnd, a->name, vs, avp_data);
1683                 if (avp != NULL) {
1684                         g_hash_table_insert(build_dict.avps, a->name, avp);
1685
1686                         {
1687                                 emem_tree_key_t k[] = {
1688                                         { 1, &(a->code) },
1689                                         { 1, &(vnd->code) },
1690                                         { 0 , NULL }
1691                                 };
1692                                 pe_tree_insert32_array(dictionary.avps,k,avp);
1693                         }
1694                 }
1695         }
1696         g_hash_table_destroy(build_dict.types);
1697         g_hash_table_destroy(build_dict.avps);
1698         g_hash_table_destroy(vendors);
1699
1700         return 1;
1701 }
1702
1703 /* registration with the filtering engine */
1704 void proto_reg_handoff_diameter(void);
1705
1706 /*
1707  * This does most of the registration work; see proto_register_diameter()
1708  * for the reason why we split it off.
1709  */
1710 static void
1711 real_proto_register_diameter(void)
1712 {
1713         module_t *diameter_module;
1714         expert_module_t* expert_diameter;
1715         guint i, ett_length;
1716
1717         hf_register_info hf_base[] = {
1718         { &hf_diameter_version,
1719                   { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1720                           NULL, HFILL }},
1721         { &hf_diameter_length,
1722                   { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1723                           NULL, HFILL }},
1724         { &hf_diameter_flags,
1725                   { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1726                           NULL, HFILL }},
1727         { &hf_diameter_flags_request,
1728                   { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_R,
1729                           NULL, HFILL }},
1730         { &hf_diameter_flags_proxyable,
1731                   { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_P,
1732                           NULL, HFILL }},
1733         { &hf_diameter_flags_error,
1734                   { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_E,
1735                           NULL, HFILL }},
1736         { &hf_diameter_flags_T,
1737                   { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_T,
1738                           NULL, HFILL }},
1739         { &hf_diameter_flags_reserved4,
1740                   { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1741                           DIAM_FLAGS_RESERVED4, NULL, HFILL }},
1742         { &hf_diameter_flags_reserved5,
1743                   { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1744                           DIAM_FLAGS_RESERVED5, NULL, HFILL }},
1745         { &hf_diameter_flags_reserved6,
1746                   { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1747                           DIAM_FLAGS_RESERVED6, NULL, HFILL }},
1748         { &hf_diameter_flags_reserved7,
1749                   { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1750                           DIAM_FLAGS_RESERVED7, NULL, HFILL }},
1751         { &hf_diameter_vendor_id,
1752                   { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC|BASE_EXT_STRING, &sminmpec_values_ext,
1753                           0x0, NULL, HFILL }},
1754         { &hf_diameter_application_id,
1755                   { "ApplicationId", "diameter.applicationId", FT_UINT32, BASE_DEC, VALS(dictionary.applications),
1756                           0x0, NULL, HFILL }},
1757         { &hf_diameter_hopbyhopid,
1758                   { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1759                           BASE_HEX, NULL, 0x0, NULL, HFILL }},
1760         { &hf_diameter_endtoendid,
1761                   { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
1762                           BASE_HEX, NULL, 0x0, NULL, HFILL }},
1763         { &hf_diameter_avp,
1764                   { "AVP","diameter.avp", FT_BYTES, BASE_NONE,
1765                           NULL, 0x0, NULL, HFILL }},
1766         { &hf_diameter_avp_len,
1767                   { "AVP Length","diameter.avp.len", FT_UINT24, BASE_DEC,
1768                           NULL, 0x0, NULL, HFILL }},
1769         { &hf_diameter_avp_code,
1770                   { "AVP Code", "diameter.avp.code", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
1771         { &hf_diameter_avp_flags,
1772                   { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1773                           NULL, 0x0, NULL, HFILL }},
1774         { &hf_diameter_avp_flags_vendor_specific,
1775                   { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_V,
1776                           NULL, HFILL }},
1777         { &hf_diameter_avp_flags_mandatory,
1778                   { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_M,
1779                           NULL, HFILL }},
1780         { &hf_diameter_avp_flags_protected,
1781                   { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_P,
1782                           NULL, HFILL }},
1783         { &hf_diameter_avp_flags_reserved3,
1784                   { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1785                           AVP_FLAGS_RESERVED3,  NULL, HFILL }},
1786         { &hf_diameter_avp_flags_reserved4,
1787                   { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1788                           AVP_FLAGS_RESERVED4,  NULL, HFILL }},
1789         { &hf_diameter_avp_flags_reserved5,
1790                   { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1791                           AVP_FLAGS_RESERVED5,  NULL, HFILL }},
1792         { &hf_diameter_avp_flags_reserved6,
1793                   { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1794                           AVP_FLAGS_RESERVED6,  NULL, HFILL }},
1795         { &hf_diameter_avp_flags_reserved7,
1796                   { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
1797                           AVP_FLAGS_RESERVED7,  NULL, HFILL }},
1798         { &hf_diameter_avp_vendor_id,
1799                   { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC|BASE_EXT_STRING,
1800                           &sminmpec_values_ext, 0x0, NULL, HFILL }},
1801         { &(unknown_avp.hf_value),
1802                   { "Value","diameter.avp.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1803         { &hf_diameter_avp_data_wrong_length,
1804                   { "Data","diameter.avp.invalid-data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1805         { &hf_diameter_avp_pad,
1806                   { "Padding","diameter.avp.pad", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1807         { &hf_diameter_code,
1808                   { "Command Code", "diameter.cmd.code", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
1809         { &hf_diameter_answer_in,
1810                 { "Answer In", "diameter.answer_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1811                 "The answer to this diameter request is in this frame", HFILL }},
1812         { &hf_diameter_answer_to,
1813                 { "Request In", "diameter.answer_to", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1814                 "This is an answer to the diameter request in this frame", HFILL }},
1815         { &hf_diameter_answer_time,
1816                 { "Response Time", "diameter.resp_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1817                 "The time between the request and the answer", HFILL }},
1818         { &hf_framed_ipv6_prefix_reserved,
1819             { "Framed IPv6 Prefix Reserved byte", "diameter.framed_ipv6_prefix_reserved",
1820             FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1821         { &hf_framed_ipv6_prefix_length,
1822             { "Framed IPv6 Prefix length (in bits)", "diameter.framed_ipv6_prefix_length",
1823             FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
1824         { &hf_framed_ipv6_prefix_bytes,
1825             { "Framed IPv6 Prefix as a bytestring", "diameter.framed_ipv6_prefix_bytes",
1826             FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
1827         { &hf_framed_ipv6_prefix_ipv6,
1828             { "Framed IPv6 Prefix as an IPv6 address", "diameter.framed_ipv6_prefix_ipv6",
1829             FT_IPv6, BASE_NONE, NULL, 0, "This field is present only if the prefix length is 128", HFILL }}
1830         };
1831
1832         gint *ett_base[] = {
1833                 &ett_diameter,
1834                 &ett_diameter_flags,
1835                 &ett_diameter_avp_flags,
1836                 &ett_diameter_avpinfo,
1837                 &ett_unknown,
1838                 &ett_err,
1839                 &(unknown_avp.ett)
1840         };
1841
1842         static ei_register_info ei[] = {
1843                 { &ei_diameter_reserved_bit_set, { "diameter.reserved_bit_set", PI_MALFORMED, PI_WARN, "Reserved bit set", EXPFILL }},
1844         };
1845
1846         wmem_array_append(build_dict.hf, hf_base, array_length(hf_base));
1847         ett_length = array_length(ett_base);
1848         for (i = 0; i < ett_length; i++) {
1849                 g_ptr_array_add(build_dict.ett, ett_base[i]);
1850         }
1851
1852         proto_diameter = proto_register_protocol ("Diameter Protocol", "DIAMETER", "diameter");
1853
1854         proto_register_field_array(proto_diameter, (hf_register_info *)wmem_array_get_raw(build_dict.hf), wmem_array_get_count(build_dict.hf));
1855         proto_register_subtree_array((gint **)build_dict.ett->pdata, build_dict.ett->len);
1856         expert_diameter = expert_register_protocol(proto_diameter);
1857         expert_register_field_array(expert_diameter, ei, array_length(ei));
1858
1859         g_ptr_array_free(build_dict.ett,TRUE);
1860
1861         /* Allow dissector to find be found by name. */
1862         new_register_dissector("diameter", dissect_diameter, proto_diameter);
1863
1864         /* Register dissector table(s) to do sub dissection of AVPs (OctetStrings) */
1865         diameter_dissector_table = register_dissector_table("diameter.base", "DIAMETER_BASE_AVPS", FT_UINT32, BASE_DEC);
1866         diameter_3gpp_avp_dissector_table = register_dissector_table("diameter.3gpp", "DIAMETER_3GPP_AVPS", FT_UINT32, BASE_DEC);
1867         diameter_ericsson_avp_dissector_table = register_dissector_table("diameter.ericsson", "DIAMETER_ERICSSON_AVPS", FT_UINT32, BASE_DEC);
1868
1869         /* Set default TCP ports */
1870         range_convert_str(&global_diameter_tcp_port_range, DEFAULT_DIAMETER_PORT_RANGE, MAX_UDP_PORT);
1871         range_convert_str(&global_diameter_sctp_port_range, DEFAULT_DIAMETER_PORT_RANGE, MAX_SCTP_PORT);
1872
1873         /* Register configuration options for ports */
1874         diameter_module = prefs_register_protocol(proto_diameter,
1875                                                   proto_reg_handoff_diameter);
1876
1877         prefs_register_range_preference(diameter_module, "tcp.ports", "Diameter TCP ports",
1878                                         "TCP ports to be decoded as Diameter (default: "
1879                                         DEFAULT_DIAMETER_PORT_RANGE ")",
1880                                         &global_diameter_tcp_port_range, MAX_UDP_PORT);
1881
1882         prefs_register_range_preference(diameter_module, "sctp.ports",
1883                                         "Diameter SCTP Ports",
1884                                         "SCTP ports to be decoded as Diameter (default: "
1885                                         DEFAULT_DIAMETER_PORT_RANGE ")",
1886                                         &global_diameter_sctp_port_range, MAX_SCTP_PORT);
1887
1888         /* Desegmentation */
1889         prefs_register_bool_preference(diameter_module, "desegment",
1890                                        "Reassemble Diameter messages\nspanning multiple TCP segments",
1891                                        "Whether the Diameter dissector should reassemble messages spanning multiple TCP segments."
1892                                        " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1893                                        &gbl_diameter_desegment);
1894
1895         prefs_register_range_preference(diameter_module, "udp.ports", "Diameter UDP ports",
1896                                         "UDP ports to be decoded as Diameter (default: 0 as Diameter over UDP is nonstandard)",
1897                                         &global_diameter_udp_port_range, MAX_UDP_PORT);
1898
1899
1900         /*  Register some preferences we no longer support, so we can report
1901          *  them as obsolete rather than just illegal.
1902          */
1903         prefs_register_obsolete_preference(diameter_module, "version");
1904         prefs_register_obsolete_preference(diameter_module, "tcp.port");
1905         prefs_register_obsolete_preference(diameter_module, "sctp.port");
1906         prefs_register_obsolete_preference(diameter_module, "command_in_header");
1907         prefs_register_obsolete_preference(diameter_module, "dictionary.name");
1908         prefs_register_obsolete_preference(diameter_module, "dictionary.use");
1909         prefs_register_obsolete_preference(diameter_module, "allow_zero_as_app_id");
1910         prefs_register_obsolete_preference(diameter_module, "suppress_console_output");
1911
1912         /* Register tap */
1913         diameter_tap = register_tap("diameter");
1914 }
1915
1916 void
1917 proto_register_diameter(void)
1918 {
1919         /*
1920          * The hf_base[] array for Diameter refers to a variable
1921          * that is set by dictionary_load(), so we need to call
1922          * dictionary_load() before hf_base[] is initialized.
1923          *
1924          * To ensure that, we call dictionary_load() and then
1925          * call a routine that defines hf_base[] and does all
1926          * the registration work.
1927          */
1928         dictionary_load();
1929         real_proto_register_diameter();
1930 } /* proto_register_diameter */
1931
1932 void
1933 proto_reg_handoff_diameter(void)
1934 {
1935         static gboolean Initialized=FALSE;
1936         static range_t *diameter_tcp_port_range;
1937         static range_t *diameter_sctp_port_range;
1938         static range_t *diameter_udp_port_range;
1939
1940         if (!Initialized) {
1941                 diameter_sctp_handle = find_dissector("diameter");
1942                 diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
1943                                                               proto_diameter);
1944                 diameter_udp_handle = new_create_dissector_handle(dissect_diameter, proto_diameter);
1945                 data_handle = find_dissector("data");
1946                 eap_handle = find_dissector("eap");
1947
1948                 dissector_add_uint("sctp.ppi", DIAMETER_PROTOCOL_ID, diameter_sctp_handle);
1949
1950                 /* Register special decoding for some AVPs */
1951                 /* AVP Code: 97 Framed-IPv6-Address */
1952                 dissector_add_uint("diameter.base", 97,
1953                         new_create_dissector_handle(dissect_diameter_base_framed_ipv6_prefix, proto_diameter));
1954                 /* AVP Code: 266 Vendor-Id */
1955                 dissector_add_uint("diameter.base", 266,
1956                         new_create_dissector_handle(dissect_diameter_vendor_id, proto_diameter));
1957                 /* AVP Code: 462 EAP-Payload */
1958                 dissector_add_uint("diameter.base", 462,
1959                         new_create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
1960                 /* AVP Code: 463 EAP-Reissued-Payload */
1961                 dissector_add_uint("diameter.base", 463,
1962                         new_create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
1963
1964                 Initialized=TRUE;
1965         } else {
1966                 dissector_delete_uint_range("tcp.port", diameter_tcp_port_range, diameter_tcp_handle);
1967                 dissector_delete_uint_range("sctp.port", diameter_sctp_port_range, diameter_sctp_handle);
1968                 dissector_delete_uint_range("udp.port", diameter_udp_port_range, diameter_udp_handle);
1969                 g_free(diameter_tcp_port_range);
1970                 g_free(diameter_sctp_port_range);
1971                 g_free(diameter_udp_port_range);
1972         }
1973
1974         /* set port for future deletes */
1975         diameter_tcp_port_range = range_copy(global_diameter_tcp_port_range);
1976         diameter_sctp_port_range = range_copy(global_diameter_sctp_port_range);
1977         diameter_sctp_port_range = range_copy(global_diameter_udp_port_range);
1978         dissector_add_uint_range("tcp.port",  diameter_tcp_port_range,  diameter_tcp_handle);
1979         dissector_add_uint_range("sctp.port", diameter_sctp_port_range, diameter_sctp_handle);
1980         dissector_add_uint_range("udp.port", diameter_udp_port_range, diameter_udp_handle);
1981
1982         exported_pdu_tap = find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_7);
1983
1984 }
1985