Wireshark-dev: Re: [Wireshark-dev] Radius Statistics Patch
From: "Anders Broman" <a.broman@xxxxxxxxx>
Date: Tue, 24 Oct 2006 07:24:34 +0200
Checked in.
BR
Anders

-----Ursprungligt meddelande-----
Från: wireshark-dev-bounces@xxxxxxxxxxxxx
[mailto:wireshark-dev-bounces@xxxxxxxxxxxxx] För Alejandro Vaquero
Skickat: den 23 oktober 2006 17:43
Till: Developer support list for Wireshark
Ämne: Re: [Wireshark-dev] Radius Statistics Patch

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)/(dou
ble)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)/(dou
ble)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
>>
>>
>>     
>
>
>