Get rid of get_ber_last_reated_item() and fix dissection of wIN-TriggerList.
[obnox/wireshark/wip.git] / epan / dissectors / packet-netflow.c
1 /*
2  ** packet-netflow.c
3  **
4  ** $Id$
5  **
6  ** (c) 2002 bill fumerola <fumerola@yahoo-inc.com>
7  ** (C) 2005-06 Luca Deri <deri@ntop.org>
8  **
9  ** All rights reserved.
10  **
11  ** Wireshark - Network traffic analyzer
12  ** By Gerald Combs <gerald@wireshark.org>
13  ** Copyright 1998 Gerald Combs
14  **
15  ** This program is free software; you can redistribute it and/or
16  ** modify it under the terms of the GNU General Public License
17  ** as published by the Free Software Foundation; either version 2
18  ** of the License, or (at your option) any later version.
19  **
20  ** This program is distributed in the hope that it will be useful,
21  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
22  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  ** GNU General Public License for more details.
24  **
25  ** You should have received a copy of the GNU General Public License
26  ** along with this program; if not, write to the Free Software
27  ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28  *****************************************************************************
29  **
30  ** Previous NetFlow dissector written by Matthew Smart <smart@monkey.org>
31  ** NetFlow v9 support added by same.
32  **
33  ** NetFlow v9 patches by Luca Deri <deri@ntop.org>
34  **
35  ** See
36  **
37  ** http://www.cisco.com/warp/public/cc/pd/iosw/prodlit/tflow_wp.htm
38  **
39  ** for NetFlow v9 information.
40  **
41  ** http://www.ietf.org/internet-drafts/draft-ietf-ipfix-info-11.txt
42  ** http://www.ietf.org/internet-drafts/draft-ietf-ipfix-protocol-19.txt
43  ** for IPFIX
44  **
45  *****************************************************************************
46  **
47  ** this code was written from the following documentation:
48  **
49  ** http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_6/iug/format.pdf
50  ** http://www.caida.org/tools/measurement/cflowd/configuration/configuration-9.html
51  **
52  ** some documentation is more accurate then others. in some cases, live data and
53  ** information contained in responses from vendors were also used. some fields
54  ** are dissected as vendor specific fields.
55  **
56  ** See also
57  **
58  ** http://www.cisco.com/univercd/cc/td/doc/cisintwk/intsolns/netflsol/nfwhite.htm
59  **
60  ** $Yahoo: //depot/fumerola/packet-netflow/packet-netflow.c#14 $
61  */
62
63 #ifdef HAVE_CONFIG_H
64 # include "config.h"
65 #endif
66
67 #include <glib.h>
68 #include <epan/packet.h>
69 #include <string.h>
70
71 #include <epan/prefs.h>
72
73 #define UDP_PORT_NETFLOW        2055
74
75 #define UDP_PORT_IPFIX          4739
76
77 static guint global_netflow_udp_port = UDP_PORT_NETFLOW;
78 static guint netflow_udp_port = 0;
79 static guint global_ipfix_port = UDP_PORT_IPFIX;
80 static guint ipfix_port = 0;
81
82 /*
83  * pdu identifiers & sizes
84  */
85
86 #define V1PDU_SIZE              (4 * 12)
87 #define V5PDU_SIZE              (4 * 12)
88 #define V7PDU_SIZE              (4 * 13)
89 #define V8PDU_AS_SIZE           (4 * 7)
90 #define V8PDU_PROTO_SIZE        (4 * 7)
91 #define V8PDU_SPREFIX_SIZE      (4 * 8)
92 #define V8PDU_DPREFIX_SIZE      (4 * 8)
93 #define V8PDU_MATRIX_SIZE       (4 * 10)
94 #define V8PDU_DESTONLY_SIZE     (4 * 8)
95 #define V8PDU_SRCDEST_SIZE      (4 * 10)
96 #define V8PDU_FULL_SIZE         (4 * 11)
97 #define V8PDU_TOSAS_SIZE        (V8PDU_AS_SIZE + 4)
98 #define V8PDU_TOSPROTOPORT_SIZE (V8PDU_PROTO_SIZE + 4)
99 #define V8PDU_TOSSRCPREFIX_SIZE V8PDU_SPREFIX_SIZE
100 #define V8PDU_TOSDSTPREFIX_SIZE V8PDU_DPREFIX_SIZE
101 #define V8PDU_TOSMATRIX_SIZE    V8PDU_MATRIX_SIZE
102 #define V8PDU_PREPORTPROTOCOL_SIZE (4 * 10)
103
104 static const value_string v5_sampling_mode[] = {
105         {0, "No sampling mode configured"},
106         {1, "Packet Interval sampling mode configured"},
107         {0, NULL}
108 };
109
110 enum {
111         V8PDU_NO_METHOD = 0,
112         V8PDU_AS_METHOD,
113         V8PDU_PROTO_METHOD,
114         V8PDU_SPREFIX_METHOD,
115         V8PDU_DPREFIX_METHOD,
116         V8PDU_MATRIX_METHOD,
117         V8PDU_DESTONLY_METHOD,
118         V8PDU_SRCDEST_METHOD,
119         V8PDU_FULL_METHOD,
120         V8PDU_TOSAS_METHOD,
121         V8PDU_TOSPROTOPORT_METHOD,
122         V8PDU_TOSSRCPREFIX_METHOD,
123         V8PDU_TOSDSTPREFIX_METHOD,
124         V8PDU_TOSMATRIX_METHOD,
125         V8PDU_PREPORTPROTOCOL_METHOD
126 };
127
128 static const value_string v8_agg[] = {
129         {V8PDU_AS_METHOD, "V8 AS aggregation"},
130         {V8PDU_PROTO_METHOD, "V8 Proto/Port aggregation"},
131         {V8PDU_SPREFIX_METHOD, "V8 Source Prefix aggregation"},
132         {V8PDU_DPREFIX_METHOD, "V8 Destination Prefix aggregation"},
133         {V8PDU_MATRIX_METHOD, "V8 Network Matrix aggregation"},
134         {V8PDU_DESTONLY_METHOD, "V8 Destination aggregation (Cisco Catalyst)"},
135         {V8PDU_SRCDEST_METHOD, "V8 Src/Dest aggregation (Cisco Catalyst)"},
136         {V8PDU_FULL_METHOD, "V8 Full aggregation (Cisco Catalyst)"},
137         {V8PDU_TOSAS_METHOD, "V8 TOS+AS aggregation aggregation"},
138         {V8PDU_TOSPROTOPORT_METHOD, "V8 TOS+Protocol aggregation"},
139         {V8PDU_TOSSRCPREFIX_METHOD, "V8 TOS+Source Prefix aggregation"},
140         {V8PDU_TOSDSTPREFIX_METHOD, "V8 TOS+Destination Prefix aggregation"},
141         {V8PDU_TOSMATRIX_METHOD, "V8 TOS+Prefix Matrix aggregation"},
142         {V8PDU_PREPORTPROTOCOL_METHOD, "V8 Port+Protocol aggregation"},
143         {0, NULL}
144 };
145
146 /* Version 9 template cache structures */
147 #define V9TEMPLATE_CACHE_MAX_ENTRIES    100
148
149 struct v9_template_entry {
150         guint16 type;
151         guint16 length;
152 };
153
154 struct v9_template {
155         guint16 id;
156         guint16 count;
157         guint32 length;
158         guint32 source_id;
159         address source_addr;
160         guint16 option_template; /* 0=data template, 1=option template */
161         guint16 count_scopes;
162         struct  v9_template_entry *scopes;
163         struct v9_template_entry *entries;
164 };
165
166 static struct v9_template v9_template_cache[V9TEMPLATE_CACHE_MAX_ENTRIES];
167
168 /*
169  * wireshark tree identifiers
170  */
171
172 static int      proto_netflow = -1;
173 static int      ett_netflow = -1;
174 static int      ett_unixtime = -1;
175 static int      ett_flow = -1;
176 static int      ett_flowtime = -1;
177 static int      ett_template = -1;
178 static int      ett_field = -1;
179 static int      ett_dataflowset = -1;
180
181 /*
182  * cflow header
183  */
184
185 static int      hf_cflow_version = -1;
186 static int      hf_cflow_count = -1;
187 static int      hf_cflow_len = -1;
188 static int      hf_cflow_sysuptime = -1;
189 static int      hf_cflow_exporttime = -1;
190 static int      hf_cflow_unix_secs = -1;
191 static int      hf_cflow_unix_nsecs = -1;
192 static int      hf_cflow_timestamp = -1;
193 static int      hf_cflow_samplingmode = -1;
194 static int      hf_cflow_samplerate = -1;
195
196 /*
197  * cflow version specific info
198  */
199 static int      hf_cflow_sequence = -1;
200 static int      hf_cflow_engine_type = -1;
201 static int      hf_cflow_engine_id = -1;
202 static int      hf_cflow_source_id = -1;
203
204 static int      hf_cflow_aggmethod = -1;
205 static int      hf_cflow_aggversion = -1;
206
207 /* Version 9 */
208
209 static int      hf_cflow_template_flowset_id = -1;
210 static int      hf_cflow_data_flowset_id = -1;
211 static int      hf_cflow_data_datarecord_id = -1;
212 static int      hf_cflow_options_flowset_id = -1;
213 static int      hf_cflow_flowset_id = -1;
214 static int      hf_cflow_flowset_length = -1;
215 static int      hf_cflow_datarecord_length = -1;
216 static int      hf_cflow_template_id = -1;
217 static int      hf_cflow_template_field_count = -1;
218 static int      hf_cflow_template_field_type = -1;
219 static int      hf_cflow_template_field_length = -1;
220 static int      hf_cflow_option_scope_length = -1;
221 static int      hf_cflow_option_length = -1;
222 static int      hf_cflow_template_scope_field_type = -1;
223 static int      hf_cflow_template_scope_field_length = -1;
224
225 static int      hf_cflow_scope_system = -1;
226 static int      hf_cflow_scope_interface = -1;
227 static int      hf_cflow_scope_linecard = -1;
228 static int      hf_cflow_scope_cache = -1;
229 static int      hf_cflow_scope_template = -1;
230 static int      hf_cflow_scope_unknown = -1;
231
232 /*
233  * pdu storage
234  */
235 static int      hf_cflow_srcaddr = -1;
236 static int      hf_cflow_srcaddr_v6 = -1;
237 static int      hf_cflow_srcnet = -1;
238 static int      hf_cflow_dstaddr = -1;
239 static int      hf_cflow_dstaddr_v6 = -1;
240 static int      hf_cflow_dstnet = -1;
241 static int      hf_cflow_nexthop = -1;
242 static int      hf_cflow_nexthop_v6 = -1;
243 static int      hf_cflow_bgpnexthop = -1;
244 static int      hf_cflow_bgpnexthop_v6 = -1;
245 static int      hf_cflow_inputint = -1;
246 static int      hf_cflow_outputint = -1;
247 static int      hf_cflow_flows = -1;
248 static int      hf_cflow_packets = -1;
249 static int      hf_cflow_packets64 = -1;
250 static int      hf_cflow_packetsout = -1;
251 static int      hf_cflow_octets = -1;
252 static int      hf_cflow_octets64 = -1;
253 static int      hf_cflow_length_min = -1;
254 static int      hf_cflow_length_max = -1;
255 static int      hf_cflow_timedelta = -1;
256 static int      hf_cflow_timestart = -1;
257 static int      hf_cflow_timeend = -1;
258 static int      hf_cflow_srcport = -1;
259 static int      hf_cflow_dstport = -1;
260 static int      hf_cflow_prot = -1;
261 static int      hf_cflow_tos = -1;
262 static int      hf_cflow_flags = -1;
263 static int      hf_cflow_tcpflags = -1;
264 static int      hf_cflow_dstas = -1;
265 static int      hf_cflow_srcas = -1;
266 static int      hf_cflow_dstmask = -1;
267 static int      hf_cflow_dstmask_v6 = -1;
268 static int      hf_cflow_srcmask = -1;
269 static int      hf_cflow_srcmask_v6 = -1;
270 static int      hf_cflow_routersc = -1;
271 static int      hf_cflow_mulpackets = -1;
272 static int      hf_cflow_muloctets = -1;
273 static int      hf_cflow_octets_exp = -1;
274 static int      hf_cflow_octets_exp64 = -1;
275 static int      hf_cflow_packets_exp = -1;
276 static int      hf_cflow_packets_exp64 = -1;
277 static int      hf_cflow_flows_exp = -1;
278 static int      hf_cflow_flows_exp64 = -1;
279 static int      hf_cflow_srcprefix = -1;
280 static int      hf_cflow_dstprefix = -1;
281 static int      hf_cflow_flow_class = -1;
282 static int      hf_cflow_ttl_minimum = -1;
283 static int      hf_cflow_ttl_maximum = -1;
284 static int      hf_cflow_ipv4_id = -1;
285 static int      hf_cflow_ip_version = -1;
286 static int      hf_cflow_icmp_type = -1;
287 static int      hf_cflow_igmp_type = -1;
288 static int      hf_cflow_sampling_interval = -1;
289 static int      hf_cflow_sampling_algorithm = -1;
290 static int      hf_cflow_flow_active_timeout = -1;
291 static int      hf_cflow_flow_inactive_timeout = -1;
292 static int      hf_cflow_mpls_top_label_type = -1;
293 static int      hf_cflow_mpls_pe_addr = -1;
294 static int      hf_cflow_sampler_mode = -1;
295 static int      hf_cflow_sampler_random_interval = -1;
296 static int      hf_cflow_direction = -1;
297 static int      hf_cflow_if_name = -1;
298 static int      hf_cflow_if_descr = -1;
299 static int      hf_cflow_sampler_name = -1;
300 static int      hf_cflow_forwarding_status = -1;
301 static int      hf_cflow_forwarding_code = -1;
302 static int      hf_cflow_peer_srcas = -1;
303 static int      hf_cflow_peer_dstas = -1;
304 static int      hf_cflow_flow_exporter = -1;
305 static int      hf_cflow_icmp_ipv4_type = -1;
306 static int      hf_cflow_icmp_ipv4_code = -1;
307 static int      hf_cflow_icmp_ipv6_type = -1;
308 static int      hf_cflow_icmp_ipv6_code = -1;
309 static int      hf_cflow_tcp_window_size = -1;
310 static int      hf_cflow_ip_total_length = -1;
311 static int      hf_cflow_ip_ttl = -1;
312 static int      hf_cflow_ip_tos = -1;
313 static int      hf_cflow_ip_dscp = -1;
314 static int      hf_cflow_octets_squared64 = -1;
315 static int      hf_cflow_udp_length = -1;
316 static int      hf_cflow_is_multicast = -1;
317 static int      hf_cflow_ip_header_words = -1;
318 static int      hf_cflow_option_map = -1;
319 static int      hf_cflow_section_header = -1;
320 static int      hf_cflow_section_payload = -1;
321
322 const value_string special_mpls_top_label_type[] = {
323         {0,     "Unknown"},
324         {1,     "TE-MIDPT"},
325         {2,     "ATOM"},
326         {3,     "VPN"},
327         {4,     "BGP"},
328         {5,     "LDP"},
329         {0,     NULL }
330 };
331
332 void
333 proto_tree_add_mpls_label(proto_tree * pdutree, tvbuff_t * tvb, int offset, int length, int level)
334 {
335         if( length == 3) {
336                 guint8 b0 = tvb_get_guint8(tvb, offset);
337                 guint8 b1 = tvb_get_guint8(tvb, offset + 1);
338                 guint8 b2 = tvb_get_guint8(tvb, offset + 2);
339                 proto_tree_add_text(pdutree, tvb, offset, length,
340                         "MPLS-Label%d: %u exp-bits: %u %s", level,
341                         ((b0<<12)+(b1<<4)+(b2>>4)),
342                         ((b2>>1)&0x7),
343                         ((b2&0x1)?"top-of-stack":""));
344         } else {
345                 proto_tree_add_text(pdutree, tvb, offset, length,
346                         "MPLS-Label%d: bad lengh %d", level, length);
347         }
348 }
349
350 void            proto_reg_handoff_netflow(void);
351
352 typedef struct _hdrinfo_t {
353         guint8 vspec;
354         guint32 src_id; /* SourceID in NetFlow V9, Observation Domain ID in IPFIX */
355         address net_src;
356 } hdrinfo_t;
357
358 typedef int     dissect_pdu_t(proto_tree * pdutree, tvbuff_t * tvb, int offset,
359                               hdrinfo_t * hdrinfo);
360
361 static int      dissect_pdu(proto_tree * tree, tvbuff_t * tvb, int offset,
362                             hdrinfo_t * hdrinfo);
363 static int      dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb,
364                                   int offset, hdrinfo_t * hdrinfo);
365 static int      dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb,
366                                    int offset, hdrinfo_t * hdrinfo);
367 static int      dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb,
368                                    int offset, hdrinfo_t * hdrinfo);
369 static int      dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb,
370                                 int offset, guint16 id, guint length, hdrinfo_t * hdrinfo);
371 static void     dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb,
372                                int offset, struct v9_template * template);
373 static int      dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb,
374                                    int offset, hdrinfo_t * hdrinfo);
375 static int      dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb,
376                                     int offset, int len, hdrinfo_t * hdrinfo);
377 static int      v9_template_hash(guint16 id, const address * net_src,
378                                  guint32 src_id);
379 static void     v9_template_add(struct v9_template * template);
380 static struct v9_template *v9_template_get(guint16 id, address  * net_src,
381                                            guint32 src_id);
382 static const char *   decode_v9_template_types(int type);
383
384 static gchar   *getprefix(const guint32 * address, int prefix);
385 static void     dissect_netflow(tvbuff_t * tvb, packet_info * pinfo,
386                                 proto_tree * tree);
387
388 static int      flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb,
389                                   int offset);
390 static int      flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb,
391                                    int offset);
392 static int      flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb,
393                                         int offset);
394 static int      flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb,
395                                     int offset);
396 static int      flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb,
397                                        int offset);
398 static int      flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb,
399                                        int offset, int bytes,
400                                        const char *text);
401
402
403 static void
404 dissect_netflow(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
405 {
406         proto_tree     *netflow_tree = NULL;
407         proto_tree     *ti;
408         proto_item     *timeitem, *pduitem;
409         proto_tree     *timetree, *pdutree;
410         unsigned int    pduret, ver = 0, pdus = 0, x = 1;
411         hdrinfo_t       hdrinfo;
412         gint            flow_len = -1;
413         size_t          available, pdusize, offset = 0;
414         nstime_t        ts;
415         dissect_pdu_t  *pduptr;
416
417         if (check_col(pinfo->cinfo, COL_PROTOCOL))
418                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CFLOW");
419         if (check_col(pinfo->cinfo, COL_INFO))
420                 col_clear(pinfo->cinfo, COL_INFO);
421
422         if (tree) {
423                 ti = proto_tree_add_item(tree, proto_netflow, tvb,
424                                          offset, -1, FALSE);
425                 netflow_tree = proto_item_add_subtree(ti, ett_netflow);
426         }
427
428         ver = tvb_get_ntohs(tvb, offset);
429
430         hdrinfo.vspec = ver;
431         hdrinfo.src_id = 0;
432         SET_ADDRESS(&hdrinfo.net_src, pinfo->net_src.type, pinfo->net_src.len,
433                     pinfo->net_src.data);
434
435
436         switch (ver) {
437         case 1:
438                 pdusize = V1PDU_SIZE;
439                 pduptr = &dissect_pdu;
440                 break;
441         case 5:
442                 pdusize = V5PDU_SIZE;
443                 pduptr = &dissect_pdu;
444                 break;
445         case 7:
446                 pdusize = V7PDU_SIZE;
447                 pduptr = &dissect_pdu;
448                 break;
449         case 8:
450                 pdusize = -1;   /* deferred */
451                 pduptr = &dissect_v8_aggpdu;
452                 break;
453         case 9:
454         case 10: /* IPFIX */
455                 pdusize = -1;   /* deferred */
456                 pduptr = &dissect_v9_flowset;
457                 break;
458         default:
459                 return;
460         }
461
462         if (tree)
463                 proto_tree_add_uint(netflow_tree, hf_cflow_version, tvb,
464                                     offset, 2, ver);
465         offset += 2;
466
467         pdus = tvb_get_ntohs(tvb, offset);
468         if (tree) {
469                 if(ver == 10) {
470                         proto_tree_add_uint(netflow_tree, hf_cflow_len, tvb,
471                                             offset, 2, pdus);
472                         flow_len = pdus;
473                 } else {
474                         proto_tree_add_uint(netflow_tree, hf_cflow_count, tvb,
475                                             offset, 2, pdus);
476                         flow_len = -1;
477                 }
478         }
479         offset += 2;
480
481         /*
482          * set something interesting in the display now that we have info
483          */
484         if (check_col(pinfo->cinfo, COL_INFO)) {
485                 if (ver == 9) {
486                         col_add_fstr(pinfo->cinfo, COL_INFO,
487                                      "total: %u (v%u) record%s", pdus, ver,
488                                      plurality(pdus, "", "s"));
489                 } else if (ver == 10) {
490                         gint remaining = tvb_length_remaining(tvb, offset)+4;
491
492                         if(remaining == flow_len)
493                                 col_add_fstr(pinfo->cinfo, COL_INFO, "IPFIX flow (%d bytes)", flow_len);
494                         else
495                                 col_add_fstr(pinfo->cinfo, COL_INFO,
496                                              "IPFIX partial flow (%u/%u bytes)",
497                                              remaining, flow_len);
498                 } else {
499                         col_add_fstr(pinfo->cinfo, COL_INFO,
500                             "total: %u (v%u) flow%s", pdus, ver,
501                             plurality(pdus, "", "s"));
502                 }
503         }
504
505         /*
506          * the rest is only interesting if we're displaying/searching the
507          * packet
508          */
509         if (!tree)
510                 return;
511
512         if(ver == 10) {
513                 proto_tree_add_item(netflow_tree, hf_cflow_exporttime, tvb,
514                                     offset, 4, FALSE);
515                 offset += 4;
516         } else {
517                 proto_tree_add_item(netflow_tree, hf_cflow_sysuptime, tvb,
518                                     offset, 4, FALSE);
519                 offset += 4;
520
521                 ts.secs = tvb_get_ntohl(tvb, offset);
522                 if ((ver != 9) && (ver != 10)) {
523                         ts.nsecs = tvb_get_ntohl(tvb, offset + 4);
524                         timeitem = proto_tree_add_time(netflow_tree,
525                                                        hf_cflow_timestamp, tvb, offset,
526                                                        8, &ts);
527                 } else {
528                         ts.nsecs = 0;
529                         timeitem = proto_tree_add_time(netflow_tree,
530                                                        hf_cflow_timestamp, tvb, offset,
531                                                        4, &ts);
532                 }
533
534                 timetree = proto_item_add_subtree(timeitem, ett_unixtime);
535
536                 proto_tree_add_item(timetree, hf_cflow_unix_secs, tvb,
537                                     offset, 4, FALSE);
538                 offset += 4;
539
540                 if (ver != 9) {
541                         proto_tree_add_item(timetree, hf_cflow_unix_nsecs, tvb,
542                                             offset, 4, FALSE);
543                         offset += 4;
544                 }
545         }
546
547         /*
548          * version specific header
549          */
550         if (ver == 5 || ver == 7 || ver == 8 || ver == 9 || ver == 10) {
551                 proto_tree_add_item(netflow_tree, hf_cflow_sequence,
552                                     tvb, offset, 4, FALSE);
553                 offset += 4;
554         }
555         if (ver == 5 || ver == 8) {
556                 proto_tree_add_item(netflow_tree, hf_cflow_engine_type,
557                                     tvb, offset++, 1, FALSE);
558                 proto_tree_add_item(netflow_tree, hf_cflow_engine_id,
559                                     tvb, offset++, 1, FALSE);
560         } else if ((ver == 9) || (ver == 10)) {
561                 proto_tree_add_item(netflow_tree, hf_cflow_source_id,
562                                     tvb, offset, 4, FALSE);
563                 hdrinfo.src_id = tvb_get_ntohl(tvb, offset);
564                 offset += 4;
565         }
566         if (ver == 8) {
567                 hdrinfo.vspec = tvb_get_guint8(tvb, offset);
568                 switch (hdrinfo.vspec) {
569                 case V8PDU_AS_METHOD:
570                         pdusize = V8PDU_AS_SIZE;
571                         break;
572                 case V8PDU_PROTO_METHOD:
573                         pdusize = V8PDU_PROTO_SIZE;
574                         break;
575                 case V8PDU_SPREFIX_METHOD:
576                         pdusize = V8PDU_SPREFIX_SIZE;
577                         break;
578                 case V8PDU_DPREFIX_METHOD:
579                         pdusize = V8PDU_DPREFIX_SIZE;
580                         break;
581                 case V8PDU_MATRIX_METHOD:
582                         pdusize = V8PDU_MATRIX_SIZE;
583                         break;
584                 case V8PDU_DESTONLY_METHOD:
585                         pdusize = V8PDU_DESTONLY_SIZE;
586                         pduptr = &dissect_v8_flowpdu;
587                         break;
588                 case V8PDU_SRCDEST_METHOD:
589                         pdusize = V8PDU_SRCDEST_SIZE;
590                         pduptr = &dissect_v8_flowpdu;
591                         break;
592                 case V8PDU_FULL_METHOD:
593                         pdusize = V8PDU_FULL_SIZE;
594                         pduptr = &dissect_v8_flowpdu;
595                         break;
596                 case V8PDU_TOSAS_METHOD:
597                         pdusize = V8PDU_TOSAS_SIZE;
598                         break;
599                 case V8PDU_TOSPROTOPORT_METHOD:
600                         pdusize = V8PDU_TOSPROTOPORT_SIZE;
601                         break;
602                 case V8PDU_TOSSRCPREFIX_METHOD:
603                         pdusize = V8PDU_TOSSRCPREFIX_SIZE;
604                         break;
605                 case V8PDU_TOSDSTPREFIX_METHOD:
606                         pdusize = V8PDU_TOSDSTPREFIX_SIZE;
607                         break;
608                 case V8PDU_TOSMATRIX_METHOD:
609                         pdusize = V8PDU_TOSMATRIX_SIZE;
610                         break;
611                 case V8PDU_PREPORTPROTOCOL_METHOD:
612                         pdusize = V8PDU_PREPORTPROTOCOL_SIZE;
613                         break;
614                 default:
615                         pdusize = -1;
616                         hdrinfo.vspec = 0;
617                         break;
618                 }
619                 proto_tree_add_uint(netflow_tree, hf_cflow_aggmethod,
620                                     tvb, offset++, 1, hdrinfo.vspec);
621                 proto_tree_add_item(netflow_tree, hf_cflow_aggversion,
622                                     tvb, offset++, 1, FALSE);
623         }
624         if (ver == 7 || ver == 8)
625                 offset = flow_process_textfield(netflow_tree, tvb, offset, 4,
626                                                 "reserved");
627         else if (ver == 5) {
628                 proto_tree_add_item(netflow_tree, hf_cflow_samplingmode,
629                                     tvb, offset, 2, FALSE);
630                 proto_tree_add_item(netflow_tree, hf_cflow_samplerate,
631                                     tvb, offset, 2, FALSE);
632                 offset += 2;
633         }
634
635         if (pdus <= 0) { /* no payload to decode - in theory */
636                 /* This is absurd, but does happens in practice.  */
637                 proto_tree_add_text(netflow_tree, tvb, offset, tvb_length_remaining(tvb, offset),
638                                         "FlowSets impossibles - PDU Count is %d", pdus);
639                 return;
640         }
641         /*
642          * everything below here should be payload
643          */
644         for (x = 1; x < pdus + 1; x++) {
645                 /*
646                  * make sure we have a pdu's worth of data
647                  */
648                 available = tvb_length_remaining(tvb, offset);
649                 if(((ver == 9) || (ver == 10)) && available >= 4) {
650                         /* pdusize can be different for each v9 flowset */
651                         pdusize = tvb_get_ntohs(tvb, offset + 2);
652                 }
653
654                 if (available < pdusize)
655                         break;
656
657                 if ((ver == 9) || (ver == 10)) {
658                         pduitem = proto_tree_add_text(netflow_tree, tvb,
659                                                       offset, pdusize,
660                                                       (ver == 9) ? "FlowSet %u" : "DataRecord %u", x);
661                 } else {
662                         pduitem = proto_tree_add_text(netflow_tree, tvb,
663                             offset, pdusize, "pdu %u/%u", x, pdus);
664                 }
665                 pdutree = proto_item_add_subtree(pduitem, ett_flow);
666
667                 pduret = pduptr(pdutree, tvb, offset, &hdrinfo);
668
669                 if (pduret < pdusize) pduret = pdusize; /* padding */
670
671                 /*
672                  * if we came up short, stop processing
673                  */
674                 if (pduret == pdusize)
675                         offset += pduret;
676                 else
677                         break;
678         }
679 }
680
681 /*
682  * flow_process_* == common groups of fields, probably could be inline
683  */
684
685 static int
686 flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb, int offset)
687 {
688         proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2, FALSE);
689         offset += 2;
690
691         proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
692                             FALSE);
693         offset += 2;
694
695         return offset;
696 }
697
698 static int
699 flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb, int offset)
700 {
701         proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2, FALSE);
702         offset += 2;
703
704         proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2, FALSE);
705         offset += 2;
706
707         return offset;
708 }
709
710 static int
711 flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb, int offset)
712 {
713         nstime_t        ts_start, ts_end;
714         int             offset_s, offset_e;
715         nstime_t        ts_delta;
716         guint32         msec_start, msec_end;
717         guint32         msec_delta;
718         proto_tree *    timetree = 0;
719         proto_item *    timeitem = 0;
720
721
722         msec_start = tvb_get_ntohl(tvb, offset);
723         ts_start.secs = msec_start / 1000;
724         ts_start.nsecs = (msec_start % 1000) * 1000000;
725         offset_s = offset;
726         offset += 4;
727
728         msec_end = tvb_get_ntohl(tvb, offset);
729         ts_end.secs = msec_end / 1000;
730         ts_end.nsecs = (msec_end % 1000) * 1000000;
731         offset_e = offset;
732         offset += 4;
733
734         msec_delta = msec_end - msec_start;
735         ts_delta.secs = msec_delta / 1000;
736         ts_delta.nsecs = (msec_delta % 1000) * 1000000;
737
738
739         timeitem = proto_tree_add_time(pdutree, hf_cflow_timedelta, tvb,
740                                        offset_s, 8, &ts_delta);
741         timetree = proto_item_add_subtree(timeitem, ett_flowtime);
742
743         proto_tree_add_time(timetree, hf_cflow_timestart, tvb, offset_s, 4,
744                             &ts_start);
745         proto_tree_add_time(timetree, hf_cflow_timeend, tvb, offset_e, 4,
746                             &ts_end);
747
748         return offset;
749 }
750
751
752 static int
753 flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb, int offset)
754 {
755         proto_tree_add_item(pdutree, hf_cflow_srcas, tvb, offset, 2, FALSE);
756         offset += 2;
757
758         proto_tree_add_item(pdutree, hf_cflow_dstas, tvb, offset, 2, FALSE);
759         offset += 2;
760
761         return offset;
762 }
763
764 static int
765 flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb, int offset)
766 {
767         proto_tree_add_item(pdutree, hf_cflow_packets, tvb, offset, 4, FALSE);
768         offset += 4;
769
770         proto_tree_add_item(pdutree, hf_cflow_octets, tvb, offset, 4, FALSE);
771         offset += 4;
772
773         return offset;
774 }
775
776 static int
777 flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb, int offset,
778                        int bytes, const char *text)
779 {
780         proto_tree_add_text(pdutree, tvb, offset, bytes, text);
781         offset += bytes;
782
783         return offset;
784 }
785
786 static int
787 dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
788                    hdrinfo_t * hdrinfo)
789 {
790         int             startoffset = offset;
791         guint8          verspec;
792
793         proto_tree_add_item(pdutree, hf_cflow_dstaddr, tvb, offset, 4, FALSE);
794         offset += 4;
795
796         verspec = hdrinfo->vspec;
797
798         if (verspec != V8PDU_DESTONLY_METHOD) {
799                 proto_tree_add_item(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
800                                     FALSE);
801                 offset += 4;
802         }
803         if (verspec == V8PDU_FULL_METHOD) {
804                 proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2,
805                                     FALSE);
806                 offset += 2;
807                 proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2,
808                                     FALSE);
809                 offset += 2;
810         }
811
812         offset = flow_process_sizecount(pdutree, tvb, offset);
813         offset = flow_process_timeperiod(pdutree, tvb, offset);
814
815         proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
816                             FALSE);
817         offset += 2;
818
819         if (verspec != V8PDU_DESTONLY_METHOD) {
820                 proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2,
821                                     FALSE);
822                 offset += 2;
823         }
824
825         proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1, FALSE);
826         if (verspec == V8PDU_FULL_METHOD)
827                 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
828                                     FALSE);
829         offset = flow_process_textfield(pdutree, tvb, offset, 1, "marked tos");
830
831         if (verspec == V8PDU_SRCDEST_METHOD)
832                 offset =
833                     flow_process_textfield(pdutree, tvb, offset, 2,
834                                            "reserved");
835         else if (verspec == V8PDU_FULL_METHOD)
836                 offset =
837                     flow_process_textfield(pdutree, tvb, offset, 1, "padding");
838
839         offset =
840             flow_process_textfield(pdutree, tvb, offset, 4, "extra packets");
841
842         proto_tree_add_item(pdutree, hf_cflow_routersc, tvb, offset, 4, FALSE);
843         offset += 4;
844
845         return (offset - startoffset);
846 }
847
848 /*
849  * dissect a version 8 pdu, returning the length of the pdu processed
850  */
851
852 static int
853 dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
854                   hdrinfo_t * hdrinfo)
855 {
856         int             startoffset = offset;
857         guint8          verspec;
858
859         proto_tree_add_item(pdutree, hf_cflow_flows, tvb, offset, 4, FALSE);
860         offset += 4;
861
862         offset = flow_process_sizecount(pdutree, tvb, offset);
863         offset = flow_process_timeperiod(pdutree, tvb, offset);
864
865         verspec = hdrinfo->vspec;
866
867         switch (verspec) {
868         case V8PDU_AS_METHOD:
869         case V8PDU_TOSAS_METHOD:
870                 offset = flow_process_aspair(pdutree, tvb, offset);
871
872                 if (verspec == V8PDU_TOSAS_METHOD) {
873                         proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
874                                             offset++, 1, FALSE);
875                         offset =
876                             flow_process_textfield(pdutree, tvb, offset, 1,
877                                                    "padding");
878                         offset =
879                             flow_process_textfield(pdutree, tvb, offset, 2,
880                                                    "reserved");
881                 }
882                 break;
883         case V8PDU_PROTO_METHOD:
884         case V8PDU_TOSPROTOPORT_METHOD:
885                 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
886                                     FALSE);
887
888                 if (verspec == V8PDU_PROTO_METHOD)
889                         offset =
890                             flow_process_textfield(pdutree, tvb, offset, 1,
891                                                    "padding");
892                 else if (verspec == V8PDU_TOSPROTOPORT_METHOD)
893                         proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
894                                             offset++, 1, FALSE);
895
896                 offset =
897                     flow_process_textfield(pdutree, tvb, offset, 2,
898                                            "reserved");
899                 offset = flow_process_ports(pdutree, tvb, offset);
900
901                 if (verspec == V8PDU_TOSPROTOPORT_METHOD)
902                         offset = flow_process_ints(pdutree, tvb, offset);
903                 break;
904         case V8PDU_SPREFIX_METHOD:
905         case V8PDU_DPREFIX_METHOD:
906         case V8PDU_TOSSRCPREFIX_METHOD:
907         case V8PDU_TOSDSTPREFIX_METHOD:
908                 proto_tree_add_item(pdutree,
909                                     verspec ==
910                                     V8PDU_SPREFIX_METHOD ?
911                                     hf_cflow_srcnet : hf_cflow_dstnet, tvb,
912                                     offset, 4, FALSE);
913                 offset += 4;
914
915                 proto_tree_add_item(pdutree,
916                                     verspec ==
917                                     V8PDU_SPREFIX_METHOD ?
918                                     hf_cflow_srcmask : hf_cflow_dstmask, tvb,
919                                     offset++, 1, FALSE);
920
921                 if (verspec == V8PDU_SPREFIX_METHOD
922                     || verspec == V8PDU_DPREFIX_METHOD)
923                         offset =
924                             flow_process_textfield(pdutree, tvb, offset, 1,
925                                                    "padding");
926                 else if (verspec == V8PDU_TOSSRCPREFIX_METHOD
927                          || verspec == V8PDU_TOSDSTPREFIX_METHOD)
928                         proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
929                                             offset++, 1, FALSE);
930
931                 proto_tree_add_item(pdutree,
932                                     verspec ==
933                                     V8PDU_SPREFIX_METHOD ? hf_cflow_srcas
934                                     : hf_cflow_dstas, tvb, offset, 2, FALSE);
935                 offset += 2;
936
937                 proto_tree_add_item(pdutree,
938                                     verspec ==
939                                     V8PDU_SPREFIX_METHOD ?
940                                     hf_cflow_inputint : hf_cflow_outputint,
941                                     tvb, offset, 2, FALSE);
942                 offset += 2;
943
944                 offset =
945                     flow_process_textfield(pdutree, tvb, offset, 2,
946                                            "reserved");
947                 break;
948         case V8PDU_MATRIX_METHOD:
949         case V8PDU_TOSMATRIX_METHOD:
950         case V8PDU_PREPORTPROTOCOL_METHOD:
951                 proto_tree_add_item(pdutree, hf_cflow_srcnet, tvb, offset, 4,
952                                     FALSE);
953                 offset += 4;
954
955                 proto_tree_add_item(pdutree, hf_cflow_dstnet, tvb, offset, 4,
956                                     FALSE);
957                 offset += 4;
958
959                 proto_tree_add_item(pdutree, hf_cflow_srcmask, tvb, offset++,
960                                     1, FALSE);
961
962                 proto_tree_add_item(pdutree, hf_cflow_dstmask, tvb, offset++,
963                                     1, FALSE);
964
965                 if (verspec == V8PDU_TOSMATRIX_METHOD ||
966                     verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
967                         proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
968                                             offset++, 1, FALSE);
969                         if (verspec == V8PDU_TOSMATRIX_METHOD) {
970                                 offset =
971                                     flow_process_textfield(pdutree, tvb,
972                                                            offset, 1,
973                                                            "padding");
974                         } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
975                                 proto_tree_add_item(pdutree, hf_cflow_prot,
976                                                     tvb, offset++, 1, FALSE);
977                         }
978                 } else {
979                         offset =
980                             flow_process_textfield(pdutree, tvb, offset, 2,
981                                                    "reserved");
982                 }
983
984                 if (verspec == V8PDU_MATRIX_METHOD
985                     || verspec == V8PDU_TOSMATRIX_METHOD) {
986                         offset = flow_process_aspair(pdutree, tvb, offset);
987                 } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
988                         offset = flow_process_ports(pdutree, tvb, offset);
989                 }
990
991                 offset = flow_process_ints(pdutree, tvb, offset);
992                 break;
993         }
994
995
996         return (offset - startoffset);
997 }
998
999 /* Dissect a version 9 FlowSet and return the length we processed. */
1000
1001 static int
1002 dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb, int offset, hdrinfo_t * hdrinfo)
1003 {
1004         int length;
1005         guint16 flowset_id;
1006         guint8 ver;
1007
1008         ver = hdrinfo->vspec;
1009
1010         if ((ver != 9) && (ver != 10))
1011                 return (0);
1012
1013         flowset_id = tvb_get_ntohs(tvb, offset);
1014         if ((flowset_id == 0) || (flowset_id == 2)) {
1015                 /* Template */
1016                 proto_tree_add_item(pdutree, hf_cflow_template_flowset_id, tvb,
1017                                     offset, 2, FALSE);
1018                 offset += 2;
1019
1020                 length = tvb_get_ntohs(tvb, offset);
1021                 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
1022                                     offset, 2, FALSE);
1023                 offset += 2;
1024
1025                 dissect_v9_template(pdutree, tvb, offset, length - 4, hdrinfo);
1026         } else if ((flowset_id == 1) || (flowset_id == 3)) {
1027                 /* Options */
1028                 proto_tree_add_item(pdutree, hf_cflow_options_flowset_id, tvb,
1029                     offset, 2, FALSE);
1030                 offset += 2;
1031
1032                 length = tvb_get_ntohs(tvb, offset);
1033                 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
1034                     offset, 2, FALSE);
1035                 offset += 2;
1036
1037                 dissect_v9_options(pdutree, tvb, offset, hdrinfo);
1038         } else if (flowset_id >= 4 && flowset_id <= 255) {
1039                 /* Reserved */
1040                 proto_tree_add_item(pdutree, hf_cflow_flowset_id, tvb,
1041                     offset, 2, FALSE);
1042                 offset += 2;
1043
1044                 length = tvb_get_ntohs(tvb, offset);
1045                 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
1046                     offset, 2, FALSE);
1047                 offset += 2;
1048         } else {
1049                 /* Data */
1050                 proto_tree_add_item(pdutree, (ver == 9) ? hf_cflow_data_flowset_id :  hf_cflow_data_datarecord_id, tvb,
1051                                     offset, 2, FALSE);
1052                 offset += 2;
1053
1054                 length = tvb_get_ntohs(tvb, offset);
1055                 proto_tree_add_item(pdutree, (ver == 9) ? hf_cflow_flowset_length : hf_cflow_datarecord_length, tvb,
1056                                     offset, 2, FALSE);
1057                 offset += 2;
1058
1059                 /*
1060                  * The length includes the length of the FlowSet ID and
1061                  * the length field itself.
1062                  */
1063                 length -= 4;
1064                 if (length > 0) {
1065                         dissect_v9_data(pdutree, tvb, offset, flowset_id,
1066                                         (guint)length, hdrinfo);
1067                 }
1068         }
1069
1070         return (length);
1071 }
1072
1073 static int
1074 dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb, int offset,
1075                 guint16 id, guint length, hdrinfo_t * hdrinfo)
1076 {
1077         struct v9_template *template;
1078         proto_tree *data_tree;
1079         proto_item *data_item;
1080
1081         template = v9_template_get(id, &hdrinfo->net_src, hdrinfo->src_id);
1082         if (template != NULL && template->length != 0) {
1083                 int count = 1;
1084
1085                 while (length >= template->length) {
1086                         data_item = proto_tree_add_text(pdutree, tvb,
1087                                                         offset, template->length, "Flow %d", count++);
1088                         data_tree = proto_item_add_subtree(data_item,
1089                             ett_dataflowset);
1090
1091                         dissect_v9_pdu(data_tree, tvb, offset, template);
1092
1093                         offset += template->length;
1094                         length -= template->length;
1095                 }
1096                 if (length != 0) {
1097                         proto_tree_add_text(pdutree, tvb, offset, length,
1098                             "Padding (%u byte%s)",
1099                             length, plurality(length, "", "s"));
1100                 }
1101         } else {
1102                 proto_tree_add_text(pdutree, tvb, offset, length,
1103                     "Data (%u byte%s), no template found",
1104                     length, plurality(length, "", "s"));
1105         }
1106
1107         return (0);
1108 }
1109
1110 static void
1111 dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
1112     struct v9_template * template)
1113 {
1114         int i;
1115         nstime_t        ts_start, ts_end;
1116         int             offset_s = 0, offset_e = 0;
1117         nstime_t        ts_delta;
1118         guint32         msec_start = 0, msec_end = 0;
1119         guint32         msec_delta;
1120         proto_tree *    timetree = 0;
1121         proto_item *    timeitem = 0;
1122
1123         if( (template->count_scopes > 0) && (template->scopes != NULL)) {
1124                 for(i = 0; i < template->count_scopes; i++) {
1125                         guint16 type = template->scopes[i].type;
1126                         guint16 length = template->scopes[i].length;
1127                         switch( type ) {
1128                         case 1: /* system */
1129                                 if( length <= 4) {
1130                                          proto_tree_add_item(pdutree, hf_cflow_scope_system,
1131                                                 tvb, offset, length, FALSE);
1132                                 } else {
1133                                          proto_tree_add_text(pdutree,
1134                                                 tvb, offset, length,
1135                                                 "ScopeSystem: invalid size %d", length );
1136                                 }
1137                                 break;
1138                         case 2: /* interface */
1139                                 if( length <= 4) {
1140                                          proto_tree_add_item(pdutree, hf_cflow_scope_interface,
1141                                                 tvb, offset, length, FALSE);
1142                                 } else {
1143                                          proto_tree_add_text(pdutree,
1144                                                 tvb, offset, length,
1145                                                 "ScopeInterface: invalid size %d", length );
1146                                 }
1147                                 break;
1148                         case 3: /* linecard */
1149                                 proto_tree_add_item(pdutree, hf_cflow_scope_linecard,
1150                                                 tvb, offset, length, FALSE);
1151                                 break;
1152                         case 4: /* netflow cache */
1153                                 proto_tree_add_item(pdutree, hf_cflow_scope_cache,
1154                                                 tvb, offset, length, FALSE);
1155                                 break;
1156                         case 5: /* template */
1157                                 proto_tree_add_item(pdutree, hf_cflow_scope_template,
1158                                                 tvb, offset, length, FALSE);
1159                                 break;
1160                         default: /* unknown */
1161                                 proto_tree_add_item(pdutree, hf_cflow_scope_unknown,
1162                                                 tvb, offset, length, FALSE);
1163                                 break;
1164                         }
1165                         offset += length;
1166                 }
1167         }
1168
1169         for (i = 0; i < template->count; i++) {
1170                 guint16 type, length;
1171
1172                 type = template->entries[i].type;
1173                 length = template->entries[i].length;
1174
1175                 switch (type) {
1176
1177                 case 85: /* BYTES_PERMANENT */
1178                 case 1: /* bytes */
1179                         if (length == 4) {
1180                                 proto_tree_add_item(pdutree, hf_cflow_octets,
1181                                     tvb, offset, length, FALSE);
1182                         } else if (length == 8) {
1183                                 proto_tree_add_item(pdutree, hf_cflow_octets64,
1184                                     tvb, offset, length, FALSE);
1185                         } else {
1186                                 proto_tree_add_text(pdutree,
1187                                     tvb, offset, length,
1188                                     "Octets: length %u", length);
1189                         }
1190                   break;
1191
1192                 case 86: /* PACKETS_PERMANENT */
1193                 case 2: /* packets */
1194                         if (length == 4) {
1195                                 proto_tree_add_item(pdutree, hf_cflow_packets,
1196                                     tvb, offset, length, FALSE);
1197                         } else if (length == 8) {
1198                                 proto_tree_add_item(pdutree, hf_cflow_packets64,
1199                                     tvb, offset, length, FALSE);
1200                         } else {
1201                                 proto_tree_add_text(pdutree,
1202                                     tvb, offset, length,
1203                                     "Packets: length %u", length);
1204                         }
1205                         break;
1206
1207                 case 3: /* flows */
1208                         if (length == 4) {
1209                                 proto_tree_add_item(pdutree, hf_cflow_flows,
1210                                     tvb, offset, length, FALSE);
1211                         } else {
1212                                 proto_tree_add_text(pdutree,
1213                                     tvb, offset, length,
1214                                     "Flows: length %u", length);
1215                         }
1216                         break;
1217
1218                 case 4: /* proto */
1219                         proto_tree_add_item(pdutree, hf_cflow_prot,
1220                             tvb, offset, length, FALSE);
1221                         break;
1222
1223                 case 5: /* TOS */
1224                         proto_tree_add_item(pdutree, hf_cflow_tos,
1225                             tvb, offset, length, FALSE);
1226                         break;
1227
1228                 case 6: /* TCP flags */
1229                         proto_tree_add_item(pdutree, hf_cflow_tcpflags,
1230                             tvb, offset, length, FALSE);
1231                         break;
1232
1233                 case 7: /* source port */
1234                         proto_tree_add_item(pdutree, hf_cflow_srcport,
1235                             tvb, offset, length, FALSE);
1236                         break;
1237
1238                 case 8: /* source IP */
1239                         if (length == 4) {
1240                                 proto_tree_add_item(pdutree, hf_cflow_srcaddr,
1241                                     tvb, offset, length, FALSE);
1242                         } else if (length == 16) {
1243                                 proto_tree_add_item(pdutree, hf_cflow_srcaddr_v6,
1244                                     tvb, offset, length, FALSE);
1245                         } else {
1246                                 proto_tree_add_text(pdutree,
1247                                     tvb, offset, length,
1248                                     "SrcAddr: length %u", length);
1249                         }
1250                         break;
1251
1252                 case 9: /* source mask */
1253                         proto_tree_add_item(pdutree, hf_cflow_srcmask,
1254                             tvb, offset, length, FALSE);
1255                         break;
1256
1257                 case 10: /* input SNMP */
1258                         proto_tree_add_item(pdutree, hf_cflow_inputint,
1259                             tvb, offset, length, FALSE);
1260                         break;
1261
1262                 case 11: /* dest port */
1263                         proto_tree_add_item(pdutree, hf_cflow_dstport,
1264                             tvb, offset, length, FALSE);
1265                         break;
1266
1267                 case 12: /* dest IP */
1268                         if (length == 4) {
1269                                 proto_tree_add_item(pdutree, hf_cflow_dstaddr,
1270                                     tvb, offset, length, FALSE);
1271                         } else if (length == 16) {
1272                                 proto_tree_add_item(pdutree, hf_cflow_dstaddr_v6,
1273                                     tvb, offset, length, FALSE);
1274                         } else {
1275                                 proto_tree_add_text(pdutree,
1276                                     tvb, offset, length,
1277                                     "DstAddr: length %u", length);
1278                         }
1279                         break;
1280
1281                 case 13: /* dest mask */
1282                         proto_tree_add_item(pdutree, hf_cflow_dstmask,
1283                             tvb, offset, length, FALSE);
1284                         break;
1285
1286                 case 14: /* output SNMP */
1287                         proto_tree_add_item(pdutree, hf_cflow_outputint,
1288                             tvb, offset, length, FALSE);
1289                         break;
1290
1291                 case 15: /* nexthop IP */
1292                         if (length == 4) {
1293                                 proto_tree_add_item(pdutree, hf_cflow_nexthop,
1294                                     tvb, offset, length, FALSE);
1295                         } else if (length == 16) {
1296                                 proto_tree_add_item(pdutree, hf_cflow_nexthop_v6,
1297                                     tvb, offset, length, FALSE);
1298                         } else {
1299                                 proto_tree_add_text(pdutree,
1300                                     tvb, offset, length,
1301                                     "NextHop: length %u", length);
1302                         }
1303                         break;
1304
1305                 case 16: /* source AS */
1306                         proto_tree_add_item(pdutree, hf_cflow_srcas,
1307                             tvb, offset, length, FALSE);
1308                         break;
1309
1310                 case 17: /* dest AS */
1311                         proto_tree_add_item(pdutree, hf_cflow_dstas,
1312                             tvb, offset, length, FALSE);
1313                         break;
1314
1315                 case 18: /* BGP nexthop IP */
1316                         if (length == 4) {
1317                                 proto_tree_add_item(pdutree, hf_cflow_bgpnexthop,
1318                                     tvb, offset, length, FALSE);
1319                         } else if (length == 16) {
1320                                 proto_tree_add_item(pdutree, hf_cflow_bgpnexthop_v6,
1321                                     tvb, offset, length, FALSE);
1322                         } else {
1323                                 proto_tree_add_text(pdutree,
1324                                     tvb, offset, length,
1325                                     "BGPNextHop: length %u", length);
1326                         }
1327                         break;
1328
1329                 case 19: /* multicast packets */
1330                         proto_tree_add_item(pdutree, hf_cflow_mulpackets,
1331                             tvb, offset, length, FALSE);
1332                         break;
1333
1334                 case 20: /* multicast octets */
1335                         proto_tree_add_item(pdutree, hf_cflow_muloctets,
1336                             tvb, offset, length, FALSE);
1337                         break;
1338
1339                 case 22: /* first switched */
1340                 case 21: /* last switched */
1341                         if(type == 22) {
1342                                 offset_s = offset;
1343                                 msec_start = tvb_get_ntohl(tvb, offset);
1344                                 ts_start.secs = msec_start / 1000;
1345                                 ts_start.nsecs = (msec_start % 1000) * 1000000;
1346                         } else {
1347                                 offset_e = offset;
1348                                 msec_end = tvb_get_ntohl(tvb, offset);
1349                                 ts_end.secs = msec_end / 1000;
1350                                 ts_end.nsecs = (msec_end % 1000) * 1000000;
1351                         }
1352                         if(offset_s && offset_e) {
1353                                 msec_delta = msec_end - msec_start;
1354                                 ts_delta.secs = msec_delta / 1000;
1355                                 ts_delta.nsecs = (msec_delta % 1000) * 1000000;
1356
1357                                 timeitem =
1358                                   proto_tree_add_time(pdutree, hf_cflow_timedelta, tvb,
1359                                                       offset_s, 0, &ts_delta);
1360                                 timetree = proto_item_add_subtree(timeitem, ett_flowtime);
1361
1362                                 proto_tree_add_time(timetree, hf_cflow_timestart, tvb,
1363                                                     offset_s, 4, &ts_start);
1364                                 proto_tree_add_time(timetree, hf_cflow_timeend, tvb,
1365                                                     offset_e, 4, &ts_end);
1366                         }
1367                         break;
1368
1369                 case 25: /* length_min */
1370                   proto_tree_add_item(pdutree, hf_cflow_length_min,
1371                                       tvb, offset, length, FALSE);
1372                   break;
1373
1374                 case 26: /* length_max */
1375                   proto_tree_add_item(pdutree, hf_cflow_length_max,
1376                                       tvb, offset, length, FALSE);
1377                   break;
1378
1379                 case 27: /* IPv6 src addr */
1380                   proto_tree_add_item(pdutree, hf_cflow_srcaddr_v6,
1381                                       tvb, offset, length, FALSE);
1382                   break;
1383
1384                 case 28: /* IPv6 dst addr */
1385                   proto_tree_add_item(pdutree, hf_cflow_dstaddr_v6,
1386                                       tvb, offset, length, FALSE);
1387                   break;
1388
1389                 case 29: /* IPv6 src addr mask */
1390                   proto_tree_add_item(pdutree, hf_cflow_srcmask_v6,
1391                                       tvb, offset, length, FALSE);
1392                   break;
1393
1394                 case 30: /* IPv6 dst addr mask */
1395                   proto_tree_add_item(pdutree, hf_cflow_dstmask_v6,
1396                                       tvb, offset, length, FALSE);
1397                   break;
1398
1399                 case 32: /* ICMP_TYPE */
1400                         proto_tree_add_item(pdutree, hf_cflow_icmp_type,
1401                             tvb, offset, length, FALSE);
1402                         break;
1403
1404                 case 33: /* IGMP_TYPE */
1405                         proto_tree_add_item(pdutree, hf_cflow_igmp_type,
1406                             tvb, offset, length, FALSE);
1407                         break;
1408
1409                 case 34: /* sampling interval */
1410                   proto_tree_add_item(pdutree, hf_cflow_sampling_interval,
1411                                       tvb, offset, length, FALSE);
1412                   break;
1413
1414                 case 35: /* sampling algorithm */
1415                   proto_tree_add_item(pdutree, hf_cflow_sampling_algorithm,
1416                                       tvb, offset, length, FALSE);
1417                   break;
1418
1419                 case 36: /* flow active timeout */
1420                    proto_tree_add_item(pdutree, hf_cflow_flow_active_timeout,
1421                                       tvb, offset, length, FALSE);
1422                   break;
1423
1424                 case 37: /* flow inactive timeout */
1425                    proto_tree_add_item(pdutree, hf_cflow_flow_inactive_timeout,
1426                                       tvb, offset, length, FALSE);
1427                   break;
1428
1429                 case 40: /* bytes exported */
1430                         if( length == 8 ) {
1431                                 proto_tree_add_item(pdutree, hf_cflow_octets_exp64,
1432                                               tvb, offset, length, FALSE);
1433                         } else {
1434                                 proto_tree_add_item(pdutree, hf_cflow_octets_exp,
1435                                               tvb, offset, length, FALSE);
1436                         }
1437                         break;
1438
1439                 case 41: /* packets exported */
1440                         if( length == 8 ) {
1441                                 proto_tree_add_item(pdutree, hf_cflow_packets_exp64,
1442                                     tvb, offset, length, FALSE);
1443                         } else {
1444                                 proto_tree_add_item(pdutree, hf_cflow_packets_exp,
1445                                     tvb, offset, length, FALSE);
1446                         }
1447                         break;
1448
1449                 case 42: /* flows exported */
1450                         if( length == 8 ) {
1451                                 proto_tree_add_item(pdutree, hf_cflow_flows_exp64,
1452                                     tvb, offset, length, FALSE);
1453                         } else {
1454                                 proto_tree_add_item(pdutree, hf_cflow_flows_exp,
1455                                     tvb, offset, length, FALSE);
1456                         }
1457                         break;
1458
1459                 case 44: /* IP source prefix */
1460                         if (length == 4) {
1461                                 proto_tree_add_item(pdutree, hf_cflow_srcprefix,
1462                                     tvb, offset, length, FALSE);
1463                         } else {
1464                                 proto_tree_add_text(pdutree, tvb, offset, length,
1465                                     "SrcPrefix: length %u", length);
1466                         }
1467                         break;
1468
1469                 case 45: /* IP destination prefix */
1470                         if (length == 4) {
1471                                 proto_tree_add_item(pdutree, hf_cflow_dstprefix,
1472                                     tvb, offset, length, FALSE);
1473                         } else {
1474                                 proto_tree_add_text(pdutree, tvb, offset, length,
1475                                     "DstPrefix: length %u", length);
1476                         }
1477                         break;
1478
1479                 case 46: /* top MPLS label type*/
1480                         proto_tree_add_item(pdutree, hf_cflow_mpls_top_label_type,
1481                             tvb, offset, length, FALSE);
1482                         break;
1483
1484                 case 47: /* top MPLS label PE address*/
1485                         proto_tree_add_item(pdutree, hf_cflow_mpls_pe_addr,
1486                             tvb, offset, length, FALSE);
1487                         break;
1488
1489                 case 48: /* Flow Sampler ID */
1490                         proto_tree_add_text(pdutree, tvb, offset, length,
1491                             "FlowSamplerID: %d", tvb_get_guint8(tvb, offset));
1492                         break;
1493
1494                 case 49: /* FLOW_SAMPLER_MODE  */
1495                         proto_tree_add_item(pdutree, hf_cflow_sampler_mode,
1496                             tvb, offset, length, FALSE);
1497                         break;
1498
1499                 case 50: /* FLOW_SAMPLER_RANDOM_INTERVAL  */
1500                         proto_tree_add_item(pdutree, hf_cflow_sampler_random_interval,
1501                             tvb, offset, length, FALSE);
1502                         break;
1503
1504                 case 51: /*  FLOW_CLASS */
1505                         proto_tree_add_item(pdutree, hf_cflow_flow_class,
1506                             tvb, offset, length, FALSE);
1507                         break;
1508
1509                 case 52: /*  TTL_MINIMUM */
1510                         proto_tree_add_item(pdutree, hf_cflow_ttl_minimum,
1511                             tvb, offset, length, FALSE);
1512                         break;
1513
1514                 case 53: /*  TTL_MAXIMUM */
1515                         proto_tree_add_item(pdutree, hf_cflow_ttl_maximum,
1516                             tvb, offset, length, FALSE);
1517                         break;
1518
1519                 case 54: /* IPV4_ID  */
1520                         proto_tree_add_item(pdutree, hf_cflow_ipv4_id,
1521                             tvb, offset, length, FALSE);
1522                         break;
1523
1524                 case 60: /* IP_VERSION */
1525                         proto_tree_add_item(pdutree, hf_cflow_ip_version,
1526                             tvb, offset, length, FALSE);
1527                         break;
1528
1529                 case 61: /* DIRECTION   */
1530                         proto_tree_add_item(pdutree, hf_cflow_direction,
1531                             tvb, offset, length, FALSE);
1532                         break;
1533
1534                 case 62: /* IPv6 BGP nexthop  */
1535                         proto_tree_add_item(pdutree, hf_cflow_bgpnexthop_v6,
1536                             tvb, offset, length, FALSE);
1537                         break;
1538
1539                 case 70: /* MPLS label1*/
1540                         proto_tree_add_mpls_label(pdutree, tvb, offset, length, 1);
1541                         break;
1542
1543                 case 71: /* MPLS label2*/
1544                         proto_tree_add_mpls_label(pdutree, tvb, offset, length, 2);
1545                         break;
1546
1547                 case 72: /* MPLS label3*/
1548                         proto_tree_add_mpls_label(pdutree, tvb, offset, length, 3);
1549                         break;
1550
1551                 case 73: /* MPLS label4*/
1552                         proto_tree_add_mpls_label(pdutree, tvb, offset, length, 4);
1553                         break;
1554
1555                 case 82: /* IF_NAME  */
1556                         proto_tree_add_item(pdutree, hf_cflow_if_name,
1557                             tvb, offset, length, FALSE);
1558                         break;
1559
1560                 case 83: /* IF_DESCR  */
1561                         proto_tree_add_item(pdutree, hf_cflow_if_descr,
1562                             tvb, offset, length, FALSE);
1563                         break;
1564
1565                 case 84: /* SAMPLER_NAME  */
1566                         proto_tree_add_item(pdutree, hf_cflow_sampler_name,
1567                             tvb, offset, length, FALSE);
1568                         break;
1569
1570                 case 89: /* FORWARDING_STATUS */
1571                         proto_tree_add_item(pdutree, hf_cflow_forwarding_status,
1572                             tvb, offset, length, FALSE);
1573                         proto_tree_add_item(pdutree, hf_cflow_forwarding_code,
1574                             tvb, offset, length, FALSE);
1575                         break;
1576
1577                 case 128: /* source AS Peer */
1578                         proto_tree_add_item(pdutree, hf_cflow_peer_srcas,
1579                             tvb, offset, length, FALSE);
1580                         break;
1581
1582                 case 129: /* dest AS Peer*/
1583                         proto_tree_add_item(pdutree, hf_cflow_peer_dstas,
1584                             tvb, offset, length, FALSE);
1585                         break;
1586
1587                 case 144: /* FLOW EXPORTER */
1588                         proto_tree_add_item(pdutree, hf_cflow_flow_exporter,
1589                             tvb, offset, length, FALSE);
1590                         break;
1591
1592                 case 176: /* ICMP_IPv4_TYPE */
1593                         proto_tree_add_item(pdutree, hf_cflow_icmp_ipv4_type,
1594                             tvb, offset, length, FALSE);
1595                         break;
1596
1597                 case 177: /* ICMP_IPv4_CODE */
1598                         proto_tree_add_item(pdutree, hf_cflow_icmp_ipv4_code,
1599                             tvb, offset, length, FALSE);
1600                         break;
1601
1602                 case 178: /* ICMP_IPv6_TYPE */
1603                         proto_tree_add_item(pdutree, hf_cflow_icmp_ipv6_type,
1604                             tvb, offset, length, FALSE);
1605                         break;
1606
1607                 case 179: /* ICMP_IPv6_CODE */
1608                         proto_tree_add_item(pdutree, hf_cflow_icmp_ipv6_code,
1609                             tvb, offset, length, FALSE);
1610                         break;
1611
1612                 case 186: /* TCP_WINDOWS_SIZE */
1613                         proto_tree_add_item(pdutree, hf_cflow_tcp_window_size,
1614                             tvb, offset, length, FALSE);
1615                         break;
1616
1617                 case 190: /* IP_TOTAL_LENGTH */
1618                         proto_tree_add_item(pdutree, hf_cflow_ip_total_length,
1619                             tvb, offset, length, FALSE);
1620                         break;
1621
1622                 case 192: /* IP_TTL */
1623                         proto_tree_add_item(pdutree, hf_cflow_ip_ttl,
1624                             tvb, offset, length, FALSE);
1625                         break;
1626
1627                 case 194: /* IP_TOS */
1628                         proto_tree_add_item(pdutree, hf_cflow_ip_tos,
1629                             tvb, offset, length, FALSE);
1630                         break;
1631
1632                 case 195: /* IP_DSCP */
1633                         proto_tree_add_item(pdutree, hf_cflow_ip_dscp,
1634                             tvb, offset, length, FALSE);
1635                         break;
1636
1637                 case 198: /* BYTES_SQUARED */
1638                 case 199: /* BYTES_SQUARED_PERMANENT */
1639                         if( length == 8 ) {
1640                                 proto_tree_add_item(pdutree, hf_cflow_octets_squared64,
1641                                     tvb, offset, length, FALSE);
1642                         } else {
1643                                 proto_tree_add_text(pdutree, tvb, offset, length,
1644                                     "Bytes Squared: length %u", length);
1645                         }
1646                         break;
1647
1648                 case 205: /* UDP_LENGTH */
1649                         proto_tree_add_item(pdutree, hf_cflow_udp_length,
1650                                             tvb, offset, length, FALSE);
1651                         break;
1652
1653                 case 206: /* IS_MULTICAST */
1654                         proto_tree_add_item(pdutree, hf_cflow_is_multicast,
1655                                             tvb, offset, length, FALSE);
1656                         break;
1657
1658                 case 207: /* IP_HEADER_WORDS */
1659                         proto_tree_add_item(pdutree, hf_cflow_ip_header_words,
1660                                             tvb, offset, length, FALSE);
1661                         break;
1662
1663                 case 208: /* OPTION_MAP */
1664                         proto_tree_add_item(pdutree, hf_cflow_option_map,
1665                                             tvb, offset, length, FALSE);
1666                         break;
1667
1668                 case 313: /* SECTION_HEADER */
1669                         proto_tree_add_item(pdutree, hf_cflow_section_header,
1670                                             tvb, offset, length, FALSE);
1671                         break;
1672
1673                 case 314: /* SECTION_PAYLOAD */
1674                         proto_tree_add_item(pdutree, hf_cflow_section_payload,
1675                                             tvb, offset, length, FALSE);
1676                         break;
1677
1678                 default:
1679                         proto_tree_add_text(pdutree, tvb, offset, length,
1680                             "Type %u %s", type, decode_v9_template_types(type));
1681                         break;
1682                 }
1683
1684                 offset += length;
1685         }
1686         if (!(offset_s && offset_e)) {
1687                 if (offset_s) {
1688                         proto_tree_add_time(pdutree, hf_cflow_timestart, tvb,
1689                                             offset_s, 4, &ts_start);
1690                 }
1691                 if (offset_e) {
1692                         proto_tree_add_time(pdutree, hf_cflow_timeend, tvb,
1693                                             offset_e, 4, &ts_end);
1694                 }
1695         }
1696
1697 }
1698
1699 static int
1700 dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb, int offset, hdrinfo_t * hdrinfo)
1701 {
1702   guint16 length, option_scope_len, option_len, i, id, size;
1703   struct v9_template template;
1704   int template_offset;
1705   int scopes_offset;
1706
1707   id = tvb_get_ntohs(tvb, offset);
1708   proto_tree_add_item(pdutree, hf_cflow_template_id, tvb,
1709                       offset, 2, FALSE);
1710   offset += 2;
1711
1712   option_scope_len = length = tvb_get_ntohs(tvb, offset);
1713   proto_tree_add_item(pdutree, hf_cflow_option_scope_length, tvb,
1714                       offset, 2, FALSE);
1715   offset += 2;
1716
1717   option_len = length = tvb_get_ntohs(tvb, offset);
1718   proto_tree_add_item(pdutree, hf_cflow_option_length, tvb,
1719                       offset, 2, FALSE);
1720   offset += 2;
1721
1722   scopes_offset = offset;
1723
1724   for(i=0; i<option_scope_len; i++) {
1725     length = tvb_get_ntohs(tvb, offset);
1726     proto_tree_add_item(pdutree, hf_cflow_template_scope_field_type, tvb,
1727                         offset, 2, FALSE);
1728     offset += 2; i += 2;
1729
1730     length = tvb_get_ntohs(tvb, offset);
1731     proto_tree_add_item(pdutree, hf_cflow_template_scope_field_length, tvb,
1732                         offset, 2, FALSE);
1733     offset += 2; i += 2;
1734   }
1735
1736   template_offset = offset;
1737
1738   for(i=0; i<option_len;) {
1739     length = tvb_get_ntohs(tvb, offset);
1740     proto_tree_add_item(pdutree, hf_cflow_template_field_type, tvb,
1741                         offset, 2, FALSE);
1742     offset += 2; i += 2;
1743
1744     length = tvb_get_ntohs(tvb, offset);
1745     proto_tree_add_item(pdutree, hf_cflow_template_field_length, tvb,
1746                         offset, 2, FALSE);
1747     offset += 2; i += 2;
1748   }
1749
1750   /* Cache template */
1751   memset(&template, 0, sizeof(template));
1752   template.id = id;
1753   template.count = option_len/4;
1754   SE_COPY_ADDRESS(&template.source_addr, &hdrinfo->net_src);
1755   template.source_id = hdrinfo->src_id;
1756   /* Option scopes */
1757   template.count_scopes = option_scope_len/4;
1758   size = template.count_scopes * sizeof(struct v9_template_entry);
1759   template.scopes      = g_malloc( size );
1760   tvb_memcpy(tvb, (guint8 *)template.scopes, scopes_offset, size);
1761
1762   template.option_template = 1; /* Option template */
1763   size = template.count * sizeof(struct v9_template_entry);
1764   template.entries = g_malloc(size);
1765   tvb_memcpy(tvb, (guint8 *)template.entries, template_offset, size);
1766
1767   v9_template_add(&template);
1768
1769   return (0);
1770 }
1771
1772 static int
1773 dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb, int offset, int len, hdrinfo_t * hdrinfo)
1774 {
1775         struct v9_template template;
1776         proto_tree *template_tree;
1777         proto_item *template_item;
1778         proto_tree *field_tree;
1779         proto_item *field_item;
1780         guint16 id, count;
1781         int remaining = len;
1782         gint32 i;
1783
1784         while (remaining > 0) {
1785
1786                 id = tvb_get_ntohs(tvb, offset);
1787                 count = tvb_get_ntohs(tvb, offset + 2);
1788
1789                 template_item = proto_tree_add_text(pdutree, tvb, offset,
1790                                                     4 + sizeof(struct v9_template_entry) * count,
1791                                                     "Template (Id = %u, Count = %u)", id, count);
1792                 template_tree = proto_item_add_subtree(template_item, ett_template);
1793
1794                 proto_tree_add_item(template_tree, hf_cflow_template_id, tvb,
1795                                     offset, 2, FALSE);
1796                 offset += 2;
1797
1798                 proto_tree_add_item(template_tree, hf_cflow_template_field_count,
1799                                     tvb, offset, 2, FALSE);
1800                 offset += 2;
1801
1802                 /* Cache template */
1803                 memset(&template, 0, sizeof(template));
1804                 template.id = id;
1805                 template.count = count;
1806                 SE_COPY_ADDRESS(&template.source_addr, &hdrinfo->net_src);
1807                 template.source_id = hdrinfo->src_id;
1808                 template.count_scopes = 0;
1809                 template.scopes = NULL;
1810                 template.option_template = 0;   /* Data template */
1811                 template.entries = g_malloc(count * sizeof(struct v9_template_entry));
1812                 tvb_memcpy(tvb, (guint8 *)template.entries, offset,
1813                            count * sizeof(struct v9_template_entry));
1814                 v9_template_add(&template);
1815
1816                 for (i = 1; i <= count; i++) {
1817                         guint16 type, length;
1818
1819                         type = tvb_get_ntohs(tvb, offset);
1820                         length = tvb_get_ntohs(tvb, offset + 2);
1821
1822                         field_item = proto_tree_add_text(template_tree, tvb,
1823                                                          offset, 4, "Field (%u/%u)", i, count);
1824                         field_tree = proto_item_add_subtree(field_item, ett_field);
1825
1826                         proto_tree_add_item(field_tree,
1827                                             hf_cflow_template_field_type, tvb, offset, 2, FALSE);
1828                         offset += 2;
1829
1830                         proto_tree_add_item(field_tree,
1831                                             hf_cflow_template_field_length, tvb, offset, 2, FALSE);
1832                         offset += 2;
1833                 }
1834                 remaining -= 4 + sizeof(struct v9_template_entry) * count;
1835         }
1836
1837         return (0);
1838 }
1839
1840 static value_string v9_template_types[] = {
1841         { 1, "BYTES" },
1842         { 2, "PKTS" },
1843         { 3, "FLOWS" },
1844         { 4, "PROTOCOL" },
1845         { 5, "IP_TOS" },
1846         { 6, "TCP_FLAGS" },
1847         { 7, "L4_SRC_PORT" },
1848         { 8, "IP_SRC_ADDR" },
1849         { 9, "SRC_MASK" },
1850         { 10, "INPUT_SNMP" },
1851         { 11, "L4_DST_PORT" },
1852         { 12, "IP_DST_ADDR" },
1853         { 13, "DST_MASK" },
1854         { 14, "OUTPUT_SNMP" },
1855         { 15, "IP_NEXT_HOP" },
1856         { 16, "SRC_AS" },
1857         { 17, "DST_AS" },
1858         { 18, "BGP_NEXT_HOP" },
1859         { 19, "MUL_DPKTS" },
1860         { 20, "MUL_DOCTETS" },
1861         { 21, "LAST_SWITCHED" },
1862         { 22, "FIRST_SWITCHED" },
1863         { 23, "OUT_BYTES" },
1864         { 24, "OUT_PKTS" },
1865         { 25, "IP LENGTH MINIMUM" },
1866         { 26, "IP LENGTH MAXIMUM" },
1867         { 27, "IPV6_SRC_ADDR" },
1868         { 28, "IPV6_DST_ADDR" },
1869         { 29, "IPV6_SRC_MASK" },
1870         { 30, "IPV6_DST_MASK" },
1871         { 31, "FLOW_LABEL" },
1872         { 32, "ICMP_TYPE" },
1873         { 33, "IGMP_TYPE" },
1874         { 34, "SAMPLING_INTERVAL" },
1875         { 35, "SAMPLING_ALGORITHM" },
1876         { 36, "FLOW_ACTIVE_TIMEOUT" },
1877         { 37, "FLOW_INACTIVE_TIMEOUT" },
1878         { 38, "ENGINE_TYPE" },
1879         { 39, "ENGINE_ID" },
1880         { 40, "TOTAL_BYTES_EXP" },
1881         { 41, "TOTAL_PKTS_EXP" },
1882         { 42, "TOTAL_FLOWS_EXP" },
1883         { 44, "IP_SRC_PREFIX" },
1884         { 45, "IP_DST_PREFIX" },
1885         { 46, "MPLS_TOP_LABEL_TYPE" },
1886         { 47, "MPLS_TOP_LABEL_ADDR" },
1887         { 48, "FLOW_SAMPLER_ID" },
1888         { 49, "FLOW_SAMPLER_MODE" },
1889         { 50, "FLOW_SAMPLER_RANDOM_INTERVAL" },
1890         { 51, "FLOW_CLASS" },
1891         { 52, "IP TTL MINIMUM" },
1892         { 53, "IP TTL MAXIMUM" },
1893         { 54, "IPv4 ID" },
1894         { 55, "DST_TOS" },
1895         { 56, "SRC_MAC" },
1896         { 57, "DST_MAC" },
1897         { 58, "SRC_VLAN" },
1898         { 59, "DST_VLAN" },
1899         { 60, "IP_PROTOCOL_VERSION" },
1900         { 61, "DIRECTION" },
1901         { 62, "IPV6_NEXT_HOP" },
1902         { 63, "BPG_IPV6_NEXT_HOP" },
1903         { 64, "IPV6_OPTION_HEADERS" },
1904         { 70, "MPLS_LABEL_1" },
1905         { 71, "MPLS_LABEL_2" },
1906         { 72, "MPLS_LABEL_3" },
1907         { 73, "MPLS_LABEL_4" },
1908         { 74, "MPLS_LABEL_5" },
1909         { 75, "MPLS_LABEL_6" },
1910         { 76, "MPLS_LABEL_7" },
1911         { 77, "MPLS_LABEL_8" },
1912         { 78, "MPLS_LABEL_9" },
1913         { 79, "MPLS_LABEL_10" },
1914         { 80, "DESTINATION_MAC" },
1915         { 81, "SOURCE_MAC" },
1916         { 82, "IF_NAME" },
1917         { 83, "IF_DESC" },
1918         { 84, "SAMPLER_NAME" },
1919         { 85, "BYTES_TOTAL" },
1920         { 86, "PACKETS_TOTAL" },
1921         { 88, "FRAGMENT_OFFSET" },
1922         { 89, "FORWARDING_STATUS" },
1923         { 90, "VPN_ROUTE_DISTINGUISHER" },
1924         { 92, "SRC_TRAFFIC_INDEX" },
1925         { 93, "DST_TRAFFIC_INDEX" },
1926         { 128, "SRC_AS_PEER" },
1927         { 129, "DST_AS_PEER" },
1928         { 130, "DROPPED_BYTES" },
1929         { 131, "DROPPED_PACKETS" },
1930         { 132, "DROPPED_BYTES_TOTAL" },
1931         { 133, "DROPPED_PACKETS_TOTAL" },
1932         { 140, "MPLS_TOP_LABEL_IPv6_ADDRESS" },
1933         { 144, "FLOW_EXPORTER" },
1934         { 176, "ICMP_IPv4_TYPE" },
1935         { 177, "ICMP_IPv4_CODE" },
1936         { 178, "ICMP_IPv6_TYPE" },
1937         { 179, "ICMP_IPv6_CODE" },
1938         { 180, "UDP_SRC_PORT" },
1939         { 181, "UDP_DST_PORT" },
1940         { 182, "TCP_SRC_PORT" },
1941         { 183, "TCP_DST_PORT" },
1942         { 184, "TCP_SEQ_NUM" },
1943         { 184, "TCP_ACK_NUM" },
1944         { 186, "TCP_WINDOW_SIZE" },
1945         { 187, "TCP_URGENT_PTR" },
1946         { 188, "TCP_HEADER_LEN" },
1947         { 189, "IP_HEADER_LEN" },
1948         { 190, "IP_TOTAL_LEN" },
1949         { 192, "IP_TTL" },
1950         { 194, "IP_TOS" },
1951         { 195, "IP_DSCP" },
1952         { 196, "IP_PRECEDENCE" },
1953         { 196, "IP_FRAGMENT_FLAGS" },
1954         { 198, "BYTES_SQUARED" },
1955         { 199, "BYTES_SQUARED_PERMANENT" },
1956         { 200, "MPLS_TOP_LABEL_TTL" },
1957         { 201, "MPLS_LABEL_STACK_OCTETS" },
1958         { 202, "MPLS_LABEL_STACK_DEPTH" },
1959         { 203, "MPLS_TOP_LABEL_EXP" },
1960         { 204, "IP_PAYLOAD_LENGTH" },
1961         { 205, "UDP_LENGTH" },
1962         { 206, "IS_MULTICAST" },
1963         { 207, "IP_HEADER_WORDS" },
1964         { 208, "IP_OPTION_MAP" },
1965         { 208, "TPC_OPTION_MAP" },
1966         { 313, "IP_SECTION HEADER" },
1967         { 314, "IP_SECTION PAYLOAD" },
1968         { 0, NULL }
1969 };
1970
1971 static value_string v9_scope_field_types[] = {
1972         { 1, "System" },
1973         { 2, "Interface" },
1974         { 3, "Line Card" },
1975         { 4, "NetFlow Cache" },
1976         { 5, "Template" },
1977         { 0, NULL }
1978 };
1979
1980 static const char *
1981 decode_v9_template_types(int type) {
1982         const char *v = match_strval(type, v9_template_types);
1983         return ((v==NULL)?"Unknown" : v);
1984 }
1985
1986 static value_string v9_sampler_mode[] = {
1987         { 0, "Determinist" },
1988         { 1, "Unknown" },
1989         { 2, "Random" },
1990         { 0, NULL }
1991 };
1992 static value_string v9_direction[] = {
1993         { 0, "Ingress" },
1994         { 1, "Egress" },
1995         { 0, NULL }
1996 };
1997 static value_string v9_forwarding_status[] = {
1998         { 0, "Unknown"},  /* Observed on IOS-XR 3.2 */
1999         { 1, "Forward"},  /* Observed on 7200 12.4(9)T */
2000         { 2, "Drop"},     /* Observed on 7200 12.4(9)T */
2001         { 3, "Consume"},  /* Observed on 7200 12.4(9)T */
2002         { 0, NULL }
2003 };
2004
2005 static int
2006 v9_template_hash(guint16 id, const address * net_src, guint32 src_id)
2007 {
2008         guint32 val = 0;
2009         const guint32 *p;
2010         int i;
2011
2012         p = (guint32 *)net_src->data;
2013
2014         val += id;
2015
2016         if (net_src->type == AT_IPv4) {
2017                 val += *p;
2018         } else if (net_src->type == AT_IPv6) {
2019                 for (i=0; i < 4; i++) {
2020                         val += *p++;
2021                 }
2022         }
2023
2024         val += src_id;
2025
2026         return val % V9TEMPLATE_CACHE_MAX_ENTRIES;
2027 }
2028
2029 static void
2030 v9_template_add(struct v9_template *template)
2031 {
2032         int i;
2033
2034         /* Add up the actual length of the data and store in proper byte order */
2035         template->length = 0;
2036         /* Options scope */
2037         for(i = 0; i < template->count_scopes; i++) {
2038                 template->scopes[i].type   = g_ntohs(template->scopes[i].type);
2039                 template->scopes[i].length = g_ntohs(template->scopes[i].length);
2040                 template->length += template->scopes[i].length;
2041         }
2042
2043         for (i = 0; i < template->count; i++) {
2044                 template->entries[i].type = g_ntohs(template->entries[i].type);
2045                 template->entries[i].length = g_ntohs(template->entries[i].length);
2046                 template->length += template->entries[i].length;
2047         }
2048
2049         memcpy(&v9_template_cache[v9_template_hash(template->id,
2050                     &template->source_addr, template->source_id)],
2051             template, sizeof(*template));
2052 }
2053
2054 static struct v9_template *
2055 v9_template_get(guint16 id, address * net_src, guint32 src_id)
2056 {
2057         struct v9_template *template;
2058
2059         template = &v9_template_cache[v9_template_hash(id, net_src, src_id)];
2060
2061         if (template->id != id ||
2062             !ADDRESSES_EQUAL(&template->source_addr, net_src) ||
2063             template->source_id != src_id) {
2064                 template = NULL;
2065         }
2066
2067         return (template);
2068 }
2069
2070 /*
2071  * dissect a version 1, 5, or 7 pdu and return the length of the pdu we
2072  * processed
2073  */
2074
2075 static int
2076 dissect_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset, hdrinfo_t * hdrinfo)
2077 {
2078         int             startoffset = offset;
2079         guint32         srcaddr, dstaddr;
2080         guint8          mask;
2081         nstime_t        ts;
2082         guint8          ver;
2083
2084         memset(&ts, '\0', sizeof(ts));
2085
2086         /*
2087          * memcpy so we can use the values later to calculate a prefix
2088          */
2089         srcaddr = tvb_get_ipv4(tvb, offset);
2090         proto_tree_add_ipv4(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
2091                             srcaddr);
2092         offset += 4;
2093
2094         dstaddr = tvb_get_ipv4(tvb, offset);
2095         proto_tree_add_ipv4(pdutree, hf_cflow_dstaddr, tvb, offset, 4,
2096                             dstaddr);
2097         offset += 4;
2098
2099         proto_tree_add_item(pdutree, hf_cflow_nexthop, tvb, offset, 4, FALSE);
2100         offset += 4;
2101
2102         offset = flow_process_ints(pdutree, tvb, offset);
2103         offset = flow_process_sizecount(pdutree, tvb, offset);
2104         offset = flow_process_timeperiod(pdutree, tvb, offset);
2105         offset = flow_process_ports(pdutree, tvb, offset);
2106
2107         /*
2108          * and the similarities end here
2109          */
2110
2111         ver = hdrinfo->vspec;
2112
2113         if (ver == 1) {
2114                 offset =
2115                     flow_process_textfield(pdutree, tvb, offset, 2, "padding");
2116
2117                 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
2118                                     FALSE);
2119
2120                 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
2121                                     FALSE);
2122
2123                 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
2124                                     1, FALSE);
2125
2126                 offset =
2127                     flow_process_textfield(pdutree, tvb, offset, 3, "padding");
2128
2129                 offset =
2130                     flow_process_textfield(pdutree, tvb, offset, 4,
2131                                            "reserved");
2132         } else {
2133                 if (ver == 5)
2134                         offset =
2135                             flow_process_textfield(pdutree, tvb, offset, 1,
2136                                                    "padding");
2137                 else {
2138                         proto_tree_add_item(pdutree, hf_cflow_flags, tvb,
2139                                             offset++, 1, FALSE);
2140                 }
2141
2142                 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
2143                                     1, FALSE);
2144
2145                 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
2146                                     FALSE);
2147
2148                 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
2149                                     FALSE);
2150
2151                 offset = flow_process_aspair(pdutree, tvb, offset);
2152
2153                 mask = tvb_get_guint8(tvb, offset);
2154                 proto_tree_add_text(pdutree, tvb, offset, 1,
2155                                     "SrcMask: %u (prefix: %s/%u)",
2156                                     mask, getprefix(&srcaddr, mask),
2157                                     mask != 0 ? mask : 32);
2158                 proto_tree_add_uint_hidden(pdutree, hf_cflow_srcmask, tvb,
2159                                            offset++, 1, mask);
2160
2161                 mask = tvb_get_guint8(tvb, offset);
2162                 proto_tree_add_text(pdutree, tvb, offset, 1,
2163                                     "DstMask: %u (prefix: %s/%u)",
2164                                     mask, getprefix(&dstaddr, mask),
2165                                     mask != 0 ? mask : 32);
2166                 proto_tree_add_uint_hidden(pdutree, hf_cflow_dstmask, tvb,
2167                                            offset++, 1, mask);
2168
2169                 offset =
2170                     flow_process_textfield(pdutree, tvb, offset, 2, "padding");
2171
2172                 if (ver == 7) {
2173                         proto_tree_add_item(pdutree, hf_cflow_routersc, tvb,
2174                                             offset, 4, FALSE);
2175                         offset += 4;
2176                 }
2177         }
2178
2179         return (offset - startoffset);
2180 }
2181
2182 static gchar   *
2183 getprefix(const guint32 * address, int prefix)
2184 {
2185         guint32         gprefix;
2186
2187         gprefix = *address & g_htonl((0xffffffff << (32 - prefix)));
2188
2189         return (ip_to_str((const guint8 *)&gprefix));
2190 }
2191
2192
2193 static void
2194 netflow_reinit(void)
2195 {
2196         int i;
2197
2198         /*
2199          * Clear out the template cache.
2200          * Free the table of fields for each entry, and then zero out
2201          * the cache.
2202          */
2203         for (i = 0; i < V9TEMPLATE_CACHE_MAX_ENTRIES; i++)
2204         {
2205                 if (v9_template_cache[i].scopes)
2206                         g_free(v9_template_cache[i].scopes);
2207                 g_free(v9_template_cache[i].entries);
2208         }
2209         memset(v9_template_cache, 0, sizeof v9_template_cache);
2210 }
2211
2212 void
2213 proto_register_netflow(void)
2214 {
2215         static hf_register_info hf[] = {
2216                 /*
2217                  * flow header
2218                  */
2219                 {&hf_cflow_version,
2220                  {"Version", "cflow.version",
2221                   FT_UINT16, BASE_DEC, NULL, 0x0,
2222                   "NetFlow Version", HFILL}
2223                 },
2224                 {&hf_cflow_len,
2225                  {"Length", "cflow.len",
2226                   FT_UINT16, BASE_DEC, NULL, 0x0,
2227                   "Length of PDUs", HFILL}
2228                 },
2229                 {&hf_cflow_count,
2230                  {"Count", "cflow.count",
2231                   FT_UINT16, BASE_DEC, NULL, 0x0,
2232                   "Count of PDUs", HFILL}
2233                  },
2234                 {&hf_cflow_sysuptime,
2235                  {"SysUptime", "cflow.sysuptime",
2236                   FT_UINT32, BASE_DEC, NULL, 0x0,
2237                   "Time since router booted (in milliseconds)", HFILL}
2238                 },
2239                 {&hf_cflow_exporttime,
2240                  {"ExportTime", "cflow.exporttime",
2241                   FT_UINT32, BASE_DEC, NULL, 0x0,
2242                   "Time when the flow has been exported", HFILL}
2243                 },
2244
2245
2246                 {&hf_cflow_timestamp,
2247                  {"Timestamp", "cflow.timestamp",
2248                   FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
2249                   "Current seconds since epoch", HFILL}
2250                  },
2251                 {&hf_cflow_unix_secs,
2252                  {"CurrentSecs", "cflow.unix_secs",
2253                   FT_UINT32, BASE_DEC, NULL, 0x0,
2254                   "Current seconds since epoch", HFILL}
2255                  },
2256                 {&hf_cflow_unix_nsecs,
2257                  {"CurrentNSecs", "cflow.unix_nsecs",
2258                   FT_UINT32, BASE_DEC, NULL, 0x0,
2259                   "Residual nanoseconds since epoch", HFILL}
2260                  },
2261                 {&hf_cflow_samplingmode,
2262                  {"SamplingMode", "cflow.samplingmode",
2263                   FT_UINT16, BASE_DEC, VALS(v5_sampling_mode), 0xC000,
2264                   "Sampling Mode of exporter", HFILL}
2265                  },
2266                 {&hf_cflow_samplerate,
2267                  {"SampleRate", "cflow.samplerate",
2268                   FT_UINT16, BASE_DEC, NULL, 0x3FFF,
2269                   "Sample Frequency of exporter", HFILL}
2270                  },
2271
2272                 /*
2273                  * end version-agnostic header
2274                  * version-specific flow header
2275                  */
2276                 {&hf_cflow_sequence,
2277                  {"FlowSequence", "cflow.sequence",
2278                   FT_UINT32, BASE_DEC, NULL, 0x0,
2279                   "Sequence number of flows seen", HFILL}
2280                  },
2281                 {&hf_cflow_engine_type,
2282                  {"EngineType", "cflow.engine_type",
2283                   FT_UINT8, BASE_DEC, NULL, 0x0,
2284                   "Flow switching engine type", HFILL}
2285                  },
2286                 {&hf_cflow_engine_id,
2287                  {"EngineId", "cflow.engine_id",
2288                   FT_UINT8, BASE_DEC, NULL, 0x0,
2289                   "Slot number of switching engine", HFILL}
2290                  },
2291                 {&hf_cflow_source_id,
2292                  {"SourceId", "cflow.source_id",
2293                   FT_UINT32, BASE_DEC, NULL, 0x0,
2294                   "Identifier for export device", HFILL}
2295                  },
2296                 {&hf_cflow_aggmethod,
2297                  {"AggMethod", "cflow.aggmethod",
2298                   FT_UINT8, BASE_DEC, VALS(v8_agg), 0x0,
2299                   "CFlow V8 Aggregation Method", HFILL}
2300                  },
2301                 {&hf_cflow_aggversion,
2302                  {"AggVersion", "cflow.aggversion",
2303                   FT_UINT8, BASE_DEC, NULL, 0x0,
2304                   "CFlow V8 Aggregation Version", HFILL}
2305                  },
2306                 /*
2307                  * end version specific header storage
2308                  */
2309                 /*
2310                  * Version 9
2311                  */
2312                 {&hf_cflow_flowset_id,
2313                  {"FlowSet Id", "cflow.flowset_id",
2314                   FT_UINT16, BASE_DEC, NULL, 0x0,
2315                   "FlowSet Id", HFILL}
2316                  },
2317                 {&hf_cflow_data_flowset_id,
2318                  {"Data FlowSet (Template Id)", "cflow.data_flowset_id",
2319                   FT_UINT16, BASE_DEC, NULL, 0x0,
2320                   "Data FlowSet with corresponding to a template Id", HFILL}
2321                 },
2322                 {&hf_cflow_data_datarecord_id,
2323                  {"DataRecord (Template Id)", "cflow.data_datarecord_id",
2324                   FT_UINT16, BASE_DEC, NULL, 0x0,
2325                   "DataRecord with corresponding to a template Id", HFILL}
2326                 },
2327                 {&hf_cflow_options_flowset_id,
2328                  {"Options FlowSet", "cflow.options_flowset_id",
2329                   FT_UINT16, BASE_DEC, NULL, 0x0,
2330                   "Options FlowSet", HFILL}
2331                  },
2332                 {&hf_cflow_template_flowset_id,
2333                  {"Template FlowSet", "cflow.template_flowset_id",
2334                   FT_UINT16, BASE_DEC, NULL, 0x0,
2335                   "Template FlowSet", HFILL}
2336                  },
2337                 {&hf_cflow_flowset_length,
2338                  {"FlowSet Length", "cflow.flowset_length",
2339                   FT_UINT16, BASE_DEC, NULL, 0x0,
2340                   "FlowSet length", HFILL}
2341                  },
2342                 {&hf_cflow_template_id,
2343                  {"Template Id", "cflow.template_id",
2344                   FT_UINT16, BASE_DEC, NULL, 0x0,
2345                   "Template Id", HFILL}
2346                  },
2347                 {&hf_cflow_template_field_count,
2348                  {"Field Count", "cflow.template_field_count",
2349                   FT_UINT16, BASE_DEC, NULL, 0x0,
2350                   "Template field count", HFILL}
2351                  },
2352                 {&hf_cflow_template_field_type,
2353                  {"Type", "cflow.template_field_type",
2354                   FT_UINT16, BASE_DEC, VALS(v9_template_types), 0x0,
2355                   "Template field type", HFILL}
2356                  },
2357                 {&hf_cflow_template_field_length,
2358                  {"Length", "cflow.template_field_length",
2359                   FT_UINT16, BASE_DEC, NULL, 0x0,
2360                   "Template field length", HFILL}
2361                  },
2362
2363                 /* options */
2364                 {&hf_cflow_option_scope_length,
2365                  {"Option Scope Length", "cflow.option_scope_length",
2366                   FT_UINT16, BASE_DEC, NULL, 0x0,
2367                   "Option scope length", HFILL}
2368                  },
2369                 {&hf_cflow_option_length,
2370                  {"Option Length", "cflow.option_length",
2371                   FT_UINT16, BASE_DEC, NULL, 0x0,
2372                   "Option length", HFILL}
2373                  },
2374                 {&hf_cflow_template_scope_field_type,
2375                  {"Scope Type", "cflow.scope_field_type",
2376                   FT_UINT16, BASE_DEC, VALS(v9_scope_field_types), 0x0,
2377                   "Scope field type", HFILL}
2378                 },
2379                 {&hf_cflow_template_scope_field_length,
2380                  {"Scope Field Length", "cflow.scope_field_length",
2381                   FT_UINT16, BASE_DEC, NULL, 0x0,
2382                   "Scope field length", HFILL}
2383                  },
2384                 {&hf_cflow_icmp_type,
2385                  {"ICMP Type", "cflow.icmp_type",
2386                   FT_UINT8, BASE_DEC, NULL, 0x0,
2387                   "ICMP type", HFILL}
2388                 },
2389                 {&hf_cflow_igmp_type,
2390                  {"IGMP Type", "cflow.igmp_type",
2391                   FT_UINT8, BASE_DEC, NULL, 0x0,
2392                   "IGMP type", HFILL}
2393                 },
2394                 {&hf_cflow_sampling_interval,
2395                  {"Sampling interval", "cflow.sampling_interval",
2396                   FT_UINT32, BASE_DEC, NULL, 0x0,
2397                   "Sampling interval", HFILL}
2398                 },
2399                 {&hf_cflow_sampling_algorithm,
2400                  {"Sampling algorithm", "cflow.sampling_algorithm",
2401                   FT_UINT8, BASE_DEC, NULL, 0x0,
2402                   "Sampling algorithm", HFILL}
2403                 },
2404                 {&hf_cflow_flow_active_timeout,
2405                  {"Flow active timeout", "cflow.flow_active_timeout",
2406                   FT_UINT16, BASE_DEC, NULL, 0x0,
2407                   "Flow active timeout", HFILL}
2408                 },
2409                 {&hf_cflow_flow_inactive_timeout,
2410                  {"Flow inactive timeout", "cflow.flow_inactive_timeout",
2411                   FT_UINT16, BASE_DEC, NULL, 0x0,
2412                   "Flow inactive timeout", HFILL}
2413                 },
2414
2415                 /*
2416                  * begin pdu content storage
2417                  */
2418                 {&hf_cflow_srcaddr,
2419                  {"SrcAddr", "cflow.srcaddr",
2420                   FT_IPv4, BASE_NONE, NULL, 0x0,
2421                   "Flow Source Address", HFILL}
2422                  },
2423                 {&hf_cflow_srcaddr_v6,
2424                  {"SrcAddr", "cflow.srcaddrv6",
2425                   FT_IPv6, BASE_NONE, NULL, 0x0,
2426                   "Flow Source Address", HFILL}
2427                  },
2428                 {&hf_cflow_srcnet,
2429                  {"SrcNet", "cflow.srcnet",
2430                   FT_IPv4, BASE_NONE, NULL, 0x0,
2431                   "Flow Source Network", HFILL}
2432                  },
2433                 {&hf_cflow_dstaddr,
2434                  {"DstAddr", "cflow.dstaddr",
2435                   FT_IPv4, BASE_NONE, NULL, 0x0,
2436                   "Flow Destination Address", HFILL}
2437                  },
2438                 {&hf_cflow_dstaddr_v6,
2439                  {"DstAddr", "cflow.dstaddrv6",
2440                   FT_IPv6, BASE_NONE, NULL, 0x0,
2441                   "Flow Destination Address", HFILL}
2442                  },
2443                 {&hf_cflow_dstnet,
2444                  {"DstNet", "cflow.dstaddr",
2445                   FT_IPv4, BASE_NONE, NULL, 0x0,
2446                   "Flow Destination Network", HFILL}
2447                  },
2448                 {&hf_cflow_nexthop,
2449                  {"NextHop", "cflow.nexthop",
2450                   FT_IPv4, BASE_NONE, NULL, 0x0,
2451                   "Router nexthop", HFILL}
2452                  },
2453                 {&hf_cflow_nexthop_v6,
2454                  {"NextHop", "cflow.nexthopv6",
2455                   FT_IPv6, BASE_NONE, NULL, 0x0,
2456                   "Router nexthop", HFILL}
2457                  },
2458                 {&hf_cflow_bgpnexthop,
2459                  {"BGPNextHop", "cflow.bgpnexthop",
2460                   FT_IPv4, BASE_NONE, NULL, 0x0,
2461                   "BGP Router Nexthop", HFILL}
2462                  },
2463                 {&hf_cflow_bgpnexthop_v6,
2464                  {"BGPNextHop", "cflow.bgpnexthopv6",
2465                   FT_IPv6, BASE_NONE, NULL, 0x0,
2466                   "BGP Router Nexthop", HFILL}
2467                  },
2468                 {&hf_cflow_inputint,
2469                  {"InputInt", "cflow.inputint",
2470                   FT_UINT16, BASE_DEC, NULL, 0x0,
2471                   "Flow Input Interface", HFILL}
2472                  },
2473                 {&hf_cflow_outputint,
2474                  {"OutputInt", "cflow.outputint",
2475                   FT_UINT16, BASE_DEC, NULL, 0x0,
2476                   "Flow Output Interface", HFILL}
2477                  },
2478                 {&hf_cflow_flows,
2479                  {"Flows", "cflow.flows",
2480                   FT_UINT32, BASE_DEC, NULL, 0x0,
2481                   "Flows Aggregated in PDU", HFILL}
2482                  },
2483                 {&hf_cflow_packets,
2484                  {"Packets", "cflow.packets",
2485                   FT_UINT32, BASE_DEC, NULL, 0x0,
2486                   "Count of packets", HFILL}
2487                  },
2488                 {&hf_cflow_packets64,
2489                  {"Packets", "cflow.packets64",
2490                   FT_UINT64, BASE_DEC, NULL, 0x0,
2491                   "Count of packets", HFILL}
2492                  },
2493                 {&hf_cflow_packetsout,
2494                  {"PacketsOut", "cflow.packetsout",
2495                   FT_UINT64, BASE_DEC, NULL, 0x0,
2496                   "Count of packets going out", HFILL}
2497                  },
2498                 {&hf_cflow_octets,
2499                  {"Octets", "cflow.octets",
2500                   FT_UINT32, BASE_DEC, NULL, 0x0,
2501                   "Count of bytes", HFILL}
2502                  },
2503                 {&hf_cflow_octets64,
2504                  {"Octets", "cflow.octets64",
2505                   FT_UINT64, BASE_DEC, NULL, 0x0,
2506                   "Count of bytes", HFILL}
2507                  },
2508                 {&hf_cflow_length_min,
2509                  {"MinLength", "cflow.length_min",
2510                   FT_UINT16, BASE_DEC, NULL, 0x0,
2511                   "Packet Length Min", HFILL}
2512                  },
2513                 {&hf_cflow_length_max,
2514                  {"MaxLength", "cflow.length_max",
2515                   FT_UINT16, BASE_DEC, NULL, 0x0,
2516                   "Packet Length Max", HFILL}
2517                  },
2518                 {&hf_cflow_timedelta,
2519                  {"Duration", "cflow.timedelta",
2520                   FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
2521                   "Duration of flow sample (end - start)", HFILL}
2522                  },
2523                 {&hf_cflow_timestart,
2524                  {"StartTime", "cflow.timestart",
2525                   FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
2526                   "Uptime at start of flow", HFILL}
2527                  },
2528                 {&hf_cflow_timeend,
2529                  {"EndTime", "cflow.timeend",
2530                   FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
2531                   "Uptime at end of flow", HFILL}
2532                  },
2533                 {&hf_cflow_srcport,
2534                  {"SrcPort", "cflow.srcport",
2535                   FT_UINT16, BASE_DEC, NULL, 0x0,
2536                   "Flow Source Port", HFILL}
2537                  },
2538                 {&hf_cflow_dstport,
2539                  {"DstPort", "cflow.dstport",
2540                   FT_UINT16, BASE_DEC, NULL, 0x0,
2541                   "Flow Destination Port", HFILL}
2542                  },
2543                 {&hf_cflow_prot,
2544                  {"Protocol", "cflow.protocol",
2545                   FT_UINT8, BASE_DEC, NULL, 0x0,
2546                   "IP Protocol", HFILL}
2547                  },
2548                 {&hf_cflow_tos,
2549                  {"IP ToS", "cflow.tos",
2550                   FT_UINT8, BASE_HEX, NULL, 0x0,
2551                   "IP Type of Service", HFILL}
2552                  },
2553                 {&hf_cflow_flags,
2554                  {"Export Flags", "cflow.flags",
2555                   FT_UINT8, BASE_HEX, NULL, 0x0,
2556                   "CFlow Flags", HFILL}
2557                  },
2558                 {&hf_cflow_tcpflags,
2559                  {"TCP Flags", "cflow.tcpflags",
2560                   FT_UINT8, BASE_HEX, NULL, 0x0,
2561                   "TCP Flags", HFILL}
2562                  },
2563                 {&hf_cflow_srcas,
2564                  {"SrcAS", "cflow.srcas",
2565                   FT_UINT16, BASE_DEC, NULL, 0x0,
2566                   "Source AS", HFILL}
2567                  },
2568                 {&hf_cflow_dstas,
2569                  {"DstAS", "cflow.dstas",
2570                   FT_UINT16, BASE_DEC, NULL, 0x0,
2571                   "Destination AS", HFILL}
2572                  },
2573                 {&hf_cflow_srcmask,
2574                  {"SrcMask", "cflow.srcmask",
2575                   FT_UINT8, BASE_DEC, NULL, 0x0,
2576                   "Source Prefix Mask", HFILL}
2577                  },
2578                 {&hf_cflow_srcmask_v6,
2579                  {"SrcMask", "cflow.srcmaskv6",
2580                   FT_UINT8, BASE_DEC, NULL, 0x0,
2581                   "IPv6 Source Prefix Mask", HFILL}
2582                  },
2583                 {&hf_cflow_dstmask,
2584                  {"DstMask", "cflow.dstmask",
2585                   FT_UINT8, BASE_DEC, NULL, 0x0,
2586                   "Destination Prefix Mask", HFILL}
2587                  },
2588                 {&hf_cflow_dstmask_v6,
2589                  {"DstMask", "cflow.dstmaskv6",
2590                   FT_UINT8, BASE_DEC, NULL, 0x0,
2591                   "IPv6 Destination Prefix Mask", HFILL}
2592                  },
2593                 {&hf_cflow_routersc,
2594                  {"Router Shortcut", "cflow.routersc",
2595                   FT_IPv4, BASE_NONE, NULL, 0x0,
2596                   "Router shortcut by switch", HFILL}
2597                  },
2598                 {&hf_cflow_mulpackets,
2599                  {"MulticastPackets", "cflow.mulpackets",
2600                   FT_UINT32, BASE_DEC, NULL, 0x0,
2601                   "Count of multicast packets", HFILL}
2602                  },
2603                 {&hf_cflow_muloctets,
2604                  {"MulticastOctets", "cflow.muloctets",
2605                   FT_UINT32, BASE_DEC, NULL, 0x0,
2606                   "Count of multicast octets", HFILL}
2607                  },
2608                 {&hf_cflow_octets_exp,
2609                  {"OctetsExp", "cflow.octetsexp",
2610                   FT_UINT32, BASE_DEC, NULL, 0x0,
2611                   "Octets exported", HFILL}
2612                  },
2613                 {&hf_cflow_octets_exp64,
2614                  {"OctetsExp ", "cflow.octetsexp",
2615                   FT_UINT64, BASE_DEC, NULL, 0x0,
2616                   "Octets exported", HFILL}
2617                  },
2618                 {&hf_cflow_packets_exp,
2619                  {"PacketsExp", "cflow.packetsexp",
2620                   FT_UINT32, BASE_DEC, NULL, 0x0,
2621                   "Packets exported", HFILL}
2622                  },
2623                 {&hf_cflow_packets_exp64,
2624                  {"PacketsExp", "cflow.packetsexp",
2625                   FT_UINT64, BASE_DEC, NULL, 0x0,
2626                   "Packets exported", HFILL}
2627                  },
2628                 {&hf_cflow_flows_exp,
2629                  {"FlowsExp  ", "cflow.flowsexp",
2630                   FT_UINT32, BASE_DEC, NULL, 0x0,
2631                   "Flows exported", HFILL}
2632                 },
2633                 {&hf_cflow_flows_exp64,
2634                  {"FlowsExp  ", "cflow.flowsexp",
2635                   FT_UINT64, BASE_DEC, NULL, 0x0,
2636                   "Flows exported", HFILL}
2637                 },
2638                 {&hf_cflow_srcprefix,
2639                  {"SrcPrefix", "cflow.srcprefix",
2640                   FT_IPv4, BASE_NONE, NULL, 0x0,
2641                   "Flow Source Prefix", HFILL}
2642                  },
2643                 {&hf_cflow_dstprefix,
2644                  {"DstPrefix", "cflow.dstprefix",
2645                   FT_IPv4, BASE_NONE, NULL, 0x0,
2646                   "Flow Destination Prefix", HFILL}
2647                  },
2648                 {&hf_cflow_mpls_top_label_type,
2649                  {"TopLabelType", "cflow.toplabeltype",
2650                   FT_UINT8, BASE_DEC, VALS(special_mpls_top_label_type), 0x0,
2651                   "Top MPLS label Type", HFILL}
2652                  },
2653                 {&hf_cflow_mpls_pe_addr,
2654                  {"TopLabelAddr", "cflow.toplabeladdr",
2655                   FT_IPv4, BASE_NONE, NULL, 0x0,
2656                   "Top MPLS label PE address", HFILL}
2657                  },
2658                 {&hf_cflow_sampler_mode ,
2659                  {"SamplerMode", "cflow.sampler_mode",
2660                   FT_UINT8, BASE_DEC, VALS(v9_sampler_mode), 0x0,
2661                   "Flow Sampler Mode", HFILL}
2662                  },
2663                 {&hf_cflow_sampler_random_interval ,
2664                  {"SamplerRandomInterval", "cflow.sampler_random_interval",
2665                   FT_UINT32, BASE_DEC, NULL, 0x0,
2666                   "Flow Sampler Random Interval", HFILL}
2667                  },
2668                 {&hf_cflow_flow_class ,
2669                  {"FlowClass", "cflow.flow_class",
2670                   FT_UINT8, BASE_DEC, NULL, 0x0,
2671                   "Flow Class", HFILL}
2672                  },
2673                 {&hf_cflow_ttl_minimum ,
2674                  {"MinTTL", "cflow.ttl_min",
2675                   FT_UINT8, BASE_DEC, NULL, 0x0,
2676                   "TTL minimum", HFILL}
2677                  },
2678                 {&hf_cflow_ttl_maximum ,
2679                  {"MaxTTL", "cflow.ttl_max",
2680                   FT_UINT8, BASE_DEC, NULL, 0x0,
2681                   "TTL maximum", HFILL}
2682                  },
2683                 {&hf_cflow_ipv4_id ,
2684                  {"IPv4Ident", "cflow.ipv4_ident",
2685                   FT_UINT16, BASE_DEC, NULL, 0x0,
2686                   "IPv4 Identifier", HFILL}
2687                  },
2688                 {&hf_cflow_ip_version ,
2689                  {"IPVersion", "cflow.ip_version",
2690                   FT_BYTES, BASE_HEX, NULL, 0x0,
2691                   "IP Version", HFILL}
2692                  },
2693                 {&hf_cflow_direction ,
2694                  {"Direction", "cflow.direction",
2695                   FT_UINT8, BASE_DEC, VALS(v9_direction), 0x0,
2696                   "Direction", HFILL}
2697                  },
2698                 {&hf_cflow_if_name ,
2699                  {"IfName", "cflow.if_name",
2700                   FT_STRINGZ/*FT_BYTES*/, BASE_HEX, NULL, 0x0,
2701                   "SNMP Interface Name", HFILL}
2702                  },
2703                 {&hf_cflow_if_descr ,
2704                  {"IfDescr", "cflow.if_descr",
2705                   FT_STRINGZ/*FT_BYTES*/, BASE_HEX, NULL, 0x0,
2706                   "SNMP Interface Description", HFILL}
2707                  },
2708                 {&hf_cflow_sampler_name ,
2709                  {"SamplerName", "cflow.sampler_name",
2710                   FT_STRINGZ/*FT_BYTES*/, BASE_HEX, NULL, 0x0,
2711                   "Sampler Name", HFILL}
2712                  },
2713                 {&hf_cflow_forwarding_status ,
2714                  {"ForwdStat", "cflow.forwarding_status",
2715                   FT_UINT8, BASE_DEC, VALS(v9_forwarding_status), 0xC0,
2716                   "Forwarding Status", HFILL}
2717                  },
2718                 {&hf_cflow_forwarding_code ,
2719                  {"ForwdCode", "cflow.forwarding_code",
2720                   FT_UINT8, BASE_DEC, NULL, 0x3F,
2721                   "Forwarding Code", HFILL}
2722                  },
2723                 {&hf_cflow_peer_srcas,
2724                  {"PeerSrcAS", "cflow.peer_srcas",
2725                   FT_UINT16, BASE_DEC, NULL, 0x0,
2726                   "Peer Source AS", HFILL}
2727                  },
2728                 {&hf_cflow_peer_dstas,
2729                  {"PeerDstAS", "cflow.peer_dstas",
2730                   FT_UINT16, BASE_DEC, NULL, 0x0,
2731                   "Peer Destination AS", HFILL}
2732                  },
2733                 {&hf_cflow_flow_exporter,
2734                  {"FlowExporter", "cflow.flow_exporter",
2735                   FT_BYTES/*FT_IPv4*/, BASE_HEX, NULL, 0x0,
2736                   "Flow Exporter", HFILL}
2737                  },
2738                 {&hf_cflow_icmp_ipv4_type,
2739                  {"IPv4 ICMP Type", "cflow.icmp_ipv4_type",
2740                   FT_UINT8, BASE_DEC, NULL, 0x0,
2741                   "IPv4 ICMP type", HFILL}
2742                 },
2743                 {&hf_cflow_icmp_ipv4_code,
2744                  {"IPv4 ICMP Code", "cflow.icmp_ipv4_code",
2745                   FT_UINT8, BASE_DEC, NULL, 0x0,
2746                   "IPv4 ICMP code", HFILL}
2747                 },
2748                 {&hf_cflow_icmp_ipv6_type,
2749                  {"IPv6 ICMP Type", "cflow.icmp_ipv6_type",
2750                   FT_UINT8, BASE_DEC, NULL, 0x0,
2751                   "IPv6 ICMP type", HFILL}
2752                 },
2753                 {&hf_cflow_icmp_ipv6_code,
2754                  {"IPv6 ICMP Code", "cflow.icmp_ipv6_code",
2755                   FT_UINT8, BASE_DEC, NULL, 0x0,
2756                   "IPv6 ICMP code", HFILL}
2757                 },
2758                 {&hf_cflow_tcp_window_size,
2759                  {"TCP Windows Size", "cflow.tcp_windows_size",
2760                   FT_UINT16, BASE_DEC, NULL, 0x0,
2761                   "TCP Windows size", HFILL}
2762                  },
2763                 {&hf_cflow_ip_total_length,
2764                  {"IP Total Length", "cflow.ip_total_length",
2765                   FT_UINT8, BASE_DEC, NULL, 0x0,
2766                   "IP total length", HFILL}
2767                 },
2768                 {&hf_cflow_ip_ttl,
2769                  {"IP TTL", "cflow.ip_ttl",
2770                   FT_UINT8, BASE_DEC, NULL, 0x0,
2771                   "IP time to live", HFILL}
2772                 },
2773                 {&hf_cflow_ip_tos,
2774                  {"IP TOS", "cflow.ip_tos",
2775                   FT_UINT8, BASE_DEC, NULL, 0x0,
2776                   "IP type of service", HFILL}
2777                 },
2778                 {&hf_cflow_ip_dscp,
2779                  {"DSCP", "cflow.ip_dscp",
2780                   FT_UINT8, BASE_DEC, NULL, 0x0,
2781                   "IP DSCP", HFILL}
2782                 },
2783                 {&hf_cflow_octets_squared64,
2784                  {"OctetsSquared  ", "cflow.octets_squared",
2785                   FT_UINT64, BASE_DEC, NULL, 0x0,
2786                   "Octets Squared", HFILL}
2787                 },
2788                 {&hf_cflow_udp_length,
2789                  {"UDP Length", "cflow.udp_length",
2790                   FT_UINT16, BASE_DEC, NULL, 0x0,
2791                   "UDP length", HFILL}
2792                 },
2793                 {&hf_cflow_is_multicast,
2794                  {"IsMulticast", "cflow.is_multicast",
2795                   FT_UINT8, BASE_DEC, NULL, 0x0,
2796                   "Is Multicast", HFILL}
2797                 },
2798                 {&hf_cflow_ip_header_words,
2799                  {"IPHeaderLen", "cflow.ip_header_words",
2800                   FT_UINT8, BASE_DEC, NULL, 0x0,
2801                   "IPHeaderLen", HFILL}
2802                 },
2803                 {&hf_cflow_option_map,
2804                  {"OptionMap", "cflow.option_map",
2805                   FT_BYTES, BASE_HEX, NULL, 0x0,
2806                   "Option Map", HFILL}
2807                 },
2808                 {&hf_cflow_section_header ,
2809                  {"SectionHeader", "cflow.section_header",
2810                   FT_BYTES, BASE_HEX, NULL, 0x0,
2811                   "Header of Packet", HFILL}
2812                  },
2813                 {&hf_cflow_section_payload ,
2814                  {"SectionPayload", "cflow.section_payload",
2815                   FT_BYTES, BASE_HEX, NULL, 0x0,
2816                   "Payload of Packet", HFILL}
2817                  },
2818                 /*
2819                  * end pdu content storage
2820                  */
2821                 {&hf_cflow_scope_system ,
2822                  {"ScopeSystem", "cflow.scope_system",
2823                   FT_IPv4, BASE_HEX, NULL, 0x0,
2824                   "Option Scope System", HFILL}
2825                  },
2826                 {&hf_cflow_scope_interface ,
2827                  {"ScopeInterface", "cflow.scope_interface",
2828                   FT_UINT32, BASE_DEC, NULL, 0x0,
2829                   "Option Scope Interface", HFILL}
2830                  },
2831                 {&hf_cflow_scope_linecard ,
2832                  {"ScopeLinecard", "cflow.scope_linecard",
2833                   FT_BYTES, BASE_HEX, NULL, 0x0,
2834                   "Option Scope Linecard", HFILL}
2835                  },
2836                 {&hf_cflow_scope_cache ,
2837                  {"ScopeCache", "cflow.scope_cache",
2838                   FT_BYTES, BASE_HEX, NULL, 0x0,
2839                   "Option Scope Cache", HFILL}
2840                  },
2841                 {&hf_cflow_scope_template ,
2842                  {"ScopeTemplate", "cflow.scope_template",
2843                   FT_BYTES, BASE_HEX, NULL, 0x0,
2844                   "Option Scope Template", HFILL}
2845                  },
2846                 {&hf_cflow_scope_unknown ,
2847                  {"Scope Unknown", "cflow.scope",
2848                   FT_BYTES, BASE_HEX, NULL, 0x0,
2849                   "Option Scope Unknown", HFILL}
2850                  }
2851         };
2852
2853         static gint    *ett[] = {
2854                 &ett_netflow,
2855                 &ett_unixtime,
2856                 &ett_flow,
2857                 &ett_flowtime,
2858                 &ett_template,
2859                 &ett_field,
2860                 &ett_dataflowset
2861         };
2862
2863         module_t *netflow_module;
2864
2865         proto_netflow = proto_register_protocol("Cisco NetFlow/IPFIX", "CFLOW",
2866                                                 "cflow");
2867
2868         proto_register_field_array(proto_netflow, hf, array_length(hf));
2869         proto_register_subtree_array(ett, array_length(ett));
2870
2871         /* Register our configuration options for NetFlow */
2872         netflow_module = prefs_register_protocol(proto_netflow,
2873             proto_reg_handoff_netflow);
2874
2875         prefs_register_uint_preference(netflow_module, "udp.port",
2876             "NetFlow UDP Port", "Set the port for NetFlow messages",
2877             10, &global_netflow_udp_port);
2878
2879         register_init_routine(&netflow_reinit);
2880 }
2881
2882
2883 /*
2884  * protocol/port association
2885  */
2886 void
2887 proto_reg_handoff_netflow(void)
2888 {
2889         static int netflow_prefs_initialized = FALSE;
2890         static dissector_handle_t netflow_handle;
2891
2892         if (!netflow_prefs_initialized) {
2893                 netflow_handle = create_dissector_handle(dissect_netflow,
2894                     proto_netflow);
2895                 netflow_prefs_initialized = TRUE;
2896         } else {
2897                 dissector_delete("udp.port", netflow_udp_port, netflow_handle);
2898                 dissector_delete("udp.port", ipfix_port,  netflow_handle);
2899                 dissector_delete("tcp.port", ipfix_port,  netflow_handle);
2900                 dissector_delete("sctp.port", ipfix_port, netflow_handle);
2901         }
2902
2903         /* Set out port number for future use */
2904         netflow_udp_port = global_netflow_udp_port;
2905
2906         dissector_add("udp.port", netflow_udp_port, netflow_handle);
2907
2908         ipfix_port = global_ipfix_port;
2909         dissector_add("udp.port", ipfix_port,  netflow_handle);
2910         dissector_add("tcp.port", ipfix_port,  netflow_handle);
2911         dissector_add("sctp.port", ipfix_port, netflow_handle);
2912 }
2913