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