/* packet_dropper.c
 *
 * This program provides an example of how to install a module into a
 *   slightly modified kernel that will randomly drop packets for a specific
 *   (hard-coded) host.
 *
 * See linux/drivers/char/random.c for details of get_random_bytes().
 *
 * Usage (must be root to use):
 *   /sbin/insmod packet_dropper
 *   /sbin/rmmod packet_dropper
 */

#define MODULE
#define MAX_UNSIGNED_SHORT 65535


#include <linux/module.h>
#include <linux/skbuff.h>  /* for struct sk_buff */
#include <linux/ip.h>      /* for struct iphdr */


extern int (*xmit_test_function)(struct sk_buff *);  /* calling function */
extern void get_random_bytes(void *buf, int nbytes); /* random function */
//unsigned short cutoff;                               /* drop cutoff */
float rate   = 0.15;                                /* drop percentage */
static int dropPoint = -1;
static unsigned int count = 0;

//__u32 target = 0x6A08B184;                           /* hard coded target */
__u32 target = 0x0202A8C0;      /* dst address 192.168.2.2 */



/************************************************************ packet_dropper
 * this is what dev_queue_xmit will call while this module is installed */
int packet_dropper(struct sk_buff *skb) {
  //unsigned short t;
  if (skb->nh.iph->daddr == target) {
  /* the get_random_bytes is too inefficient */
  /* the following code is modified by lin : begin (*/
        //get_random_bytes(&t,2);
        //if (t <= cutoff) return 1;    /* drop this packet */
        count ++;
        if ( count == dropPoint )
        {
                count = 0;
                return 1;
        }
  /* modified by lin : end ) */
  }
  return 0;                       /* continue with normal routine */
}  /* packet_dropper */



/*************************************************************** init_module
 * this function replaces the null pointer with a real one */
int init_module() {
  EXPORT_NO_SYMBOLS;
  //cutoff = rate * MAX_UNSIGNED_SHORT;

  /* added by lin begin ( */
  if ( rate == 0.0 )
        dropPoint = -1;
  else
        dropPoint = (int) ( 1/rate );
  /* added by lin end   ) */

  xmit_test_function = packet_dropper;
  //printk("<1> packet_dropper: now dropping packets below %u\n",cutoff);
  printk("<1> packet_dropper: now dropping one out of every %u packets\n",
                dropPoint );
  return 0;
}  /* init_module */



/************************************************************ cleanup_module
 * this function resets the function pointer back to null */
void cleanup_module() {
  xmit_test_function = 0;
  printk("<1> packet_dropper: uninstalled\n");
}  /* cleanup_module */