Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Wireshark-dev: Re: [Wireshark-dev] Radius Statistics Patch

From: Alejandro Vaquero <alejandrovaquero@xxxxxxxxx>
Date: Mon, 23 Oct 2006 08:43:17 -0700
Here it is...

LEGO wrote:
Alejandro,
  Could you (g)zip the patch and send it back?

On 10/23/06, Alejandro Vaquero <alejandrovaquero@xxxxxxxxx> wrote:
Hi All,
    find attached a patch for the Radius dissector to add statistics in
the "Service Response Time" menu and the tshark stats.

Regards
Alejandro


Index: config.nmake
===================================================================
--- config.nmake        (revision 19652)
+++ config.nmake        (working copy)
@@ -205,14 +205,16 @@
 # If you don't have PORTAUDIO, comment this line out, so that
 # PORTAUDIO_DIR isn't defined.
 #
-PORTAUDIO_DIR=$(WIRESHARK_LIBS)\portaudio_v18_1
+#PORTAUDIO_DIR=$(WIRESHARK_LIBS)\portaudio_v18_1
+PORTAUDIO_DIR=$(WIRESHARK_LIBS)\portaudio_v19
+
 #PORTAUDIO_DIR=$(WIRESHARK_LIBS)\portaudio_v19

 #
 # Version number of PortAudio
 #
-PORTAUDIO_VERSION=18
-#PORTAUDIO_VERSION=19
+#PORTAUDIO_VERSION=18
+PORTAUDIO_VERSION=19

 #
 # Mandatory for GTK >= 2: Iconv
Index: epan/dissectors/packet-radius.c
===================================================================
--- epan/dissectors/packet-radius.c     (revision 19652)
+++ epan/dissectors/packet-radius.c     (working copy)
@@ -4,6 +4,7 @@
  * Copyright 1999 Johan Feyaerts
  * Changed 03/12/2003 Rui Carmo (http://the.taoofmac.com - added all 3GPP VSAs, some parsing)
  * Changed 07/2005 Luis Ontanon <luis.ontanon@xxxxxxxxx> - use FreeRADIUS' dictionary
+ * Changed 10/2006 Alejandro Vaquero <alejandrovaquero@xxxxxxxxx> - add Conversations support
  *
  * $Id$
  *
@@ -60,6 +61,8 @@
 #include <epan/crypt-md5.h>
 #include <epan/sminmpec.h>
 #include <epan/filesystem.h>
+#include <epan/conversation.h>
+#include <epan/tap.h>
 #include <epan/addr_resolv.h>
 #include <epan/emem.h>

@@ -86,38 +89,20 @@
 #define UDP_PORT_RADACCT       1646
 #define UDP_PORT_RADACCT_NEW   1813

-#define RADIUS_ACCESS_REQUEST                  1
-#define RADIUS_ACCESS_ACCEPT                   2
-#define RADIUS_ACCESS_REJECT                   3
-#define RADIUS_ACCOUNTING_REQUEST              4
-#define RADIUS_ACCOUNTING_RESPONSE             5
-#define RADIUS_ACCOUNTING_STATUS               6
-#define RADIUS_ACCESS_PASSWORD_REQUEST         7
-#define RADIUS_ACCESS_PASSWORD_ACK             8
-#define RADIUS_ACCESS_PASSWORD_REJECT          9
-#define RADIUS_ACCOUNTING_MESSAGE              10
-#define RADIUS_ACCESS_CHALLENGE                        11
-#define RADIUS_STATUS_SERVER                   12
-#define RADIUS_STATUS_CLIENT                   13
+static radius_dictionary_t* dict = NULL;

-#define RADIUS_VENDOR_SPECIFIC_CODE            26
-#define RADIUS_ASCEND_ACCESS_NEXT_CODE         29
-#define RADIUS_ASCEND_ACCESS_NEW_PIN           30
-#define RADIUS_ASCEND_PASSWORD_EXPIRED         32
-#define RADIUS_ASCEND_ACCESS_EVENT_REQUEST     33
-#define RADIUS_ASCEND_ACCESS_EVENT_RESPONSE    34
-#define RADIUS_DISCONNECT_REQUEST              40
-#define RADIUS_DISCONNECT_REQUEST_ACK          41
-#define RADIUS_DISCONNECT_REQUEST_NAK          42
-#define RADIUS_CHANGE_FILTER_REQUEST           43
-#define RADIUS_CHANGE_FILTER_REQUEST_ACK       44
-#define RADIUS_CHANGE_FILTER_REQUEST_NAK       45
-#define RADIUS_EAP_MESSAGE_CODE                                79
-#define RADIUS_RESERVED                                255
+static int proto_radius = -1;

-static radius_dictionary_t* dict = NULL;
+static int hf_radius_req = -1;
+static int hf_radius_rsp = -1;
+static int hf_radius_req_frame = -1;
+static int hf_radius_rsp_frame = -1;
+static int hf_radius_time = -1;

-static int proto_radius = -1;
+static int hf_radius_dup = -1;
+static int hf_radius_req_dup = -1;
+static int hf_radius_rsp_dup = -1;
+
 static int hf_radius_id = -1;
 static int hf_radius_code = -1;
 static int hf_radius_length = -1;
@@ -134,6 +119,11 @@
 static gint ett_radius_avp = -1;
 static gint ett_eap = -1;

+/*
+ * Define the tap for radius
+ */
+static int radius_tap = -1;
+
 radius_vendor_info_t no_vendor = {"Unknown Vendor",0,NULL,-1};

 radius_attr_info_t no_dictionary_entry = {"Unknown-Attribute",0,FALSE,FALSE,radius_octets, NULL, NULL, -1, -1, -1, -1, -1 };
@@ -150,6 +140,8 @@

 static const value_string* radius_vendors = NULL;

+static radius_info_t rad_info;
+
 static const value_string radius_vals[] =
 {
        {RADIUS_ACCESS_REQUEST,         "Access-Request"},
@@ -181,6 +173,67 @@
        {0, NULL}
 };

+/*
+ * Init Hash table stuff for converation
+ */
+
+typedef struct _radius_call_info_key
+{
+       guint code;
+       guint ident;
+       conversation_t *conversation;
+       nstime_t req_time;
+} radius_call_info_key;
+
+static GMemChunk *radius_call_info_key_chunk;
+static GMemChunk *radius_call_info_value_chunk;
+static GHashTable *radius_calls;
+
+/* Compare 2 keys */
+static gint radius_call_equal(gconstpointer k1, gconstpointer k2)
+{
+       const radius_call_info_key* key1 = (const radius_call_info_key*) k1;
+       const radius_call_info_key* key2 = (const radius_call_info_key*) k2;
+
+       if (key1->ident == key2->ident && key1->conversation == key2->conversation) {
+               nstime_t delta;
+
+               nstime_delta(&delta, &key1->req_time, &key2->req_time);
+               if (abs(nstime_to_sec(&delta)) > (double) 5) return 0;
+
+               if (key1->code == key2->code)
+                       return 1;
+               /* check the request and response are of the same code type */
+               if (key1->code == RADIUS_ACCESS_REQUEST && ( key2->code == RADIUS_ACCESS_ACCEPT || key2->code == RADIUS_ACCESS_REJECT ) )
+                       return 1;
+
+               if (key1->code == RADIUS_ACCOUNTING_REQUEST && key2->code == RADIUS_ACCOUNTING_RESPONSE )
+                       return 1;
+
+               if (key1->code == RADIUS_ACCESS_PASSWORD_REQUEST && ( key2->code == RADIUS_ACCESS_PASSWORD_ACK || key2->code == RADIUS_ACCESS_PASSWORD_REJECT ) )
+                       return 1;
+
+               if (key1->code == RADIUS_ASCEND_ACCESS_EVENT_REQUEST && key2->code == RADIUS_ASCEND_ACCESS_EVENT_RESPONSE )
+                       return 1;
+
+               if (key1->code == RADIUS_DISCONNECT_REQUEST && ( key2->code == RADIUS_DISCONNECT_REQUEST_ACK || key2->code == RADIUS_DISCONNECT_REQUEST_NAK ) )
+                       return 1;
+
+               if (key1->code == RADIUS_CHANGE_FILTER_REQUEST && ( key2->code == RADIUS_CHANGE_FILTER_REQUEST_ACK || key2->code == RADIUS_CHANGE_FILTER_REQUEST_NAK ) )
+                       return 1;
+       }
+       return 0;
+}
+
+/* Calculate a hash key */
+static guint radius_call_hash(gconstpointer k)
+{
+       const radius_call_info_key* key = (const radius_call_info_key*) k;
+
+       return key->ident + /*key->code + */ key->conversation->index;
+}
+
+
 static const gchar *dissect_framed_ip_address(proto_tree* tree, tvbuff_t* tvb) {
        int len;
        guint32 ip;
@@ -790,7 +843,24 @@
        guint rhident;
        guint avplength;
        e_radiushdr rh;
-
+
+       conversation_t* conversation;
+       radius_call_info_key radius_call_key;
+       radius_call_info_key *new_radius_call_key = NULL;
+       radius_call_t *radius_call = NULL;
+       nstime_t delta;
+       static address null_address = { AT_NONE, 0, NULL };
+
+       /* Initialise stat info for passing to tap */
+       rad_info.code = 0;
+       rad_info.ident = 0;
+       rad_info.req_time.secs = 0;
+       rad_info.req_time.nsecs = 0;
+       rad_info.is_duplicate = FALSE;
+       rad_info.request_available = FALSE;
+       rad_info.req_num = 0; /* frame number request seen */
+       rad_info.rspcode = 0;
+
        if (check_col(pinfo->cinfo, COL_PROTOCOL))
                col_set_str(pinfo->cinfo, COL_PROTOCOL, "RADIUS");
        if (check_col(pinfo->cinfo, COL_INFO))
@@ -813,6 +883,10 @@
                *  is 4096.
                */

+       /* tap stat info */
+       rad_info.code = rhcode;
+       rad_info.ident = rhident;
+
        if (check_col(pinfo->cinfo, COL_INFO))
        {
                col_add_fstr(pinfo->cinfo,COL_INFO,"%s(%d) (id=%d, l=%d)",
@@ -856,15 +930,225 @@
        }
        tvb_memcpy(tvb,authenticator,4,AUTHENTICATOR_LENGTH);

-       if (tree && avplength > 0) {
-               /* list the attribute value pairs */
-               avptf = proto_tree_add_text(radius_tree, tvb, HDR_LENGTH,
-                                           avplength, "Attribute Value Pairs");
-               avptree = proto_item_add_subtree(avptf, ett_radius_avp);
-
-               dissect_attribute_value_pairs(avptree, pinfo, tvb, HDR_LENGTH,
-                                             avplength);
+       if (tree) {
+
+               /* Conversation support REQUEST/RESPONSES */
+               switch (rhcode)
+               {
+                       case RADIUS_ACCESS_REQUEST:
+                       case RADIUS_ACCOUNTING_REQUEST:
+                       case RADIUS_ACCESS_PASSWORD_REQUEST:
+                       case RADIUS_ASCEND_ACCESS_EVENT_REQUEST:
+                       case RADIUS_DISCONNECT_REQUEST:
+                       case RADIUS_CHANGE_FILTER_REQUEST:
+                               proto_tree_add_boolean_hidden(radius_tree, hf_radius_req, tvb, 0, 0, TRUE);
+                               /* Keep track of the address and port whence the call came
+                                *  so that we can match up requests with replies.
+                                *
+                                * Because it is UDP and the reply can come from any IP
+                                * and port (not necessarly the request dest), we only
+                                * track the source IP and port of the request to match
+                                * the reply.
+                                */
+
+                               /*
+                                * XXX - can we just use NO_ADDR_B?  Unfortunately,
+                                * you currently still have to pass a non-null
+                                * pointer for the second address argument even
+                                * if you do that.
+                                */
+                               conversation = find_conversation(pinfo->fd->num, &pinfo->src,
+                                                                        &null_address, pinfo->ptype, pinfo->srcport,
+                                                                        pinfo->destport, 0);
+                               if (conversation == NULL)
+                               {
+                                       /* It's not part of any conversation - create a new one. */
+                                       conversation = conversation_new(pinfo->fd->num, &pinfo->src,
+                                                                       &null_address, pinfo->ptype, pinfo->srcport,
+                                                                       pinfo->destport, 0);
+                               }
+
+                               /* Prepare the key data */
+                               radius_call_key.code = rhcode;
+                               radius_call_key.ident = rhident;
+                               radius_call_key.conversation = conversation;
+                               radius_call_key.req_time = pinfo->fd->abs_ts;
+
+                               /* Look up the request */
+                               radius_call = g_hash_table_lookup(radius_calls, &radius_call_key);
+                               if (radius_call != NULL)
+                               {
+                                       /* We've seen a request with this ID, with the same
+                                          destination, before - but was it *this* request? */
+                                       if (pinfo->fd->num != radius_call->req_num)
+                                       {
+                                               /* No, so it's a duplicate request. Mark it as such. */
+                                               rad_info.is_duplicate = TRUE;
+                                               rad_info.req_num = radius_call->req_num;
+                                               if (check_col(pinfo->cinfo, COL_INFO))
+                                               {
+                                                       col_append_fstr(pinfo->cinfo, COL_INFO,
+                                                                       ", Duplicate Request ID:%u",
+                                                                       rhident);
+                                               }
+                                               if (tree)
+                                               {
+                                                       proto_item* item;
+                                                       proto_tree_add_uint_hidden(radius_tree, hf_radius_dup, tvb, 0,0, rhident);
+                                                       item = proto_tree_add_uint(radius_tree, hf_radius_req_dup, tvb, 0,0, rhident);
+                                                       PROTO_ITEM_SET_GENERATED(item);
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       /* Prepare the value data.
+                                          "req_num" and "rsp_num" are frame numbers;
+                                          frame numbers are 1-origin, so we use 0
+                                          to mean "we don't yet know in which frame
+                                          the reply for this call appears". */
+                                       new_radius_call_key = g_mem_chunk_alloc(radius_call_info_key_chunk);
+                                       *new_radius_call_key = radius_call_key;
+                                       radius_call = g_mem_chunk_alloc(radius_call_info_value_chunk);
+                                       radius_call->req_num = pinfo->fd->num;
+                                       radius_call->rsp_num = 0;
+                                       radius_call->ident = rhident;
+                                       radius_call->code = rhcode;
+                                       radius_call->responded = FALSE;
+                                       radius_call->req_time=pinfo->fd->abs_ts;
+                                       radius_call->rspcode = 0;
+
+                                       /* Store it */
+                                       g_hash_table_insert(radius_calls, new_radius_call_key, radius_call);
+                               }
+                               if (radius_call && radius_call->rsp_num)
+                               {
+                                       proto_item* item = proto_tree_add_uint_format(radius_tree, hf_radius_rsp_frame,
+                                                                                     tvb, 0, 0, radius_call->rsp_num,
+                                                                                     "The response to this request is in frame %u",
+                                                                                     radius_call->rsp_num);
+                                       PROTO_ITEM_SET_GENERATED(item);
+                               }
+                               break;
+                       case RADIUS_ACCESS_ACCEPT:
+                       case RADIUS_ACCESS_REJECT:
+                       case RADIUS_ACCOUNTING_RESPONSE:
+                       case RADIUS_ACCESS_PASSWORD_ACK:
+                       case RADIUS_ACCESS_PASSWORD_REJECT:
+                       case RADIUS_ASCEND_ACCESS_EVENT_RESPONSE:
+                       case RADIUS_DISCONNECT_REQUEST_ACK:
+                       case RADIUS_DISCONNECT_REQUEST_NAK:
+                       case RADIUS_CHANGE_FILTER_REQUEST_ACK:
+                       case RADIUS_CHANGE_FILTER_REQUEST_NAK:
+                               proto_tree_add_boolean_hidden(radius_tree, hf_radius_rsp, tvb, 0, 0, TRUE);
+                               /* Check for RADIUS response.  A response must match a call that
+                                * we've seen, and the response must be sent to the same
+                                * port and address that the call came from.
+                                *
+                                * Because it is UDP and the reply can come from any IP
+                                * and port (not necessarly the request dest), we only
+                                * track the source IP and port of the request to match
+                                * the reply.
+                                */
+
+                               /* XXX - can we just use NO_ADDR_B?  Unfortunately,
+                                * you currently still have to pass a non-null
+                                * pointer for the second address argument even
+                                * if you do that.
+                                */
+                               conversation = find_conversation(pinfo->fd->num, &null_address,
+                                                                        &pinfo->dst, pinfo->ptype, pinfo->srcport,
+                                                                        pinfo->destport, 0);
+                               if (conversation != NULL)
+                               {
+                                       /* Look only for matching request, if
+                                          matching conversation is available. */
+                                       /* Prepare the key data */
+                                       radius_call_key.code = rhcode;
+                                       radius_call_key.ident = rhident;
+                                       radius_call_key.conversation = conversation;
+                                       radius_call_key.req_time = pinfo->fd->abs_ts;
+
+                                       radius_call = g_hash_table_lookup(radius_calls, &radius_call_key);
+                                       if (radius_call)
+                                       {
+                                               /* Indicate the frame to which this is a reply. */
+                                               if (radius_call->req_num)
+                                               {
+                                                       proto_item* item;
+                                                       rad_info.request_available = TRUE;
+                                                       rad_info.req_num = radius_call->req_num;
+                                                       radius_call->responded = TRUE;
+
+                                                       item = proto_tree_add_uint_format(radius_tree, hf_radius_req_frame,
+                                                                                         tvb, 0, 0, radius_call->req_num,
+                                                                                         "This is a response to a request in frame %u",
+                                                                                         radius_call->req_num);
+                                                       PROTO_ITEM_SET_GENERATED(item);
+                                                       nstime_delta(&delta, &pinfo->fd->abs_ts, &radius_call->req_time);
+                                                       item = proto_tree_add_time(radius_tree, hf_radius_time, tvb, 0, 0, &delta);
+                                                       PROTO_ITEM_SET_GENERATED(item);
+                                               }
+
+                                               if (radius_call->rsp_num == 0)
+                                               {
+                                                       /* We have not yet seen a response to that call, so
+                                                          this must be the first response; remember its
+                                                          frame number. */
+                                                       radius_call->rsp_num = pinfo->fd->num;
+                                               }
+                                               else
+                                               {
+                                                       /* We have seen a response to this call - but was it
+                                                          *this* response? (disregard provisional responses) */
+                                                       if ( (radius_call->rsp_num != pinfo->fd->num) && (radius_call->rspcode == rhcode) )
+                                                       {
+                                                               /* No, so it's a duplicate response. Mark it as such. */
+                                                               rad_info.is_duplicate = TRUE;
+                                                               if (check_col(pinfo->cinfo, COL_INFO))
+                                                               {
+                                                                       col_append_fstr(pinfo->cinfo, COL_INFO,
+                                                                                       ", Duplicate Response ID:%u",
+                                                                                       rhident);
+                                                               }
+                                                               if (tree)
+                                                               {
+                                                                       proto_item* item;
+                                                                       proto_tree_add_uint_hidden(radius_tree, hf_radius_dup, tvb, 0,0, rhident);
+                                                                       item = proto_tree_add_uint(radius_tree, hf_radius_rsp_dup,
+                                                                                                  tvb, 0, 0, rhident);
+                                                                       PROTO_ITEM_SET_GENERATED(item);
+                                                               }
+                                                       }
+                                               }
+                                               /* Now store the response code (after comparison above) */
+                                               radius_call->rspcode = rhcode;
+                                               rad_info.rspcode = rhcode;
+                                       }
+                               }
+                               break;
+                       default:
+                               break;
+               }
+
+               if (radius_call)
+               {
+                       rad_info.req_time.secs = radius_call->req_time.secs;
+                       rad_info.req_time.nsecs = radius_call->req_time.nsecs;
+               }
+
+               if (avplength > 0) {
+                       /* list the attribute value pairs */
+                       avptf = proto_tree_add_text(radius_tree, tvb, HDR_LENGTH,
+                                                       avplength, "Attribute Value Pairs");
+                       avptree = proto_item_add_subtree(avptf, ett_radius_avp);
+
+                       dissect_attribute_value_pairs(avptree, pinfo, tvb, HDR_LENGTH,
+                                                         avplength);
+               }
        }
+
+       tap_queue_packet(radius_tap, pinfo, &rad_info);
 }


@@ -1034,10 +1318,62 @@
        }
 }

+/* Discard and init any state we've saved */
+static void
+radius_init_protocol(void)
+{
+       if (radius_calls != NULL)
+       {
+               g_hash_table_destroy(radius_calls);
+               radius_calls = NULL;
+       }
+       if (radius_call_info_key_chunk != NULL)
+       {
+               g_mem_chunk_destroy(radius_call_info_key_chunk);
+               radius_call_info_key_chunk = NULL;
+       }
+       if (radius_call_info_value_chunk != NULL)
+       {
+               g_mem_chunk_destroy(radius_call_info_value_chunk);
+               radius_call_info_value_chunk = NULL;
+       }
+
+       radius_calls = g_hash_table_new(radius_call_hash, radius_call_equal);
+       radius_call_info_key_chunk = g_mem_chunk_new("call_info_key_chunk",
+                                                  sizeof(radius_call_info_key),
+                                                  200 * sizeof(radius_call_info_key),
+                                                  G_ALLOC_ONLY);
+       radius_call_info_value_chunk = g_mem_chunk_new("call_info_value_chunk",
+                                                    sizeof(radius_call_t),
+                                                    200 * sizeof(radius_call_t),
+                                                    G_ALLOC_ONLY);
+}
+
 void
 proto_register_radius(void)
 {
        hf_register_info base_hf[] = {
+
+       { &hf_radius_req,
+    { "Request", "radius.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+               "TRUE if RADIUS request", HFILL }},
+
+       { &hf_radius_rsp,
+       { "Response", "radius.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+               "TRUE if RADIUS response", HFILL }},
+
+       { &hf_radius_req_frame,
+       { "Request Frame", "radius.reqframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
+            "Request Frame", HFILL }},
+
+       { &hf_radius_rsp_frame,
+       { "Response Frame", "radius.rspframe", FT_FRAMENUM, BASE_NONE, NULL, 0,
+            "Response Frame", HFILL }},
+
+       { &hf_radius_time,
+       { "Time from request", "radius.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
+                       "Timedelta between Request and Response", HFILL }},
+
        { &hf_radius_code,
        { "Code","radius.code", FT_UINT8, BASE_DEC, VALS(radius_vals), 0x0,
                "", HFILL }},
@@ -1082,7 +1418,18 @@
        { "Cosine-VCI","radius.Cosine-Vci", FT_UINT16, BASE_DEC, NULL, 0x0,
                "", HFILL }},

-
+       { &hf_radius_dup,
+       { "Duplicate Message", "radius.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
+               "Duplicate Message", HFILL }},
+
+       { &hf_radius_req_dup,
+       { "Duplicate Request", "radius.req.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
+               "Duplicate Request", HFILL }},
+
+       { &hf_radius_rsp_dup,
+       { "Duplicate Response", "radius.rsp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
+               "Duplicate Response", HFILL }},
+
        };

        gint *base_ett[] = {
@@ -1154,6 +1501,8 @@
        proto_register_field_array(proto_radius,(hf_register_info*)(ri.hf->data),ri.hf->len);
        proto_register_subtree_array((gint**)(ri.ett->data), ri.ett->len);

+       register_init_routine(&radius_init_protocol);
+
        g_array_free(ri.hf,FALSE);
        g_array_free(ri.ett,FALSE);
        g_array_free(ri.vend_vs,FALSE);
@@ -1170,6 +1519,7 @@

     no_vendor.attrs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);

+       radius_tap = register_tap("radius");
 }

 void
Index: epan/dissectors/packet-radius.h
===================================================================
--- epan/dissectors/packet-radius.h     (revision 19652)
+++ epan/dissectors/packet-radius.h     (working copy)
@@ -23,6 +23,35 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */

+#define RADIUS_ACCESS_REQUEST                  1
+#define RADIUS_ACCESS_ACCEPT                   2
+#define RADIUS_ACCESS_REJECT                   3
+#define RADIUS_ACCOUNTING_REQUEST              4
+#define RADIUS_ACCOUNTING_RESPONSE             5
+#define RADIUS_ACCOUNTING_STATUS               6
+#define RADIUS_ACCESS_PASSWORD_REQUEST         7
+#define RADIUS_ACCESS_PASSWORD_ACK             8
+#define RADIUS_ACCESS_PASSWORD_REJECT          9
+#define RADIUS_ACCOUNTING_MESSAGE              10
+#define RADIUS_ACCESS_CHALLENGE                        11
+#define RADIUS_STATUS_SERVER                   12
+#define RADIUS_STATUS_CLIENT                   13
+
+#define RADIUS_VENDOR_SPECIFIC_CODE            26
+#define RADIUS_ASCEND_ACCESS_NEXT_CODE         29
+#define RADIUS_ASCEND_ACCESS_NEW_PIN           30
+#define RADIUS_ASCEND_PASSWORD_EXPIRED         32
+#define RADIUS_ASCEND_ACCESS_EVENT_REQUEST     33
+#define RADIUS_ASCEND_ACCESS_EVENT_RESPONSE    34
+#define RADIUS_DISCONNECT_REQUEST              40
+#define RADIUS_DISCONNECT_REQUEST_ACK          41
+#define RADIUS_DISCONNECT_REQUEST_NAK          42
+#define RADIUS_CHANGE_FILTER_REQUEST           43
+#define RADIUS_CHANGE_FILTER_REQUEST_ACK       44
+#define RADIUS_CHANGE_FILTER_REQUEST_NAK       45
+#define RADIUS_EAP_MESSAGE_CODE                                79
+#define RADIUS_RESERVED                                255
+
 typedef struct _radius_vendor_info_t {
        const gchar *name;
        guint code;
@@ -71,3 +100,28 @@

 /* from radius_dict.l */
 radius_dictionary_t* radius_load_dictionary (gchar* directory, const gchar* filename, gchar** err_str);
+
+/* Item of request list */
+typedef struct _radius_call_t
+{
+       guint code;
+       guint ident;
+
+       guint32 req_num; /* frame number request seen */
+       guint32 rsp_num; /* frame number response seen */
+       guint32 rspcode;
+       nstime_t req_time;
+       gboolean responded;
+} radius_call_t;
+
+/* Container for tapping relevant data */
+typedef struct _radius_info_t
+{
+       guint code;
+       guint ident;
+       nstime_t req_time;
+       gboolean is_duplicate;
+       gboolean request_available;
+       guint32 req_num; /* frame number request seen */
+       guint32 rspcode;
+} radius_info_t;
\ No newline at end of file
Index: gtk/Makefile.common
===================================================================
--- gtk/Makefile.common (revision 19652)
+++ gtk/Makefile.common (working copy)
@@ -164,6 +164,7 @@
        mtp3_stat.c     \
        mtp3_summary.c  \
        ncp_stat.c  \
+       radius_stat.c   \
        rpc_progs.c     \
        rpc_stat.c      \
        rtp_analysis.c  \
Index: gtk/radius_stat.c
===================================================================
--- gtk/radius_stat.c   (revision 0)
+++ gtk/radius_stat.c   (revision 0)
@@ -0,0 +1,373 @@
+/* radius_stat.c
+ * radius-statistics for Wireshark
+ * Copyright 2006 Alejandro Vaquero <alejandrovaquero@xxxxxxxxx>
+ *
+ *
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@xxxxxxxxxxxxx>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include <epan/packet_info.h>
+#include <epan/epan.h>
+#include <epan/value_string.h>
+
+#include <epan/tap.h>
+#include "../register.h"
+#include <epan/dissectors/packet-radius.h>
+#include "../timestats.h"
+#include "gui_stat_util.h"
+#include "compat_macros.h"
+#include "../simple_dialog.h"
+#include "dlg_utils.h"
+#include "../file.h"
+#include "../globals.h"
+#include "../stat_menu.h"
+#include "../tap_dfilter_dlg.h"
+#include "gui_utils.h"
+
+
+#define NUM_TIMESTATS 8
+#define NUM_COLUMNS 11
+
+/* Summary of response-time calculations*/
+typedef struct _radius_rtd_t {
+       guint32 open_req_num;
+       guint32 disc_rsp_num;
+       guint32 req_dup_num;
+       guint32 rsp_dup_num;
+       timestat_t stats;
+} radius_rtd_t;
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _radiusstat_t {
+       GtkWidget *win;
+       GtkWidget *vbox;
+       char *filter;
+       GtkWidget *scrolled_window;
+       GtkCList *table;
+       radius_rtd_t radius_rtd[NUM_TIMESTATS];
+} radiusstat_t;
+
+static const value_string radius_message_code[] = {
+  {  0,        "Overall"},
+  {  1,        "Access"},
+  {  2,        "Accounting"},
+  {  3,        "Access Password"},
+  {  4, "Ascend Access Event"},
+  {  5, "Diconnect"},
+  {  6, "Change Filter"},
+  {  7, "Other"},
+};
+
+typedef enum _radius_category {
+       OVERALL,
+       ACCESS,
+       ACCOUNTING,
+       ACCESS_PASSWORD,
+       ASCEND_ACCESS_EVENT,
+       DISCONNECT,
+       CHANGE_FILTER,
+       OTHERS
+}radius_category;
+
+static void
+radiusstat_reset(void *prs)
+{
+       radiusstat_t *rs=(radiusstat_t *)prs;
+       int i;
+
+
+       for(i=0;i<NUM_TIMESTATS;i++) {
+               rs->radius_rtd[i].stats.num=0;
+               rs->radius_rtd[i].stats.min_num=0;
+               rs->radius_rtd[i].stats.max_num=0;
+               rs->radius_rtd[i].stats.min.secs=0;
+        rs->radius_rtd[i].stats.min.nsecs=0;
+        rs->radius_rtd[i].stats.max.secs=0;
+        rs->radius_rtd[i].stats.max.nsecs=0;
+        rs->radius_rtd[i].stats.tot.secs=0;
+        rs->radius_rtd[i].stats.tot.nsecs=0;
+               rs->radius_rtd[i].open_req_num = 0;
+               rs->radius_rtd[i].disc_rsp_num = 0;
+               rs->radius_rtd[i].req_dup_num = 0;
+               rs->radius_rtd[i].rsp_dup_num = 0;
+       }
+
+}
+
+
+static int
+radiusstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
+{
+       radiusstat_t *rs=(radiusstat_t *)prs;
+       const radius_info_t *ri=pri;
+       nstime_t delta;
+       radius_category radius_cat = OTHERS;
+
+       switch (ri->code) {
+               case RADIUS_ACCESS_REQUEST:
+               case RADIUS_ACCESS_ACCEPT:
+               case RADIUS_ACCESS_REJECT:
+                       radius_cat = ACCESS;
+                       break;
+               case RADIUS_ACCOUNTING_REQUEST:
+               case RADIUS_ACCOUNTING_RESPONSE:
+                       radius_cat = ACCOUNTING;
+                       break;
+               case RADIUS_ACCESS_PASSWORD_REQUEST:
+               case RADIUS_ACCESS_PASSWORD_ACK:
+               case RADIUS_ACCESS_PASSWORD_REJECT:
+                       radius_cat = ACCESS_PASSWORD;
+                       break;
+               case RADIUS_ASCEND_ACCESS_EVENT_REQUEST:
+               case RADIUS_ASCEND_ACCESS_EVENT_RESPONSE:
+                       radius_cat = ASCEND_ACCESS_EVENT;
+                       break;
+               case RADIUS_DISCONNECT_REQUEST:
+               case RADIUS_DISCONNECT_REQUEST_ACK:
+               case RADIUS_DISCONNECT_REQUEST_NAK:
+                       radius_cat = DISCONNECT;
+                       break;
+               case RADIUS_CHANGE_FILTER_REQUEST:
+               case RADIUS_CHANGE_FILTER_REQUEST_ACK:
+               case RADIUS_CHANGE_FILTER_REQUEST_NAK:
+                       radius_cat = CHANGE_FILTER;
+                       break;
+       }
+
+       switch (ri->code) {
+
+       case RADIUS_ACCESS_REQUEST:
+       case RADIUS_ACCOUNTING_REQUEST:
+       case RADIUS_ACCESS_PASSWORD_REQUEST:
+       case RADIUS_ASCEND_ACCESS_EVENT_REQUEST:
+       case RADIUS_DISCONNECT_REQUEST:
+       case RADIUS_CHANGE_FILTER_REQUEST:
+               if(ri->is_duplicate){
+                       /* Duplicate is ignored */
+                       rs->radius_rtd[OVERALL].req_dup_num++;
+                       rs->radius_rtd[radius_cat].req_dup_num++;
+                       return 0;
+               }
+               else {
+                       rs->radius_rtd[OVERALL].open_req_num++;
+                       rs->radius_rtd[radius_cat].open_req_num++;
+                       return 0;
+               }
+       break;
+
+       case RADIUS_ACCESS_ACCEPT:
+       case RADIUS_ACCESS_REJECT:
+       case RADIUS_ACCOUNTING_RESPONSE:
+       case RADIUS_ACCESS_PASSWORD_ACK:
+       case RADIUS_ACCESS_PASSWORD_REJECT:
+       case RADIUS_ASCEND_ACCESS_EVENT_RESPONSE:
+       case RADIUS_DISCONNECT_REQUEST_ACK:
+       case RADIUS_DISCONNECT_REQUEST_NAK:
+       case RADIUS_CHANGE_FILTER_REQUEST_ACK:
+       case RADIUS_CHANGE_FILTER_REQUEST_NAK:
+               if(ri->is_duplicate){
+                       /* Duplicate is ignored */
+                       rs->radius_rtd[OVERALL].rsp_dup_num++;
+                       rs->radius_rtd[radius_cat].rsp_dup_num++;
+                       return 0;
+               }
+               else if (!ri->request_available) {
+                       /* no request was seen */
+                       rs->radius_rtd[OVERALL].disc_rsp_num++;
+                       rs->radius_rtd[radius_cat].disc_rsp_num++;
+                       return 0;
+               }
+               else {
+                       rs->radius_rtd[OVERALL].open_req_num--;
+                       rs->radius_rtd[radius_cat].open_req_num--;
+                       /* calculate time delta between request and response */
+                       nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->req_time);
+
+                       time_stat_update(&(rs->radius_rtd[OVERALL].stats),&delta, pinfo);
+                       time_stat_update(&(rs->radius_rtd[radius_cat].stats),&delta, pinfo);
+
+                       return 1;
+               }
+       break;
+
+       default:
+               return 0;
+       break;
+       }
+}
+
+static void
+radiusstat_draw(void *prs)
+{
+       radiusstat_t *rs=(radiusstat_t *)prs;
+       int i;
+       /* gtk1 using a scrollable clist*/
+       char *str[NUM_COLUMNS];
+
+       for(i=0;i<NUM_COLUMNS;i++) {
+               str[i]=g_malloc(sizeof(char[256]));
+       }
+
+       /* clear list before printing */
+       gtk_clist_clear(rs->table);
+
+       for(i=0;i<NUM_TIMESTATS;i++) {
+               /* nothing seen, nothing to do */
+               if(rs->radius_rtd[i].stats.num==0){
+                       continue;
+               }
+
+               g_snprintf(str[0], sizeof(char[256]), "%s", val_to_str(i,radius_message_code,"Other"));
+               g_snprintf(str[1], sizeof(char[256]), "%d", rs->radius_rtd[i].stats.num);
+               g_snprintf(str[2], sizeof(char[256]), "%8.2f msec", nstime_to_msec(&(rs->radius_rtd[i].stats.min)));
+               g_snprintf(str[3], sizeof(char[256]), "%8.2f msec", nstime_to_msec(&(rs->radius_rtd[i].stats.max)));
+               g_snprintf(str[4], sizeof(char[256]), "%8.2f msec", get_average(&(rs->radius_rtd[i].stats.tot), rs->radius_rtd[i].stats.num));
+               g_snprintf(str[5], sizeof(char[256]), "%6u", rs->radius_rtd[i].stats.min_num);
+               g_snprintf(str[6], sizeof(char[256]), "%6u", rs->radius_rtd[i].stats.max_num);
+               g_snprintf(str[7], sizeof(char[256]), "%4u", rs->radius_rtd[i].open_req_num);
+               g_snprintf(str[8], sizeof(char[256]), "%4u", rs->radius_rtd[i].disc_rsp_num);
+               g_snprintf(str[9], sizeof(char[256]), "%4u (%4.2f%%)", rs->radius_rtd[i].req_dup_num,
+                       rs->radius_rtd[i].stats.num?((double)rs->radius_rtd[i].req_dup_num*100)/(double)rs->radius_rtd[i].stats.num:0);
+               g_snprintf(str[10], sizeof(char[256]), "%4u (%4.2f%%)", rs->radius_rtd[i].rsp_dup_num,
+                       rs->radius_rtd[i].stats.num?((double)rs->radius_rtd[i].rsp_dup_num*100)/(double)rs->radius_rtd[i].stats.num:0);
+
+               gtk_clist_append(rs->table, str);
+       }
+
+       gtk_widget_show(GTK_WIDGET(rs->table));
+       for(i=0;i<NUM_COLUMNS;i++) {
+               g_free(str[i]);
+       }
+}
+
+void protect_thread_critical_region(void);
+void unprotect_thread_critical_region(void);
+static void
+win_destroy_cb(GtkWindow *win _U_, gpointer data)
+{
+       radiusstat_t *rs=(radiusstat_t *)data;
+
+       protect_thread_critical_region();
+       remove_tap_listener(rs);
+       unprotect_thread_critical_region();
+
+       if(rs->filter){
+               g_free(rs->filter);
+               rs->filter=NULL;
+       }
+       g_free(rs);
+}
+
+static const gchar *titles[]={
+                       "Type",
+                       "Messages",
+                       "Min SRT",
+                       "Max SRT",
+                       "Avg SRT",
+                       "Min in Frame",
+                       "Max in Frame",
+                       "Open Requests",
+                       "Discarded Responses",
+                       "Repeated Requests",
+                       "Repeated Responses" };
+
+static void
+gtk_radiusstat_init(const char *optarg, void *userdata _U_)
+{
+       radiusstat_t *rs;
+       const char *filter=NULL;
+       GString *error_string;
+       GtkWidget *bt_close;
+       GtkWidget *bbox;
+
+       if(strncmp(optarg,"radius,srt,",11) == 0){
+               filter=optarg+11;
+       } else {
+               filter="";
+       }
+
+       rs=g_malloc(sizeof(radiusstat_t));
+       rs->filter=g_strdup(filter);
+
+       radiusstat_reset(rs);
+
+       rs->win=window_new(GTK_WINDOW_TOPLEVEL, "RADIUS SRT");
+       gtk_window_set_default_size(GTK_WINDOW(rs->win), 600, 150);
+
+       rs->vbox=gtk_vbox_new(FALSE, 3);
+
+       init_main_stat_window(rs->win, rs->vbox, "RADIUS Service Response Time (SRT) Statistics", filter);
+
+       /* GTK1 using a scrollable clist*/
+        /* init a scrolled window*/
+       rs->scrolled_window = scrolled_window_new(NULL, NULL);
+
+       rs->table = create_stat_table(rs->scrolled_window, rs->vbox, NUM_COLUMNS, titles);
+
+       error_string=register_tap_listener("radius", rs, filter, radiusstat_reset, radiusstat_packet, radiusstat_draw);
+       if(error_string){
+               simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str);
+               g_string_free(error_string, TRUE);
+               g_free(rs->filter);
+               g_free(rs);
+               return;
+       }
+
+       /* Button row. */
+       bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
+       gtk_box_pack_start(GTK_BOX(rs->vbox), bbox, FALSE, FALSE, 0);
+
+       bt_close = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
+       window_set_cancel_button(rs->win, bt_close, window_cancel_button_cb);
+
+       SIGNAL_CONNECT(rs->win, "delete_event", window_delete_event_cb, NULL);
+       SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
+
+       gtk_widget_show_all(rs->win);
+       window_present(rs->win);
+
+       cf_retap_packets(&cfile, FALSE);
+}
+
+static tap_dfilter_dlg radius_srt_dlg = {
+       "RADIUS Service Response Time (SRT) Statistics",
+       "radius,srt",
+       gtk_radiusstat_init,
+       -1
+};
+
+void
+register_tap_listener_gtkradiusstat(void)
+{
+       register_dfilter_stat(&radius_srt_dlg, "RADIUS",
+                   REGISTER_STAT_GROUP_RESPONSE_TIME);
+}
Index: Makefile.common
===================================================================
--- Makefile.common     (revision 19652)
+++ Makefile.common     (working copy)
@@ -110,6 +110,7 @@
        tap-mgcpstat.c  \
        tap-protocolinfo.c      \
        tap-protohierstat.c     \
+       tap-radiusstat.c        \
        tap-rpcstat.c   \
        tap-rpcprogs.c  \
        tap-sctpchunkstat.c     \
Index: tap-radiusstat.c
===================================================================
--- tap-radiusstat.c    (revision 0)
+++ tap-radiusstat.c    (revision 0)
@@ -0,0 +1,226 @@
+/* tap-radiusstat.c
+ * Copyright 2006 Alejandro Vaquero <alejandrovaquero@xxxxxxxxx>
+ *
+ *
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@xxxxxxxxxxxxx>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <string.h>
+#include "epan/packet_info.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include "epan/value_string.h"
+#include "register.h"
+#include <epan/dissectors/packet-radius.h>
+#include "timestats.h"
+
+#define NUM_TIMESTATS 8
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _radiusstat_t {
+       char *filter;
+       timestat_t rtd[NUM_TIMESTATS];
+       guint32 open_req_num;
+       guint32 disc_rsp_num;
+       guint32 req_dup_num;
+       guint32 rsp_dup_num;
+} radiusstat_t;
+
+static const value_string radius_message_code[] = {
+  {  0,        "Overall       "},
+  {  1,        "Access        "},
+  {  2,        "Accounting    "},
+  {  3,        "Access Passw  "},
+  {  4, "Ascend Acce Ev"},
+  {  5, "Diconnect     "},
+  {  6, "Change Filter "},
+  {  7, "Other         "},
+};
+
+static int
+radiusstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
+{
+       radiusstat_t *rs=(radiusstat_t *)prs;
+       const radius_info_t *ri=pri;
+       nstime_t delta;
+
+       switch (ri->code) {
+
+       case RADIUS_ACCESS_REQUEST:
+       case RADIUS_ACCOUNTING_REQUEST:
+       case RADIUS_ACCESS_PASSWORD_REQUEST:
+       case RADIUS_ASCEND_ACCESS_EVENT_REQUEST:
+       case RADIUS_DISCONNECT_REQUEST:
+       case RADIUS_CHANGE_FILTER_REQUEST:
+               if(ri->is_duplicate){
+                       /* Duplicate is ignored */
+                       rs->req_dup_num++;
+                       return 0;
+               }
+               else {
+                       rs->open_req_num++;
+                       return 0;
+               }
+       break;
+
+       case RADIUS_ACCESS_ACCEPT:
+       case RADIUS_ACCESS_REJECT:
+       case RADIUS_ACCOUNTING_RESPONSE:
+       case RADIUS_ACCESS_PASSWORD_ACK:
+       case RADIUS_ACCESS_PASSWORD_REJECT:
+       case RADIUS_ASCEND_ACCESS_EVENT_RESPONSE:
+       case RADIUS_DISCONNECT_REQUEST_ACK:
+       case RADIUS_DISCONNECT_REQUEST_NAK:
+       case RADIUS_CHANGE_FILTER_REQUEST_ACK:
+       case RADIUS_CHANGE_FILTER_REQUEST_NAK:
+               if(ri->is_duplicate){
+                       /* Duplicate is ignored */
+                       rs->rsp_dup_num++;
+                       return 0;
+               }
+               else if (!ri->request_available) {
+                       /* no request was seen */
+                       rs->disc_rsp_num++;
+                       return 0;
+               }
+               else {
+                       rs->open_req_num--;
+                       /* calculate time delta between request and response */
+                       nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->req_time);
+
+                       time_stat_update(&(rs->rtd[0]),&delta, pinfo);
+                       if (ri->code == RADIUS_ACCESS_ACCEPT || ri->code == RADIUS_ACCESS_REJECT) {
+                               time_stat_update(&(rs->rtd[1]),&delta, pinfo);
+                       }
+                       else if (ri->code == RADIUS_ACCOUNTING_RESPONSE) {
+                               time_stat_update(&(rs->rtd[2]),&delta, pinfo);
+                       }
+
+
+
+                       else {
+                               time_stat_update(&(rs->rtd[7]),&delta, pinfo);
+                       }
+
+                       return 1;
+               }
+       break;
+
+       default:
+               return 0;
+       break;
+       }
+}
+
+static void
+radiusstat_draw(void *prs)
+{
+       radiusstat_t *rs=(radiusstat_t *)prs;
+       int i;
+
+       /* printing results */
+       printf("\n");
+       printf("===========================================================================================================\n");
+       printf("RADIUS Response Time Delay (RTD) Statistics:\n");
+       printf("Filter for statistics: %s\n",rs->filter?rs->filter:"");
+        printf("Duplicate requests: %u\n",rs->req_dup_num);
+        printf("Duplicate responses: %u\n",rs->rsp_dup_num);
+        printf("Open requests: %u\n",rs->open_req_num);
+        printf("Discarded responses: %u\n",rs->disc_rsp_num);
+        printf("Type           | Messages   |    Min RTD    |    Max RTD    |    Avg RTD    | Min in Frame | Max in Frame |\n");
+        for(i=0;i<NUM_TIMESTATS;i++) {
+               if(rs->rtd[i].num) {
+                       printf("%s | %7u    | %8.2f msec | %8.2f msec | %8.2f msec |  %10u  |  %10u  |\n",
+                               val_to_str(i,radius_message_code,"Other  "),rs->rtd[i].num,
+                               nstime_to_msec(&(rs->rtd[i].min)), nstime_to_msec(&(rs->rtd[i].max)),
+                               get_average(&(rs->rtd[i].tot), rs->rtd[i].num),
+                               rs->rtd[i].min_num, rs->rtd[i].max_num
+                       );
+               }
+       }
+        printf("===========================================================================================================\n");
+}
+
+
+static void
+radiusstat_init(const char *optarg, void* userdata _U_)
+{
+       radiusstat_t *rs;
+       int i;
+       const char *filter=NULL;
+       GString *error_string;
+
+       if(!strncmp(optarg,"radius,rtd,",11)){
+               filter=optarg+11;
+       } else {
+               filter="";
+       }
+
+       rs=g_malloc(sizeof(radiusstat_t));
+       rs->filter=g_malloc(strlen(filter)+1);
+       strcpy(rs->filter, filter);
+
+       for(i=0;i<NUM_TIMESTATS;i++) {
+               rs->rtd[i].num=0;
+               rs->rtd[i].min_num=0;
+               rs->rtd[i].max_num=0;
+               rs->rtd[i].min.secs=0;
+        rs->rtd[i].min.nsecs=0;
+        rs->rtd[i].max.secs=0;
+        rs->rtd[i].max.nsecs=0;
+        rs->rtd[i].tot.secs=0;
+        rs->rtd[i].tot.nsecs=0;
+       }
+
+       rs->open_req_num=0;
+       rs->disc_rsp_num=0;
+       rs->req_dup_num=0;
+       rs->rsp_dup_num=0;
+
+       error_string=register_tap_listener("radius", rs, filter, NULL, radiusstat_packet, radiusstat_draw);
+       if(error_string){
+               /* error, we failed to attach to the tap. clean up */
+               g_free(rs->filter);
+               g_free(rs);
+
+               fprintf(stderr, "tshark: Couldn't register radius,rtd tap: %s\n",
+                   error_string->str);
+               g_string_free(error_string, TRUE);
+               exit(1);
+       }
+}
+
+
+void
+register_tap_listener_radiusstat(void)
+{
+       register_stat_cmd_arg("radius,rtd", radiusstat_init, NULL);
+}
+


_______________________________________________
Wireshark-dev mailing list
Wireshark-dev@xxxxxxxxxxxxx
http://www.wireshark.org/mailman/listinfo/wireshark-dev




Attachment: radius_patch.patch.gz
Description: GNU Zip compressed data