Get rid of get_ber_last_reated_item() and fix dissection of wIN-TriggerList.
[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 "packet-sflow.h"*/
59
60 #define UDP_PORT_SFLOW 6343
61
62 #define ADDRESS_IPV4 1
63 #define ADDRESS_IPV6 2
64
65 #define FLOWSAMPLE 1
66 #define COUNTERSSAMPLE 2
67
68 static const value_string sflow_sampletype[] = {
69         { FLOWSAMPLE, "Flow sample" },
70         { COUNTERSSAMPLE, "Counters sample" },
71         { 0, NULL }
72 };
73
74 /* interface counter types */
75 #define SFLOW_COUNTERS_GENERIC 1
76 #define SFLOW_COUNTERS_ETHERNET 2
77 #define SFLOW_COUNTERS_TOKENRING 3
78 #define SFLOW_COUNTERS_FDDI 4
79 #define SFLOW_COUNTERS_VG 5
80 #define SFLOW_COUNTERS_WAN 6
81 #define SFLOW_COUNTERS_VLAN 7
82
83 static const value_string sflow_counterstype [] = {
84         { SFLOW_COUNTERS_GENERIC, "Generic counters" },
85         { SFLOW_COUNTERS_ETHERNET, "Ethernet counters" },
86         { SFLOW_COUNTERS_FDDI, "FDDI counters" },
87         { SFLOW_COUNTERS_VG, "100baseVG counters" },
88         { SFLOW_COUNTERS_WAN, "WAN counters" },
89         { SFLOW_COUNTERS_VLAN, "VLAN counters" },
90         { 0, NULL }
91 };
92
93 #define MAX_HEADER_SIZE 256
94
95 #define SFLOW_PACKET_DATA_TYPE_HEADER 1
96 #define SFLOW_PACKET_DATA_TYPE_IPV4 2
97 #define SFLOW_PACKET_DATA_TYPE_IPV6 3
98
99 static const value_string sflow_packet_information_type [] = {
100         { SFLOW_PACKET_DATA_TYPE_HEADER, "Packet headers are sampled" },
101         { SFLOW_PACKET_DATA_TYPE_IPV4, "IP Version 4 data" },
102         { SFLOW_PACKET_DATA_TYPE_IPV6, "IP Version 6 data" },
103         { 0, NULL}
104 };
105
106 #define SFLOW_HEADER_ETHERNET 1
107 #define SFLOW_HEADER_TOKENBUS 2
108 #define SFLOW_HEADER_TOKENRING 3
109 #define SFLOW_HEADER_FDDI 4
110 #define SFLOW_HEADER_FRAME_RELAY 5
111 #define SFLOW_HEADER_X25 6
112 #define SFLOW_HEADER_PPP 7
113 #define SFLOW_HEADER_SMDS 8
114 #define SFLOW_HEADER_AAL5 9
115 #define SFLOW_HEADER_AAL5_IP 10
116 #define SFLOW_HEADER_IPv4 11
117 #define SFLOW_HEADER_IPv6 12
118 #define SFLOW_HEADER_MPLS 13
119
120 static const value_string sflow_header_protocol[] = {
121         { SFLOW_HEADER_ETHERNET, "Ethernet" },
122         { SFLOW_HEADER_TOKENBUS, "Token Bus" },
123         { SFLOW_HEADER_TOKENRING, "Token Ring" },
124         { SFLOW_HEADER_FDDI, "FDDI" },
125         { SFLOW_HEADER_FRAME_RELAY, "Frame Relay" },
126         { SFLOW_HEADER_X25, "X.25" },
127         { SFLOW_HEADER_PPP, "PPP" },
128         { SFLOW_HEADER_SMDS, "SMDS" },
129         { SFLOW_HEADER_AAL5, "ATM AAL5" },
130         { SFLOW_HEADER_AAL5_IP, "ATM AAL5-IP (e.g., Cisco AAL5 mux)" },
131         { SFLOW_HEADER_IPv4, "IPv4" },
132         { SFLOW_HEADER_IPv6, "IPv6" },
133         { SFLOW_HEADER_MPLS, "MPLS" },
134         { 0, NULL }
135 };
136
137 /* extended data types */
138 #define SFLOW_EXTENDED_SWITCH 1
139 #define SFLOW_EXTENDED_ROUTER 2
140 #define SFLOW_EXTENDED_GATEWAY 3
141 #define SFLOW_EXTENDED_USER 4
142 #define SFLOW_EXTENDED_URL 5
143
144 static const value_string sflow_extended_data_types[] = {
145         { SFLOW_EXTENDED_SWITCH, "Extended switch information" },
146         { SFLOW_EXTENDED_ROUTER, "Extended router information" },
147         { SFLOW_EXTENDED_GATEWAY, "Extended gateway information" },
148         { SFLOW_EXTENDED_USER, "Extended user information" },   
149         { SFLOW_EXTENDED_URL, "Extended URL information" },     
150         { 0, NULL }
151 };
152
153
154 /* flow sample header */
155 struct sflow_flow_sample_header {
156         guint32         sequence_number;
157         guint32         source_id;
158         guint32         sampling_rate;
159         guint32         sample_pool;
160         guint32         drops;
161         guint32         input;
162         guint32         output;
163 };
164
165 /* counters sample header */
166 struct sflow_counters_sample_header {
167         guint32         sequence_number;
168         guint32         source_id;
169         guint32         sampling_interval;
170         guint32     counters_type;
171 };
172
173 /* generic interface counters */
174 struct if_counters {
175         guint32         ifIndex;
176         guint32         ifType;
177         guint64         ifSpeed;
178         guint32         ifDirection;
179         guint32         ifStatus;
180         guint64         ifInOctets;
181         guint32         ifInUcastPkts;
182         guint32         ifInMulticastPkts;
183         guint32         ifInBroadcastPkts;
184         guint32         ifInDiscards;
185         guint32         ifInErrors;
186         guint32         ifInUnknownProtos;
187         guint64         ifOutOctets;
188         guint32         ifOutUcastPkts;
189         guint32         ifOutMulticastPkts;
190         guint32         ifOutBroadcastPkts;
191         guint32         ifOutDiscards;
192         guint32         ifOutErrors;
193         guint32         ifPromiscuousMode;
194 };
195
196 /* ethernet counters.  These will be preceded by generic counters. */
197 struct ethernet_counters {
198         guint32         dot3StatsAlignmentErrors;
199         guint32         dot3StatsFCSErrors;
200         guint32         dot3StatsSingleCollisionFrames;
201         guint32         dot3StatsMultipleCollisionFrames;
202         guint32         dot3StatsSQETestErrors;
203         guint32         dot3StatsDeferredTransmissions;
204         guint32         dot3StatsLateCollisions;
205         guint32         dot3StatsExcessiveCollisions;
206         guint32         dot3StatsInternalMacTransmitErrors;
207         guint32         dot3StatsCarrierSenseErrors;
208         guint32         dot3StatsFrameTooLongs;
209         guint32         dot3StatsInternalMacReceiveErrors;
210         guint32         dot3StatsSymbolErrors;
211 };
212
213 /* Token Ring counters */
214 struct token_ring_counters {
215         guint32         dot5StatsLineErrors;
216         guint32         dot5StatsBurstErrors;
217         guint32         dot5StatsACErrors;
218         guint32         dot5StatsAbortTransErrors;
219         guint32         dot5StatsInternalErrors;
220         guint32         dot5StatsLostFrameErrors;
221         guint32         dot5StatsReceiveCongestions;
222         guint32         dot5StatsFrameCopiedErrors;
223         guint32         dot5StatsTokenErrors;
224         guint32         dot5StatsSoftErrors;
225         guint32         dot5StatsHardErrors;
226         guint32         dot5StatsSignalLoss;
227         guint32         dot5StatsTransmitBeacons;
228         guint32         dot5StatsRecoverys;
229         guint32         dot5StatsLobeWires;
230         guint32         dot5StatsRemoves;
231         guint32         dot5StatsSingles;
232         guint32         dot5StatsFreqErrors;
233 };
234
235 /* 100BaseVG counters */
236
237 struct vg_counters {
238         guint32         dot12InHighPriorityFrames;
239         guint64         dot12InHighPriorityOctets;
240         guint32         dot12InNormPriorityFrames;
241         guint64         dot12InNormPriorityOctets;
242         guint32         dot12InIPMErrors;
243         guint32         dot12InOversizeFrameErrors;
244         guint32         dot12InDataErrors;
245         guint32         dot12InNullAddressedFrames;
246         guint32         dot12OutHighPriorityFrames;
247         guint64         dot12OutHighPriorityOctets;
248         guint32         dot12TransitionIntoTrainings;
249         guint64         dot12HCInHighPriorityOctets;
250         guint64         dot12HCInNormPriorityOctets;
251         guint64         dot12HCOutHighPriorityOctets;
252 };
253
254 /* VLAN counters */
255
256 struct vlan_counters {
257         guint32         vlan_id;
258         guint32         octets;
259         guint32         ucastPkts;
260         guint32         multicastPkts;
261         guint32         broadcastPkts;
262         guint32         discards;
263 };
264
265 /* Initialize the protocol and registered fields */
266 static int proto_sflow = -1;
267 static int hf_sflow_version = -1;
268 /*static int hf_sflow_agent_address_type = -1; */
269 static int hf_sflow_agent_address_v4 = -1;
270 static int hf_sflow_agent_address_v6 = -1;
271 static int hf_sflow_sub_agent_id = -1;
272 static int hf_sflow_seqnum = -1;
273 static int hf_sflow_sysuptime = -1;
274 static int hf_sflow_numsamples = -1;
275 static int hf_sflow_header_protocol = -1;
276 static int hf_sflow_sampletype = -1;
277 static int hf_sflow_header = -1;
278 static int hf_sflow_packet_information_type = -1;
279 static int hf_sflow_extended_information_type = -1;
280 static int hf_sflow_vlan_in = -1;   /* incoming 802.1Q VLAN ID */
281 static int hf_sflow_vlan_out = -1;   /* outgoing 802.1Q VLAN ID */
282 static int hf_sflow_pri_in = -1;   /* incominging 802.1p priority */
283 static int hf_sflow_pri_out = -1;   /* outgoing 802.1p priority */
284 static int hf_sflow_nexthop_v4 = -1;   /* nexthop address */
285 static int hf_sflow_nexthop_v6 = -1;   /* nexthop address */
286 static int hf_sflow_nexthop_src_mask = -1;
287 static int hf_sflow_nexthop_dst_mask = -1;
288 static int hf_sflow_ifindex = -1;
289 static int hf_sflow_iftype = -1;
290 static int hf_sflow_ifspeed = -1;
291 static int hf_sflow_ifdirection = -1;
292 static int hf_sflow_ifstatus = -1;
293 static int hf_sflow_ifinoct = -1;
294 static int hf_sflow_ifinpkt = -1;
295 static int hf_sflow_ifinmcast = -1;
296 static int hf_sflow_ifinbcast = -1;
297 static int hf_sflow_ifinerr = -1;
298 static int hf_sflow_ifindisc = -1;
299 static int hf_sflow_ifinunk = -1;
300 static int hf_sflow_ifoutoct = -1;
301 static int hf_sflow_ifoutpkt = -1;
302 static int hf_sflow_ifoutmcast = -1;
303 static int hf_sflow_ifoutbcast = -1;
304 static int hf_sflow_ifoutdisc = -1;
305 static int hf_sflow_ifouterr = -1;
306 static int hf_sflow_ifpromisc = -1;
307
308 /* Initialize the subtree pointers */
309 static gint ett_sflow = -1;
310 static gint ett_sflow_sample = -1;
311 static gint ett_sflow_extended_data = -1;
312 static gint ett_sflow_sampled_header = -1;
313
314 /* dissectors for other protocols */
315 static dissector_handle_t eth_withoutfcs_handle;
316 static dissector_handle_t tr_handle;
317 static dissector_handle_t fddi_handle;
318 static dissector_handle_t fr_handle;
319 static dissector_handle_t x25_handle;
320 static dissector_handle_t ppp_handle;
321 static dissector_handle_t smds_handle;
322 static dissector_handle_t aal5_handle;
323 static dissector_handle_t ipv4_handle;
324 static dissector_handle_t ipv6_handle;
325 static dissector_handle_t mpls_handle;
326
327 /* dissect a sampled header - layer 2 protocols */
328 static gint
329 dissect_sflow_sampled_header(tvbuff_t *tvb, packet_info *pinfo,
330                                                          proto_tree *tree, volatile gint offset)
331 {
332         guint32         header_proto, frame_length;
333         volatile        guint32         header_length;
334         tvbuff_t        *next_tvb;
335         proto_tree      *sflow_header_tree;
336         proto_item      *ti;
337         /* stuff for saving column state before calling other dissectors.
338          * Thanks to Guy Harris for the tip. */
339         gboolean                        save_writable;
340         volatile address        save_dl_src;
341         volatile address        save_dl_dst;
342         volatile address        save_net_src;
343         volatile address        save_net_dst;
344         volatile address        save_src;
345         volatile address        save_dst;
346
347         header_proto = tvb_get_ntohl(tvb,offset);
348         proto_tree_add_item(tree, hf_sflow_header_protocol, tvb, offset,
349                                                 4, FALSE);
350         offset += 4;
351         frame_length = tvb_get_ntohl(tvb,offset);
352         proto_tree_add_text(tree, tvb, offset, 4, "Frame Length: %d bytes",
353                                                 frame_length);
354         offset += 4;
355         header_length = tvb_get_ntohl(tvb,offset);
356         offset += 4;
357
358         if (header_length % 4) /* XDR requires 4-byte alignment */
359                 header_length += 4 - (header_length % 4);
360
361         
362         ti = proto_tree_add_item(tree, hf_sflow_header, tvb, offset, 
363                                                          header_length, FALSE);
364         sflow_header_tree = proto_item_add_subtree(ti, ett_sflow_sampled_header);
365
366         /* hand the header off to the appropriate dissector.  It's probably
367          * a short frame, so ignore any exceptions. */
368         next_tvb = tvb_new_subset(tvb, offset, header_length, frame_length);
369
370         /* save some state */
371         save_writable = col_get_writable(pinfo->cinfo);
372         col_set_writable(pinfo->cinfo, FALSE);
373         save_dl_src = pinfo->dl_src;
374         save_dl_dst = pinfo->dl_dst;
375         save_net_src = pinfo->net_src;
376         save_net_dst = pinfo->net_dst;
377         save_src = pinfo->src;
378         save_dst = pinfo->dst;
379
380         TRY {
381                 switch (header_proto) {
382                 case SFLOW_HEADER_ETHERNET:
383                         call_dissector(eth_withoutfcs_handle, next_tvb, pinfo, sflow_header_tree);
384                         break;
385                 case SFLOW_HEADER_TOKENRING:
386                         call_dissector(tr_handle, next_tvb, pinfo, sflow_header_tree);
387                         break;
388                 case SFLOW_HEADER_FDDI:
389                         call_dissector(fddi_handle, next_tvb, pinfo, sflow_header_tree);
390                         break;
391                 case SFLOW_HEADER_FRAME_RELAY:
392                         call_dissector(fr_handle, next_tvb, pinfo, sflow_header_tree);
393                         break;
394                 case SFLOW_HEADER_X25:
395                         call_dissector(x25_handle, next_tvb, pinfo, sflow_header_tree);
396                         break;
397                 case SFLOW_HEADER_PPP:
398                         call_dissector(ppp_handle, next_tvb, pinfo, sflow_header_tree);
399                         break;
400                 case SFLOW_HEADER_SMDS:
401                         call_dissector(smds_handle, next_tvb, pinfo, sflow_header_tree);
402                         break;
403                 case SFLOW_HEADER_AAL5:
404                 case SFLOW_HEADER_AAL5_IP:
405                         /* I'll be surprised if this works! I have no AAL5 captures
406                          * to test with, and I'm not sure how the encapsulation goes */
407                         call_dissector(aal5_handle, next_tvb, pinfo, sflow_header_tree);
408                         break;
409                 case SFLOW_HEADER_IPv4:
410                         call_dissector(ipv4_handle, next_tvb, pinfo, sflow_header_tree);
411                         break;
412                 case SFLOW_HEADER_IPv6:
413                         call_dissector(ipv6_handle, next_tvb, pinfo, sflow_header_tree);
414                         break;
415                 case SFLOW_HEADER_MPLS:
416                         call_dissector(mpls_handle, next_tvb, pinfo, sflow_header_tree);
417                         break;
418                 default:
419                         /* some of the protocols, I have no clue where to begin. */
420                         break;
421                 };
422         }
423         CATCH2(BoundsError, ReportedBoundsError) {
424                 ; /* do nothing */
425         }
426         ENDTRY;
427
428         /* restore saved state */
429         col_set_writable(pinfo->cinfo, save_writable);
430         pinfo->dl_src = save_dl_src;
431         pinfo->dl_dst = save_dl_dst;
432         pinfo->net_src = save_net_src;
433         pinfo->net_dst = save_net_dst;
434         pinfo->src = save_src;
435         pinfo->dst = save_dst;
436         
437         offset += header_length;
438         return offset;
439 }
440
441 /* extended switch data, after the packet data */
442 static gint
443 dissect_sflow_extended_switch(tvbuff_t *tvb, proto_tree *tree, gint offset)
444 {
445         gint32 len = 0;
446         
447         proto_tree_add_item(tree, hf_sflow_vlan_in, tvb, offset + len, 4, FALSE);
448         len += 4;
449         proto_tree_add_item(tree, hf_sflow_pri_in, tvb, offset + len, 4, FALSE);
450         len += 4;
451         proto_tree_add_item(tree, hf_sflow_vlan_out, tvb, offset + len, 4, FALSE);
452         len += 4;
453         proto_tree_add_item(tree, hf_sflow_pri_out, tvb, offset + len, 4, FALSE);
454         len += 4;
455
456         return len;
457 }
458
459 /* extended router data, after the packet data */
460 static gint
461 dissect_sflow_extended_router(tvbuff_t *tvb, proto_tree *tree, gint offset)
462 {
463         gint32  len = 0;
464         guint32 address_type;
465
466         address_type = tvb_get_ntohl(tvb, offset);
467         len += 4;
468         switch (address_type) {
469         case ADDRESS_IPV4:
470                 proto_tree_add_item(tree, hf_sflow_nexthop_v4, tvb, offset + len,
471                                                         4, FALSE);
472                 len += 4;
473                 break;
474         case ADDRESS_IPV6:
475                 proto_tree_add_item(tree, hf_sflow_nexthop_v6, tvb, offset + len,
476                                                         16, FALSE);
477                 len += 16;
478                 break;
479         default:
480                 proto_tree_add_text(tree, tvb, offset + len - 4, 4,
481                                                         "Unknown address type (%d)", address_type);
482                 len += 4;  /* not perfect, but what else to do? */
483                 return len;  /* again, this is wrong.  but... ? */
484                 break;
485         };
486         
487         proto_tree_add_item(tree, hf_sflow_nexthop_src_mask, tvb, offset + len,
488                                                         4, FALSE);
489         len += 4;
490         proto_tree_add_item(tree, hf_sflow_nexthop_dst_mask, tvb, offset + len,
491                                                         4, FALSE);
492         len += 4;
493         return len;
494 }
495
496 /* dissect a flow sample */
497 static gint
498 dissect_sflow_flow_sample(tvbuff_t *tvb, packet_info *pinfo,
499                                                   proto_tree *tree, gint offset, proto_item *parent)
500 {
501         struct sflow_flow_sample_header         flow_header;
502         proto_tree      *extended_data_tree;
503         proto_item *ti;
504         guint32         packet_type, extended_data, ext_type, i;
505
506         /* grab the flow header.  This will remain in network byte
507            order, so must convert each item before use */
508         tvb_memcpy(tvb,(guint8 *)&flow_header,offset,sizeof(flow_header));
509         proto_tree_add_text(tree, tvb, offset, 4,
510                                                 "Sequence number: %u",
511                                                 g_ntohl(flow_header.sequence_number));
512         proto_item_append_text(parent, ", seq %u",
513                                                    g_ntohl(flow_header.sequence_number));
514         proto_tree_add_text(tree, tvb, offset+4, 4,
515                                                 "Source ID class: %u index: %u",
516                                                 g_ntohl(flow_header.source_id) >> 24,
517                                                 g_ntohl(flow_header.source_id) & 0x00ffffff);
518         proto_tree_add_text(tree, tvb, offset+8, 4,
519                                                 "Sampling rate: 1 out of %u packets",
520                                                 g_ntohl(flow_header.sampling_rate));
521         proto_tree_add_text(tree, tvb, offset+12, 4,
522                                                 "Sample pool: %u total packets",
523                                                 g_ntohl(flow_header.sample_pool));
524         proto_tree_add_text(tree, tvb, offset+16, 4,
525                                                 "Dropped packets: %u",
526                                                 g_ntohl(flow_header.drops));
527         proto_tree_add_text(tree, tvb, offset+20, 4,
528                                                 "Input Interface: ifIndex %u",
529                                                 g_ntohl(flow_header.input));
530         if (g_ntohl(flow_header.output) >> 31)
531                 proto_tree_add_text(tree, tvb, offset+24, 4,
532                                                         "multiple outputs: %u interfaces",
533                                                         g_ntohl(flow_header.output) & 0x00ffffff);
534         else 
535                 proto_tree_add_text(tree, tvb, offset+24, 4,
536                                                         "Output interface: ifIndex %u",
537                                                         g_ntohl(flow_header.output) & 0x00ffffff);
538         offset += sizeof(flow_header);
539
540         /* what kind of flow sample is it? */
541         packet_type = tvb_get_ntohl(tvb, offset);
542         proto_tree_add_uint(tree, hf_sflow_packet_information_type, tvb, offset,
543             4, packet_type);
544         offset += 4;
545         switch (packet_type) {
546         case SFLOW_PACKET_DATA_TYPE_HEADER:
547                 offset = dissect_sflow_sampled_header(tvb, pinfo, tree, offset);
548                 break;
549         case SFLOW_PACKET_DATA_TYPE_IPV4:
550         case SFLOW_PACKET_DATA_TYPE_IPV6:
551         default:
552                 break;
553         };
554         /* still need to dissect extended data */
555         extended_data = tvb_get_ntohl(tvb,offset);
556         offset += 4; 
557
558         for (i=0; i < extended_data; i++) {
559                 /* figure out what kind of extended data it is */
560                 ext_type = tvb_get_ntohl(tvb,offset);
561
562                 /* create a subtree.  Might want to move this to
563                  * the end, so more info can be correct.
564                  */
565                 ti = proto_tree_add_text(tree, tvb, offset, -1, "%s",
566                                                                  val_to_str(ext_type, 
567                                                                                         sflow_extended_data_types,
568                                                                                         "Unknown extended information"));
569                 extended_data_tree = proto_item_add_subtree(ti, ett_sflow_extended_data);
570                 proto_tree_add_uint(extended_data_tree,
571                     hf_sflow_extended_information_type, tvb, offset, 4,
572                     ext_type);
573                 offset += 4;
574
575                 switch (ext_type) {
576                 case SFLOW_EXTENDED_SWITCH:
577                         offset += dissect_sflow_extended_switch(tvb, extended_data_tree,
578                                                                                                         offset);
579                         break;
580                 case SFLOW_EXTENDED_ROUTER:
581                         offset += dissect_sflow_extended_router(tvb, extended_data_tree,
582                                                                                                         offset);
583                         break;
584                 case SFLOW_EXTENDED_GATEWAY:
585                         break;
586                 case SFLOW_EXTENDED_USER:
587                         break;
588                 case SFLOW_EXTENDED_URL:
589                         break;
590                 default:
591                         break;
592                 }
593                 proto_item_set_end(ti, tvb, offset);
594         }
595         return offset;
596         
597 }
598
599 /* dissect a counters sample */
600 static gint
601 dissect_sflow_counters_sample(tvbuff_t *tvb, proto_tree *tree,
602                                                           gint offset, proto_item *parent)
603 {
604         struct sflow_counters_sample_header     counters_header;
605         struct if_counters ifc;
606         struct ethernet_counters ethc;
607         struct token_ring_counters tokc;
608         struct vg_counters vgc;
609         struct vlan_counters vlanc;
610         
611         /* grab the flow header.  This will remain in network byte
612            order, so must convert each item before use */
613         tvb_memcpy(tvb,(guint8 *)&counters_header,offset,sizeof(counters_header));
614         proto_tree_add_text(tree, tvb, offset, 4,
615                                                 "Sequence number: %u",
616                                                 g_ntohl(counters_header.sequence_number));
617         proto_item_append_text(parent, ", seq %u",
618                                                    g_ntohl(counters_header.sequence_number));
619         proto_tree_add_text(tree, tvb, offset + 4, 4,
620                                                 "Source ID class: %u index: %u",
621                                                 g_ntohl(counters_header.source_id) >> 24,
622                                                 g_ntohl(counters_header.source_id) & 0x00ffffff);
623         proto_tree_add_text(tree, tvb, offset + 8, 4,
624                                                 "Sampling Interval: %u",
625                                                 g_ntohl(counters_header.sampling_interval));
626         proto_tree_add_text(tree, tvb, offset + 12, 4, "Counters type: %s",
627                                                 val_to_str(g_ntohl(counters_header.counters_type),
628                                                                    sflow_counterstype, "Unknown type"));
629
630         offset += sizeof(counters_header);
631
632         /* most counters types have the "generic" counters first */
633         switch (g_ntohl(counters_header.counters_type)) {
634         case SFLOW_COUNTERS_GENERIC:
635         case SFLOW_COUNTERS_ETHERNET:
636         case SFLOW_COUNTERS_TOKENRING:
637         case SFLOW_COUNTERS_FDDI:
638         case SFLOW_COUNTERS_VG:
639         case SFLOW_COUNTERS_WAN:
640                 tvb_memcpy(tvb,(guint8 *)&ifc, offset, sizeof(ifc));
641                 proto_item_append_text(parent, ", ifIndex %u",
642                                                            g_ntohl(ifc.ifIndex));
643                 proto_tree_add_item(tree, hf_sflow_ifindex, tvb, offset, 4, FALSE);
644                 offset += 4;
645                 proto_tree_add_item(tree, hf_sflow_iftype, tvb, offset, 4, FALSE);
646                 offset += 4;
647                 proto_tree_add_item(tree, hf_sflow_ifspeed, tvb, offset, 8, FALSE);
648                 offset += 8;
649                 proto_tree_add_item(tree, hf_sflow_ifdirection, tvb, offset, 
650                                                         4, FALSE);
651                 offset += 4;
652                 proto_tree_add_item(tree, hf_sflow_ifstatus, tvb, offset, 4, FALSE);
653                 offset += 4;
654                 proto_tree_add_item(tree, hf_sflow_ifinoct, tvb, offset, 8, FALSE);
655                 offset += 8;
656                 proto_tree_add_item(tree, hf_sflow_ifinpkt, tvb, offset, 4, FALSE);
657                 offset += 4;
658                 proto_tree_add_item(tree, hf_sflow_ifinmcast, tvb, offset,
659                                                         4, FALSE);
660                 offset += 4;
661                 proto_tree_add_item(tree, hf_sflow_ifinbcast, tvb, offset,
662                                                         4, FALSE);
663                 offset += 4;
664                 proto_tree_add_item(tree, hf_sflow_ifindisc, tvb, offset,
665                                                         4, FALSE);
666                 offset += 4;
667                 proto_tree_add_item(tree, hf_sflow_ifinerr, tvb, offset,
668                                                         4, FALSE);
669                 offset += 4;
670                 proto_tree_add_item(tree, hf_sflow_ifinunk, tvb, offset,
671                                                         4, FALSE);
672                 offset += 4;
673                 proto_tree_add_item(tree, hf_sflow_ifoutoct, tvb, offset, 8, FALSE);
674                 offset += 8;
675                 proto_tree_add_item(tree, hf_sflow_ifoutpkt, tvb, offset, 4, FALSE);
676                 offset += 4;
677                 proto_tree_add_item(tree, hf_sflow_ifoutmcast, tvb, offset,
678                                                         4, FALSE);
679                 offset += 4;
680                 proto_tree_add_item(tree, hf_sflow_ifoutbcast, tvb, offset,
681                                                         4, FALSE);
682                 offset += 4;
683                 proto_tree_add_item(tree, hf_sflow_ifoutdisc, tvb, offset,
684                                                         4, FALSE);
685                 offset += 4;
686                 proto_tree_add_item(tree, hf_sflow_ifouterr, tvb, offset,
687                                                         4, FALSE);
688                 offset += 4;
689                 proto_tree_add_item(tree, hf_sflow_ifpromisc, tvb, offset,
690                                                         4, FALSE);
691                 offset += 4;
692                 break;
693         };
694         
695         /* Some counter types have other info to gather */
696         switch (g_ntohl(counters_header.counters_type)) {
697         case SFLOW_COUNTERS_ETHERNET:
698                 tvb_memcpy(tvb,(guint8 *)&ethc, offset, sizeof(ethc));
699                 offset += sizeof(ethc);
700                 break;
701         case SFLOW_COUNTERS_TOKENRING:
702                 tvb_memcpy(tvb,(guint8 *)&tokc, offset, sizeof(tokc));
703                 offset += sizeof(tokc);
704                 break;
705         case SFLOW_COUNTERS_VG:
706                 tvb_memcpy(tvb,(guint8 *)&vgc, offset, sizeof(vgc));
707                 offset += sizeof(vgc);
708                 break;
709         case SFLOW_COUNTERS_VLAN:
710                 tvb_memcpy(tvb,(guint8 *)&vlanc, offset, sizeof(vlanc));
711                 offset += sizeof(vlanc);
712                 break;
713         default:
714                 break;
715         }
716         return offset;
717 }
718
719 /* Code to dissect the sflow samples */
720 static gint
721 dissect_sflow_samples(tvbuff_t *tvb, packet_info *pinfo,
722                                           proto_tree *tree, gint offset)
723 {
724         proto_tree      *sflow_sample_tree;
725         proto_item      *ti; /* tree item */
726         guint32         sample_type;
727         
728         /* decide what kind of sample it is. */
729         sample_type = tvb_get_ntohl(tvb,offset);
730
731         ti = proto_tree_add_text(tree, tvb, offset, -1, "%s",
732                                                          val_to_str(sample_type, sflow_sampletype,
733                                                                                 "Unknown sample type"));
734         sflow_sample_tree = proto_item_add_subtree(ti, ett_sflow_sample);
735
736         proto_tree_add_item(sflow_sample_tree, hf_sflow_sampletype, tvb,
737                                                 offset, 4, FALSE);
738         offset += 4;
739
740         switch (sample_type) {
741         case FLOWSAMPLE:
742                 offset = dissect_sflow_flow_sample(tvb, pinfo, sflow_sample_tree,
743                                                                                  offset, ti);
744                 break;
745         case COUNTERSSAMPLE:
746                 offset = dissect_sflow_counters_sample(tvb, sflow_sample_tree,
747                                                                                          offset, ti);
748                 break;
749         default:
750                 break;
751         }
752         proto_item_set_end(ti, tvb, offset);
753         return offset;
754 }
755
756 /* Code to actually dissect the packets */
757 static void
758 dissect_sflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
759 {
760
761 /* Set up structures needed to add the protocol subtree and manage it */
762         proto_item *ti;
763         proto_tree *sflow_tree;
764         guint32         version, sub_agent_id, seqnum;
765         guint32         agent_address_type;
766         union {
767                 guint8  v4[4];
768                 guint8  v6[16];
769         } agent_address;
770         guint32         numsamples;
771         volatile guint          offset=0;
772         guint   i=0;
773
774 /* Make entries in Protocol column and Info column on summary display */
775         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
776                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "sFlow");
777     
778
779         /* create display subtree for the protocol */
780         ti = proto_tree_add_item(tree, proto_sflow, tvb, 0, -1, FALSE);
781         
782         sflow_tree = proto_item_add_subtree(ti, ett_sflow);
783                 
784         version = tvb_get_ntohl(tvb, offset);
785         if (check_col(pinfo->cinfo, COL_INFO)) 
786                 col_add_fstr(pinfo->cinfo, COL_INFO, "V%u",
787                                          version);
788         proto_tree_add_item(sflow_tree,
789                                                 hf_sflow_version, tvb, offset, 4, FALSE);
790         offset += 4;
791
792         agent_address_type = tvb_get_ntohl(tvb, offset);
793         offset += 4;
794         switch (agent_address_type) {
795         case ADDRESS_IPV4:
796                 tvb_memcpy(tvb, agent_address.v4, offset, 4);
797                 if (check_col(pinfo->cinfo, COL_INFO)) 
798                         col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
799                                                  ip_to_str(agent_address.v4));
800                 proto_tree_add_item(sflow_tree,
801                                                         hf_sflow_agent_address_v4, tvb, offset,
802                                                         4, FALSE);
803                 offset += 4;
804                 break;
805         case ADDRESS_IPV6:
806                 tvb_memcpy(tvb, agent_address.v6, offset, 16);
807                 if (check_col(pinfo->cinfo, COL_INFO)) 
808                         col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
809                                                         ip6_to_str((struct e_in6_addr *)agent_address.v6));
810                 proto_tree_add_item(sflow_tree,
811                                                         hf_sflow_agent_address_v6, tvb, offset,
812                                                         16, FALSE);
813                 offset += 16;
814                 break;
815         default:
816                 /* unknown address.  this will cause a malformed packet.  */
817                 break;
818         };
819
820         if (version == 5) {
821                 sub_agent_id = tvb_get_ntohl(tvb, offset);
822                 if (check_col(pinfo->cinfo, COL_INFO)) 
823                         col_append_fstr(pinfo->cinfo, COL_INFO, ", sub-agent ID %u",
824                                                         sub_agent_id);
825                 proto_tree_add_uint(sflow_tree, hf_sflow_sub_agent_id, tvb,
826                                                 offset, 4, sub_agent_id);
827                 offset += 4;
828         }
829         seqnum = tvb_get_ntohl(tvb, offset);
830         if (check_col(pinfo->cinfo, COL_INFO))
831                 col_append_fstr(pinfo->cinfo, COL_INFO, ", seq %u", seqnum);
832         proto_tree_add_uint(sflow_tree, hf_sflow_seqnum, tvb,
833                                                 offset, 4, seqnum);
834         offset += 4;
835         proto_tree_add_item(sflow_tree, hf_sflow_sysuptime, tvb,
836                                                 offset, 4, FALSE);
837         offset += 4;
838         numsamples = tvb_get_ntohl(tvb,offset);
839         if (check_col(pinfo->cinfo, COL_INFO))
840                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u samples",
841                                                 numsamples);
842         proto_tree_add_uint(sflow_tree, hf_sflow_numsamples, tvb,
843                                                 offset, 4, numsamples);
844         offset += 4;
845
846         /* Ok, we're now at the end of the sflow datagram header;
847          * everything from here out should be samples. Loop over
848          * the expected number of samples, and pass them to the appropriate
849          * dissectors.
850          */
851         if (version == 5) {
852                 proto_tree_add_text(sflow_tree, tvb, offset, -1,
853                     "sFlow V5 samples (please write and contribute code to dissect them!)");
854         } else {
855                 for (i=0; i < numsamples; i++) {
856                         offset = dissect_sflow_samples(tvb, pinfo, sflow_tree,
857                             offset);
858                 }
859         }
860 }
861
862
863 /* Register the protocol with Wireshark */
864
865 /* this format is require because a script is used to build the C function
866    that calls all the protocol registration.
867 */
868
869 void
870 proto_register_sflow(void)
871 {                 
872
873 /* Setup list of header fields  See Section 1.6.1 for details*/
874         static hf_register_info hf[] = {
875                 { &hf_sflow_version,
876                         { "datagram version", "sflow.version",
877                         FT_UINT32, BASE_DEC, NULL, 0x0,          
878                         "sFlow datagram version", HFILL }
879                 },
880                 { &hf_sflow_agent_address_v4,
881                         { "agent address", "sflow.agent",
882                         FT_IPv4, BASE_NONE, NULL, 0x0,          
883                         "sFlow Agent IP address", HFILL }
884                 },
885                 { &hf_sflow_agent_address_v6,
886                         { "agent address", "sflow.agent.v6",
887                         FT_IPv6, BASE_NONE, NULL, 0x0,          
888                         "sFlow Agent IPv6 address", HFILL }
889                 },
890                 { &hf_sflow_sub_agent_id,
891                         { "Sub-agent ID", "sflow.sub_agent_id",
892                         FT_UINT32, BASE_DEC, NULL, 0x0,          
893                         "sFlow sub-agent ID", HFILL }
894                 },
895                 { &hf_sflow_seqnum,
896                         { "Sequence number", "sflow.sequence_number",
897                         FT_UINT32, BASE_DEC, NULL, 0x0,          
898                         "sFlow datagram sequence number", HFILL }
899                 },
900                 { &hf_sflow_sysuptime,
901                         { "SysUptime", "sflow.sysuptime",
902                         FT_UINT32, BASE_DEC, NULL, 0x0,          
903                         "System Uptime", HFILL }
904                 },
905                 { &hf_sflow_numsamples,
906                         { "NumSamples", "sflow.numsamples",
907                         FT_UINT32, BASE_DEC, NULL, 0x0,          
908                         "Number of samples in sFlow datagram", HFILL }
909                 },
910                 { &hf_sflow_sampletype,
911                         { "sFlow sample type", "sflow.sampletype",
912                         FT_UINT32, BASE_DEC, VALS(sflow_sampletype), 0x0,          
913                         "Type of sFlow sample", HFILL }
914                 },
915                 { &hf_sflow_header_protocol,
916                         { "Header protocol", "sflow.header_protocol",
917                         FT_UINT32, BASE_DEC, VALS(sflow_header_protocol), 0x0,          
918                         "Protocol of sampled header", HFILL }
919                 },
920                 { &hf_sflow_header,
921                         { "Header of sampled packet", "sflow.header",
922                         FT_BYTES, BASE_HEX, NULL, 0x0,          
923                         "Data from sampled header", HFILL }
924                 },
925                 { &hf_sflow_packet_information_type,
926                         { "Sample type", "sflow.packet_information_type",
927                         FT_UINT32, BASE_DEC, VALS(sflow_packet_information_type), 0x0,
928                         "Type of sampled information", HFILL }
929                 },
930                 { &hf_sflow_extended_information_type,
931                         { "Extended information type", "sflow.extended_information_type",
932                         FT_UINT32, BASE_DEC, VALS(sflow_extended_data_types), 0x0,
933                         "Type of extended information", HFILL }
934                 },
935                 { &hf_sflow_vlan_in,
936                         { "Incoming 802.1Q VLAN", "sflow.vlan.in",
937                         FT_UINT32, BASE_DEC, NULL, 0x0,
938                         "Incoming VLAN ID", HFILL }
939                 },
940                 { &hf_sflow_vlan_out,
941                         { "Outgoing 802.1Q VLAN", "sflow.vlan.out",
942                         FT_UINT32, BASE_DEC, NULL, 0x0,
943                         "Outgoing VLAN ID", HFILL }
944                 },
945                 { &hf_sflow_pri_in,
946                         { "Incoming 802.1p priority", "sflow.pri.in",
947                         FT_UINT32, BASE_DEC, NULL, 0x0,
948                         "Incoming 802.1p priority", HFILL }
949                 },
950                 { &hf_sflow_pri_out,
951                         { "Outgoing 802.1p priority", "sflow.pri.out",
952                         FT_UINT32, BASE_DEC, NULL, 0x0,
953                         "Outgoing 802.1p priority", HFILL }
954                 },
955                 { &hf_sflow_nexthop_v4,
956                         { "Next hop", "sflow.nexthop",
957                         FT_IPv4, BASE_DEC, NULL, 0x0,
958                         "Next hop address", HFILL }
959                 },
960                 { &hf_sflow_nexthop_v6,
961                         { "Next hop", "sflow.nexthop",
962                         FT_IPv6, BASE_HEX, NULL, 0x0,
963                         "Next hop address", HFILL }
964                 },
965                 { &hf_sflow_nexthop_src_mask,
966                   { "Next hop source mask", "sflow.nexthop.src_mask",
967                         FT_UINT32, BASE_DEC, NULL, 0x0,
968                         "Next hop source mask bits", HFILL }
969                 },
970                 { &hf_sflow_nexthop_dst_mask,
971                   { "Next hop destination mask", "sflow.nexthop.dst_mask",
972                         FT_UINT32, BASE_DEC, NULL, 0x0,
973                         "Next hop destination mask bits", HFILL }
974                 },
975                 { &hf_sflow_ifindex,
976                   { "Interface index", "sflow.ifindex",
977                         FT_UINT32, BASE_DEC, NULL, 0x0,
978                         "Interface Index", HFILL }
979                 },
980                 { &hf_sflow_iftype,
981                   { "Interface Type", "sflow.iftype",
982                         FT_UINT32, BASE_DEC, NULL, 0x0,
983                         "Interface Type", HFILL }
984                 },
985                 { &hf_sflow_ifspeed,
986                   { "Interface Speed", "sflow.ifspeed",
987                         FT_UINT64, BASE_DEC, NULL, 0x0,
988                         "Interface Speed", HFILL }
989                 },
990                 { &hf_sflow_ifdirection,
991                   { "Interface Direction", "sflow.ifdirection",
992                         FT_UINT32, BASE_DEC, NULL, 0x0,
993                         "Interface Direction", HFILL }
994                 },
995                 { &hf_sflow_ifstatus,
996                   { "Interface Status", "sflow.ifstatus",
997                         FT_UINT32, BASE_DEC, NULL, 0x0,
998                         "Interface Status", HFILL }
999                 },
1000                 { &hf_sflow_ifinoct,
1001                   { "Input Octets", "sflow.ifinoct",
1002                         FT_UINT64, BASE_DEC, NULL, 0x0,
1003                         "Interface Input Octets", HFILL }
1004                 },
1005                 { &hf_sflow_ifinpkt,
1006                   { "Input Packets", "sflow.ifinpkt",
1007                         FT_UINT32, BASE_DEC, NULL, 0x0,
1008                         "Interface Input Packets", HFILL }
1009                 },
1010                 { &hf_sflow_ifinmcast,
1011                   { "Input Multicast Packets", "sflow.ifinmcast",
1012                         FT_UINT32, BASE_DEC, NULL, 0x0,
1013                         "Interface Input Multicast Packets", HFILL }
1014                 },
1015                 { &hf_sflow_ifinbcast,
1016                   { "Input Broadcast Packets", "sflow.ifinbcast",
1017                         FT_UINT32, BASE_DEC, NULL, 0x0,
1018                         "Interface Input Broadcast Packets", HFILL }
1019                 },
1020                 { &hf_sflow_ifindisc,
1021                   { "Input Discarded Packets", "sflow.ifindisc",
1022                         FT_UINT32, BASE_DEC, NULL, 0x0,
1023                         "Interface Input Discarded Packets", HFILL }
1024                 },
1025                 { &hf_sflow_ifinerr,
1026                   { "Input Errors", "sflow.ifinerr",
1027                         FT_UINT32, BASE_DEC, NULL, 0x0,
1028                         "Interface Input Errors", HFILL }
1029                 },
1030                 { &hf_sflow_ifinunk,
1031                   { "Input Unknown Protocol Packets", "sflow.ifinunk",
1032                         FT_UINT32, BASE_DEC, NULL, 0x0,
1033                         "Interface Input Unknown Protocol Packets", HFILL }
1034                 },
1035                 { &hf_sflow_ifoutoct,
1036                   { "Output Octets", "sflow.ifoutoct",
1037                         FT_UINT64, BASE_DEC, NULL, 0x0,
1038                         "Outterface Output Octets", HFILL }
1039                 },
1040                 { &hf_sflow_ifoutpkt,
1041                   { "Output Packets", "sflow.ifoutpkt",
1042                         FT_UINT32, BASE_DEC, NULL, 0x0,
1043                         "Interface Output Packets", HFILL }
1044                 },
1045                 { &hf_sflow_ifoutmcast,
1046                   { "Output Multicast Packets", "sflow.ifoutmcast",
1047                         FT_UINT32, BASE_DEC, NULL, 0x0,
1048                         "Interface Output Multicast Packets", HFILL }
1049                 },
1050                 { &hf_sflow_ifoutbcast,
1051                   { "Output Broadcast Packets", "sflow.ifoutbcast",
1052                         FT_UINT32, BASE_DEC, NULL, 0x0,
1053                         "Interface Output Broadcast Packets", HFILL }
1054                 },
1055                 { &hf_sflow_ifoutdisc,
1056                   { "Output Discarded Packets", "sflow.ifoutdisc",
1057                         FT_UINT32, BASE_DEC, NULL, 0x0,
1058                         "Interface Output Discarded Packets", HFILL }
1059                 },
1060                 { &hf_sflow_ifouterr,
1061                   { "Output Errors", "sflow.ifouterr",
1062                         FT_UINT32, BASE_DEC, NULL, 0x0,
1063                         "Interface Output Errors", HFILL }
1064                 },
1065                 { &hf_sflow_ifpromisc,
1066                   { "Promiscuous Mode", "sflow.ifpromisc",
1067                         FT_UINT32, BASE_DEC, NULL, 0x0,
1068                         "Interface Promiscuous Mode", HFILL }
1069                 },
1070         };
1071
1072 /* Setup protocol subtree array */
1073         static gint *ett[] = {
1074                 &ett_sflow,
1075                 &ett_sflow_sample,
1076                 &ett_sflow_extended_data,
1077                 &ett_sflow_sampled_header,
1078         };
1079
1080 /* Register the protocol name and description */
1081         proto_sflow = proto_register_protocol("InMon sFlow",
1082             "sFlow", "sflow");
1083
1084 /* Required function calls to register the header fields and subtrees used */
1085         proto_register_field_array(proto_sflow, hf, array_length(hf));
1086         proto_register_subtree_array(ett, array_length(ett));
1087 }
1088
1089
1090 /* If this dissector uses sub-dissector registration add a registration routine.
1091    This format is required because a script is used to find these routines and
1092    create the code that calls these routines.
1093 */
1094 void
1095 proto_reg_handoff_sflow(void)
1096 {
1097         dissector_handle_t sflow_handle;
1098
1099         /*
1100          * XXX - should this be done with a dissector table?
1101          */
1102         eth_withoutfcs_handle = find_dissector("eth_withoutfcs");
1103         tr_handle = find_dissector("tr");
1104         fddi_handle = find_dissector("fddi");
1105         fr_handle = find_dissector("fr");
1106         x25_handle = find_dissector("x.25");
1107         ppp_handle = find_dissector("ppp");
1108 #if 0
1109         smds_handle = find_dissector("smds");
1110 #else
1111         /* We don't have an SMDS dissector yet */
1112         smds_handle = find_dissector("data");
1113 #endif
1114 #if 0
1115         aal5_handle = find_dissector("atm");
1116 #else
1117         /* What dissector should be used here? */
1118         aal5_handle = find_dissector("data");
1119 #endif
1120         ipv4_handle = find_dissector("ip");
1121         ipv6_handle = find_dissector("ipv6");
1122         mpls_handle = find_dissector("mpls");
1123
1124         sflow_handle = create_dissector_handle(dissect_sflow,
1125             proto_sflow);
1126         dissector_add("udp.port", UDP_PORT_SFLOW, sflow_handle);
1127 }