/**************************************************************************** 
**
** File: stats.c
**
** Author: Mike Borella
**
** Comments: Statistics collection module
**
** $Id: stats.c,v 1.2 2001/09/07 19:27:02 mborella Exp $
**
** 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 Library 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.
**
*****************************************************************************/

#include "global.h"
#include "error.h"
#include "stats.h"

typedef struct stats
{
  int ip;
  int udp;
  int tcp;
  int ipx;
  int gre;
  int icmp;
  int ipv6;
  int icmpv6;
  int ospf;
  int rsvp;
  int arp;
  int ah;
  int esp;
  int igmp;
} stats_t;

stats_t statistics;

static int stats_counted_ip = 0; 
static int stats_counted_udp = 0;
static int stats_counted_tcp = 0;
static int stats_paused = 0; /* when set, stats will not be counted */

/*----------------------------------------------------------------------------
**
** stats_ispaused()
**
** Check if stats counting is paused
**
**----------------------------------------------------------------------------
*/

inline int stats_ispaused(void)
{
  return stats_paused;
}

/*----------------------------------------------------------------------------
**
** stats_pause()
**
** Temporarily stop doing stats.  Typically used when an ICMP packet is 
** encountered so that the encapsulated IP/UDP/TCP headers are not counted.
**
**----------------------------------------------------------------------------
*/

inline void stats_pause(void)
{
  stats_paused = 1;
}

/*----------------------------------------------------------------------------
**
** stats_unpause()
**
** Restart doing stats.  Typically used at the begining of processing each
** packet.
**
**----------------------------------------------------------------------------
*/

inline void stats_unpause(void)
{
  stats_paused = 0;
}

/*----------------------------------------------------------------------------
**
** stats_reset()
**
**----------------------------------------------------------------------------
*/

inline void stats_reset(void)
{
  stats_counted_ip = 0;
  stats_counted_udp = 0;
  stats_counted_tcp = 0;
}

/*----------------------------------------------------------------------------
**
** stats_init()
**
**----------------------------------------------------------------------------
*/

inline void stats_init(void)
{
  memset(&statistics, 0, sizeof(stats_t));
}

/*----------------------------------------------------------------------------
**
** stats_update()
**
**----------------------------------------------------------------------------
*/

inline void stats_update(int type)
{
  if (stats_ispaused())
    return;

  switch(type)
    {
    case STATS_IP:
      /* Avoid double counting tunneled packets */
      if (stats_counted_ip) 
	return;
      stats_counted_ip = 1;
      statistics.ip++;
      break;
      
    case STATS_UDP:
      /* Avoid double counting tunneled packets */
      if (stats_counted_udp) 
	return;
      stats_counted_udp = 1;
      statistics.udp++;
      break;
      
    case STATS_TCP:
      /* Avoid double counting tunneled packets */
      if (stats_counted_tcp) 
	return;
      stats_counted_tcp = 1;
      statistics.tcp++;
      break;
      
    case STATS_IPX:
      statistics.ipx++;
      break;
      
    case STATS_GRE:
      statistics.gre++;
      break;
      
    case STATS_ICMP:
      statistics.icmp++;
      stats_pause();
      break;
      
    case STATS_IPV6:
      statistics.ipv6++;
      break;
      
    case STATS_ICMPV6:
      statistics.icmpv6++;
      stats_pause();
      break;
      
    case STATS_OSPF:
      statistics.ospf++;
      break;
      
    case STATS_RSVP:
      statistics.rsvp++;
      break;
      
    case STATS_ARP:
      statistics.arp++;
      break;
      
    case STATS_AH:
      statistics.ah++;
      break;
      
    case STATS_ESP:
      statistics.esp++;
      break;
      
    case STATS_IGMP:
      statistics.igmp++;
      break;
      
    default:
      error_fatal("unknown packet type for statistics: %d\n", type);
      break;
    }
}

/*----------------------------------------------------------------------------
**
** stats_dump()
**
**----------------------------------------------------------------------------
*/

inline void stats_dump(void)
{
  fprintf(stderr, "ARP:    %d\n", statistics.arp);
  fprintf(stderr, "IP:     %d\n", statistics.ip);
  fprintf(stderr, "ICMP:   %d\n", statistics.icmp);
  fprintf(stderr, "IGMP:   %d\n", statistics.igmp);
  fprintf(stderr, "UDP:    %d\n", statistics.udp);
  fprintf(stderr, "TCP:    %d\n", statistics.tcp);
  fprintf(stderr, "IPX:    %d\n", statistics.ipx);
  fprintf(stderr, "GRE:    %d\n", statistics.gre);
  fprintf(stderr, "IPv6:   %d\n", statistics.ipv6);
  fprintf(stderr, "ICMPv6: %d\n", statistics.icmpv6);
  fprintf(stderr, "OSPF:   %d\n", statistics.ospf);
  fprintf(stderr, "RSVP:   %d\n", statistics.rsvp);
  fprintf(stderr, "AH:     %d\n", statistics.ah);
  fprintf(stderr, "ESP:    %d\n", statistics.esp);
}

