change a whole bunch of ethereal into wireshark
[obnox/wireshark/wip.git] / epan / dissectors / packet-netflow.c
1 /*
2  ** packet-netflow.c
3  ** 
4  *****************************************************************************
5  ** (c) 2002 bill fumerola <fumerola@yahoo-inc.com>
6  ** All rights reserved.
7  ** 
8  ** This program is free software; you can redistribute it and/or
9  ** modify it under the terms of the GNU General Public License
10  ** as published by the Free Software Foundation; either version 2
11  ** of the License, or (at your option) any later version.
12  ** 
13  ** This program is distributed in the hope that it will be useful,
14  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  ** GNU General Public License for more details.
17  ** 
18  ** You should have received a copy of the GNU General Public License
19  ** along with this program; if not, write to the Free Software
20  ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  *****************************************************************************
22  **
23  ** Previous NetFlow dissector written by Matthew Smart <smart@monkey.org>
24  ** NetFlow v9 support added by same.
25  **
26  ** NetFlow v9 patches by Luca Deri <deri@ntop.org>
27  **
28  ** See
29  **
30  ** http://www.cisco.com/warp/public/cc/pd/iosw/prodlit/tflow_wp.htm
31  **
32  ** for NetFlow v9 information.
33  **
34  *****************************************************************************
35  **
36  ** this code was written from the following documentation:
37  **
38  ** http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_6/iug/format.pdf
39  ** http://www.caida.org/tools/measurement/cflowd/configuration/configuration-9.html
40  **
41  ** some documentation is more accurate then others. in some cases, live data and
42  ** information contained in responses from vendors were also used. some fields
43  ** are dissected as vendor specific fields.
44  **
45  ** See also
46  **
47  ** http://www.cisco.com/univercd/cc/td/doc/cisintwk/intsolns/netflsol/nfwhite.htm
48  **
49  ** $Yahoo: //depot/fumerola/packet-netflow/packet-netflow.c#14 $
50  ** $Id$
51  */
52
53 #ifdef HAVE_CONFIG_H
54 # include "config.h"
55 #endif
56
57 #include <glib.h>
58 #include <epan/packet.h>
59 #include <string.h>
60
61 #include <epan/prefs.h>
62
63 #define UDP_PORT_NETFLOW        2055
64
65 static guint global_netflow_udp_port = UDP_PORT_NETFLOW;
66 static guint netflow_udp_port = 0;
67
68 /*
69  * pdu identifiers & sizes 
70  */
71
72 #define V1PDU_SIZE              (4 * 12)
73 #define V5PDU_SIZE              (4 * 12)
74 #define V7PDU_SIZE              (4 * 13)
75 #define V8PDU_AS_SIZE           (4 * 7)
76 #define V8PDU_PROTO_SIZE        (4 * 7)
77 #define V8PDU_SPREFIX_SIZE      (4 * 8)
78 #define V8PDU_DPREFIX_SIZE      (4 * 8)
79 #define V8PDU_MATRIX_SIZE       (4 * 10)
80 #define V8PDU_DESTONLY_SIZE     (4 * 8)
81 #define V8PDU_SRCDEST_SIZE      (4 * 10)
82 #define V8PDU_FULL_SIZE         (4 * 11)
83 #define V8PDU_TOSAS_SIZE        (V8PDU_AS_SIZE + 4)
84 #define V8PDU_TOSPROTOPORT_SIZE (V8PDU_PROTO_SIZE + 4)
85 #define V8PDU_TOSSRCPREFIX_SIZE V8PDU_SPREFIX_SIZE
86 #define V8PDU_TOSDSTPREFIX_SIZE V8PDU_DPREFIX_SIZE
87 #define V8PDU_TOSMATRIX_SIZE    V8PDU_MATRIX_SIZE
88 #define V8PDU_PREPORTPROTOCOL_SIZE (4 * 10)
89
90 static const value_string v5_sampling_mode[] = {
91         {0, "No sampling mode configured"},
92         {1, "Packet Interval sampling mode configured"},
93         {0, NULL}
94 };
95
96 enum {
97         V8PDU_NO_METHOD = 0,
98         V8PDU_AS_METHOD,
99         V8PDU_PROTO_METHOD,
100         V8PDU_SPREFIX_METHOD,
101         V8PDU_DPREFIX_METHOD,
102         V8PDU_MATRIX_METHOD,
103         V8PDU_DESTONLY_METHOD,
104         V8PDU_SRCDEST_METHOD,
105         V8PDU_FULL_METHOD,
106         V8PDU_TOSAS_METHOD,
107         V8PDU_TOSPROTOPORT_METHOD,
108         V8PDU_TOSSRCPREFIX_METHOD,
109         V8PDU_TOSDSTPREFIX_METHOD,
110         V8PDU_TOSMATRIX_METHOD,
111         V8PDU_PREPORTPROTOCOL_METHOD
112 };
113
114 static const value_string v8_agg[] = {
115         {V8PDU_AS_METHOD, "V8 AS aggregation"},
116         {V8PDU_PROTO_METHOD, "V8 Proto/Port aggregation"},
117         {V8PDU_SPREFIX_METHOD, "V8 Source Prefix aggregation"},
118         {V8PDU_DPREFIX_METHOD, "V8 Destination Prefix aggregation"},
119         {V8PDU_MATRIX_METHOD, "V8 Network Matrix aggregation"},
120         {V8PDU_DESTONLY_METHOD, "V8 Destination aggregation (Cisco Catalyst)"},
121         {V8PDU_SRCDEST_METHOD, "V8 Src/Dest aggregation (Cisco Catalyst)"},
122         {V8PDU_FULL_METHOD, "V8 Full aggregation (Cisco Catalyst)"},
123         {V8PDU_TOSAS_METHOD, "V8 TOS+AS aggregation aggregation"},
124         {V8PDU_TOSPROTOPORT_METHOD, "V8 TOS+Protocol aggregation"},
125         {V8PDU_TOSSRCPREFIX_METHOD, "V8 TOS+Source Prefix aggregation"},
126         {V8PDU_TOSDSTPREFIX_METHOD, "V8 TOS+Destination Prefix aggregation"},
127         {V8PDU_TOSMATRIX_METHOD, "V8 TOS+Prefix Matrix aggregation"},
128         {V8PDU_PREPORTPROTOCOL_METHOD, "V8 Port+Protocol aggregation"},
129         {0, NULL}
130 };
131
132 /* Version 9 template cache structures */
133 #define V9TEMPLATE_CACHE_MAX_ENTRIES    100
134
135 struct v9_template_entry {
136         guint16 type;
137         guint16 length;
138 };
139
140 struct v9_template {
141         guint16 id;
142         guint16 count;
143         guint32 length;
144         guint32 source_id;
145         guint32 source_addr;
146         guint16 option_template; /* 0=data template, 1=option template */
147         struct v9_template_entry *entries;
148 };
149
150 static struct v9_template v9_template_cache[V9TEMPLATE_CACHE_MAX_ENTRIES];
151
152 /*
153  * wireshark tree identifiers
154  */
155
156 static int      proto_netflow = -1;
157 static int      ett_netflow = -1;
158 static int      ett_unixtime = -1;
159 static int      ett_flow = -1;
160 static int      ett_template = -1;
161 static int      ett_field = -1;
162 static int      ett_dataflowset = -1;
163
164 /*
165  * cflow header 
166  */
167
168 static int      hf_cflow_version = -1;
169 static int      hf_cflow_count = -1;
170 static int      hf_cflow_sysuptime = -1;
171 static int      hf_cflow_unix_secs = -1;
172 static int      hf_cflow_unix_nsecs = -1;
173 static int      hf_cflow_timestamp = -1;
174 static int      hf_cflow_samplingmode = -1;
175 static int      hf_cflow_samplerate = -1;
176
177 /*
178  * cflow version specific info 
179  */
180 static int      hf_cflow_sequence = -1;
181 static int      hf_cflow_engine_type = -1;
182 static int      hf_cflow_engine_id = -1;
183 static int      hf_cflow_source_id = -1;
184
185 static int      hf_cflow_aggmethod = -1;
186 static int      hf_cflow_aggversion = -1;
187
188 /* Version 9 */
189
190 static int      hf_cflow_template_flowset_id = -1;
191 static int      hf_cflow_data_flowset_id = -1;
192 static int      hf_cflow_options_flowset_id = -1;
193 static int      hf_cflow_flowset_id = -1;
194 static int      hf_cflow_flowset_length = -1;
195 static int      hf_cflow_template_id = -1;
196 static int      hf_cflow_template_field_count = -1;
197 static int      hf_cflow_template_field_type = -1;
198 static int      hf_cflow_template_field_length = -1;
199 static int      hf_cflow_option_scope_length = -1;
200 static int      hf_cflow_option_length = -1;
201 static int      hf_cflow_template_scope_field_type = -1;
202 static int      hf_cflow_template_scope_field_length = -1;
203
204
205 /*
206  * pdu storage
207  */
208 static int      hf_cflow_srcaddr = -1;
209 static int      hf_cflow_srcaddr_v6 = -1;
210 static int      hf_cflow_srcnet = -1;
211 static int      hf_cflow_dstaddr = -1;
212 static int      hf_cflow_dstaddr_v6 = -1;
213 static int      hf_cflow_dstnet = -1;
214 static int      hf_cflow_nexthop = -1;
215 static int      hf_cflow_nexthop_v6 = -1;
216 static int      hf_cflow_bgpnexthop = -1;
217 static int      hf_cflow_bgpnexthop_v6 = -1;
218 static int      hf_cflow_inputint = -1;
219 static int      hf_cflow_outputint = -1;
220 static int      hf_cflow_flows = -1;
221 static int      hf_cflow_packets = -1;
222 static int      hf_cflow_packets64 = -1;
223 static int      hf_cflow_packetsout = -1;
224 static int      hf_cflow_octets = -1;
225 static int      hf_cflow_octets64 = -1;
226 static int      hf_cflow_timestart = -1;
227 static int      hf_cflow_timeend = -1;
228 static int      hf_cflow_srcport = -1;
229 static int      hf_cflow_dstport = -1;
230 static int      hf_cflow_prot = -1;
231 static int      hf_cflow_tos = -1;
232 static int      hf_cflow_flags = -1;
233 static int      hf_cflow_tcpflags = -1;
234 static int      hf_cflow_dstas = -1;
235 static int      hf_cflow_srcas = -1;
236 static int      hf_cflow_dstmask = -1;
237 static int      hf_cflow_srcmask = -1;
238 static int      hf_cflow_routersc = -1;
239 static int      hf_cflow_mulpackets = -1;
240 static int      hf_cflow_muloctets = -1;
241 static int      hf_cflow_octets_exp = -1;
242 static int      hf_cflow_packets_exp = -1;
243 static int      hf_cflow_flows_exp = -1;
244 static int      hf_cflow_sampling_interval = -1;
245 static int      hf_cflow_sampling_algorithm = -1;
246 static int      hf_cflow_flow_active_timeout = -1;
247 static int      hf_cflow_flow_inactive_timeout = -1;
248 static int      hf_cflow_mpls_top_label_type = -1;
249 static int      hf_cflow_mpls_pe_addr = -1;
250 const value_string special_mpls_top_label_type[] = {
251         {0,     "Unknown"},
252         {1,     "TE-MIDPT"},
253         {2,     "ATOM"},
254         {3,     "VPN"},
255         {4,     "BGP"},
256         {5,     "LDP"},
257
258         {0,     NULL }
259 };
260
261 void
262 proto_tree_add_mpls_label(proto_tree * pdutree, tvbuff_t * tvb, int offset, int length, int level)
263 {
264         if( length == 3) {
265                 guint8 b0 = tvb_get_guint8(tvb, offset);
266                 guint8 b1 = tvb_get_guint8(tvb, offset + 1);
267                 guint8 b2 = tvb_get_guint8(tvb, offset + 2);
268                 proto_tree_add_text(pdutree, tvb, offset, length,
269                         "MPLS-Label%d: %u exp-bits: %u %s", level,
270                         ((b0<<12)+(b1<<4)+(b2>>4)), 
271                         ((b2>>1)&0x7), 
272                         ((b2&0x1)?"top-of-stack":""));
273         } else {
274                 proto_tree_add_text(pdutree, tvb, offset, length,
275                         "MPLS-Label%d: bad lengh %d", level, length);
276         }
277 }
278
279 void            proto_reg_handoff_netflow(void);
280
281 typedef int     dissect_pdu_t(proto_tree * pdutree, tvbuff_t * tvb, int offset,
282                               int verspec);
283 static int      dissect_pdu(proto_tree * tree, tvbuff_t * tvb, int offset,
284                             int verspec);
285 static int      dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb,
286                                   int offset, int verspec);
287 static int      dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb,
288                                    int offset, int verspec);
289 static int      dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb,
290                                    int offset, int verspec);
291 static int      dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb,
292                                int offset, guint16 id, guint length);
293 static void     dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb,
294                                int offset, struct v9_template * template);
295 static int      dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb,
296                                int offset);
297 static int      dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb,
298                                     int offset, int len);
299 static void     v9_template_add(struct v9_template * template);
300 static struct v9_template *v9_template_get(guint16 id, guint32 src_addr,
301                                            guint32 src_id);
302
303 static gchar   *getprefix(const guint32 * address, int prefix);
304 static void     dissect_netflow(tvbuff_t * tvb, packet_info * pinfo,
305                                 proto_tree * tree);
306
307 static int      flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb,
308                                   int offset);
309 static int      flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb,
310                                    int offset);
311 static int      flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb,
312                                         int offset);
313 static int      flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb,
314                                     int offset);
315 static int      flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb,
316                                        int offset);
317 static int      flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb,
318                                        int offset, int bytes,
319                                        const char *text);
320
321
322 static void
323 dissect_netflow(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
324 {
325         proto_tree     *netflow_tree = NULL;
326         proto_tree     *ti;
327         proto_item     *timeitem, *pduitem;
328         proto_tree     *timetree, *pdutree;
329         unsigned int    pduret, ver = 0, pdus = 0, x = 1, vspec;
330         size_t          available, pdusize, offset = 0;
331         nstime_t        ts;
332         dissect_pdu_t  *pduptr;
333
334         if (check_col(pinfo->cinfo, COL_PROTOCOL))
335                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CFLOW");
336         if (check_col(pinfo->cinfo, COL_INFO))
337                 col_clear(pinfo->cinfo, COL_INFO);
338
339         if (tree) {
340                 ti = proto_tree_add_item(tree, proto_netflow, tvb,
341                                          offset, -1, FALSE);
342                 netflow_tree = proto_item_add_subtree(ti, ett_netflow);
343         }
344
345         ver = tvb_get_ntohs(tvb, offset);
346         vspec = ver;
347         switch (ver) {
348         case 1:
349                 pdusize = V1PDU_SIZE;
350                 pduptr = &dissect_pdu;
351                 break;
352         case 5:
353                 pdusize = V5PDU_SIZE;
354                 pduptr = &dissect_pdu;
355                 break;
356         case 7:
357                 pdusize = V7PDU_SIZE;
358                 pduptr = &dissect_pdu;
359                 break;
360         case 8:
361                 pdusize = -1;   /* deferred */
362                 pduptr = &dissect_v8_aggpdu;
363                 break;
364         case 9:
365                 pdusize = -1;   /* deferred */
366                 pduptr = &dissect_v9_flowset;
367                 break;
368         default:
369                 return;
370         }
371
372         if (tree)
373                 proto_tree_add_uint(netflow_tree, hf_cflow_version, tvb,
374                                     offset, 2, ver);
375         offset += 2;
376
377         pdus = tvb_get_ntohs(tvb, offset);
378         if (pdus <= 0)
379                 return;
380         if (tree)
381                 proto_tree_add_uint(netflow_tree, hf_cflow_count, tvb,
382                                     offset, 2, pdus);
383         offset += 2;
384
385         /*
386          * set something interesting in the display now that we have info 
387          */
388         if (check_col(pinfo->cinfo, COL_INFO)) {
389                 if (ver == 9) {
390                         col_add_fstr(pinfo->cinfo, COL_INFO,
391                             "total: %u (v%u) record%s", pdus, ver,
392                             plurality(pdus, "", "s"));
393                 } else {
394                         col_add_fstr(pinfo->cinfo, COL_INFO,
395                             "total: %u (v%u) flow%s", pdus, ver,
396                             plurality(pdus, "", "s"));
397                 }
398         }
399
400         /*
401          * the rest is only interesting if we're displaying/searching the
402          * packet 
403          */
404         if (!tree)
405                 return;
406
407         proto_tree_add_item(netflow_tree, hf_cflow_sysuptime, tvb,
408                             offset, 4, FALSE);
409         offset += 4;
410
411         ts.secs = tvb_get_ntohl(tvb, offset);
412         if (ver != 9) {
413           ts.nsecs = tvb_get_ntohl(tvb, offset + 4);
414           timeitem = proto_tree_add_time(netflow_tree,
415                                          hf_cflow_timestamp, tvb, offset,
416                                          8, &ts);
417         } else {
418           ts.nsecs = 0;
419           timeitem = proto_tree_add_time(netflow_tree,
420                                          hf_cflow_timestamp, tvb, offset,
421                                          4, &ts);
422         }
423
424         timetree = proto_item_add_subtree(timeitem, ett_unixtime);
425
426         proto_tree_add_item(timetree, hf_cflow_unix_secs, tvb,
427                             offset, 4, FALSE);
428         offset += 4;
429
430         if (ver != 9) {
431                 proto_tree_add_item(timetree, hf_cflow_unix_nsecs, tvb,
432                                     offset, 4, FALSE);
433                 offset += 4;
434         }
435
436         /*
437          * version specific header 
438          */
439         if (ver == 5 || ver == 7 || ver == 8 || ver == 9) {
440                 proto_tree_add_item(netflow_tree, hf_cflow_sequence,
441                                     tvb, offset, 4, FALSE);
442                 offset += 4;
443         }
444         if (ver == 5 || ver == 8) {
445                 proto_tree_add_item(netflow_tree, hf_cflow_engine_type,
446                                     tvb, offset++, 1, FALSE);
447                 proto_tree_add_item(netflow_tree, hf_cflow_engine_id,
448                                     tvb, offset++, 1, FALSE);
449         } else if (ver == 9) {
450                 proto_tree_add_item(netflow_tree, hf_cflow_source_id,
451                                     tvb, offset, 4, FALSE);
452                 offset += 4;
453         }
454         if (ver == 8) {
455                 vspec = tvb_get_guint8(tvb, offset);
456                 switch (vspec) {
457                 case V8PDU_AS_METHOD:
458                         pdusize = V8PDU_AS_SIZE;
459                         break;
460                 case V8PDU_PROTO_METHOD:
461                         pdusize = V8PDU_PROTO_SIZE;
462                         break;
463                 case V8PDU_SPREFIX_METHOD:
464                         pdusize = V8PDU_SPREFIX_SIZE;
465                         break;
466                 case V8PDU_DPREFIX_METHOD:
467                         pdusize = V8PDU_DPREFIX_SIZE;
468                         break;
469                 case V8PDU_MATRIX_METHOD:
470                         pdusize = V8PDU_MATRIX_SIZE;
471                         break;
472                 case V8PDU_DESTONLY_METHOD:
473                         pdusize = V8PDU_DESTONLY_SIZE;
474                         pduptr = &dissect_v8_flowpdu;
475                         break;
476                 case V8PDU_SRCDEST_METHOD:
477                         pdusize = V8PDU_SRCDEST_SIZE;
478                         pduptr = &dissect_v8_flowpdu;
479                         break;
480                 case V8PDU_FULL_METHOD:
481                         pdusize = V8PDU_FULL_SIZE;
482                         pduptr = &dissect_v8_flowpdu;
483                         break;
484                 case V8PDU_TOSAS_METHOD:
485                         pdusize = V8PDU_TOSAS_SIZE;
486                         break;
487                 case V8PDU_TOSPROTOPORT_METHOD:
488                         pdusize = V8PDU_TOSPROTOPORT_SIZE;
489                         break;
490                 case V8PDU_TOSSRCPREFIX_METHOD:
491                         pdusize = V8PDU_TOSSRCPREFIX_SIZE;
492                         break;
493                 case V8PDU_TOSDSTPREFIX_METHOD:
494                         pdusize = V8PDU_TOSDSTPREFIX_SIZE;
495                         break;
496                 case V8PDU_TOSMATRIX_METHOD:
497                         pdusize = V8PDU_TOSMATRIX_SIZE;
498                         break;
499                 case V8PDU_PREPORTPROTOCOL_METHOD:
500                         pdusize = V8PDU_PREPORTPROTOCOL_SIZE;
501                         break;
502                 default:
503                         pdusize = -1;
504                         vspec = 0;
505                         break;
506                 }
507                 proto_tree_add_uint(netflow_tree, hf_cflow_aggmethod,
508                                     tvb, offset++, 1, vspec);
509                 proto_tree_add_item(netflow_tree, hf_cflow_aggversion,
510                                     tvb, offset++, 1, FALSE);
511         }
512         if (ver == 7 || ver == 8)
513                 offset = flow_process_textfield(netflow_tree, tvb, offset, 4,
514                                                 "reserved");
515         else if (ver == 5) {
516                 proto_tree_add_item(netflow_tree, hf_cflow_samplingmode,
517                                     tvb, offset, 2, FALSE);
518                 proto_tree_add_item(netflow_tree, hf_cflow_samplerate,
519                                     tvb, offset, 2, FALSE);
520                 offset += 2;
521         }
522
523         /*
524          * everything below here should be payload 
525          */
526         for (x = 1; x < pdus + 1; x++) {
527                 /*
528                  * make sure we have a pdu's worth of data 
529                  */
530                 available = tvb_length_remaining(tvb, offset);
531                 if (ver == 9 && available >= 4) {
532                         /* pdusize can be different for each v9 flowset */
533                         pdusize = tvb_get_ntohs(tvb, offset + 2);
534                 }
535
536                 if (available < pdusize)
537                         break;
538
539                 if (ver == 9) {
540                         pduitem = proto_tree_add_text(netflow_tree, tvb,
541                             offset, pdusize, "FlowSet %u", x);
542                 } else {
543                         pduitem = proto_tree_add_text(netflow_tree, tvb,
544                             offset, pdusize, "pdu %u/%u", x, pdus);
545                 }
546                 pdutree = proto_item_add_subtree(pduitem, ett_flow);
547
548                 pduret = pduptr(pdutree, tvb, offset, vspec);
549
550                 if (pduret < pdusize) pduret = pdusize; /* padding */
551
552                 /*
553                  * if we came up short, stop processing 
554                  */
555                 if (pduret == pdusize)
556                         offset += pduret;
557                 else
558                         break;
559         }
560 }
561
562 /*
563  * flow_process_* == common groups of fields, probably could be inline 
564  */
565
566 static int
567 flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb, int offset)
568 {
569         proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2, FALSE);
570         offset += 2;
571
572         proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
573                             FALSE);
574         offset += 2;
575
576         return offset;
577 }
578
579 static int
580 flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb, int offset)
581 {
582         proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2, FALSE);
583         offset += 2;
584
585         proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2, FALSE);
586         offset += 2;
587
588         return offset;
589 }
590
591 static int
592 flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb, int offset)
593 {
594         nstime_t        ts;
595         guint32         msec;
596
597         msec = tvb_get_ntohl(tvb, offset);
598         ts.secs = msec / 1000;
599         ts.nsecs = (msec % 1000) * 1000000;
600         proto_tree_add_time(pdutree, hf_cflow_timestart, tvb, offset, 4, &ts);
601         offset += 4;
602
603         msec = tvb_get_ntohl(tvb, offset);
604         ts.secs = msec / 1000;
605         ts.nsecs = (msec % 1000) * 1000000;
606         proto_tree_add_time(pdutree, hf_cflow_timeend, tvb, offset, 4, &ts);
607         offset += 4;
608
609         return offset;
610 }
611
612
613 static int
614 flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb, int offset)
615 {
616         proto_tree_add_item(pdutree, hf_cflow_srcas, tvb, offset, 2, FALSE);
617         offset += 2;
618
619         proto_tree_add_item(pdutree, hf_cflow_dstas, tvb, offset, 2, FALSE);
620         offset += 2;
621
622         return offset;
623 }
624
625 static int
626 flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb, int offset)
627 {
628         proto_tree_add_item(pdutree, hf_cflow_packets, tvb, offset, 4, FALSE);
629         offset += 4;
630
631         proto_tree_add_item(pdutree, hf_cflow_octets, tvb, offset, 4, FALSE);
632         offset += 4;
633
634         return offset;
635 }
636
637 static int
638 flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb, int offset,
639                        int bytes, const char *text)
640 {
641         proto_tree_add_text(pdutree, tvb, offset, bytes, text);
642         offset += bytes;
643
644         return offset;
645 }
646
647 static int
648 dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
649                    int verspec)
650 {
651         int             startoffset = offset;
652
653         proto_tree_add_item(pdutree, hf_cflow_dstaddr, tvb, offset, 4, FALSE);
654         offset += 4;
655
656         if (verspec != V8PDU_DESTONLY_METHOD) {
657                 proto_tree_add_item(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
658                                     FALSE);
659                 offset += 4;
660         }
661         if (verspec == V8PDU_FULL_METHOD) {
662                 proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2,
663                                     FALSE);
664                 offset += 2;
665                 proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2,
666                                     FALSE);
667                 offset += 2;
668         }
669
670         offset = flow_process_sizecount(pdutree, tvb, offset);
671         offset = flow_process_timeperiod(pdutree, tvb, offset);
672
673         proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
674                             FALSE);
675         offset += 2;
676
677         if (verspec != V8PDU_DESTONLY_METHOD) {
678                 proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2,
679                                     FALSE);
680                 offset += 2;
681         }
682
683         proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1, FALSE);
684         if (verspec == V8PDU_FULL_METHOD)
685                 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
686                                     FALSE);
687         offset = flow_process_textfield(pdutree, tvb, offset, 1, "marked tos");
688
689         if (verspec == V8PDU_SRCDEST_METHOD)
690                 offset =
691                     flow_process_textfield(pdutree, tvb, offset, 2,
692                                            "reserved");
693         else if (verspec == V8PDU_FULL_METHOD)
694                 offset =
695                     flow_process_textfield(pdutree, tvb, offset, 1, "padding");
696
697         offset =
698             flow_process_textfield(pdutree, tvb, offset, 4, "extra packets");
699
700         proto_tree_add_item(pdutree, hf_cflow_routersc, tvb, offset, 4, FALSE);
701         offset += 4;
702
703         return (offset - startoffset);
704 }
705
706 /*
707  * dissect a version 8 pdu, returning the length of the pdu processed 
708  */
709
710 static int
711 dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
712                   int verspec)
713 {
714         int             startoffset = offset;
715
716         proto_tree_add_item(pdutree, hf_cflow_flows, tvb, offset, 4, FALSE);
717         offset += 4;
718
719         offset = flow_process_sizecount(pdutree, tvb, offset);
720         offset = flow_process_timeperiod(pdutree, tvb, offset);
721
722         switch (verspec) {
723         case V8PDU_AS_METHOD:
724         case V8PDU_TOSAS_METHOD:
725                 offset = flow_process_aspair(pdutree, tvb, offset);
726
727                 if (verspec == V8PDU_TOSAS_METHOD) {
728                         proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
729                                             offset++, 1, FALSE);
730                         offset =
731                             flow_process_textfield(pdutree, tvb, offset, 1,
732                                                    "padding");
733                         offset =
734                             flow_process_textfield(pdutree, tvb, offset, 2,
735                                                    "reserved");
736                 }
737                 break;
738         case V8PDU_PROTO_METHOD:
739         case V8PDU_TOSPROTOPORT_METHOD:
740                 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
741                                     FALSE);
742
743                 if (verspec == V8PDU_PROTO_METHOD)
744                         offset =
745                             flow_process_textfield(pdutree, tvb, offset, 1,
746                                                    "padding");
747                 else if (verspec == V8PDU_TOSPROTOPORT_METHOD)
748                         proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
749                                             offset++, 1, FALSE);
750
751                 offset =
752                     flow_process_textfield(pdutree, tvb, offset, 2,
753                                            "reserved");
754                 offset = flow_process_ports(pdutree, tvb, offset);
755
756                 if (verspec == V8PDU_TOSPROTOPORT_METHOD)
757                         offset = flow_process_ints(pdutree, tvb, offset);
758                 break;
759         case V8PDU_SPREFIX_METHOD:
760         case V8PDU_DPREFIX_METHOD:
761         case V8PDU_TOSSRCPREFIX_METHOD:
762         case V8PDU_TOSDSTPREFIX_METHOD:
763                 proto_tree_add_item(pdutree,
764                                     verspec ==
765                                     V8PDU_SPREFIX_METHOD ?
766                                     hf_cflow_srcnet : hf_cflow_dstnet, tvb,
767                                     offset, 4, FALSE);
768                 offset += 4;
769
770                 proto_tree_add_item(pdutree,
771                                     verspec ==
772                                     V8PDU_SPREFIX_METHOD ?
773                                     hf_cflow_srcmask : hf_cflow_dstmask, tvb,
774                                     offset++, 1, FALSE);
775
776                 if (verspec == V8PDU_SPREFIX_METHOD
777                     || verspec == V8PDU_DPREFIX_METHOD)
778                         offset =
779                             flow_process_textfield(pdutree, tvb, offset, 1,
780                                                    "padding");
781                 else if (verspec == V8PDU_TOSSRCPREFIX_METHOD
782                          || verspec == V8PDU_TOSDSTPREFIX_METHOD)
783                         proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
784                                             offset++, 1, FALSE);
785
786                 proto_tree_add_item(pdutree,
787                                     verspec ==
788                                     V8PDU_SPREFIX_METHOD ? hf_cflow_srcas
789                                     : hf_cflow_dstas, tvb, offset, 2, FALSE);
790                 offset += 2;
791
792                 proto_tree_add_item(pdutree,
793                                     verspec ==
794                                     V8PDU_SPREFIX_METHOD ?
795                                     hf_cflow_inputint : hf_cflow_outputint,
796                                     tvb, offset, 2, FALSE);
797                 offset += 2;
798
799                 offset =
800                     flow_process_textfield(pdutree, tvb, offset, 2,
801                                            "reserved");
802                 break;
803         case V8PDU_MATRIX_METHOD:
804         case V8PDU_TOSMATRIX_METHOD:
805         case V8PDU_PREPORTPROTOCOL_METHOD:
806                 proto_tree_add_item(pdutree, hf_cflow_srcnet, tvb, offset, 4,
807                                     FALSE);
808                 offset += 4;
809
810                 proto_tree_add_item(pdutree, hf_cflow_dstnet, tvb, offset, 4,
811                                     FALSE);
812                 offset += 4;
813
814                 proto_tree_add_item(pdutree, hf_cflow_srcmask, tvb, offset++,
815                                     1, FALSE);
816
817                 proto_tree_add_item(pdutree, hf_cflow_dstmask, tvb, offset++,
818                                     1, FALSE);
819
820                 if (verspec == V8PDU_TOSMATRIX_METHOD ||
821                     verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
822                         proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
823                                             offset++, 1, FALSE);
824                         if (verspec == V8PDU_TOSMATRIX_METHOD) {
825                                 offset =
826                                     flow_process_textfield(pdutree, tvb,
827                                                            offset, 1,
828                                                            "padding");
829                         } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
830                                 proto_tree_add_item(pdutree, hf_cflow_prot,
831                                                     tvb, offset++, 1, FALSE);
832                         }
833                 } else {
834                         offset =
835                             flow_process_textfield(pdutree, tvb, offset, 2,
836                                                    "reserved");
837                 }
838
839                 if (verspec == V8PDU_MATRIX_METHOD
840                     || verspec == V8PDU_TOSMATRIX_METHOD) {
841                         offset = flow_process_aspair(pdutree, tvb, offset);
842                 } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
843                         offset = flow_process_ports(pdutree, tvb, offset);
844                 }
845
846                 offset = flow_process_ints(pdutree, tvb, offset);
847                 break;
848         }
849
850
851         return (offset - startoffset);
852 }
853
854 /* Dissect a version 9 FlowSet and return the length we processed. */
855
856 static int
857 dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb, int offset, int ver)
858 {
859         int length;
860         guint16 flowset_id;
861
862         if (ver != 9)
863                 return (0);
864
865         flowset_id = tvb_get_ntohs(tvb, offset);
866         if (flowset_id == 0) {
867                 /* Template */
868                 proto_tree_add_item(pdutree, hf_cflow_template_flowset_id, tvb,
869                     offset, 2, FALSE);
870                 offset += 2;
871
872                 length = tvb_get_ntohs(tvb, offset);
873                 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
874                     offset, 2, FALSE);
875                 offset += 2;
876
877                 dissect_v9_template(pdutree, tvb, offset, length - 4);
878         } else if (flowset_id == 1) {
879                 /* Options */
880                 proto_tree_add_item(pdutree, hf_cflow_options_flowset_id, tvb,
881                     offset, 2, FALSE);
882                 offset += 2;
883
884                 length = tvb_get_ntohs(tvb, offset);
885                 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
886                     offset, 2, FALSE);
887                 offset += 2;
888
889                 dissect_v9_options(pdutree, tvb, offset);
890         } else if (flowset_id >= 2 && flowset_id <= 255) {
891                 /* Reserved */
892                 proto_tree_add_item(pdutree, hf_cflow_flowset_id, tvb,
893                     offset, 2, FALSE);
894                 offset += 2;
895
896                 length = tvb_get_ntohs(tvb, offset);
897                 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
898                     offset, 2, FALSE);
899                 offset += 2;
900         } else {
901                 /* Data */
902                 proto_tree_add_item(pdutree, hf_cflow_data_flowset_id, tvb,
903                     offset, 2, FALSE);
904                 offset += 2;
905
906                 length = tvb_get_ntohs(tvb, offset);
907                 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
908                     offset, 2, FALSE);
909                 offset += 2;
910
911                 /*
912                  * The length includes the length of the FlowSet ID and
913                  * the length field itself.
914                  */
915                 length -= 4;
916                 if (length > 0) {
917                         dissect_v9_data(pdutree, tvb, offset, flowset_id,
918                             (guint)length);
919                 }
920         }
921
922         return (length);
923 }
924
925 static int
926 dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb, int offset,
927     guint16 id, guint length)
928 {
929         struct v9_template *template;
930         proto_tree *data_tree;
931         proto_item *data_item;
932
933         template = v9_template_get(id, 0, 0);
934         if (template != NULL && template->length != 0) {
935                 int count;
936
937                 count = 1;
938                 while (length >= template->length) {
939                         data_item = proto_tree_add_text(pdutree, tvb,
940                             offset, template->length, "pdu %d", count++);
941                         data_tree = proto_item_add_subtree(data_item,
942                             ett_dataflowset);
943
944                         dissect_v9_pdu(data_tree, tvb, offset, template);
945
946                         offset += template->length;
947                         length -= template->length;
948                 }
949                 if (length != 0) {
950                         proto_tree_add_text(pdutree, tvb, offset, length,
951                             "Padding (%u byte%s)",
952                             length, plurality(length, "", "s"));
953                 }
954         } else {
955                 proto_tree_add_text(pdutree, tvb, offset, length,
956                     "Data (%u byte%s), no template found",
957                     length, plurality(length, "", "s"));
958         }
959
960         return (0);
961 }
962
963 static void
964 dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
965     struct v9_template * template)
966 {
967         int i;
968
969         for (i = 0; i < template->count; i++) {
970                 guint16 type, length;
971                 nstime_t ts;
972                 guint32 msec;
973
974                 type = template->entries[i].type;
975                 length = template->entries[i].length;
976
977                 switch (type) {
978                 case 1: /* bytes */
979                         if (length == 4) {
980                                 proto_tree_add_item(pdutree, hf_cflow_octets,
981                                     tvb, offset, length, FALSE);
982                         } else if (length == 8) {
983                                 proto_tree_add_item(pdutree, hf_cflow_octets64,
984                                     tvb, offset, length, FALSE);
985                         } else {
986                                 proto_tree_add_text(pdutree,
987                                     tvb, offset, length,
988                                     "Octets: length %u", length);
989                         }
990                   break;
991
992                 case 2: /* packets */
993                         if (length == 4) {
994                                 proto_tree_add_item(pdutree, hf_cflow_packets,
995                                     tvb, offset, length, FALSE);
996                         } else if (length == 8) {
997                                 proto_tree_add_item(pdutree, hf_cflow_packets64,
998                                     tvb, offset, length, FALSE);
999                         } else {
1000                                 proto_tree_add_text(pdutree,
1001                                     tvb, offset, length,
1002                                     "Packets: length %u", length);
1003                         }
1004                         break;
1005
1006                 case 3: /* flows */
1007                         if (length == 4) {
1008                                 proto_tree_add_item(pdutree, hf_cflow_flows,
1009                                     tvb, offset, length, FALSE);
1010                         } else {
1011                                 proto_tree_add_text(pdutree,
1012                                     tvb, offset, length,
1013                                     "Flows: length %u", length);
1014                         }
1015                         break;
1016
1017                 case 4: /* proto */
1018                         proto_tree_add_item(pdutree, hf_cflow_prot,
1019                             tvb, offset, length, FALSE);
1020                         break;
1021
1022                 case 5: /* TOS */
1023                         proto_tree_add_item(pdutree, hf_cflow_tos,
1024                             tvb, offset, length, FALSE);
1025                         break;
1026
1027                 case 6: /* TCP flags */
1028                         proto_tree_add_item(pdutree, hf_cflow_tcpflags,
1029                             tvb, offset, length, FALSE);
1030                         break;
1031
1032                 case 7: /* source port */
1033                         proto_tree_add_item(pdutree, hf_cflow_srcport,
1034                             tvb, offset, length, FALSE);
1035                         break;
1036
1037                 case 8: /* source IP */
1038                         if (length == 4) {
1039                                 proto_tree_add_item(pdutree, hf_cflow_srcaddr,
1040                                     tvb, offset, length, FALSE);
1041                         } else if (length == 16) {
1042                                 proto_tree_add_item(pdutree, hf_cflow_srcaddr_v6,
1043                                     tvb, offset, length, FALSE);
1044                         } else {
1045                                 proto_tree_add_text(pdutree,
1046                                     tvb, offset, length,
1047                                     "SrcAddr: length %u", length);
1048                         }
1049                         break;
1050
1051                 case 9: /* source mask */
1052                         proto_tree_add_item(pdutree, hf_cflow_srcmask,
1053                             tvb, offset, length, FALSE);
1054                         break;
1055
1056                 case 10: /* input SNMP */
1057                         proto_tree_add_item(pdutree, hf_cflow_inputint,
1058                             tvb, offset, length, FALSE);
1059                         break;
1060
1061                 case 11: /* dest port */
1062                         proto_tree_add_item(pdutree, hf_cflow_dstport,
1063                             tvb, offset, length, FALSE);
1064                         break;
1065
1066                 case 12: /* dest IP */
1067                         if (length == 4) {
1068                                 proto_tree_add_item(pdutree, hf_cflow_dstaddr,
1069                                     tvb, offset, length, FALSE);
1070                         } else if (length == 16) {
1071                                 proto_tree_add_item(pdutree, hf_cflow_dstaddr_v6,
1072                                     tvb, offset, length, FALSE);
1073                         } else {
1074                                 proto_tree_add_text(pdutree,
1075                                     tvb, offset, length,
1076                                     "DstAddr: length %u", length);
1077                         }
1078                         break;
1079
1080                 case 13: /* dest mask */
1081                         proto_tree_add_item(pdutree, hf_cflow_dstmask,
1082                             tvb, offset, length, FALSE);
1083                         break;
1084
1085                 case 14: /* output SNMP */
1086                         proto_tree_add_item(pdutree, hf_cflow_outputint,
1087                             tvb, offset, length, FALSE);
1088                         break;
1089
1090                 case 15: /* nexthop IP */
1091                         if (length == 4) {
1092                                 proto_tree_add_item(pdutree, hf_cflow_nexthop,
1093                                     tvb, offset, length, FALSE);
1094                         } else if (length == 16) {
1095                                 proto_tree_add_item(pdutree, hf_cflow_nexthop_v6,
1096                                     tvb, offset, length, FALSE);
1097                         } else {
1098                                 proto_tree_add_text(pdutree,
1099                                     tvb, offset, length,
1100                                     "NextHop: length %u", length);
1101                         }
1102                         break;
1103
1104                 case 16: /* source AS */
1105                         proto_tree_add_item(pdutree, hf_cflow_srcas,
1106                             tvb, offset, length, FALSE);
1107                         break;
1108
1109                 case 17: /* dest AS */
1110                         proto_tree_add_item(pdutree, hf_cflow_dstas,
1111                             tvb, offset, length, FALSE);
1112                         break;
1113
1114                 case 18: /* BGP nexthop IP */
1115                         if (length == 4) {
1116                                 proto_tree_add_item(pdutree, hf_cflow_bgpnexthop,
1117                                     tvb, offset, length, FALSE);
1118                         } else if (length == 16) {
1119                                 proto_tree_add_item(pdutree, hf_cflow_bgpnexthop_v6,
1120                                     tvb, offset, length, FALSE);
1121                         } else {
1122                                 proto_tree_add_text(pdutree,
1123                                     tvb, offset, length,
1124                                     "BGPNextHop: length %u", length);
1125                         }
1126                         break;
1127
1128                 case 19: /* multicast packets */
1129                         proto_tree_add_item(pdutree, hf_cflow_mulpackets,
1130                             tvb, offset, length, FALSE);
1131                         break;
1132
1133                 case 20: /* multicast octets */
1134                         proto_tree_add_item(pdutree, hf_cflow_muloctets,
1135                             tvb, offset, length, FALSE);
1136                         break;
1137
1138                 case 21: /* last switched */
1139                         msec = tvb_get_ntohl(tvb, offset);
1140                         ts.secs = msec / 1000;
1141                         ts.nsecs = (msec % 1000) * 1000000;
1142                         proto_tree_add_time(pdutree, hf_cflow_timeend,
1143                             tvb, offset, length, &ts);
1144                         break;
1145
1146                 case 22: /* first switched */
1147                         msec = tvb_get_ntohl(tvb, offset);
1148                         ts.secs = msec / 1000;
1149                         ts.nsecs = (msec % 1000) * 1000000;
1150                         proto_tree_add_time(pdutree, hf_cflow_timestart,
1151                             tvb, offset, length, &ts);
1152                         break;
1153                         
1154                 case 34: /* sampling interval */
1155                   proto_tree_add_item(pdutree, hf_cflow_sampling_interval,
1156                                       tvb, offset, length, FALSE);
1157                   break;
1158
1159                 case 35: /* sampling algorithm */
1160                   proto_tree_add_item(pdutree, hf_cflow_sampling_algorithm,
1161                                       tvb, offset, length, FALSE);
1162                   break;
1163
1164                 case 36: /* flow active timeout */
1165                    proto_tree_add_item(pdutree, hf_cflow_flow_active_timeout,
1166                                       tvb, offset, length, FALSE);
1167                   break;
1168
1169                 case 37: /* flow inactive timeout */
1170                    proto_tree_add_item(pdutree, hf_cflow_flow_inactive_timeout,
1171                                       tvb, offset, length, FALSE);
1172                   break;
1173
1174                 case 40: /* bytes exported */
1175                         proto_tree_add_item(pdutree, hf_cflow_octets_exp,
1176                             tvb, offset, length, FALSE);
1177                         break;
1178
1179                 case 41: /* packets exported */
1180                         proto_tree_add_item(pdutree, hf_cflow_packets_exp,
1181                             tvb, offset, length, FALSE);
1182                         break;
1183
1184                 case 42: /* flows exported */
1185                         proto_tree_add_item(pdutree, hf_cflow_flows_exp,
1186                             tvb, offset, length, FALSE);
1187                         break;
1188
1189                 case 46: /* top MPLS label type*/ 
1190                         proto_tree_add_item(pdutree, hf_cflow_mpls_top_label_type,
1191                             tvb, offset, length, FALSE);
1192                         break;
1193                 case 47: /* top MPLS label PE address*/ 
1194                         proto_tree_add_item(pdutree, hf_cflow_mpls_pe_addr,
1195                             tvb, offset, length, FALSE);
1196                         break;
1197                 case 70: /* MPLS label1*/ 
1198                         proto_tree_add_mpls_label(pdutree, tvb, offset, length, 1);
1199                         break;
1200                 case 71: /* MPLS label2*/ 
1201                         proto_tree_add_mpls_label(pdutree, tvb, offset, length, 2);
1202                         break;
1203                 case 72: /* MPLS label3*/ 
1204                         proto_tree_add_mpls_label(pdutree, tvb, offset, length, 3);
1205                         break;
1206                 case 73: /* MPLS label4*/ 
1207                         proto_tree_add_mpls_label(pdutree, tvb, offset, length, 4);
1208                         break;
1209                 default:
1210                         proto_tree_add_text(pdutree, tvb, offset, length,
1211                             "Type %u", type);
1212                         break;
1213                 }
1214
1215                 offset += length;
1216         }
1217 }
1218
1219 static int
1220 dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb, int offset)
1221 {
1222   guint16 length, option_scope_len, option_len, i, id, size;
1223   struct v9_template template;
1224   int template_offset;
1225
1226   id = tvb_get_ntohs(tvb, offset);
1227   proto_tree_add_item(pdutree, hf_cflow_template_id, tvb,
1228                       offset, 2, FALSE);
1229   offset += 2;
1230
1231   option_scope_len = length = tvb_get_ntohs(tvb, offset);
1232   proto_tree_add_item(pdutree, hf_cflow_option_scope_length, tvb,
1233                       offset, 2, FALSE);
1234   offset += 2;
1235
1236   option_len = length = tvb_get_ntohs(tvb, offset);
1237   proto_tree_add_item(pdutree, hf_cflow_option_length, tvb,
1238                       offset, 2, FALSE);
1239   offset += 2;
1240
1241   for(i=0; i<option_scope_len; i++) {
1242     length = tvb_get_ntohs(tvb, offset);
1243     proto_tree_add_item(pdutree, hf_cflow_template_scope_field_type, tvb,
1244                         offset, 2, FALSE);
1245     offset += 2; i += 2;
1246
1247     length = tvb_get_ntohs(tvb, offset);
1248     proto_tree_add_item(pdutree, hf_cflow_template_scope_field_length, tvb,
1249                         offset, 2, FALSE);
1250     offset += 2; i += 2;
1251   }
1252
1253   template_offset = offset;
1254
1255   for(i=0; i<option_len;) {
1256     length = tvb_get_ntohs(tvb, offset);
1257     proto_tree_add_item(pdutree, hf_cflow_template_field_type, tvb,
1258                         offset, 2, FALSE);
1259     offset += 2; i += 2;
1260
1261     length = tvb_get_ntohs(tvb, offset);
1262     proto_tree_add_item(pdutree, hf_cflow_template_field_length, tvb,
1263                         offset, 2, FALSE);
1264     offset += 2; i += 2;
1265   }
1266
1267   /* Cache template */
1268   memset(&template, 0, sizeof(template));
1269   template.id = id;
1270   template.count = option_len/4;
1271   template.source_addr = 0;     /* XXX */
1272   template.source_id = 0;       /* XXX */
1273   template.option_template = 1; /* Option template */
1274   size = template.count * sizeof(struct v9_template_entry);
1275   template.entries = g_malloc(size);
1276   tvb_memcpy(tvb, (guint8 *)template.entries, template_offset, size);
1277
1278   v9_template_add(&template);
1279   
1280   return (0);
1281 }
1282
1283 static int
1284 dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb, int offset, int len)
1285 {
1286         struct v9_template template;
1287         proto_tree *template_tree;
1288         proto_item *template_item;
1289         proto_tree *field_tree;
1290         proto_item *field_item;
1291         guint16 id, count;
1292         int remaining = len;
1293         gint32 i;
1294
1295         while (remaining > 0) {
1296
1297           id = tvb_get_ntohs(tvb, offset);
1298           count = tvb_get_ntohs(tvb, offset + 2);
1299
1300           template_item = proto_tree_add_text(pdutree, tvb, offset, 
1301               4 + sizeof(struct v9_template_entry) * count, 
1302               "Template (Id = %u, Count = %u)", id, count);
1303           template_tree = proto_item_add_subtree(template_item, ett_template);
1304
1305           proto_tree_add_item(template_tree, hf_cflow_template_id, tvb,
1306               offset, 2, FALSE);
1307           offset += 2;
1308
1309           proto_tree_add_item(template_tree, hf_cflow_template_field_count, 
1310               tvb, offset, 2, FALSE);
1311           offset += 2;
1312
1313           /* Cache template */
1314           memset(&template, 0, sizeof(template));
1315           template.id = id;
1316           template.count = count;
1317           template.source_addr = 0;     /* XXX */
1318           template.source_id = 0;               /* XXX */
1319           template.option_template = 0;   /* Data template */
1320           template.entries = g_malloc(count * sizeof(struct v9_template_entry));
1321           tvb_memcpy(tvb, (guint8 *)template.entries, offset,
1322               count * sizeof(struct v9_template_entry));
1323           v9_template_add(&template);
1324
1325           for (i = 1; i <= count; i++) {
1326             guint16 type, length;
1327
1328             type = tvb_get_ntohs(tvb, offset);
1329             length = tvb_get_ntohs(tvb, offset + 2);
1330
1331             field_item = proto_tree_add_text(template_tree, tvb,
1332                 offset, 4, "Field (%u/%u)", i, count);
1333             field_tree = proto_item_add_subtree(field_item, ett_field);
1334
1335             proto_tree_add_item(field_tree,
1336                 hf_cflow_template_field_type, tvb, offset, 2, FALSE);
1337             offset += 2;
1338
1339             proto_tree_add_item(field_tree,
1340                 hf_cflow_template_field_length, tvb, offset, 2, FALSE);
1341             offset += 2;
1342           }
1343           remaining -= 4 + sizeof(struct v9_template_entry) * count;
1344         }
1345
1346         return (0);
1347 }
1348
1349 static value_string v9_template_types[] = {
1350         { 1, "BYTES" },
1351         { 2, "PKTS" },
1352         { 3, "FLOWS" },
1353         { 4, "PROT" },
1354         { 5, "TOS" },
1355         { 6, "TCP_FLAGS" },
1356         { 7, "L4_SRC_PORT" },
1357         { 8, "IP_SRC_ADDR" },
1358         { 9, "SRC_MASK" },
1359         { 10, "INPUT_SNMP" },
1360         { 11, "L4_DST_PORT" },
1361         { 12, "IP_DST_ADDR" },
1362         { 13, "DST_MASK" },
1363         { 14, "OUTPUT_SNMP" },
1364         { 15, "IP_NEXT_HOP" },
1365         { 16, "SRC_AS" },
1366         { 17, "DST_AS" },
1367         { 18, "BGP_NEXT_HOP" },
1368         { 19, "MUL_DPKTS" },
1369         { 20, "MUL_DOCTETS" },
1370         { 21, "LAST_SWITCHED" },
1371         { 22, "FIRST_SWITCHED" },
1372         { 23, "OUT_BYTES" },
1373         { 24, "OUT_PKTS" },
1374         { 27, "IPV6_SRC_ADDR" },
1375         { 28, "IPV6_DST_ADDR" },
1376         { 29, "IPV6_SRC_MASK" },
1377         { 30, "IPV6_DST_MASK" },
1378         { 31, "FLOW_LABEL" },
1379         { 32, "ICMP_TYPE" },
1380         { 33, "IGMP_TYPE" },
1381         { 34, "SAMPLING_INTERVAL" },
1382         { 35, "SAMPLING_ALGORITHM" },
1383         { 36, "FLOW_ACTIVE_TIMEOUT" },
1384         { 37, "FLOW_INACTIVE_TIMEOUT" },
1385         { 38, "ENGINE_TYPE" },
1386         { 39, "ENGINE_ID" },
1387         { 40, "TOTAL_BYTES_EXP" },
1388         { 41, "TOTAL_PKTS_EXP" },
1389         { 42, "TOTAL_FLOWS_EXP" },
1390         { 46, "MPLS_TOP_LABEL_TYPE" },
1391         { 47, "MPLS_TOP_LABEL_ADDR" },
1392         { 48, "FLOW_SAMPLER_ID" },
1393         { 49, "FLOW_SAMPLER_MODE" },
1394         { 50, "FLOW_SAMPLER_RANDOM_INTERVAL" },
1395         { 55, "DST_TOS" },
1396         { 56, "SRC_MAC" },
1397         { 57, "DST_MAC" },
1398         { 58, "SRC_VLAN" },
1399         { 59, "DST_VLAN" },
1400         { 60, "IP_PROTOCOL_VERSION" },
1401         { 61, "DIRECTION" },
1402         { 62, "IPV6_NEXT_HOP" },
1403         { 63, "BPG_IPV6_NEXT_HOP" },
1404         { 64, "IPV6_OPTION_HEADERS" },
1405         { 70, "MPLS_LABEL_1" },
1406         { 71, "MPLS_LABEL_2" },
1407         { 72, "MPLS_LABEL_3" },
1408         { 73, "MPLS_LABEL_4" },
1409         { 74, "MPLS_LABEL_5" },
1410         { 75, "MPLS_LABEL_6" },
1411         { 76, "MPLS_LABEL_7" },
1412         { 77, "MPLS_LABEL_8" },
1413         { 78, "MPLS_LABEL_9" },
1414         { 79, "MPLS_LABEL_10" },
1415         { 0, NULL },
1416 };
1417
1418 static value_string v9_scope_field_types[] = {
1419         { 1, "System" },
1420         { 2, "Interface" },
1421         { 3, "Line Card" },
1422         { 4, "NetFlow Cache" },
1423         { 5, "Template" },
1424         { 0, NULL },
1425 };
1426
1427 static void
1428 v9_template_add(struct v9_template *template)
1429 {
1430         int i;
1431
1432         /* Add up the actual length of the data and store in proper byte order */
1433         template->length = 0;
1434         for (i = 0; i < template->count; i++) {
1435                 template->entries[i].type = g_ntohs(template->entries[i].type);
1436                 template->entries[i].length = g_ntohs(template->entries[i].length);
1437                 template->length += template->entries[i].length;
1438         }
1439
1440         memmove(&v9_template_cache[template->id % V9TEMPLATE_CACHE_MAX_ENTRIES],
1441             template, sizeof(*template));
1442 }
1443
1444 static struct v9_template *
1445 v9_template_get(guint16 id, guint32 src_addr, guint32 src_id)
1446 {
1447         struct v9_template *template;
1448
1449         src_addr = 0;
1450         template = &v9_template_cache[id % V9TEMPLATE_CACHE_MAX_ENTRIES];
1451
1452         if (template->id != id ||
1453             template->source_addr != src_addr ||
1454             template->source_id != src_id) {
1455                 template = NULL;
1456         }
1457
1458         return (template);
1459 }
1460
1461 /*
1462  * dissect a version 1, 5, or 7 pdu and return the length of the pdu we
1463  * processed
1464  */
1465
1466 static int
1467 dissect_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset, int ver)
1468 {
1469         int             startoffset = offset;
1470         guint32         srcaddr, dstaddr;
1471         guint8          mask;
1472         nstime_t        ts;
1473
1474         memset(&ts, '\0', sizeof(ts));
1475
1476         /*
1477          * memcpy so we can use the values later to calculate a prefix 
1478          */
1479         srcaddr = tvb_get_ipv4(tvb, offset);
1480         proto_tree_add_ipv4(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
1481                             srcaddr);
1482         offset += 4;
1483
1484         dstaddr = tvb_get_ipv4(tvb, offset);
1485         proto_tree_add_ipv4(pdutree, hf_cflow_dstaddr, tvb, offset, 4,
1486                             dstaddr);
1487         offset += 4;
1488
1489         proto_tree_add_item(pdutree, hf_cflow_nexthop, tvb, offset, 4, FALSE);
1490         offset += 4;
1491
1492         offset = flow_process_ints(pdutree, tvb, offset);
1493         offset = flow_process_sizecount(pdutree, tvb, offset);
1494         offset = flow_process_timeperiod(pdutree, tvb, offset);
1495         offset = flow_process_ports(pdutree, tvb, offset);
1496
1497         /*
1498          * and the similarities end here 
1499          */
1500         if (ver == 1) {
1501                 offset =
1502                     flow_process_textfield(pdutree, tvb, offset, 2, "padding");
1503
1504                 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
1505                                     FALSE);
1506
1507                 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
1508                                     FALSE);
1509
1510                 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
1511                                     1, FALSE);
1512
1513                 offset =
1514                     flow_process_textfield(pdutree, tvb, offset, 3, "padding");
1515
1516                 offset =
1517                     flow_process_textfield(pdutree, tvb, offset, 4,
1518                                            "reserved");
1519         } else {
1520                 if (ver == 5)
1521                         offset =
1522                             flow_process_textfield(pdutree, tvb, offset, 1,
1523                                                    "padding");
1524                 else {
1525                         proto_tree_add_item(pdutree, hf_cflow_flags, tvb,
1526                                             offset++, 1, FALSE);
1527                 }
1528
1529                 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
1530                                     1, FALSE);
1531
1532                 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
1533                                     FALSE);
1534
1535                 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
1536                                     FALSE);
1537
1538                 offset = flow_process_aspair(pdutree, tvb, offset);
1539
1540                 mask = tvb_get_guint8(tvb, offset);
1541                 proto_tree_add_text(pdutree, tvb, offset, 1,
1542                                     "SrcMask: %u (prefix: %s/%u)",
1543                                     mask, getprefix(&srcaddr, mask),
1544                                     mask != 0 ? mask : 32);
1545                 proto_tree_add_uint_hidden(pdutree, hf_cflow_srcmask, tvb,
1546                                            offset++, 1, mask);
1547
1548                 mask = tvb_get_guint8(tvb, offset);
1549                 proto_tree_add_text(pdutree, tvb, offset, 1,
1550                                     "DstMask: %u (prefix: %s/%u)",
1551                                     mask, getprefix(&dstaddr, mask),
1552                                     mask != 0 ? mask : 32);
1553                 proto_tree_add_uint_hidden(pdutree, hf_cflow_dstmask, tvb,
1554                                            offset++, 1, mask);
1555
1556                 offset =
1557                     flow_process_textfield(pdutree, tvb, offset, 2, "padding");
1558
1559                 if (ver == 7) {
1560                         proto_tree_add_item(pdutree, hf_cflow_routersc, tvb,
1561                                             offset, 4, FALSE);
1562                         offset += 4;
1563                 }
1564         }
1565
1566         return (offset - startoffset);
1567 }
1568
1569 static gchar   *
1570 getprefix(const guint32 * address, int prefix)
1571 {
1572         guint32         gprefix;
1573
1574         gprefix = *address & g_htonl((0xffffffff << (32 - prefix)));
1575
1576         return (ip_to_str((const guint8 *)&gprefix));
1577 }
1578
1579
1580 static void
1581 netflow_reinit(void)
1582 {
1583         int i;
1584
1585         /*
1586          * Clear out the template cache.
1587          * Free the table of fields for each entry, and then zero out
1588          * the cache.
1589          */
1590         for (i = 0; i < V9TEMPLATE_CACHE_MAX_ENTRIES; i++)
1591                 g_free(v9_template_cache[i].entries);
1592         memset(v9_template_cache, 0, sizeof v9_template_cache);
1593 }
1594
1595 void
1596 proto_register_netflow(void)
1597 {
1598         static hf_register_info hf[] = {
1599                 /*
1600                  * flow header 
1601                  */
1602                 {&hf_cflow_version,
1603                  {"Version", "cflow.version",
1604                   FT_UINT16, BASE_DEC, NULL, 0x0,
1605                   "NetFlow Version", HFILL}
1606                  },
1607                 {&hf_cflow_count,
1608                  {"Count", "cflow.count",
1609                   FT_UINT16, BASE_DEC, NULL, 0x0,
1610                   "Count of PDUs", HFILL}
1611                  },
1612                 {&hf_cflow_sysuptime,
1613                  {"SysUptime", "cflow.sysuptime",
1614                   FT_UINT32, BASE_DEC, NULL, 0x0,
1615                   "Time since router booted (in milliseconds)", HFILL}
1616                  },
1617
1618                 {&hf_cflow_timestamp,
1619                  {"Timestamp", "cflow.timestamp",
1620                   FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1621                   "Current seconds since epoch", HFILL}
1622                  },
1623                 {&hf_cflow_unix_secs,
1624                  {"CurrentSecs", "cflow.unix_secs",
1625                   FT_UINT32, BASE_DEC, NULL, 0x0,
1626                   "Current seconds since epoch", HFILL}
1627                  },
1628                 {&hf_cflow_unix_nsecs,
1629                  {"CurrentNSecs", "cflow.unix_nsecs",
1630                   FT_UINT32, BASE_DEC, NULL, 0x0,
1631                   "Residual nanoseconds since epoch", HFILL}
1632                  },
1633                 {&hf_cflow_samplingmode,
1634                  {"SamplingMode", "cflow.samplingmode",
1635                   FT_UINT16, BASE_DEC, VALS(v5_sampling_mode), 0xC000,
1636                   "Sampling Mode of exporter", HFILL}
1637                  },
1638                 {&hf_cflow_samplerate,
1639                  {"SampleRate", "cflow.samplerate",
1640                   FT_UINT16, BASE_DEC, NULL, 0x3FFF,
1641                   "Sample Frequency of exporter", HFILL}
1642                  },
1643
1644                 /*
1645                  * end version-agnostic header
1646                  * version-specific flow header 
1647                  */
1648                 {&hf_cflow_sequence,
1649                  {"FlowSequence", "cflow.sequence",
1650                   FT_UINT32, BASE_DEC, NULL, 0x0,
1651                   "Sequence number of flows seen", HFILL}
1652                  },
1653                 {&hf_cflow_engine_type,
1654                  {"EngineType", "cflow.engine_type",
1655                   FT_UINT8, BASE_DEC, NULL, 0x0,
1656                   "Flow switching engine type", HFILL}
1657                  },
1658                 {&hf_cflow_engine_id,
1659                  {"EngineId", "cflow.engine_id",
1660                   FT_UINT8, BASE_DEC, NULL, 0x0,
1661                   "Slot number of switching engine", HFILL}
1662                  },
1663                 {&hf_cflow_source_id,
1664                  {"SourceId", "cflow.source_id",
1665                   FT_UINT32, BASE_DEC, NULL, 0x0,
1666                   "Identifier for export device", HFILL}
1667                  },
1668                 {&hf_cflow_aggmethod,
1669                  {"AggMethod", "cflow.aggmethod",
1670                   FT_UINT8, BASE_DEC, VALS(v8_agg), 0x0,
1671                   "CFlow V8 Aggregation Method", HFILL}
1672                  },
1673                 {&hf_cflow_aggversion,
1674                  {"AggVersion", "cflow.aggversion",
1675                   FT_UINT8, BASE_DEC, NULL, 0x0,
1676                   "CFlow V8 Aggregation Version", HFILL}
1677                  },
1678                 /*
1679                  * end version specific header storage 
1680                  */
1681                 /*
1682                  * Version 9
1683                  */
1684                 {&hf_cflow_flowset_id,
1685                  {"FlowSet Id", "cflow.flowset_id",
1686                   FT_UINT16, BASE_DEC, NULL, 0x0,
1687                   "FlowSet Id", HFILL}
1688                  },
1689                 {&hf_cflow_data_flowset_id,
1690                  {"Data FlowSet (Template Id)", "cflow.data_flowset_id",
1691                   FT_UINT16, BASE_DEC, NULL, 0x0,
1692                   "Data FlowSet with corresponding to a template Id", HFILL}
1693                  },
1694                 {&hf_cflow_options_flowset_id,
1695                  {"Options FlowSet", "cflow.options_flowset_id",
1696                   FT_UINT16, BASE_DEC, NULL, 0x0,
1697                   "Options FlowSet", HFILL}
1698                  },
1699                 {&hf_cflow_template_flowset_id,
1700                  {"Template FlowSet", "cflow.template_flowset_id",
1701                   FT_UINT16, BASE_DEC, NULL, 0x0,
1702                   "Template FlowSet", HFILL}
1703                  },
1704                 {&hf_cflow_flowset_length,
1705                  {"FlowSet Length", "cflow.flowset_length",
1706                   FT_UINT16, BASE_DEC, NULL, 0x0,
1707                   "FlowSet length", HFILL}
1708                  },
1709                 {&hf_cflow_template_id,
1710                  {"Template Id", "cflow.template_id",
1711                   FT_UINT16, BASE_DEC, NULL, 0x0,
1712                   "Template Id", HFILL}
1713                  },
1714                 {&hf_cflow_template_field_count,
1715                  {"Field Count", "cflow.template_field_count",
1716                   FT_UINT16, BASE_DEC, NULL, 0x0,
1717                   "Template field count", HFILL}
1718                  },
1719                 {&hf_cflow_template_field_type,
1720                  {"Type", "cflow.template_field_type",
1721                   FT_UINT16, BASE_DEC, VALS(v9_template_types), 0x0,
1722                   "Template field type", HFILL}
1723                  },
1724                 {&hf_cflow_template_field_length,
1725                  {"Length", "cflow.template_field_length",
1726                   FT_UINT16, BASE_DEC, NULL, 0x0,
1727                   "Template field length", HFILL}
1728                  },
1729
1730                 /* options */
1731                 {&hf_cflow_option_scope_length,
1732                  {"Option Scope Length", "cflow.option_scope_length",
1733                   FT_UINT16, BASE_DEC, NULL, 0x0,
1734                   "Option scope length", HFILL}
1735                  },
1736                 {&hf_cflow_option_length,
1737                  {"Option Length", "cflow.option_length",
1738                   FT_UINT16, BASE_DEC, NULL, 0x0,
1739                   "Option length", HFILL}
1740                  },
1741                 {&hf_cflow_template_scope_field_type,
1742                  {"Scope Type", "cflow.scope_field_type",
1743                   FT_UINT16, BASE_DEC, VALS(v9_scope_field_types), 0x0,
1744                   "Scope field type", HFILL}
1745                  },             
1746                 {&hf_cflow_template_scope_field_length,
1747                  {"Scope Field Length", "cflow.scope_field_length",
1748                   FT_UINT16, BASE_DEC, NULL, 0x0,
1749                   "Scope field length", HFILL}
1750                  },
1751                 {&hf_cflow_sampling_interval,
1752                  {"Sampling interval", "cflow.sampling_interval",
1753                   FT_UINT32, BASE_DEC, NULL, 0x0,
1754                   "Sampling interval", HFILL}
1755                 },
1756                 {&hf_cflow_sampling_algorithm,
1757                  {"Sampling algorithm", "cflow.sampling_algorithm",
1758                   FT_UINT8, BASE_DEC, NULL, 0x0,
1759                   "Sampling algorithm", HFILL}
1760                 },
1761                 {&hf_cflow_flow_active_timeout,
1762                  {"Flow active timeout", "cflow.flow_active_timeout",
1763                   FT_UINT16, BASE_DEC, NULL, 0x0,
1764                   "Flow active timeout", HFILL}
1765                 },
1766                 {&hf_cflow_flow_inactive_timeout,
1767                  {"Flow inactive timeout", "cflow.flow_inactive_timeout",
1768                   FT_UINT16, BASE_DEC, NULL, 0x0,
1769                   "Flow inactive timeout", HFILL}
1770                 },
1771
1772                 /*
1773                  * begin pdu content storage 
1774                  */
1775                 {&hf_cflow_srcaddr,
1776                  {"SrcAddr", "cflow.srcaddr",
1777                   FT_IPv4, BASE_NONE, NULL, 0x0,
1778                   "Flow Source Address", HFILL}
1779                  },
1780                 {&hf_cflow_srcaddr_v6,
1781                  {"SrcAddr", "cflow.srcaddrv6",
1782                   FT_IPv6, BASE_NONE, NULL, 0x0,
1783                   "Flow Source Address", HFILL}
1784                  },
1785                 {&hf_cflow_srcnet,
1786                  {"SrcNet", "cflow.srcnet",
1787                   FT_IPv4, BASE_NONE, NULL, 0x0,
1788                   "Flow Source Network", HFILL}
1789                  },
1790                 {&hf_cflow_dstaddr,
1791                  {"DstAddr", "cflow.dstaddr",
1792                   FT_IPv4, BASE_NONE, NULL, 0x0,
1793                   "Flow Destination Address", HFILL}
1794                  },
1795                 {&hf_cflow_dstaddr_v6,
1796                  {"DstAddr", "cflow.dstaddrv6",
1797                   FT_IPv6, BASE_NONE, NULL, 0x0,
1798                   "Flow Destination Address", HFILL}
1799                  },
1800                 {&hf_cflow_dstnet,
1801                  {"DstNet", "cflow.dstaddr",
1802                   FT_IPv4, BASE_NONE, NULL, 0x0,
1803                   "Flow Destination Network", HFILL}
1804                  },
1805                 {&hf_cflow_nexthop,
1806                  {"NextHop", "cflow.nexthop",
1807                   FT_IPv4, BASE_NONE, NULL, 0x0,
1808                   "Router nexthop", HFILL}
1809                  },
1810                 {&hf_cflow_nexthop_v6,
1811                  {"NextHop", "cflow.nexthopv6",
1812                   FT_IPv6, BASE_NONE, NULL, 0x0,
1813                   "Router nexthop", HFILL}
1814                  },
1815                 {&hf_cflow_bgpnexthop,
1816                  {"BGPNextHop", "cflow.bgpnexthop",
1817                   FT_IPv4, BASE_NONE, NULL, 0x0,
1818                   "BGP Router Nexthop", HFILL}
1819                  },
1820                 {&hf_cflow_bgpnexthop_v6,
1821                  {"BGPNextHop", "cflow.bgpnexthopv6",
1822                   FT_IPv6, BASE_NONE, NULL, 0x0,
1823                   "BGP Router Nexthop", HFILL}
1824                  },
1825                 {&hf_cflow_inputint,
1826                  {"InputInt", "cflow.inputint",
1827                   FT_UINT16, BASE_DEC, NULL, 0x0,
1828                   "Flow Input Interface", HFILL}
1829                  },
1830                 {&hf_cflow_outputint,
1831                  {"OutputInt", "cflow.outputint",
1832                   FT_UINT16, BASE_DEC, NULL, 0x0,
1833                   "Flow Output Interface", HFILL}
1834                  },
1835                 {&hf_cflow_flows,
1836                  {"Flows", "cflow.flows",
1837                   FT_UINT32, BASE_DEC, NULL, 0x0,
1838                   "Flows Aggregated in PDU", HFILL}
1839                  },
1840                 {&hf_cflow_packets,
1841                  {"Packets", "cflow.packets",
1842                   FT_UINT32, BASE_DEC, NULL, 0x0,
1843                   "Count of packets", HFILL}
1844                  },
1845                 {&hf_cflow_packets64,
1846                  {"Packets", "cflow.packets64",
1847                   FT_UINT64, BASE_DEC, NULL, 0x0,
1848                   "Count of packets", HFILL}
1849                  },
1850                 {&hf_cflow_packetsout,
1851                  {"PacketsOut", "cflow.packetsout",
1852                   FT_UINT64, BASE_DEC, NULL, 0x0,
1853                   "Count of packets going out", HFILL}
1854                  },
1855                 {&hf_cflow_octets,
1856                  {"Octets", "cflow.octets",
1857                   FT_UINT32, BASE_DEC, NULL, 0x0,
1858                   "Count of bytes", HFILL}
1859                  },
1860                 {&hf_cflow_octets64,
1861                  {"Octets", "cflow.octets64",
1862                   FT_UINT64, BASE_DEC, NULL, 0x0,
1863                   "Count of bytes", HFILL}
1864                  },
1865                 {&hf_cflow_timestart,
1866                  {"StartTime", "cflow.timestart",
1867                   FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1868                   "Uptime at start of flow", HFILL}
1869                  },
1870                 {&hf_cflow_timeend,
1871                  {"EndTime", "cflow.timeend",
1872                   FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1873                   "Uptime at end of flow", HFILL}
1874                  },
1875                 {&hf_cflow_srcport,
1876                  {"SrcPort", "cflow.srcport",
1877                   FT_UINT16, BASE_DEC, NULL, 0x0,
1878                   "Flow Source Port", HFILL}
1879                  },
1880                 {&hf_cflow_dstport,
1881                  {"DstPort", "cflow.dstport",
1882                   FT_UINT16, BASE_DEC, NULL, 0x0,
1883                   "Flow Destination Port", HFILL}
1884                  },
1885                 {&hf_cflow_prot,
1886                  {"Protocol", "cflow.protocol",
1887                   FT_UINT8, BASE_DEC, NULL, 0x0,
1888                   "IP Protocol", HFILL}
1889                  },
1890                 {&hf_cflow_tos,
1891                  {"IP ToS", "cflow.tos",
1892                   FT_UINT8, BASE_HEX, NULL, 0x0,
1893                   "IP Type of Service", HFILL}
1894                  },
1895                 {&hf_cflow_flags,
1896                  {"Export Flags", "cflow.flags",
1897                   FT_UINT8, BASE_HEX, NULL, 0x0,
1898                   "CFlow Flags", HFILL}
1899                  },
1900                 {&hf_cflow_tcpflags,
1901                  {"TCP Flags", "cflow.tcpflags",
1902                   FT_UINT8, BASE_HEX, NULL, 0x0,
1903                   "TCP Flags", HFILL}
1904                  },
1905                 {&hf_cflow_srcas,
1906                  {"SrcAS", "cflow.srcas",
1907                   FT_UINT16, BASE_DEC, NULL, 0x0,
1908                   "Source AS", HFILL}
1909                  },
1910                 {&hf_cflow_dstas,
1911                  {"DstAS", "cflow.dstas",
1912                   FT_UINT16, BASE_DEC, NULL, 0x0,
1913                   "Destination AS", HFILL}
1914                  },
1915                 {&hf_cflow_srcmask,
1916                  {"SrcMask", "cflow.srcmask",
1917                   FT_UINT8, BASE_DEC, NULL, 0x0,
1918                   "Source Prefix Mask", HFILL}
1919                  },
1920                 {&hf_cflow_dstmask,
1921                  {"DstMask", "cflow.dstmask",
1922                   FT_UINT8, BASE_DEC, NULL, 0x0,
1923                   "Destination Prefix Mask", HFILL}
1924                  },
1925                 {&hf_cflow_routersc,
1926                  {"Router Shortcut", "cflow.routersc",
1927                   FT_IPv4, BASE_NONE, NULL, 0x0,
1928                   "Router shortcut by switch", HFILL}
1929                  },
1930                 {&hf_cflow_mulpackets,
1931                  {"MulticastPackets", "cflow.mulpackets",
1932                   FT_UINT32, BASE_DEC, NULL, 0x0,
1933                   "Count of multicast packets", HFILL}
1934                  },
1935                 {&hf_cflow_muloctets,
1936                  {"MulticastOctets", "cflow.muloctets",
1937                   FT_UINT32, BASE_DEC, NULL, 0x0,
1938                   "Count of multicast octets", HFILL}
1939                  },
1940                 {&hf_cflow_octets_exp,
1941                  {"OctetsExp", "cflow.octetsexp",
1942                   FT_UINT32, BASE_DEC, NULL, 0x0,
1943                   "Octets exported", HFILL}
1944                  },
1945                 {&hf_cflow_packets_exp,
1946                  {"PacketsExp", "cflow.packetsexp",
1947                   FT_UINT32, BASE_DEC, NULL, 0x0,
1948                   "Packets exported", HFILL}
1949                  },
1950                 {&hf_cflow_mpls_top_label_type, 
1951                  {"TopLabelType", "cflow.toplabeltype",
1952                   FT_UINT8, BASE_DEC, VALS(special_mpls_top_label_type), 0x0,
1953                   "Top MPLS label Type", HFILL}
1954                  },
1955                 {&hf_cflow_mpls_pe_addr, 
1956                  {"TopLabelAddr", "cflow.toplabeladdr",
1957                   FT_IPv4, BASE_NONE, NULL, 0x0,
1958                   "Top MPLS label PE address", HFILL}
1959                  },
1960                 {&hf_cflow_flows_exp,
1961                  {"FlowsExp", "cflow.flowsexp",
1962                   FT_UINT32, BASE_DEC, NULL, 0x0,
1963                   "Flows exported", HFILL}
1964                  }
1965                 /*
1966                  * end pdu content storage 
1967                  */
1968         };
1969
1970         static gint    *ett[] = {
1971                 &ett_netflow,
1972                 &ett_unixtime,
1973                 &ett_flow,
1974                 &ett_template,
1975                 &ett_field,
1976                 &ett_dataflowset
1977         };
1978
1979         module_t *netflow_module;
1980
1981         proto_netflow = proto_register_protocol("Cisco NetFlow", "CFLOW",
1982                                                 "cflow");
1983
1984         proto_register_field_array(proto_netflow, hf, array_length(hf));
1985         proto_register_subtree_array(ett, array_length(ett));
1986
1987         /* Register our configuration options for NetFlow */
1988         netflow_module = prefs_register_protocol(proto_netflow,
1989             proto_reg_handoff_netflow);
1990
1991         prefs_register_uint_preference(netflow_module, "udp.port",
1992             "NetFlow UDP Port", "Set the port for NetFlow messages",
1993             10, &global_netflow_udp_port);
1994
1995         register_init_routine(&netflow_reinit);
1996 }
1997
1998
1999 /*
2000  * protocol/port association 
2001  */
2002 void
2003 proto_reg_handoff_netflow(void)
2004 {
2005         static int netflow_prefs_initialized = FALSE;
2006         static dissector_handle_t netflow_handle;
2007
2008         if (!netflow_prefs_initialized) {
2009                 netflow_handle = create_dissector_handle(dissect_netflow,
2010                     proto_netflow);
2011                 netflow_prefs_initialized = TRUE;
2012         } else {
2013                 dissector_delete("udp.port", netflow_udp_port, netflow_handle);
2014         }
2015
2016         /* Set out port number for future use */
2017         netflow_udp_port = global_netflow_udp_port;
2018
2019         dissector_add("udp.port", netflow_udp_port, netflow_handle);
2020 }