/*
$Id: choke_module.c,v 1.4 1999/04/29 06:18:37 jeremiah Exp $
$Log: choke_module.c,v $
Revision 1.4  1999/04/29 06:18:37  jeremiah
add some comments and made the code look better

Revision 1.3  1999/04/29 06:13:53  jeremiah
Added a time, and now drop packets if they are over our maximum throughput. Also send icmp SQUENCH packet to host for slow down.

Revision 1.2  1999/04/28 23:39:26  jeremiah
inital creation
module entry/usage finalized


 */

#include "choke_module.h"
#include "choke_ip.h"

/* this is our main function, it takes an mbuffer as input and returns an int. a positive value causes the packet to be kept, a value less than zero causes the packet to be dropped */
static int ip_choke(struct mbuf **m){
  
  static unsigned int total_length = 0;
  struct ip * ip_hdr;
  static int old_time = 0;
 
  if (total_length == 0)
    old_time = (int)time_second;
  /* get the ip_packet from mbuf */
  ip_hdr = mtod(*m,struct ip *);
  /* increment the amount of data received this second */
  total_length += ip_hdr->ip_len;
  /* see if we've been around for a full second yet, if so reset the total_length */
  if (((int)time_second - (int)old_time) >= 1){
    total_length = 0;
  }
  /* determine if the amount of data we have recived during this second is over our limit, if so drop the packets, and send a quench packet */
  else if (total_length > 2048){
    /* send an icmp quench packet to source */   
    icmp_error(*m,ICMP_SOURCEQUENCH,0,0L,0);
    *m = NULL;
    return -1;
  }  
  return 0;
}

/*The `sysent' struct for the new module. It contains the actual function call for the module. */
static struct sysent choke_sysent = {
  1,			/*the number of arguments */
  ip_choke	       /* the name of the system call */
 };

/* The offset in sysent where the module is allocated.*/
static int offset = NO_SYSCALL;


/* this is the function that is called when the module is loaded */
static int load (struct module *module, int cmd, void * arg)
{
  
  static ip_choke_t *ip_choke_ptr_old;
  int error = 0;
  switch (cmd) {
  case MOD_LOAD :
    printf ("choke_module loaded at %d\n", offset);
    /* save the value of the old function pointer */
    ip_choke_ptr_old = ip_choke_ptr;
    /* set the value of the function pointer to our new function */
    ip_choke_ptr = ip_choke;
    break;
  case MOD_UNLOAD :
    printf ("choke_module unloaded from %d\n", offset);
    /* set the value of the function pointer to its original value */
    ip_choke_ptr = ip_choke_ptr_old;
    break;
  default :
    error = EINVAL;
    break;
  }
  
  if (error != 0)
    printf("choke_module: error: %d\n", error);
  return error;
}


/* this is the macro the generates our module */
SYSCALL_MODULE(choke_module, &offset, &choke_sysent, load, NULL);

