From Andrew Feren:
[obnox/wireshark/wip.git] / epan / dissectors / packet-sflow.c
1 /* packet-sflow.c
2  * Routines for sFlow dissection
3  * Copyright 2003, Jeff Rizzo <riz@boogers.sf.ca.us>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 /* This file (mostly) implements a dissector for sFlow (RFC3176), 
27  * from the version 4 spec at http://www.sflow.org/SFLOW-DATAGRAM.txt . 
28  *
29  * TODO:
30  *   Fix the highlighting of the datastream when bits are selected
31  *   split things out into packet-sflow.h ?
32  *   make routines more consistent as to whether they return
33  *     'offset' or bytes consumed ('len')
34  *   implement sampled_ipv4 and sampled_ipv6 packet data types
35  *   implement extended_gateway
36  *   implement extended_user
37  *   implement extended_url
38  *   implement non-generic counters sampling
39  *   implement the samples from the draft version 5 spec; see
40  *      http://www.sflow.org/SFLOW-DATAGRAM5.txt (see epan/sminmpec.h
41  *      for tables of SMI Network Management Private Enterprise Codes;
42  *      use sminmpec_values, adding new values to epan/sminmpect.h and
43  *      and sminmpec_values in epan/sminmpec.c if necessary - don't create
44  *      your own table)
45  */
46
47 #ifdef HAVE_CONFIG_H
48 # include "config.h"
49 #endif
50
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54
55 #include <glib.h>
56
57 #include <epan/packet.h>
58 #include <epan/prefs.h>
59
60 /*#include "packet-sflow.h"*/
61
62 #define SFLOW_UDP_PORTS "6343"
63
64 static dissector_handle_t sflow_handle;
65
66 /*
67  *      global_sflow_ports : holds the configured range of ports for sflow
68  */
69 static range_t *global_sflow_ports = NULL;
70
71 /*
72  *      sflow_ports : holds the currently used range of ports for sflow
73  */
74 static range_t *sflow_ports = NULL;
75 static gboolean global_dissect_samp_headers = TRUE;
76 static gboolean global_analyze_samp_ip_headers = FALSE;
77
78
79
80 #define ADDRESS_IPV4 1
81 #define ADDRESS_IPV6 2
82
83 #define FLOWSAMPLE 1
84 #define COUNTERSSAMPLE 2
85
86 static const value_string sflow_sampletype[] = {
87         { FLOWSAMPLE, "Flow sample" },
88         { COUNTERSSAMPLE, "Counters sample" },
89         { 0, NULL }
90 };
91
92 /* interface counter types */
93 #define SFLOW_COUNTERS_GENERIC 1
94 #define SFLOW_COUNTERS_ETHERNET 2
95 #define SFLOW_COUNTERS_TOKENRING 3
96 #define SFLOW_COUNTERS_FDDI 4
97 #define SFLOW_COUNTERS_VG 5
98 #define SFLOW_COUNTERS_WAN 6
99 #define SFLOW_COUNTERS_VLAN 7
100
101 static const value_string sflow_counterstype [] = {
102         { SFLOW_COUNTERS_GENERIC, "Generic counters" },
103         { SFLOW_COUNTERS_ETHERNET, "Ethernet counters" },
104         { SFLOW_COUNTERS_FDDI, "FDDI counters" },
105         { SFLOW_COUNTERS_VG, "100baseVG counters" },
106         { SFLOW_COUNTERS_WAN, "WAN counters" },
107         { SFLOW_COUNTERS_VLAN, "VLAN counters" },
108         { 0, NULL }
109 };
110
111 #define MAX_HEADER_SIZE 256
112
113 #define SFLOW_PACKET_DATA_TYPE_HEADER 1
114 #define SFLOW_PACKET_DATA_TYPE_IPV4 2
115 #define SFLOW_PACKET_DATA_TYPE_IPV6 3
116
117 static const value_string sflow_packet_information_type [] = {
118         { SFLOW_PACKET_DATA_TYPE_HEADER, "Packet headers are sampled" },
119         { SFLOW_PACKET_DATA_TYPE_IPV4, "IP Version 4 data" },
120         { SFLOW_PACKET_DATA_TYPE_IPV6, "IP Version 6 data" },
121         { 0, NULL}
122 };
123
124 #define SFLOW_HEADER_ETHERNET 1
125 #define SFLOW_HEADER_TOKENBUS 2
126 #define SFLOW_HEADER_TOKENRING 3
127 #define SFLOW_HEADER_FDDI 4
128 #define SFLOW_HEADER_FRAME_RELAY 5
129 #define SFLOW_HEADER_X25 6
130 #define SFLOW_HEADER_PPP 7
131 #define SFLOW_HEADER_SMDS 8
132 #define SFLOW_HEADER_AAL5 9
133 #define SFLOW_HEADER_AAL5_IP 10
134 #define SFLOW_HEADER_IPv4 11
135 #define SFLOW_HEADER_IPv6 12
136 #define SFLOW_HEADER_MPLS 13
137
138 static const value_string sflow_header_protocol[] = {
139         { SFLOW_HEADER_ETHERNET, "Ethernet" },
140         { SFLOW_HEADER_TOKENBUS, "Token Bus" },
141         { SFLOW_HEADER_TOKENRING, "Token Ring" },
142         { SFLOW_HEADER_FDDI, "FDDI" },
143         { SFLOW_HEADER_FRAME_RELAY, "Frame Relay" },
144         { SFLOW_HEADER_X25, "X.25" },
145         { SFLOW_HEADER_PPP, "PPP" },
146         { SFLOW_HEADER_SMDS, "SMDS" },
147         { SFLOW_HEADER_AAL5, "ATM AAL5" },
148         { SFLOW_HEADER_AAL5_IP, "ATM AAL5-IP (e.g., Cisco AAL5 mux)" },
149         { SFLOW_HEADER_IPv4, "IPv4" },
150         { SFLOW_HEADER_IPv6, "IPv6" },
151         { SFLOW_HEADER_MPLS, "MPLS" },
152         { 0, NULL }
153 };
154
155 /* extended data types */
156 #define SFLOW_EXTENDED_SWITCH 1
157 #define SFLOW_EXTENDED_ROUTER 2
158 #define SFLOW_EXTENDED_GATEWAY 3
159 #define SFLOW_EXTENDED_USER 4
160 #define SFLOW_EXTENDED_URL 5
161
162 static const value_string sflow_extended_data_types[] = {
163         { SFLOW_EXTENDED_SWITCH, "Extended switch information" },
164         { SFLOW_EXTENDED_ROUTER, "Extended router information" },
165         { SFLOW_EXTENDED_GATEWAY, "Extended gateway information" },
166         { SFLOW_EXTENDED_USER, "Extended user information" },   
167         { SFLOW_EXTENDED_URL, "Extended URL information" },     
168         { 0, NULL }
169 };
170
171
172 /* flow sample header */
173 struct sflow_flow_sample_header {
174         guint32         sequence_number;
175         guint32         source_id;
176         guint32         sampling_rate;
177         guint32         sample_pool;
178         guint32         drops;
179         guint32         input;
180         guint32         output;
181 };
182
183 /* counters sample header */
184 struct sflow_counters_sample_header {
185         guint32         sequence_number;
186         guint32         source_id;
187         guint32         sampling_interval;
188         guint32     counters_type;
189 };
190
191 /* generic interface counters */
192 struct if_counters {
193         guint32         ifIndex;
194         guint32         ifType;
195         guint64         ifSpeed;
196         guint32         ifDirection;
197         guint32         ifStatus;
198         guint64         ifInOctets;
199         guint32         ifInUcastPkts;
200         guint32         ifInMulticastPkts;
201         guint32         ifInBroadcastPkts;
202         guint32         ifInDiscards;
203         guint32         ifInErrors;
204         guint32         ifInUnknownProtos;
205         guint64         ifOutOctets;
206         guint32         ifOutUcastPkts;
207         guint32         ifOutMulticastPkts;
208         guint32         ifOutBroadcastPkts;
209         guint32         ifOutDiscards;
210         guint32         ifOutErrors;
211         guint32         ifPromiscuousMode;
212 };
213
214 /* ethernet counters.  These will be preceded by generic counters. */
215 struct ethernet_counters {
216         guint32         dot3StatsAlignmentErrors;
217         guint32         dot3StatsFCSErrors;
218         guint32         dot3StatsSingleCollisionFrames;
219         guint32         dot3StatsMultipleCollisionFrames;
220         guint32         dot3StatsSQETestErrors;
221         guint32         dot3StatsDeferredTransmissions;
222         guint32         dot3StatsLateCollisions;
223         guint32         dot3StatsExcessiveCollisions;
224         guint32         dot3StatsInternalMacTransmitErrors;
225         guint32         dot3StatsCarrierSenseErrors;
226         guint32         dot3StatsFrameTooLongs;
227         guint32         dot3StatsInternalMacReceiveErrors;
228         guint32         dot3StatsSymbolErrors;
229 };
230
231 /* Token Ring counters */
232 struct token_ring_counters {
233         guint32         dot5StatsLineErrors;
234         guint32         dot5StatsBurstErrors;
235         guint32         dot5StatsACErrors;
236         guint32         dot5StatsAbortTransErrors;
237         guint32         dot5StatsInternalErrors;
238         guint32         dot5StatsLostFrameErrors;
239         guint32         dot5StatsReceiveCongestions;
240         guint32         dot5StatsFrameCopiedErrors;
241         guint32         dot5StatsTokenErrors;
242         guint32         dot5StatsSoftErrors;
243         guint32         dot5StatsHardErrors;
244         guint32         dot5StatsSignalLoss;
245         guint32         dot5StatsTransmitBeacons;
246         guint32         dot5StatsRecoverys;
247         guint32         dot5StatsLobeWires;
248         guint32         dot5StatsRemoves;
249         guint32         dot5StatsSingles;
250         guint32         dot5StatsFreqErrors;
251 };
252
253 /* 100BaseVG counters */
254
255 struct vg_counters {
256         guint32         dot12InHighPriorityFrames;
257         guint64         dot12InHighPriorityOctets;
258         guint32         dot12InNormPriorityFrames;
259         guint64         dot12InNormPriorityOctets;
260         guint32         dot12InIPMErrors;
261         guint32         dot12InOversizeFrameErrors;
262         guint32         dot12InDataErrors;
263         guint32         dot12InNullAddressedFrames;
264         guint32         dot12OutHighPriorityFrames;
265         guint64         dot12OutHighPriorityOctets;
266         guint32         dot12TransitionIntoTrainings;
267         guint64         dot12HCInHighPriorityOctets;
268         guint64         dot12HCInNormPriorityOctets;
269         guint64         dot12HCOutHighPriorityOctets;
270 };
271
272 /* VLAN counters */
273
274 struct vlan_counters {
275         guint32         vlan_id;
276         guint32         octets;
277         guint32         ucastPkts;
278         guint32         multicastPkts;
279         guint32         broadcastPkts;
280         guint32         discards;
281 };
282
283 /* Initialize the protocol and registered fields */
284 static int proto_sflow = -1;
285 static int hf_sflow_version = -1;
286 /*static int hf_sflow_agent_address_type = -1; */
287 static int hf_sflow_agent_address_v4 = -1;
288 static int hf_sflow_agent_address_v6 = -1;
289 static int hf_sflow_sub_agent_id = -1;
290 static int hf_sflow_seqnum = -1;
291 static int hf_sflow_sysuptime = -1;
292 static int hf_sflow_numsamples = -1;
293 static int hf_sflow_header_protocol = -1;
294 static int hf_sflow_sampletype = -1;
295 static int hf_sflow_header = -1;
296 static int hf_sflow_packet_information_type = -1;
297 static int hf_sflow_extended_information_type = -1;
298 static int hf_sflow_vlan_in = -1;   /* incoming 802.1Q VLAN ID */
299 static int hf_sflow_vlan_out = -1;   /* outgoing 802.1Q VLAN ID */
300 static int hf_sflow_pri_in = -1;   /* incominging 802.1p priority */
301 static int hf_sflow_pri_out = -1;   /* outgoing 802.1p priority */
302 static int hf_sflow_nexthop_v4 = -1;   /* nexthop address */
303 static int hf_sflow_nexthop_v6 = -1;   /* nexthop address */
304 static int hf_sflow_nexthop_src_mask = -1;
305 static int hf_sflow_nexthop_dst_mask = -1;
306 static int hf_sflow_ifindex = -1;
307 static int hf_sflow_iftype = -1;
308 static int hf_sflow_ifspeed = -1;
309 static int hf_sflow_ifdirection = -1;
310 static int hf_sflow_ifstatus = -1;
311 static int hf_sflow_ifinoct = -1;
312 static int hf_sflow_ifinpkt = -1;
313 static int hf_sflow_ifinmcast = -1;
314 static int hf_sflow_ifinbcast = -1;
315 static int hf_sflow_ifinerr = -1;
316 static int hf_sflow_ifindisc = -1;
317 static int hf_sflow_ifinunk = -1;
318 static int hf_sflow_ifoutoct = -1;
319 static int hf_sflow_ifoutpkt = -1;
320 static int hf_sflow_ifoutmcast = -1;
321 static int hf_sflow_ifoutbcast = -1;
322 static int hf_sflow_ifoutdisc = -1;
323 static int hf_sflow_ifouterr = -1;
324 static int hf_sflow_ifpromisc = -1;
325
326 /* Initialize the subtree pointers */
327 static gint ett_sflow = -1;
328 static gint ett_sflow_sample = -1;
329 static gint ett_sflow_extended_data = -1;
330 static gint ett_sflow_sampled_header = -1;
331
332 /* dissectors for other protocols */
333 static dissector_handle_t eth_withoutfcs_handle;
334 static dissector_handle_t tr_handle;
335 static dissector_handle_t fddi_handle;
336 static dissector_handle_t fr_handle;
337 static dissector_handle_t x25_handle;
338 static dissector_handle_t ppp_handle;
339 static dissector_handle_t smds_handle;
340 static dissector_handle_t aal5_handle;
341 static dissector_handle_t ipv4_handle;
342 static dissector_handle_t ipv6_handle;
343 static dissector_handle_t mpls_handle;
344 /* don't dissect */
345 static dissector_handle_t data_handle;
346
347 void proto_reg_handoff_sflow(void);
348
349 /* dissect a sampled header - layer 2 protocols */
350 static gint
351 dissect_sflow_sampled_header(tvbuff_t *tvb, packet_info *pinfo,
352                              proto_tree *tree, volatile gint offset)
353 {
354         guint32         header_proto, frame_length;
355         volatile        guint32         header_length;
356         tvbuff_t        *next_tvb;
357         proto_tree      *sflow_header_tree;
358         proto_item      *ti;
359         /* stuff for saving column state before calling other dissectors.
360          * Thanks to Guy Harris for the tip. */
361         gboolean save_writable;
362         gboolean save_in_error_pkt;
363         volatile address        save_dl_src;
364         volatile address        save_dl_dst;
365         volatile address        save_net_src;
366         volatile address        save_net_dst;
367         volatile address        save_src;
368         volatile address        save_dst;
369
370         header_proto = tvb_get_ntohl(tvb,offset);
371         proto_tree_add_item(tree, hf_sflow_header_protocol, tvb, offset,
372                                                 4, FALSE);
373         offset += 4;
374         frame_length = tvb_get_ntohl(tvb,offset);
375         proto_tree_add_text(tree, tvb, offset, 4, "Frame Length: %d bytes",
376                                                 frame_length);
377         offset += 4;
378         header_length = tvb_get_ntohl(tvb,offset);
379         offset += 4;
380
381         if (header_length % 4) /* XDR requires 4-byte alignment */
382                 header_length += 4 - (header_length % 4);
383
384         
385         ti = proto_tree_add_item(tree, hf_sflow_header, tvb, offset, 
386                                                          header_length, FALSE);
387         sflow_header_tree = proto_item_add_subtree(ti, ett_sflow_sampled_header);
388
389         /* hand the header off to the appropriate dissector.  It's probably
390          * a short frame, so ignore any exceptions. */
391         next_tvb = tvb_new_subset(tvb, offset, header_length, frame_length);
392
393         /* save some state */
394         save_writable = col_get_writable(pinfo->cinfo);
395
396         /* 
397            If sFlow samples a TCP packet it is very likely that the
398            TCP analysis will flag the packet as having some error with
399            the sequence numbers.  sFlow only report on a "sample" of
400            traffic so many packets will not be reported on.  This is
401            most obvious if the colorizing rules are on, but will also
402            cause confusion if you attempt to filter on
403            "tcp.analysis.flags".
404
405            The following only works to suppress IP/TCP errors, but
406            it is a start anyway.  Other protocols carried as payloads
407            may exhibit similar issues.
408
409            I think what is really needed is a more general
410            "protocol_as_payload" flag.  Of course then someone has to
411            play whack-a-mole and add code to implement it to any
412            protocols that could be carried as a payload.  In the case
413            of sFlow that pretty much means anything on your network.
414         */
415         save_in_error_pkt = pinfo->in_error_pkt;
416         if (!global_analyze_samp_ip_headers) {
417           pinfo->in_error_pkt = TRUE;
418         }
419
420         col_set_writable(pinfo->cinfo, FALSE);
421         save_dl_src = pinfo->dl_src;
422         save_dl_dst = pinfo->dl_dst;
423         save_net_src = pinfo->net_src;
424         save_net_dst = pinfo->net_dst;
425         save_src = pinfo->src;
426         save_dst = pinfo->dst;
427
428         TRY {
429                 switch (header_proto) {
430                 case SFLOW_HEADER_ETHERNET:
431                         call_dissector(eth_withoutfcs_handle, next_tvb, pinfo, sflow_header_tree);
432                         break;
433                 case SFLOW_HEADER_TOKENRING:
434                         call_dissector(tr_handle, next_tvb, pinfo, sflow_header_tree);
435                         break;
436                 case SFLOW_HEADER_FDDI:
437                         call_dissector(fddi_handle, next_tvb, pinfo, sflow_header_tree);
438                         break;
439                 case SFLOW_HEADER_FRAME_RELAY:
440                         call_dissector(fr_handle, next_tvb, pinfo, sflow_header_tree);
441                         break;
442                 case SFLOW_HEADER_X25:
443                         call_dissector(x25_handle, next_tvb, pinfo, sflow_header_tree);
444                         break;
445                 case SFLOW_HEADER_PPP:
446                         call_dissector(ppp_handle, next_tvb, pinfo, sflow_header_tree);
447                         break;
448                 case SFLOW_HEADER_SMDS:
449                         call_dissector(smds_handle, next_tvb, pinfo, sflow_header_tree);
450                         break;
451                 case SFLOW_HEADER_AAL5:
452                 case SFLOW_HEADER_AAL5_IP:
453                         /* I'll be surprised if this works! I have no AAL5 captures
454                          * to test with, and I'm not sure how the encapsulation goes */
455                         call_dissector(aal5_handle, next_tvb, pinfo, sflow_header_tree);
456                         break;
457                 case SFLOW_HEADER_IPv4:
458                         call_dissector(ipv4_handle, next_tvb, pinfo, sflow_header_tree);
459                         break;
460                 case SFLOW_HEADER_IPv6:
461                         call_dissector(ipv6_handle, next_tvb, pinfo, sflow_header_tree);
462                         break;
463                 case SFLOW_HEADER_MPLS:
464                         call_dissector(mpls_handle, next_tvb, pinfo, sflow_header_tree);
465                         break;
466                 default:
467                         /* some of the protocols, I have no clue where to begin. */
468                         break;
469                 };
470         }
471         CATCH2(BoundsError, ReportedBoundsError) {
472                 ; /* do nothing */
473         }
474         ENDTRY;
475
476         /* restore saved state */
477         col_set_writable(pinfo->cinfo, save_writable);
478         pinfo->in_error_pkt = save_in_error_pkt;
479
480         pinfo->dl_src = save_dl_src;
481         pinfo->dl_dst = save_dl_dst;
482         pinfo->net_src = save_net_src;
483         pinfo->net_dst = save_net_dst;
484         pinfo->src = save_src;
485         pinfo->dst = save_dst;
486         
487         offset += header_length;
488         return offset;
489 }
490
491 /* extended switch data, after the packet data */
492 static gint
493 dissect_sflow_extended_switch(tvbuff_t *tvb, proto_tree *tree, gint offset)
494 {
495         gint32 len = 0;
496         
497         proto_tree_add_item(tree, hf_sflow_vlan_in, tvb, offset + len, 4, FALSE);
498         len += 4;
499         proto_tree_add_item(tree, hf_sflow_pri_in, tvb, offset + len, 4, FALSE);
500         len += 4;
501         proto_tree_add_item(tree, hf_sflow_vlan_out, tvb, offset + len, 4, FALSE);
502         len += 4;
503         proto_tree_add_item(tree, hf_sflow_pri_out, tvb, offset + len, 4, FALSE);
504         len += 4;
505
506         return len;
507 }
508
509 /* extended router data, after the packet data */
510 static gint
511 dissect_sflow_extended_router(tvbuff_t *tvb, proto_tree *tree, gint offset)
512 {
513         gint32  len = 0;
514         guint32 address_type;
515
516         address_type = tvb_get_ntohl(tvb, offset);
517         len += 4;
518         switch (address_type) {
519         case ADDRESS_IPV4:
520                 proto_tree_add_item(tree, hf_sflow_nexthop_v4, tvb, offset + len,
521                                                         4, FALSE);
522                 len += 4;
523                 break;
524         case ADDRESS_IPV6:
525                 proto_tree_add_item(tree, hf_sflow_nexthop_v6, tvb, offset + len,
526                                                         16, FALSE);
527                 len += 16;
528                 break;
529         default:
530                 proto_tree_add_text(tree, tvb, offset + len - 4, 4,
531                                                         "Unknown address type (%d)", address_type);
532                 len += 4;  /* not perfect, but what else to do? */
533                 return len;  /* again, this is wrong.  but... ? */
534                 break;
535         };
536         
537         proto_tree_add_item(tree, hf_sflow_nexthop_src_mask, tvb, offset + len,
538                                                         4, FALSE);
539         len += 4;
540         proto_tree_add_item(tree, hf_sflow_nexthop_dst_mask, tvb, offset + len,
541                                                         4, FALSE);
542         len += 4;
543         return len;
544 }
545
546 /* dissect a flow sample */
547 static gint
548 dissect_sflow_flow_sample(tvbuff_t *tvb, packet_info *pinfo,
549                                                   proto_tree *tree, gint offset, proto_item *parent)
550 {
551         struct sflow_flow_sample_header         flow_header;
552         proto_tree      *extended_data_tree;
553         proto_item *ti;
554         guint32         packet_type, extended_data, ext_type, i;
555
556         /* grab the flow header.  This will remain in network byte
557            order, so must convert each item before use */
558         tvb_memcpy(tvb,(guint8 *)&flow_header,offset,sizeof(flow_header));
559         proto_tree_add_text(tree, tvb, offset, 4,
560                                                 "Sequence number: %u",
561                                                 g_ntohl(flow_header.sequence_number));
562         proto_item_append_text(parent, ", seq %u",
563                                                    g_ntohl(flow_header.sequence_number));
564         proto_tree_add_text(tree, tvb, offset+4, 4,
565                                                 "Source ID class: %u index: %u",
566                                                 g_ntohl(flow_header.source_id) >> 24,
567                                                 g_ntohl(flow_header.source_id) & 0x00ffffff);
568         proto_tree_add_text(tree, tvb, offset+8, 4,
569                                                 "Sampling rate: 1 out of %u packets",
570                                                 g_ntohl(flow_header.sampling_rate));
571         proto_tree_add_text(tree, tvb, offset+12, 4,
572                                                 "Sample pool: %u total packets",
573                                                 g_ntohl(flow_header.sample_pool));
574         proto_tree_add_text(tree, tvb, offset+16, 4,
575                                                 "Dropped packets: %u",
576                                                 g_ntohl(flow_header.drops));
577         proto_tree_add_text(tree, tvb, offset+20, 4,
578                                                 "Input Interface: ifIndex %u",
579                                                 g_ntohl(flow_header.input));
580         if (g_ntohl(flow_header.output) >> 31)
581                 proto_tree_add_text(tree, tvb, offset+24, 4,
582                                                         "multiple outputs: %u interfaces",
583                                                         g_ntohl(flow_header.output) & 0x00ffffff);
584         else 
585                 proto_tree_add_text(tree, tvb, offset+24, 4,
586                                                         "Output interface: ifIndex %u",
587                                                         g_ntohl(flow_header.output) & 0x00ffffff);
588         offset += sizeof(flow_header);
589
590         /* what kind of flow sample is it? */
591         packet_type = tvb_get_ntohl(tvb, offset);
592         proto_tree_add_uint(tree, hf_sflow_packet_information_type, tvb, offset,
593             4, packet_type);
594         offset += 4;
595         switch (packet_type) {
596         case SFLOW_PACKET_DATA_TYPE_HEADER:
597                 offset = dissect_sflow_sampled_header(tvb, pinfo, tree, offset);
598                 break;
599         case SFLOW_PACKET_DATA_TYPE_IPV4:
600         case SFLOW_PACKET_DATA_TYPE_IPV6:
601         default:
602                 break;
603         };
604         /* still need to dissect extended data */
605         extended_data = tvb_get_ntohl(tvb,offset);
606         offset += 4; 
607
608         for (i=0; i < extended_data; i++) {
609                 /* figure out what kind of extended data it is */
610                 ext_type = tvb_get_ntohl(tvb,offset);
611
612                 /* create a subtree.  Might want to move this to
613                  * the end, so more info can be correct.
614                  */
615                 ti = proto_tree_add_text(tree, tvb, offset, -1, "%s",
616                                                                  val_to_str(ext_type, 
617                                                                                         sflow_extended_data_types,
618                                                                                         "Unknown extended information"));
619                 extended_data_tree = proto_item_add_subtree(ti, ett_sflow_extended_data);
620                 proto_tree_add_uint(extended_data_tree,
621                     hf_sflow_extended_information_type, tvb, offset, 4,
622                     ext_type);
623                 offset += 4;
624
625                 switch (ext_type) {
626                 case SFLOW_EXTENDED_SWITCH:
627                         offset += dissect_sflow_extended_switch(tvb, extended_data_tree,
628                                                                                                         offset);
629                         break;
630                 case SFLOW_EXTENDED_ROUTER:
631                         offset += dissect_sflow_extended_router(tvb, extended_data_tree,
632                                                                                                         offset);
633                         break;
634                 case SFLOW_EXTENDED_GATEWAY:
635                         break;
636                 case SFLOW_EXTENDED_USER:
637                         break;
638                 case SFLOW_EXTENDED_URL:
639                         break;
640                 default:
641                         break;
642                 }
643                 proto_item_set_end(ti, tvb, offset);
644         }
645         return offset;
646         
647 }
648
649 /* dissect a counters sample */
650 static gint
651 dissect_sflow_counters_sample(tvbuff_t *tvb, proto_tree *tree,
652                                                           gint offset, proto_item *parent)
653 {
654         struct sflow_counters_sample_header     counters_header;
655         struct if_counters ifc;
656         struct ethernet_counters ethc;
657         struct token_ring_counters tokc;
658         struct vg_counters vgc;
659         struct vlan_counters vlanc;
660         
661         /* grab the flow header.  This will remain in network byte
662            order, so must convert each item before use */
663         tvb_memcpy(tvb,(guint8 *)&counters_header,offset,sizeof(counters_header));
664         proto_tree_add_text(tree, tvb, offset, 4,
665                                                 "Sequence number: %u",
666                                                 g_ntohl(counters_header.sequence_number));
667         proto_item_append_text(parent, ", seq %u",
668                                                    g_ntohl(counters_header.sequence_number));
669         proto_tree_add_text(tree, tvb, offset + 4, 4,
670                                                 "Source ID class: %u index: %u",
671                                                 g_ntohl(counters_header.source_id) >> 24,
672                                                 g_ntohl(counters_header.source_id) & 0x00ffffff);
673         proto_tree_add_text(tree, tvb, offset + 8, 4,
674                                                 "Sampling Interval: %u",
675                                                 g_ntohl(counters_header.sampling_interval));
676         proto_tree_add_text(tree, tvb, offset + 12, 4, "Counters type: %s",
677                                                 val_to_str(g_ntohl(counters_header.counters_type),
678                                                                    sflow_counterstype, "Unknown type"));
679
680         offset += sizeof(counters_header);
681
682         /* most counters types have the "generic" counters first */
683         switch (g_ntohl(counters_header.counters_type)) {
684         case SFLOW_COUNTERS_GENERIC:
685         case SFLOW_COUNTERS_ETHERNET:
686         case SFLOW_COUNTERS_TOKENRING:
687         case SFLOW_COUNTERS_FDDI:
688         case SFLOW_COUNTERS_VG:
689         case SFLOW_COUNTERS_WAN:
690                 tvb_memcpy(tvb,(guint8 *)&ifc, offset, sizeof(ifc));
691                 proto_item_append_text(parent, ", ifIndex %u",
692                                                            g_ntohl(ifc.ifIndex));
693                 proto_tree_add_item(tree, hf_sflow_ifindex, tvb, offset, 4, FALSE);
694                 offset += 4;
695                 proto_tree_add_item(tree, hf_sflow_iftype, tvb, offset, 4, FALSE);
696                 offset += 4;
697                 proto_tree_add_item(tree, hf_sflow_ifspeed, tvb, offset, 8, FALSE);
698                 offset += 8;
699                 proto_tree_add_item(tree, hf_sflow_ifdirection, tvb, offset, 
700                                                         4, FALSE);
701                 offset += 4;
702                 proto_tree_add_item(tree, hf_sflow_ifstatus, tvb, offset, 4, FALSE);
703                 offset += 4;
704                 proto_tree_add_item(tree, hf_sflow_ifinoct, tvb, offset, 8, FALSE);
705                 offset += 8;
706                 proto_tree_add_item(tree, hf_sflow_ifinpkt, tvb, offset, 4, FALSE);
707                 offset += 4;
708                 proto_tree_add_item(tree, hf_sflow_ifinmcast, tvb, offset,
709                                                         4, FALSE);
710                 offset += 4;
711                 proto_tree_add_item(tree, hf_sflow_ifinbcast, tvb, offset,
712                                                         4, FALSE);
713                 offset += 4;
714                 proto_tree_add_item(tree, hf_sflow_ifindisc, tvb, offset,
715                                                         4, FALSE);
716                 offset += 4;
717                 proto_tree_add_item(tree, hf_sflow_ifinerr, tvb, offset,
718                                                         4, FALSE);
719                 offset += 4;
720                 proto_tree_add_item(tree, hf_sflow_ifinunk, tvb, offset,
721                                                         4, FALSE);
722                 offset += 4;
723                 proto_tree_add_item(tree, hf_sflow_ifoutoct, tvb, offset, 8, FALSE);
724                 offset += 8;
725                 proto_tree_add_item(tree, hf_sflow_ifoutpkt, tvb, offset, 4, FALSE);
726                 offset += 4;
727                 proto_tree_add_item(tree, hf_sflow_ifoutmcast, tvb, offset,
728                                                         4, FALSE);
729                 offset += 4;
730                 proto_tree_add_item(tree, hf_sflow_ifoutbcast, tvb, offset,
731                                                         4, FALSE);
732                 offset += 4;
733                 proto_tree_add_item(tree, hf_sflow_ifoutdisc, tvb, offset,
734                                                         4, FALSE);
735                 offset += 4;
736                 proto_tree_add_item(tree, hf_sflow_ifouterr, tvb, offset,
737                                                         4, FALSE);
738                 offset += 4;
739                 proto_tree_add_item(tree, hf_sflow_ifpromisc, tvb, offset,
740                                                         4, FALSE);
741                 offset += 4;
742                 break;
743         };
744         
745         /* Some counter types have other info to gather */
746         switch (g_ntohl(counters_header.counters_type)) {
747         case SFLOW_COUNTERS_ETHERNET:
748                 tvb_memcpy(tvb,(guint8 *)&ethc, offset, sizeof(ethc));
749                 offset += sizeof(ethc);
750                 break;
751         case SFLOW_COUNTERS_TOKENRING:
752                 tvb_memcpy(tvb,(guint8 *)&tokc, offset, sizeof(tokc));
753                 offset += sizeof(tokc);
754                 break;
755         case SFLOW_COUNTERS_VG:
756                 tvb_memcpy(tvb,(guint8 *)&vgc, offset, sizeof(vgc));
757                 offset += sizeof(vgc);
758                 break;
759         case SFLOW_COUNTERS_VLAN:
760                 tvb_memcpy(tvb,(guint8 *)&vlanc, offset, sizeof(vlanc));
761                 offset += sizeof(vlanc);
762                 break;
763         default:
764                 break;
765         }
766         return offset;
767 }
768
769 /* Code to dissect the sflow samples */
770 static gint
771 dissect_sflow_samples(tvbuff_t *tvb, packet_info *pinfo,
772                                           proto_tree *tree, gint offset)
773 {
774         proto_tree      *sflow_sample_tree;
775         proto_item      *ti; /* tree item */
776         guint32         sample_type;
777         
778         /* decide what kind of sample it is. */
779         sample_type = tvb_get_ntohl(tvb,offset);
780
781         ti = proto_tree_add_text(tree, tvb, offset, -1, "%s",
782                                                          val_to_str(sample_type, sflow_sampletype,
783                                                                                 "Unknown sample type"));
784         sflow_sample_tree = proto_item_add_subtree(ti, ett_sflow_sample);
785
786         proto_tree_add_item(sflow_sample_tree, hf_sflow_sampletype, tvb,
787                                                 offset, 4, FALSE);
788         offset += 4;
789
790         switch (sample_type) {
791         case FLOWSAMPLE:
792                 offset = dissect_sflow_flow_sample(tvb, pinfo, sflow_sample_tree,
793                                                                                  offset, ti);
794                 break;
795         case COUNTERSSAMPLE:
796                 offset = dissect_sflow_counters_sample(tvb, sflow_sample_tree,
797                                                                                          offset, ti);
798                 break;
799         default:
800                 break;
801         }
802         proto_item_set_end(ti, tvb, offset);
803         return offset;
804 }
805
806 /* Code to actually dissect the packets */
807 static int
808 dissect_sflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
809 {
810
811 /* Set up structures needed to add the protocol subtree and manage it */
812         proto_item *ti;
813         proto_tree *sflow_tree;
814         guint32         version, sub_agent_id, seqnum;
815         guint32         agent_address_type;
816         union {
817                 guint8  v4[4];
818                 guint8  v6[16];
819         } agent_address;
820         guint32         numsamples;
821         volatile guint          offset=0;
822         guint   i=0;
823
824 /* Make entries in Protocol column and Info column on summary display */
825         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
826                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "sFlow");
827     
828
829         /* create display subtree for the protocol */
830         ti = proto_tree_add_item(tree, proto_sflow, tvb, 0, -1, FALSE);
831         
832         sflow_tree = proto_item_add_subtree(ti, ett_sflow);
833                 
834         version = tvb_get_ntohl(tvb, offset);
835         if (check_col(pinfo->cinfo, COL_INFO)) 
836                 col_add_fstr(pinfo->cinfo, COL_INFO, "V%u",
837                                          version);
838         proto_tree_add_item(sflow_tree,
839                                                 hf_sflow_version, tvb, offset, 4, FALSE);
840         offset += 4;
841
842         agent_address_type = tvb_get_ntohl(tvb, offset);
843         offset += 4;
844         switch (agent_address_type) {
845         case ADDRESS_IPV4:
846                 tvb_memcpy(tvb, agent_address.v4, offset, 4);
847                 if (check_col(pinfo->cinfo, COL_INFO)) 
848                         col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
849                                                  ip_to_str(agent_address.v4));
850                 proto_tree_add_item(sflow_tree,
851                                                         hf_sflow_agent_address_v4, tvb, offset,
852                                                         4, FALSE);
853                 offset += 4;
854                 break;
855         case ADDRESS_IPV6:
856                 tvb_memcpy(tvb, agent_address.v6, offset, 16);
857                 if (check_col(pinfo->cinfo, COL_INFO)) 
858                         col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
859                                                         ip6_to_str((struct e_in6_addr *)agent_address.v6));
860                 proto_tree_add_item(sflow_tree,
861                                                         hf_sflow_agent_address_v6, tvb, offset,
862                                                         16, FALSE);
863                 offset += 16;
864                 break;
865         default:
866                 return 0;
867                 /* unknown address.  this will cause a malformed packet.  */
868                 break;
869         };
870
871         if (version == 5) {
872                 sub_agent_id = tvb_get_ntohl(tvb, offset);
873                 if (check_col(pinfo->cinfo, COL_INFO)) 
874                         col_append_fstr(pinfo->cinfo, COL_INFO, ", sub-agent ID %u",
875                                                         sub_agent_id);
876                 proto_tree_add_uint(sflow_tree, hf_sflow_sub_agent_id, tvb,
877                                                 offset, 4, sub_agent_id);
878                 offset += 4;
879         }
880         seqnum = tvb_get_ntohl(tvb, offset);
881         if (check_col(pinfo->cinfo, COL_INFO))
882                 col_append_fstr(pinfo->cinfo, COL_INFO, ", seq %u", seqnum);
883         proto_tree_add_uint(sflow_tree, hf_sflow_seqnum, tvb,
884                                                 offset, 4, seqnum);
885         offset += 4;
886         proto_tree_add_item(sflow_tree, hf_sflow_sysuptime, tvb,
887                                                 offset, 4, FALSE);
888         offset += 4;
889         numsamples = tvb_get_ntohl(tvb,offset);
890         if (check_col(pinfo->cinfo, COL_INFO))
891                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u samples",
892                                                 numsamples);
893         proto_tree_add_uint(sflow_tree, hf_sflow_numsamples, tvb,
894                                                 offset, 4, numsamples);
895         offset += 4;
896
897         /* Ok, we're now at the end of the sflow datagram header;
898          * everything from here out should be samples. Loop over
899          * the expected number of samples, and pass them to the appropriate
900          * dissectors.
901          */
902         if (version == 5) {
903                 proto_tree_add_text(sflow_tree, tvb, offset, -1,
904                     "sFlow V5 samples (please write and contribute code to dissect them!)");
905         } else {
906                 for (i=0; i < numsamples; i++) {
907                         offset = dissect_sflow_samples(tvb, pinfo, sflow_tree,
908                             offset);
909                 }
910         }
911
912         return tvb_length(tvb);
913 }
914
915
916 static void
917 sflow_delete_callback(guint32 port)
918 {
919     if ( port ) {
920         dissector_delete("udp.port", port, sflow_handle);
921     }
922 }
923 static void
924 sflow_add_callback(guint32 port)
925 {
926     if ( port ) {
927         dissector_add("udp.port", port, sflow_handle);
928     }
929 }
930
931
932 static void
933 sflow_reinit(void)
934 {
935         if (sflow_ports) {
936           range_foreach(sflow_ports, sflow_delete_callback);
937           g_free(sflow_ports);
938         }
939
940         sflow_ports = range_copy(global_sflow_ports);
941
942         range_foreach(sflow_ports, sflow_add_callback);
943 }
944
945
946 /* Register the protocol with Wireshark */
947
948 /* this format is require because a script is used to build the C function
949    that calls all the protocol registration.
950 */
951
952 void
953 proto_register_sflow(void)
954 {
955         module_t *sflow_module;
956
957 /* Setup list of header fields  See Section 1.6.1 for details*/
958         static hf_register_info hf[] = {
959                 { &hf_sflow_version,
960                         { "datagram version", "sflow.version",
961                         FT_UINT32, BASE_DEC, NULL, 0x0,          
962                         "sFlow datagram version", HFILL }
963                 },
964                 { &hf_sflow_agent_address_v4,
965                         { "agent address", "sflow.agent",
966                         FT_IPv4, BASE_NONE, NULL, 0x0,          
967                         "sFlow Agent IP address", HFILL }
968                 },
969                 { &hf_sflow_agent_address_v6,
970                         { "agent address", "sflow.agent.v6",
971                         FT_IPv6, BASE_NONE, NULL, 0x0,          
972                         "sFlow Agent IPv6 address", HFILL }
973                 },
974                 { &hf_sflow_sub_agent_id,
975                         { "Sub-agent ID", "sflow.sub_agent_id",
976                         FT_UINT32, BASE_DEC, NULL, 0x0,          
977                         "sFlow sub-agent ID", HFILL }
978                 },
979                 { &hf_sflow_seqnum,
980                         { "Sequence number", "sflow.sequence_number",
981                         FT_UINT32, BASE_DEC, NULL, 0x0,          
982                         "sFlow datagram sequence number", HFILL }
983                 },
984                 { &hf_sflow_sysuptime,
985                         { "SysUptime", "sflow.sysuptime",
986                         FT_UINT32, BASE_DEC, NULL, 0x0,          
987                         "System Uptime", HFILL }
988                 },
989                 { &hf_sflow_numsamples,
990                         { "NumSamples", "sflow.numsamples",
991                         FT_UINT32, BASE_DEC, NULL, 0x0,          
992                         "Number of samples in sFlow datagram", HFILL }
993                 },
994                 { &hf_sflow_sampletype,
995                         { "sFlow sample type", "sflow.sampletype",
996                         FT_UINT32, BASE_DEC, VALS(sflow_sampletype), 0x0,          
997                         "Type of sFlow sample", HFILL }
998                 },
999                 { &hf_sflow_header_protocol,
1000                         { "Header protocol", "sflow.header_protocol",
1001                         FT_UINT32, BASE_DEC, VALS(sflow_header_protocol), 0x0,          
1002                         "Protocol of sampled header", HFILL }
1003                 },
1004                 { &hf_sflow_header,
1005                         { "Header of sampled packet", "sflow.header",
1006                         FT_BYTES, BASE_HEX, NULL, 0x0,          
1007                         "Data from sampled header", HFILL }
1008                 },
1009                 { &hf_sflow_packet_information_type,
1010                         { "Sample type", "sflow.packet_information_type",
1011                         FT_UINT32, BASE_DEC, VALS(sflow_packet_information_type), 0x0,
1012                         "Type of sampled information", HFILL }
1013                 },
1014                 { &hf_sflow_extended_information_type,
1015                         { "Extended information type", "sflow.extended_information_type",
1016                         FT_UINT32, BASE_DEC, VALS(sflow_extended_data_types), 0x0,
1017                         "Type of extended information", HFILL }
1018                 },
1019                 { &hf_sflow_vlan_in,
1020                         { "Incoming 802.1Q VLAN", "sflow.vlan.in",
1021                         FT_UINT32, BASE_DEC, NULL, 0x0,
1022                         "Incoming VLAN ID", HFILL }
1023                 },
1024                 { &hf_sflow_vlan_out,
1025                         { "Outgoing 802.1Q VLAN", "sflow.vlan.out",
1026                         FT_UINT32, BASE_DEC, NULL, 0x0,
1027                         "Outgoing VLAN ID", HFILL }
1028                 },
1029                 { &hf_sflow_pri_in,
1030                         { "Incoming 802.1p priority", "sflow.pri.in",
1031                         FT_UINT32, BASE_DEC, NULL, 0x0,
1032                         "Incoming 802.1p priority", HFILL }
1033                 },
1034                 { &hf_sflow_pri_out,
1035                         { "Outgoing 802.1p priority", "sflow.pri.out",
1036                         FT_UINT32, BASE_DEC, NULL, 0x0,
1037                         "Outgoing 802.1p priority", HFILL }
1038                 },
1039                 { &hf_sflow_nexthop_v4,
1040                         { "Next hop", "sflow.nexthop",
1041                         FT_IPv4, BASE_DEC, NULL, 0x0,
1042                         "Next hop address", HFILL }
1043                 },
1044                 { &hf_sflow_nexthop_v6,
1045                         { "Next hop", "sflow.nexthop",
1046                         FT_IPv6, BASE_HEX, NULL, 0x0,
1047                         "Next hop address", HFILL }
1048                 },
1049                 { &hf_sflow_nexthop_src_mask,
1050                   { "Next hop source mask", "sflow.nexthop.src_mask",
1051                         FT_UINT32, BASE_DEC, NULL, 0x0,
1052                         "Next hop source mask bits", HFILL }
1053                 },
1054                 { &hf_sflow_nexthop_dst_mask,
1055                   { "Next hop destination mask", "sflow.nexthop.dst_mask",
1056                         FT_UINT32, BASE_DEC, NULL, 0x0,
1057                         "Next hop destination mask bits", HFILL }
1058                 },
1059                 { &hf_sflow_ifindex,
1060                   { "Interface index", "sflow.ifindex",
1061                         FT_UINT32, BASE_DEC, NULL, 0x0,
1062                         "Interface Index", HFILL }
1063                 },
1064                 { &hf_sflow_iftype,
1065                   { "Interface Type", "sflow.iftype",
1066                         FT_UINT32, BASE_DEC, NULL, 0x0,
1067                         "Interface Type", HFILL }
1068                 },
1069                 { &hf_sflow_ifspeed,
1070                   { "Interface Speed", "sflow.ifspeed",
1071                         FT_UINT64, BASE_DEC, NULL, 0x0,
1072                         "Interface Speed", HFILL }
1073                 },
1074                 { &hf_sflow_ifdirection,
1075                   { "Interface Direction", "sflow.ifdirection",
1076                         FT_UINT32, BASE_DEC, NULL, 0x0,
1077                         "Interface Direction", HFILL }
1078                 },
1079                 { &hf_sflow_ifstatus,
1080                   { "Interface Status", "sflow.ifstatus",
1081                         FT_UINT32, BASE_DEC, NULL, 0x0,
1082                         "Interface Status", HFILL }
1083                 },
1084                 { &hf_sflow_ifinoct,
1085                   { "Input Octets", "sflow.ifinoct",
1086                         FT_UINT64, BASE_DEC, NULL, 0x0,
1087                         "Interface Input Octets", HFILL }
1088                 },
1089                 { &hf_sflow_ifinpkt,
1090                   { "Input Packets", "sflow.ifinpkt",
1091                         FT_UINT32, BASE_DEC, NULL, 0x0,
1092                         "Interface Input Packets", HFILL }
1093                 },
1094                 { &hf_sflow_ifinmcast,
1095                   { "Input Multicast Packets", "sflow.ifinmcast",
1096                         FT_UINT32, BASE_DEC, NULL, 0x0,
1097                         "Interface Input Multicast Packets", HFILL }
1098                 },
1099                 { &hf_sflow_ifinbcast,
1100                   { "Input Broadcast Packets", "sflow.ifinbcast",
1101                         FT_UINT32, BASE_DEC, NULL, 0x0,
1102                         "Interface Input Broadcast Packets", HFILL }
1103                 },
1104                 { &hf_sflow_ifindisc,
1105                   { "Input Discarded Packets", "sflow.ifindisc",
1106                         FT_UINT32, BASE_DEC, NULL, 0x0,
1107                         "Interface Input Discarded Packets", HFILL }
1108                 },
1109                 { &hf_sflow_ifinerr,
1110                   { "Input Errors", "sflow.ifinerr",
1111                         FT_UINT32, BASE_DEC, NULL, 0x0,
1112                         "Interface Input Errors", HFILL }
1113                 },
1114                 { &hf_sflow_ifinunk,
1115                   { "Input Unknown Protocol Packets", "sflow.ifinunk",
1116                         FT_UINT32, BASE_DEC, NULL, 0x0,
1117                         "Interface Input Unknown Protocol Packets", HFILL }
1118                 },
1119                 { &hf_sflow_ifoutoct,
1120                   { "Output Octets", "sflow.ifoutoct",
1121                         FT_UINT64, BASE_DEC, NULL, 0x0,
1122                         "Outterface Output Octets", HFILL }
1123                 },
1124                 { &hf_sflow_ifoutpkt,
1125                   { "Output Packets", "sflow.ifoutpkt",
1126                         FT_UINT32, BASE_DEC, NULL, 0x0,
1127                         "Interface Output Packets", HFILL }
1128                 },
1129                 { &hf_sflow_ifoutmcast,
1130                   { "Output Multicast Packets", "sflow.ifoutmcast",
1131                         FT_UINT32, BASE_DEC, NULL, 0x0,
1132                         "Interface Output Multicast Packets", HFILL }
1133                 },
1134                 { &hf_sflow_ifoutbcast,
1135                   { "Output Broadcast Packets", "sflow.ifoutbcast",
1136                         FT_UINT32, BASE_DEC, NULL, 0x0,
1137                         "Interface Output Broadcast Packets", HFILL }
1138                 },
1139                 { &hf_sflow_ifoutdisc,
1140                   { "Output Discarded Packets", "sflow.ifoutdisc",
1141                         FT_UINT32, BASE_DEC, NULL, 0x0,
1142                         "Interface Output Discarded Packets", HFILL }
1143                 },
1144                 { &hf_sflow_ifouterr,
1145                   { "Output Errors", "sflow.ifouterr",
1146                         FT_UINT32, BASE_DEC, NULL, 0x0,
1147                         "Interface Output Errors", HFILL }
1148                 },
1149                 { &hf_sflow_ifpromisc,
1150                   { "Promiscuous Mode", "sflow.ifpromisc",
1151                         FT_UINT32, BASE_DEC, NULL, 0x0,
1152                         "Interface Promiscuous Mode", HFILL }
1153                 },
1154         };
1155
1156 /* Setup protocol subtree array */
1157         static gint *ett[] = {
1158                 &ett_sflow,
1159                 &ett_sflow_sample,
1160                 &ett_sflow_extended_data,
1161                 &ett_sflow_sampled_header,
1162         };
1163
1164 /* Register the protocol name and description */
1165         proto_sflow = proto_register_protocol("InMon sFlow",
1166             "sFlow", "sflow");
1167
1168 /* Required function calls to register the header fields and subtrees used */
1169         proto_register_field_array(proto_sflow, hf, array_length(hf));
1170         proto_register_subtree_array(ett, array_length(ett));
1171
1172 /* Register our configuration options for sFlow */
1173         sflow_module = prefs_register_protocol(proto_sflow,
1174                                                proto_reg_handoff_sflow);
1175
1176 /* Set default Neflow port(s) */
1177         range_convert_str(&global_sflow_ports, SFLOW_UDP_PORTS,
1178                           MAX_UDP_PORT);
1179
1180         prefs_register_obsolete_preference(sflow_module, "udp.port");
1181
1182         prefs_register_range_preference(sflow_module, "ports",
1183                                         "sFlow UDP Port(s)",
1184                                         "Set the port(s) for sFlow messages"
1185                                         " (default: " SFLOW_UDP_PORTS ")",
1186                                         &global_sflow_ports, MAX_UDP_PORT);
1187
1188         /* 
1189            If I use a filter like "ip.src == 10.1.1.1" this will, in
1190            addition to the usual suspects, find every sFlow packet
1191            where *any* of the payload headers contain 10.1.1.1 as a
1192            src addr.  I think this may not be the desired behavior.
1193            It can certainly be confusing since the ip.src being found
1194            is buried about 3 subtrees deep and the subtrees might be
1195            under any one of the sampled (payload) header trees. It is
1196            certainly not quickly obvious why the filter matched.
1197         */
1198         prefs_register_bool_preference(sflow_module, "enable_dissection",
1199                                        "Dissect data in sampled headers",
1200                                        "Enabling dissection makes it easy to view protocol details in each of the sampled headers.  Disabling dissection may reduce noise caused when display filters match the contents of any sampled header(s).",
1201                                         &global_dissect_samp_headers);
1202         /* 
1203            It is not clear to me that it *ever* makes sense to enable
1204            this option.  However, it was previously the default
1205            behavior so I'll leave it as an option if someone thinks
1206            they have a use for it.
1207         */
1208         prefs_register_bool_preference(sflow_module, "enable_analysis",
1209                                        "Analyze data in sampled IP headers",
1210                                        "This option only makes sense if dissection of sampled headers is enabled and probably not even then.",
1211                                         &global_analyze_samp_ip_headers );
1212
1213
1214         register_init_routine(&sflow_reinit);
1215 }
1216
1217
1218 /* If this dissector uses sub-dissector registration add a
1219    registration routine.  This format is required because a script is
1220    used to find these routines and create the code that calls these
1221    routines.
1222 */
1223 void
1224 proto_reg_handoff_sflow(void)
1225 {
1226         static int sflow_prefs_initialized = FALSE;
1227         if (!sflow_prefs_initialized) {
1228                 sflow_handle = new_create_dissector_handle(dissect_sflow,
1229                                                            proto_sflow);
1230
1231                 sflow_prefs_initialized = TRUE;
1232         }
1233
1234
1235         sflow_reinit();
1236
1237         /*dissector_handle_t sflow_handle;*/
1238
1239         /*
1240          * XXX - should this be done with a dissector table?
1241          */
1242         data_handle = find_dissector("data");
1243
1244         if (global_dissect_samp_headers) {
1245             eth_withoutfcs_handle = find_dissector("eth_withoutfcs");
1246             tr_handle = find_dissector("tr");
1247             fddi_handle = find_dissector("fddi");
1248             fr_handle = find_dissector("fr");
1249             x25_handle = find_dissector("x.25");
1250             ppp_handle = find_dissector("ppp");
1251 #if 0
1252             smds_handle = find_dissector("smds");
1253 #else
1254             /* We don't have an SMDS dissector yet */
1255             smds_handle = data_handle;
1256 #endif
1257 #if 0
1258             aal5_handle = find_dissector("atm");
1259 #else
1260             /* What dissector should be used here? */
1261             aal5_handle = data_handle;
1262 #endif
1263             ipv4_handle = find_dissector("ip");
1264             ipv6_handle = find_dissector("ipv6");
1265             mpls_handle = find_dissector("mpls");
1266         } else {
1267             eth_withoutfcs_handle = data_handle;
1268             tr_handle = data_handle;
1269             fddi_handle = data_handle;
1270             fr_handle = data_handle;
1271             x25_handle = data_handle;
1272             ppp_handle = data_handle;
1273             smds_handle = data_handle;
1274             aal5_handle = data_handle;
1275             ipv4_handle = data_handle;
1276             ipv6_handle = data_handle;
1277             mpls_handle = data_handle;
1278         }
1279
1280 }