#include <linux/list.h>
#include <linux/tasks.h>
#include <asm/uaccess.h>
#include <linux/smp_lock.h>
#include <asm/signal.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/notifier.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
#include <net/slhc.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <net/br.h>
#include <net/dst.h>
#include <net/pkt_sched.h>
#include <net/profile.h>
#include <linux/init.h>
#include <linux/kmod.h>
				
#include <linux/time.h>
#include <asm/processor.h>

#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <linux/ip.h>
#include <net/udp.h>
#include <net/tcp.h>

#include <rk/rk_linux.h>
#include <rk/rk_error.h>
#include <rk/rk.h>
#include <rk/timespec.h>


static int rcv_net_reserve_destroy (rk_reserve_t);
static void rcv_net_reserve_replenish(rk_reserve_t, cpu_tick_t, cpu_tick_t dummy);
//static void rcv_net_reserve_enforce (rk_reserve_t);
static void rcv_net_reserve_attach (rk_reserve_t, struct rs_proc_list *);
static void rcv_net_reserve_detach (rk_reserve_t, struct rs_proc_list *);
//static void rcv_net_reserve_sleep_on (rk_reserve_t);
static int rcv_net_reserve_read_proc (rk_reserve_t, char *);

struct rk_reserve_ops rcv_net_reserve_ops = {
  rcv_net_reserve_destroy,
  NULL,				/* start_account */
  NULL,				/* stop_account */
  rcv_net_reserve_replenish,
  NULL,                      //rcv_net_reserve_enforce,
  rcv_net_reserve_attach,
  rcv_net_reserve_detach,
#ifdef	linux
  NULL,                      //rcv_net_reserve_sleep_on,
  rcv_net_reserve_read_proc,
#endif
};


#define SUPER_CHARGED			1
#ifdef SUPER_CHARGED
#define RATE_MONOTONIC			0
#define DEADLINE_MONOTONIC 		1


#define PACKET_RESCHED_COUNT 1 //3

static int rcv_net_reserves_scheduling_policy = DEADLINE_MONOTONIC;
#endif /* SUPER_CHARGED */


#define LINK_SPEED_10MBPS   (10*1000*1000/8)
#define LINK_SPEED_100MBPS  (100*1000*1000)
#define BYT_TX_TIME_10MBPS  (8*100) // in ns
#define BYT_TX_TIME_100MBPS (8*10) //in ns
#define BYTE_TRANSMISSION_TIME  (8*10)	// in ns
#define TOTAL_BUFFER_SPACE      300

static int rcv_net_reserve_available_buffer_pool;
static int rcv_net_reserve_queues;

#define	CAPACITY_INT(x)		((x)/100)
#define	CAPACITY_FRAC(x)	((x)-(x/100)*100)
#define	INT2CAPACITY(x)		((x)*10000)
#define	CAPACITY2INT(x)		((x)/10000)
#define	PERCENT2CAPACITY(x)	((x)*100)
#define	CAPACITY_OF(c,t)	(INT2CAPACITY(c)/(t))

int byt_rx_time;
static int link_netr_speed=80*1000*1000;

network_thread unrsv_proto_thread;
unsigned int unrsv_thread_pid;

network_thread rsv_proto_thread;
unsigned int unrsv_thread_pid;

struct list_head rcv_net_reserve_head;
net_capacity_t rcv_net_reserve_current_capacity;	/* for admission control */
unsigned long rcv_net_bandwidth;
cpu_tick_data_t bw_period_ticks;
struct timespec bw_period;

struct sk_buff_head *backlog_list = NULL;
struct packet_type *ptype_rk_all = NULL;
char unrsv_q_empty = 1;
extern struct packet_type *ptype_base[16];
extern struct packet_type *ptype_all;


void unrsv_protocol_thread(network_thread *thread);
void rsv_protocol_thread(network_thread *thread);

void start_proto_thread(int (*func)(void *), network_thread *thread);
void stop_proto_thread(network_thread *thread);

extern struct sock *udp_v4_lookup(u32 sad, u16 spo, u32 dad, u16 dpo, int dif);
extern struct sock *tcp_v4_lookup(u32 saddr, u16, u32 daddr, u16, int);

inline int rk_process_pkt(rcv_net_reserve_t rcv_net, struct sk_buff_head *back_list, struct packet_type *ptype_all);

#define rcv_net_reserve_entry(list) list_entry((list), struct rcv_net_reserve, rcv_net_link)
static int efficient_timespec_ceil (struct timespec dividend,
				    struct timespec divider);
static int ceiling (unsigned long dividend, unsigned long divider);
static int timespec_ceiling (struct timespec dividend,
			     struct timespec divider);
static struct timespec timespec_mult (struct timespec multiplicand,
				      int multiplier);
static struct timespec timespec_mult (struct timespec, int);

static int admit_reserve_request(rcv_net_reserve_t net);
void rcv_priority_list_add(rcv_net_reserve_t net, struct list_head *head);
int rcv_priority_list_remove(rcv_net_reserve_t net, struct list_head *head);

unsigned static char thread_started  = 0;
unsigned static char rk_network_active = 0;
extern atomic_t netdev_rx_dropped;
extern int netdev_dropping;
int net_max_backlog= 350;


/******************** Kernel Hooks *****************************************/
extern int (*rk_netif_rx_hook)(struct sk_buff_head *, struct sk_buff *);
extern void (*rk_process_pkt_hook)(struct sk_buff_head *, struct packet_type *,
								   int *);

int rk_rcv_pkt (struct sk_buff_head *back_list, struct sk_buff *skb);
void rk_netbh (struct sk_buff_head * back_list, 
	       struct packet_type *ptype_all, int * rk_recv_processing);


extern int rk_rcv_pkt_dummy (struct sk_buff_head *head, struct sk_buff *skb);
extern void dummy_process_pkt (struct sk_buff_head *back_list,struct packet_type *ptype_all, int * rk_recv_processing);

//#ifndef THREADED_NET
#if 0
extern void (*bh_attach_rs_hook)(void);
extern void (*bh_detach_rs_hook)(void);
void bh_attach_rs(void);
void bh_detach_rs(void);

//#endif
extern void (*intr_st_acct_hook)(void);
extern void (*intr_ed_acct_hook)(void);
void intr_st_acct(void);
void intr_ed_acct(void);
#endif
/*************************end *******************************************/
cpu_tick_data_t start_bh, end_bh, bh_time, start_intr, end_intr, intr_time;
rk_resource_set_t rs_recv_net = NULL;
rk_resource_set_t rs_current = NULL;
rk_resource_set_t rs_current1 = NULL;
extern rk_resource_set_t rk_default_resource_set;
extern rk_resource_set_t rk_idle_resource_set;
static unsigned long rx_data;

extern rk_reserve_t cpu_reserve_create(rk_resource_set_t rs, cpu_reserve_attr_t cpu_attr);
#if 0
rk_timer_t netdev_timer = NULL;
void netdev_replenish_bw(rk_timer_t tmr);
#endif
void rcv_net_processing_init(void)
{


  //#ifndef THREADED_NET
#if 1
  //cpu_reserve_attr_data_t recv_cpu_attr;
  //rk_reserve_t recv_reserve= NULL;

  unsigned long now_jiffy = jiffies;

  INIT_LIST_HEAD(&rcv_net_reserve_head);

#ifndef THREADED_NET
  while(jiffies < now_jiffy + 2);


  //bh_attach_rs_hook = bh_attach_rs;
  //bh_detach_rs_hook = bh_detach_rs;
#endif

  //intr_st_acct_hook = intr_st_acct;
  //intr_ed_acct_hook = intr_ed_acct;

#ifdef THREADED_NET

  INIT_LIST_HEAD(&rcv_net_reserve_head);
  rcv_net_reserve_current_capacity = 0;
  
  rcv_net_reserve_available_buffer_pool = 350;
  
  link_netr_speed = LINK_SPEED_100MBPS;
  // byt_rx_time = BYT_TX_TIME_100MBPS;

  printk("assigned receiving link speed %d bps\n", link_netr_speed);
  //link_netr_speed = NETRBW_IN_BITS_PER_SEC/8;
  byt_rx_time = (1000*1000*1000/link_netr_speed)*8; // in ns
  /***************************************************************/

  while(jiffies < now_jiffy + 2);
  
  start_proto_thread((int (*)(void *))unrsv_protocol_thread, 
			    &unrsv_proto_thread);
#if 0
  start_proto_thread((int (*)(void *))rsv_protocol_thread, 
			    &rsv_proto_thread);
#endif

  rk_netif_rx_hook = rk_rcv_pkt; // Interrupt handler extension
  rk_process_pkt_hook = rk_netbh; //Bottom half extension

#endif
  
#endif
}


/*****************************************************************/
/**********Interrupt Handler Extension ***************************/
cpu_tick_data_t rx_start, rx_end;
unsigned long rx_diff;
int rk_rcv_pkt (struct sk_buff_head *back_list, struct sk_buff *skb)
{
  unsigned short type;
  rk_reserve_t rsv;
  rcv_net_reserve_t rcvrsv;
  cpu_tick_data_t diff, diff1;

  skb->h.raw = skb->nh.raw = skb->data;
  type = skb->protocol;

  if (rx_data == 0)
    rk_rdtsc(&rx_start);

  rx_data += skb->len;

  if (rx_data > 300000)
    {
      rk_rdtsc(&rx_end);
      diff = rx_end - rx_start;
      tick2usec(&diff, &diff1);
      
      rx_diff = (unsigned long)(diff1);
      rcv_net_bandwidth = rx_data/rx_diff;
      
      //rx_start = 0;
      rx_data = 0;
    }
  //#if 0
if (type == 8) {
  	struct udphdr *uh= NULL;
	struct tcphdr *th = NULL;
	struct sock *sk = NULL;
	struct iphdr *iph = skb->nh.iph;
				    
		if(iph->protocol == 17 || iph->protocol == 6) {
			u32 saddr = iph->saddr;
			u32 daddr = iph->daddr;

			if (iph->protocol == 17) {
				

			    uh = (struct udphdr *)(skb->nh.raw + iph->ihl*4);
				

			    sk = udp_v4_lookup(saddr, uh->source, daddr, 
								   uh->dest, skb->dev->ifindex);
			} else {
				
			    th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4);
			    sk = tcp_v4_lookup(saddr, th->source, daddr, 
								   th->dest, skb->dev->ifindex);
			}

			
			
			if (sk != NULL) {
			   
			    if (sk->rcv_queue != NULL && sk->state != TCP_TIME_WAIT) {
				
			      rsv = sk->rk_rcv_net_reserve;
			      rcvrsv = (rcv_net_reserve_t)(rsv->rsv_rsv);
					
			      
			      if(sk->rcv_queue->qlen < rcvrsv->net_res_attr.buffer_space) {
						
						if (rk_network_active == 0) {
							rk_network_active = 1;
							ptype_rk_all = ptype_all;
						}
						rsv = sk->rk_rcv_net_reserve;
						rcvrsv = rsv->rsv_rsv;
				
						skb_queue_tail(sk->rcv_queue,skb);
						//rcvrsv->proto_thread.net_queue_empty = 0;
						//rcvrsv->proto_thread.thread_active = 1;

						unrsv_q_empty = 0;
			
						if (waitqueue_active (&unrsv_proto_thread.queue))
							wake_up(&unrsv_proto_thread.queue);
				
						return 0;
					} else {
						atomic_inc(&netdev_rx_dropped);
						kfree_skb(skb);
						return 0;
					}
				}
			}
#if 0
			/*sk = NULL! so drop the packet right away unless it is from the "localhost"!! */ 
			else if (saddr != 0x100007f) // 0x100007f=localhost
			  {
			    atomic_inc(&netdev_rx_dropped);
			    kfree_skb(skb);
			    return 0;
			    
			  }
#endif
			
		}
}
//#endif


 if (back_list->qlen <= rcv_net_reserve_available_buffer_pool) {

		
   if (back_list->qlen) {
     if (netdev_dropping == 0) {

       //New addition			  
       if (skb->dev->flags & IFF_SLAVE  && 
	   skb->dev->slave) {
	 skb->dev = skb->dev->slave;
       }
       
       skb_queue_tail(back_list,skb);
       unrsv_q_empty = 0;

       if (rk_network_active == 0) {
	 rk_network_active = 1;
	 
	 ptype_rk_all = ptype_all;
	 backlog_list = back_list;
	 
       }
       
       if (thread_started == 1) {
	 
	 
	 if (waitqueue_active(&unrsv_proto_thread.queue))
	   {
	    
	   wake_up(&unrsv_proto_thread.queue);
	   }
	 return (0);
       }
       
       
				/******************************/
       return (0);
     }
     
     atomic_inc(&netdev_rx_dropped);
     kfree_skb(skb);
     return (0);
   }
   
   netdev_dropping = 0;
   
   if (skb->dev->flags & IFF_SLAVE  &&  skb->dev->slave) {
     skb->dev = skb->dev->slave;
   }

   skb_queue_tail(back_list,skb);
   unrsv_q_empty = 0;
   
   if (rk_network_active == 0) {
     
     rk_network_active = 1;
     ptype_rk_all = ptype_all;
     backlog_list = back_list;
     return 0;
   }
   
   
   if (thread_started == 1) {
     
     
     if (waitqueue_active(&unrsv_proto_thread.queue))
       {
	 
       wake_up(&unrsv_proto_thread.queue);
       }
     return (0);
   }
   
   
   return (0);
 }
 
 
 netdev_dropping = 1;
 atomic_inc(&netdev_rx_dropped);
 kfree_skb(skb);
 
 return (0);				
}

/***********************************************************************/
/*******************Bottom Half Extension *****************************/


void rk_netbh (struct sk_buff_head * back_list, 
					 struct packet_type *ptype_all, int * rk_recv_processing)
{ 

  *rk_recv_processing = 2;
  
  //printk("bh\n");
  return;

}


void rcv_net_processing_cleanup(void)
{




#if 1
  list_del(&rcv_net_reserve_head);
  INIT_LIST_HEAD(&rcv_net_reserve_head);
  rcv_net_reserve_current_capacity = 0;
  rcv_net_bandwidth = 0;
#if 0
  rk_timer_destroy(netdev_timer);
#endif

  //intr_st_acct_hook = NULL;
  //intr_ed_acct_hook = NULL;

#ifndef THREADED_NET
  //bh_attach_rs_hook = NULL;
  // bh_detach_rs_hook = NULL;
#endif

#ifdef THREADED_NET
  rk_netif_rx_hook = rk_rcv_pkt_dummy; // Interrupt handler extension

  stop_proto_thread(&unrsv_proto_thread);

  rk_process_pkt_hook = dummy_process_pkt; //Bottom half extension
#if 0
  stop_proto_thread(&rsv_proto_thread);
#endif


#endif
#endif


}

/* create a new kernel thread */
void start_proto_thread(int (*func)(void *), network_thread *thread)
{
	thread->startstop_sem = MUTEX_LOCKED;

	
	/* create the new thread */
	kernel_thread(func, (void *)thread, 0);

	/* wait till it has reached the setup_thread routine */
	down(&thread->startstop_sem);
               
}

void stop_proto_thread(network_thread *thread)
{
	if (thread->thread == NULL) {
		printk("kill_proto_thread: killing non existing thread!\n");
		return;
	}

	//remove_task(thread->thread);

	/* get the global lock to prevent a race in the
	   fall-asleep phase of the thread */
	thread->startstop_sem = MUTEX_LOCKED;

#ifdef __alpha
	/* on Alpha platform we need to do a memory barrier
	   here to be sure that the flags are visible on
	   all CPUs. This is not portable, we should e.g.
	   use atomic_t here for passing the information.
	*/
	mb();
#endif

	/* set flag to request thread termination */
	thread->terminate = 1;
	//thread->net_queue_empty = 1;
	//thread->rs->netr_rsv->rsv_state &= ~RSV_IS_DEPLETED;
	printk("wake up\n");
	wake_up(&thread->queue);

	
	printk("killing protocol processing thread...\n");

	//kill_proc(SIGKILL, thread->pid, 1);
       
	printk("killed \n");
	/* block till thread terminated */
	down(&thread->startstop_sem);
}


void setup_thread(network_thread *thread)
{
  //printk("entring setup\n");
    /* lock the kernel */
	lock_kernel();
	/* release insmod's memory map, use the kernel one's */
	exit_mm(current);
	/* set session leader and process group to init process */
	current->session = 1;
	current->pgrp = 1;
	/* set name of this process (max 15 chars + 0 !) */
	sprintf(current->comm, "net_thread");

	//printk("thread cr");
	/* disconnect from the fs usage */
	exit_files(current);
	exit_fs(current);
	//current->flags |= PF_NOMM;
	//printk("after fs\n");
	/* fill in thread structure */
	thread->thread = current;

	/* set signal mask to what we want to respond */
	/*siginitsetinv(&current->blocked, 
	  sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));*/
	
	siginitsetinv(&current->blocked, sigmask(SIGINT));

	current->state = TASK_UNINTERRUPTIBLE;
	/* initialise wait queue */
	//thread->queue = NULL;
	init_waitqueue(&thread->queue);

	/* initialise termination flag */
	thread->terminate = 0;
	//init_waitqueue(&thread->queue);

	/* let others run */
	unlock_kernel();

	/* tell the creator that we are ready and let him run */
	up(&thread->startstop_sem);
        
}


void leave_proto_thread(network_thread *thread)
{
	/* we are terminating */
	/* lock the kernel, the exit will unlock it */
	thread->thread = NULL;

#ifdef __alpha
	mb();
#endif

	/* notify the kill_thread() routine that we are terminating. */
	up(&thread->startstop_sem);
}

void rsv_protocol_thread(network_thread *thread)

{
}



extern int __fast_resource_set_swap(rk_resource_set_t, struct task_struct *, rk_resource_set_t);



#ifndef THREADED_NET

unsigned long nors_count, rs_count;

void bh_attach_rs(void)
{
  unsigned long flags;

  // save_flags(flags);

  //cli();
  rs_current = current->rk_resource_set;



  if (rs_current)
    {

      
      //printk("rs %lu\n", rs_count);
      
      rk_rdtsc(&start_bh);
      
    }

  else
    {
      
      nors_count++;
      //printk("nors %lu\n", nors_count);
      //rk_rdtsc(&start_bh);
      //printk("pid %d\n", current->pid);
      
    /* no resource set attached */
     

    }
  // restore_flags(flags);
  /*
  if (rs_current && rs_recv_net)
    __fast_resource_set_swap(rs_current, current, rs_recv_net);

  */
}

void bh_detach_rs(void)
{
          

  if (rs_current)
    {

      
      rk_rdtsc(&end_bh);
      
      rs_current->sched_ovhd += end_bh - start_bh;
      end_bh = start_bh = 0;

    }

  
}
#endif

/****Interrupt handler accounting*****/
void intr_st_acct(void)
{
  rs_current1 = current->rk_resource_set;
  
  if (rs_current1)
    {
    
      rk_rdtsc(&start_intr);

    }

}

void intr_ed_acct(void)
{
  if (rs_current1)
    {

      rk_rdtsc(&end_intr);
      rs_current1->sched_ovhd += end_intr - start_intr;
      end_intr = start_intr = 0;

}
}
/************************************/
#ifdef THREADED_NET
void unrsv_protocol_thread(network_thread *thread)
{
  int byte_count, count;
  unsigned long flags;
  cpu_reserve_attr_data_t recv_cpu_attr;
  pid_t pid;
  //unsigned int packet_count;
  rk_reserve_t recv_reserve= NULL;
  int done;
  int  cpu_reserve_state;
  rcv_net_reserve_t rcv_net;
  //  cpu_reserve_t rcv_cpu;
  struct list_head *ptr=NULL;
  // struct sk_buff *skb_head=NULL;
  unsigned char q_empty;
  //struct list_head *head = &rcv_net_reserve_head;
  rk_resource_set_t current_rs;
  rk_reserve_t rsv_rcv_net;
  
  setup_thread(thread);

  cpu_reserve_state = 1;
  unrsv_thread_pid = current->pid;
  q_empty = 0;

  //#if 0
  
  if (rs_recv_net == NULL)
    rs_recv_net = rk_resource_set_create("recv_scheduler");


  

  if (rs_recv_net)
    {
      recv_cpu_attr.compute_time.tv_sec = 0; 
  
      recv_cpu_attr.compute_time.tv_nsec = 18*10*1000*1000; /*  is reserved */
      recv_cpu_attr.period.tv_sec = 0;
      recv_cpu_attr.period.tv_nsec = 10*100*1000*1000;
      
      recv_cpu_attr.deadline.tv_sec = 0;
      recv_cpu_attr.deadline.tv_nsec = 10*100*1000*1000;

      recv_cpu_attr.start_time.tv_sec = 0;
      recv_cpu_attr.start_time.tv_nsec = 0;

      recv_cpu_attr.blocking_time.tv_sec = 0;
      recv_cpu_attr.blocking_time.tv_nsec = 0;

      recv_cpu_attr.reserve_type.enf_mode = RSV_SOFT;
      recv_cpu_attr.reserve_type.sch_mode = RSV_SOFT;
      recv_cpu_attr.reserve_type.rep_mode = RSV_SOFT;
      //recv_cpu_attr.ticket_type = CONSTANT;
      //recv_cpu_attr.processor = RK_ANY_CPU;

     
      recv_reserve = cpu_reserve_create(rs_recv_net, &recv_cpu_attr);
      

      if (recv_reserve != NULL)
	{
	printk("reserve created for the default protocol processing thread \n");
    } else {
      printk("oops!! couldn't create  reserve for the dlft protocol processing thread :-((\n");	  
      
	}


      pid = thread->thread->pid;



      printk("attaching thread\n");
      if((done = resource_set_attach_process(rs_recv_net, thread->thread)) != 0)
	{
	  printk("COULD NOT ATTACH RESOURCE SET \n");
	  printk("----------------------------\n");
	
	}
  

      current_rs = rs_recv_net;
           
    }


  thread_started = 1;
  q_empty = 0;
  count = 100;
  current_rs = rs_recv_net;

  for (;;)
    {
      
      if (thread->terminate)
	{
			/* we received a request to terminate ourself */
	  break;    
	}
      
      
      	if (rk_network_active == 1)
		{

		  ptr = rcv_net_reserve_head.next;

		  
		   while (ptr != &rcv_net_reserve_head) {
		      rcv_net = rcv_net_reserve_entry(ptr);
		      
		      rsv_rcv_net = rcv_net->rsv;
		       
		      if (rsv_rcv_net->rsv_state != RSV_IS_DEPLETED)
			{

			  /*** Check if the CPU reserve is depleted ****
			       if so, put ptr to the next in the list ***/

			  if (rcv_net->rsv->rsv_rs->rs_cpu != NULL_RESERVE)
			 cpu_reserve_state = cpu_reserve_eligible(rcv_net->rsv->rsv_rs->rs_cpu);
			  else
			    {
			      cpu_reserve_state = 0;
			    
			    }
			  /**** cpu_reserve_state = 0 means cpu reserve is depleted *******/
			  
			  if (cpu_reserve_state != 0) // NOT depleted

			    {
			      if (!skb_queue_empty(&rcv_net->queue))
			  
				break;

			      else // pkt queue is empty
				{
				  ptr = ptr->next; 
				  continue;

				}
			    }

			  else //cpu reserve is depleted
			    {
			      ptr = ptr->next;
			      
			      continue;

			    }
			    
			}

		      else
			{
			  ptr = ptr->next;
			  continue;
			}


			}
		      

		   if (ptr != &rcv_net_reserve_head)
		     {

		       if (current_rs != rcv_net->rsv->rsv_rs)
			 {
			   // current_rs = rcv_net->rsv->rsv_rs;
			   if ((done = __fast_resource_set_swap(current_rs,thread->thread, rcv_net->rsv->rsv_rs)) != 0)
			     {
			       printk("at");
			     }
			   current_rs = rcv_net->rsv->rsv_rs;
			      
			   schedule();
			 }


		       byte_count = rk_process_pkt(rcv_net, &rcv_net->queue, ptype_rk_all);

		       if (byte_count <= 0)
			 {

			   if (current_rs != rs_recv_net)
			     {

				      
			       if ((done = __fast_resource_set_swap(current_rs,thread->thread, rs_recv_net)) != 0)
				 {
				   printk("dt");
				 }
			       current_rs = rs_recv_net;
			     }


			 }
		       
#if 0
		       if (byte_count != 0)
				    {
				  rk_spin_lock(flags);
				  rcv_net->used_amount+=  byte_count;
				  count = rcv_net->available_amount -rcv_net->used_amount; 
				  if (count <= 0)
				    {

				    rsv_rcv_net = rcv_net->rsv;
				  rsv_rcv_net->rsv_state = RSV_IS_DEPLETED;
				  rk_spin_unlock(flags);

				  if (current_rs != rs_recv_net)
				    {

				      
				      if ((done = __fast_resource_set_swap(current_rs,thread->thread, rs_recv_net)) != 0)
					{
					  printk("dt");
					}
				      current_rs = rs_recv_net;
				    }
				  
				    }
				  else
				  rk_spin_unlock(flags);


				  schedule();
				    }
#endif
		       
		       continue;


		     }

		    
		   if (current_rs != rs_recv_net)
		     {
	      
		       if ((done = __fast_resource_set_swap(current_rs,thread->thread, rs_recv_net)) != 0)
			 {
			   printk("dt");
			 }
		       current_rs = rs_recv_net;

		       schedule();
		     }			   
		   
		   
		   
		   byte_count = rk_process_pkt(NULL, backlog_list, ptype_rk_all);
		  

		  //spin_lock_irqsave(&skb_queue_lock, flags);
		  
		  //rk_spin_lock(flags);
		  if (byte_count == 0)
		  unrsv_q_empty = 1;
		  //rk_spin_unlock(flags);
		else
		 unrsv_q_empty = 0;
		  
		  //spin_unlock_irqrestore(&skb_queue_lock,flags); 

		  if (unrsv_q_empty == 1)
		    {
		   
   		      mark_bh(NET_BH);

		      __wait_event(thread->queue, ((unrsv_q_empty == 0)|| (thread->terminate == 1)));


		      
		      
		      continue;
		  
		    } else 
		      {

			
			schedule();
			
			continue;
		      }

		}

	else //should be waiting for the interrupt handler to run atleast once...
	  {

	    

	    __wait_event(thread->queue, ((rk_network_active == 1)||(thread->terminate == 1)));

	    continue;

	  }

    }

  /* here we go only in case of termination of the thread */

  /* cleanup the thread, leave */

  thread_started = 0;
  leave_proto_thread(thread);

}
  
inline int rk_process_pkt (rcv_net_reserve_t rcv_net, struct sk_buff_head *back_list, struct packet_type *ptype_all)
     
{

struct packet_type *ptype;
struct packet_type *pt_prev;
unsigned short type;
int i;
 int byte_count, count;
 //#if 0
 unsigned long flags;
 //#endif
 //rk_reserve_t rsv_rcv_net;


 byte_count = 0;


 //save_flags(flags);
 //cli();
 //rk_spin_lock(flags);
 start_bh_atomic();

     for (i = 0; i < PACKET_RESCHED_COUNT; i++)
       {

  
	 struct sk_buff * skb;

	 /* Check if any higher-priority process is running:
	    
	    if true: switch back to the scheduler 

	    come back to this task after the schduler is done running 

	    lets see if this can be done efficiently 
	 */

	
#if 0
	 spin_lock_irqsave(&skb_queue_lock, flags);
	 if (skb_queue_empty(back_list))
	   {
    	  
	     spin_unlock_irqrestore(&skb_queue_lock, flags);
	     return 0;
	   }
  
	 spin_unlock_irqrestore(&skb_queue_lock, flags);
#endif
	 

	 skb = skb_dequeue(back_list);
	 
	 if (skb == NULL)
	   {
	     //unrsv_q_empty = 1;
	     //restore_flags(flags);
	     end_bh_atomic();
	     //rk_spin_unlock(flags);
	   return (byte_count);
	   }
  
	
  /* XXX: Every time!!! */
  skb->h.raw = skb->nh.raw = skb->data;
  
  if (skb->mac.raw < skb->head || skb->mac.raw > skb->data) {
			printk(KERN_CRIT "%s: wrong mac.raw ptr, proto=%04x\n", skb->dev->name, skb->protocol);
			kfree_skb(skb);
			continue;
  }
 

  type = skb->protocol;

  byte_count += skb->len;

  pt_prev = NULL;
  for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next)
    {
      if (!ptype->dev || ptype->dev == skb->dev) {
	if(pt_prev)
	  {
				  struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC);
				  if(skb2)
				    pt_prev->func(skb2,skb->dev, pt_prev);
	  }
				pt_prev=ptype;
      }
			printk("all\n");
    }
  
		for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) 
		  {
		    if (ptype->type == type && (!ptype->dev || ptype->dev==skb->dev))
		      {
				/*
				 *	We already have a match queued. Deliver
				 *	to it and then remember the new match
				 */
			if(pt_prev)
			  {
			    struct sk_buff *skb2;
			    
			    skb2=skb_clone(skb, GFP_ATOMIC);

			    /*
			     *	Kick the protocol handler. This should be fast
					 *	and efficient code.
					 */
			    //printk("kicking handler 1 \n");
			    if(skb2)
			      pt_prev->func(skb2, skb->dev, pt_prev);
			  }
				/* Remember the current last to do */
			pt_prev=ptype;
		      }
		    
		  } /* End of protocol list loop */
		
		/*
		 *	Is there a last item to send to ?
		 */

		if(pt_prev)
		  {
		    //printk("kicking handler 2\n");
		    pt_prev->func(skb, skb->dev, pt_prev); 
		  }
		/*
		 * 	Has an unknown packet has been received ?
		 */
	 
		else {
		  kfree_skb(skb);
		}		
				
	
   }
     end_bh_atomic();

     rk_spin_lock(flags);

     if (rcv_net != NULL)
       {
	 rcv_net->used_amount += byte_count;
	 count = rcv_net->available_amount - rcv_net->used_amount;
	 byte_count = count;
	 if (byte_count <=0)
	   {
	   rcv_net->rsv->rsv_state = RSV_IS_DEPLETED;
	   }
       }
     // restore_flags(flags);
     rk_spin_unlock(flags);
     return(byte_count);

    
   }
#endif

rk_reserve_t
rcv_net_reserve_create (rk_resource_set_t rs,
		    net_reserve_attr_t net_attr, void *data)
{
  rk_reserve_t rsv= NULL;
  rcv_net_reserve_t netrsv;
  net_capacity_t capacity;
  net_capacity_t new_capacity;
  net_capacity_quad_t qc, qt, qd;
  unsigned long flags;
  /*
#ifdef	linux
  struct device *netdev = data;
#endif
  */

  
  if (rs == NULL)
    return NULL_RESERVE;

  rk_spin_lock (flags);
  /* check for validity of "rs" first */
  if (!rk_valid_rset (rs))
    goto leave;

  if (rs->rs_rcv)
    {
      /* pre-existing rnet reserve */
      goto leave;
    }
  if (rs->rs_cpu == NULL_RESERVE) {
		goto leave;
    } 

  /* admission control */
  /*  
     now the amount is in net_attr
     qc = b;
   */
  qc = net_attr->amount;

  net_attr->net_time.tv_sec =
    (net_attr->amount * BYTE_TRANSMISSION_TIME) / (1000 * 1000 * 1000);

  net_attr->net_time.tv_nsec = net_attr->amount * BYTE_TRANSMISSION_TIME -
    net_attr->net_time.tv_sec * 1000 * 1000 * 1000;

  /*                 items for the period
     qt = t->tv_sec; qt *= NANOSEC; qt += t->tv_nsec;
   */
  qt = net_attr->period.tv_sec;
  qt *= NANOSEC;
  qt += net_attr->period.tv_nsec;

  qd = net_attr->deadline.tv_sec;
  qd *= NANOSEC;
  qd += net_attr->deadline.tv_nsec;

  if (!qt)
    {
      printk ("rcv_net_reserve_create: null time period\n");
      return NULL_RESERVE;
    }

  if (!net_attr->amount)
    {
      printk ("net_reserve_create: null amount time\n");
      return NULL_RESERVE;
    }

  /* Check deadline */
  if (timespec_gt (net_attr->deadline, net_attr->period))
    {
      printk ("net_reserve_create: deadline greater than period\n");
      return NULL_RESERVE;
    }

  /* Check for the start_time value */
  if (net_attr->start_time.tv_nsec >= NANOSEC)
    {
      printk ("net_reserve_create: start_time greater than NANOSEC\n");
      return NULL_RESERVE;
    }

  capacity = CAPACITY_OF (qc, (qt * link_netr_speed) / NANOSEC);
     new_capacity = capacity + rcv_net_reserve_current_capacity;
  /*
     if (new_capacity > NET_CAPACITY_MAX) {
     return NULL_RESERVE;
     }
   */
  rcv_net_reserve_current_capacity = new_capacity;
  /* create net reserve object and set static data */
  netrsv = malloc (sizeof (struct rcv_net_reserve));
  bzero (netrsv, sizeof (struct rcv_net_reserve));
  memcpy (&(netrsv->net_res_attr), net_attr,
	  sizeof (net_reserve_attr_data_t));

  /*  
     as above
     netrsv->period = *t;
     netrsv->amount = b;
   */

  netrsv->period = net_attr->period;
  netrsv->amount = net_attr->amount;
  nanosec2tick (&qt, &netrsv->period_ticks);
  netrsv->capacity = capacity;
  /*  
     We don't neet this list, now we use 
     net_reserve_head for the priority list
     list_add(&netrsv->net_link, &net_reserve_head);
   */

  /* init per period data */
  netrsv->available_amount = netrsv->amount;

  if (net_attr->buffer_space < rcv_net_reserve_available_buffer_pool)
    {
	/** This is for downward compatibiliy */
      if (net_attr->buffer_space != 0)
	{
	  //netrsv->buffer_space = 
	  netrsv->net_res_attr.buffer_space = net_attr->buffer_space;
	}
      else
	{
	  //netrsv->buffer_space = 
	    netrsv->net_res_attr.buffer_space = 100;
	}
      rcv_net_reserve_available_buffer_pool -= netrsv->net_res_attr.buffer_space;
    }
  else
    {
	/**** XXX; is this correct?? */
      if (rcv_net_reserve_available_buffer_pool > 100 )
	{
	  //netrsv->buffer_space = 
	  netrsv->net_res_attr.buffer_space = 100 ;
	}
      else
	{
	  //netrsv->buffer_space = 
	    netrsv->net_res_attr.buffer_space = rcv_net_reserve_available_buffer_pool;
	}
      rcv_net_reserve_available_buffer_pool -= netrsv->net_res_attr.buffer_space;
    }

  printk ("buffer space %d\n", netrsv->net_res_attr.buffer_space);

  if (rcv_net_reserve_available_buffer_pool <= 0)
    {
      printk ("net_reserve_create: Warning!!: buffer pool is finished\n");
    }

/* Luca: Why priority_list_remove is protected and priority_list_add is not? */
  rcv_priority_list_add (netrsv, &rcv_net_reserve_head);

  if (!admit_reserve_request (netrsv))
    {
      //rk_disable();
      rcv_net_reserve_available_buffer_pool += netrsv->net_res_attr.buffer_space;
      rcv_priority_list_remove (netrsv, &rcv_net_reserve_head);
      free (netrsv);

      printk ("net_reserve_create: admission control failed\n");
      return NULL_RESERVE;
    }

  
  /*Increment the number of active real-time packet queues */
  rcv_net_reserve_queues++;


  /* create generic reserve object */
  rsv = rk_reserve_create (rs, RSV_RCV);

  rsv->rsv_state = RSV_IS_NULL;
  rsv->rsv_rsv = netrsv;
  rsv->rsv_ops = &rcv_net_reserve_ops;
  netrsv->rsv = rsv;
  skb_queue_head_init(&netrsv->queue);

  /*    
     Now the reserve param are in net_attr
     rsv->rsv_reserve_param = *p;
   */
  rsv->rsv_reserve_param = net_attr->reserve_type;

  // init_waitqueue (&netrsv->depleted_wait);

  /* create a timer for it */
  rk_replenish_timer_create (rsv, net_attr->start_time);



  /* attach reserve to resource set */
#if 0				/* Now, attachment is performed by the timer.. */
  if (rk_resource_set_attach_reserve (rs, rsv) != RK_SUCCESS)
    {
      printk ("Cannot Attach...\n");
      return NULL_RESERVE;
    }
#endif
leave:
  rk_spin_unlock (flags);

  return rsv;			/* success */
}

static int
rcv_net_reserve_ctl (rk_reserve_t rsv, net_reserve_attr_t net_attr)
{
  rcv_net_reserve_t net;
  net_reserve_attr_data_t old_local_attr;
  net_capacity_t capacity;
  net_capacity_t new_capacity, old_capacity;
  net_capacity_quad_t qc, qt, qd;
  int admit_ok = FALSE;
  int pos_adjust = FALSE;

  if ((rsv == NULL) || (!rk_valid_rsv (rsv)))
    {
      return -EINVAL;
    }

  if ((void *) (net = rsv->rsv_rsv) == NULL_RESERVE)
    {
      return -EINVAL;
    }

  /*check for zero reservation request */
  if (!net_attr->amount)
    {
      printk ("net_reserve_create: null amount time\n");
      return -EINVAL;
    }

  /* check deadline */
  if (timespec_gt (net_attr->deadline, net_attr->period))
    {
      /* deadline cannot be greater than the period */
      return -EINVAL;
    }

  /* calculate a new capacity */
  qc = net_attr->amount;

  qt = net_attr->period.tv_sec;
  qt *= NANOSEC;
  qt += net_attr->period.tv_nsec;

  qd = net_attr->deadline.tv_sec;
  qd *= NANOSEC;
  qd += net_attr->deadline.tv_nsec;

  net_attr->net_time.tv_sec =
    (net_attr->amount * byt_rx_time) / (1000 * 1000 * 1000);

  net_attr->net_time.tv_nsec = net_attr->amount * byt_rx_time -
    net_attr->net_time.tv_sec * 1000 * 1000 * 1000;

  capacity = CAPACITY_OF (qc, qt);

  /* save the old parameters */
  memcpy (&old_local_attr, &(net->net_res_attr),
	  sizeof (net_reserve_attr_data_t));

  old_capacity = net->capacity;

  /* load the new parameters */
  memcpy (&(net->net_res_attr), net_attr, sizeof (net_reserve_attr_data_t));
  net->capacity = capacity;
  {
    int adjust = FALSE;
    switch (rcv_net_reserves_scheduling_policy)
      {
      case RATE_MONOTONIC:
	if (timespec_ne (old_local_attr.period, net_attr->period))
	  {
	    adjust = TRUE;
	    break;
	  }
	if ((timespec_eq (old_local_attr.deadline, net_attr->deadline))
	    &&
	    (timespec_ge
	     (old_local_attr.blocking_time, net_attr->blocking_time))
	    && (timespec_ge (old_local_attr.net_time, net_attr->net_time)))
	  {
	    /* same period, same deadline, less compute time: must be ok */
	    admit_ok = TRUE;
	  }
	break;
      case DEADLINE_MONOTONIC:
	if (timespec_ne (old_local_attr.deadline, net_attr->deadline))
	  {
	    adjust = TRUE;
	    break;
	  }
	if ((timespec_eq (old_local_attr.period, net_attr->period)) &&
	    (timespec_ge (old_local_attr.blocking_time,
			  net_attr->blocking_time)) &&
	    (timespec_ge (old_local_attr.net_time, net_attr->net_time)))
	  {
	    /* same period, same deadline, less compute time: must be ok */
	    admit_ok = TRUE;
	  }
	break;

      }

    if (adjust)
      {
	pos_adjust = TRUE;	/* need this for possible resetting later */
	rcv_priority_list_remove (net, &rcv_net_reserve_head);
	rcv_priority_list_add (net, &rcv_net_reserve_head);
      }
  }


  /* do a new admission control test */
  if ((!admit_ok) && (!admit_reserve_request (net)))
    {
      /* admission control failed: return to original values */
      memcpy (&(net->net_res_attr), &old_local_attr,
	      sizeof (net_reserve_attr_data_t));
      net->capacity = old_capacity;

      if (pos_adjust)
	{
	  /* remove and add from list again */
	  rcv_priority_list_remove (net, &rcv_net_reserve_head);
	  rcv_priority_list_add (net, &rcv_net_reserve_head);
	}
      return RK_ERROR;		/* error since change failed */
    }

  /* Admission control test for buffer management */

  if (rcv_net_reserve_available_buffer_pool + old_local_attr.buffer_space -
      net->net_res_attr.buffer_space < 0)
    {
      /* admission control failed: return to original values */
      memcpy (&(net->net_res_attr), &old_local_attr,
	      sizeof (net_reserve_attr_data_t));
      net->capacity = old_capacity;

      if (pos_adjust)
	{
	  /* remove and add from list again */
	  rcv_priority_list_remove (net, &rcv_net_reserve_head);
	  rcv_priority_list_add (net, &rcv_net_reserve_head);
	}

      return RK_ERROR;		/* error since change failed */
    }

  rcv_net_reserve_available_buffer_pool +=
    old_local_attr.buffer_space - net->net_res_attr.buffer_space;

  /* available utilization: is this really needed? */
  new_capacity = capacity + rcv_net_reserve_current_capacity - net->capacity;

  rcv_net_reserve_current_capacity = new_capacity;

  return RK_SUCCESS;		/* success */
}

static int
rcv_net_reserve_destroy (rk_reserve_t rsv)
{
  //void empty_skb_list (int queue_number);
  rcv_net_reserve_t netrsv = rsv->rsv_rsv;
  unsigned long flags;
  rk_resource_set_t rs;
  struct sk_buff *skb;
  struct sk_buff_head *list;

  
  
  rs = rsv->rsv_rs;


  list = &netrsv->queue;
  
  /* destroy timer */
  rk_replenish_timer_destroy (rsv);
  /* return capacity */
  rcv_net_reserve_current_capacity -= netrsv->capacity;
  if ((int) rcv_net_reserve_current_capacity < 0)
    {
      rcv_net_reserve_current_capacity = 0;
    }

  
  //rk_spin_lock(flags);

while(!skb_queue_empty(list)) {
    /* Warning!!! We also need to free the sockbuff!!! */
    skb =  skb_dequeue(list);
    kfree_skb(skb);
  }
 
 rk_spin_lock(flags);
 

  /* Release the buffer space */
rcv_net_reserve_available_buffer_pool += netrsv->net_res_attr.buffer_space;

  /* Release the queue */

  rcv_priority_list_remove (netrsv, &rcv_net_reserve_head);

  
 
  /*Decrement the number of active real-time queues */
  rcv_net_reserve_queues--;

  

  list_del (&netrsv->rcv_net_link);
  
  INIT_LIST_HEAD (&netrsv->rcv_net_link);	/* for sure */

  
  kfree (netrsv);
  
  rsv->rsv_rsv = NULL_RESERVE;

    
  rk_reserve_destroy (rsv);

  
  rk_spin_unlock(flags);

  return RK_SUCCESS;		/* success */
}


static void
rcv_net_reserve_replenish(rk_reserve_t rsv, cpu_tick_t period, cpu_tick_t dummy)
{
  rcv_net_reserve_t netrsv = rsv->rsv_rsv;
  net_capacity_t c;
  long long signed int amount;

#ifdef EVAL_RK_NET
  unsigned long count;
  struct net_eval_data *datap;
#endif

  *period = netrsv->period_ticks;
//*period = 1000000000; Probably this eliminate the crashes?
  //      c = CAPACITY_OF(netrsv->used_amount, netrsv->available_amount);

  c = CAPACITY_OF (netrsv->used_amount, netrsv->period_ticks);

  if (netrsv->max_utilization < c)
    {
      netrsv->max_utilization = c;
    }
  else if (netrsv->min_utilization > c || netrsv->max_utilization == 0)
    {
      netrsv->min_utilization = c;
    }

  netrsv->average.total_utils += c;
  netrsv->average.total_count++;

  netrsv->prev_used_amount = netrsv->used_amount;

  /* refill the capacity */

    //netrsv->used_amount = 0;
  switch (rsv->rsv_reserve_param.rep_mode)
    {
    case RSV_SOFT:
      netrsv->available_amount = netrsv->amount;
      break;

    case RSV_FIRM:
      amount = netrsv->used_amount - netrsv->amount;

      if (amount > 0)
	{
	  size_t next;
	  next = netrsv->amount - amount;
	  if (next >= 0)
	    {
	      netrsv->available_amount = next;
	    }
	  else
	    {
	      netrsv->available_amount = 0;
	    }
	}
      else
	{
	  netrsv->available_amount = netrsv->amount;
	}
      break;

    case RSV_HARD:
      amount = netrsv->used_amount - netrsv->amount;
      if (netrsv->used_amount > netrsv->amount)
	{
	  size_t next;
	  next = netrsv->amount - amount;
	  if (next >= 0)
	    {
	      netrsv->available_amount = next;
	    }
	  else
	    {
	      netrsv->available_amount = 0;
	    }
	}
      else
	{
	  netrsv->available_amount = netrsv->amount;
	}
      break;
    }
  netrsv->used_amount = 0;
  rsv->rsv_state &= ~RSV_IS_DEPLETED;
#if 0
  if (hard_net_reserve_active == 1)
    {
      hard_net_reserve_active = 0;
      mark_bh(NET_BH);
	    
    }
#endif
}


static void
rcv_net_reserve_attach (rk_reserve_t rsv, struct rs_proc_list *rs_proc)
{
  rcv_net_reserve_t netrsv;
  struct rs_sock_list *rs_sock;
  struct sock *sk;
  struct list_head *sock_list;

  //printk("ATTACH\n");

  netrsv = rsv->rsv_rsv;
  sock_list = &rs_proc->rs_proc_task->rs_sock_list;

  for (sock_list = sock_list->next;
       sock_list != &rs_proc->rs_proc_task->rs_sock_list;
       sock_list = sock_list->next)
    {

      rs_sock = list_entry (sock_list, struct rs_sock_list, rs_sock_list);

      sk = rs_sock->sk;

      if (sk != NULL)
	{
	sk->rk_rcv_net_reserve = rsv;
      sk->rcv_queue = &netrsv->queue;
	}
    }
}

static void
rcv_net_reserve_detach (rk_reserve_t rsv, struct rs_proc_list *rs_proc)
{
  rcv_net_reserve_t netrsv;
  struct rs_sock_list *rs_sock;
  struct sock *sk;
  struct list_head *sock_list;
  unsigned long flags;

  rk_spin_lock(flags);
  netrsv = rsv->rsv_rsv;
  sock_list = &rs_proc->rs_proc_task->rs_sock_list;

  for (sock_list = sock_list->next;
       sock_list != &rs_proc->rs_proc_task->rs_sock_list;
       sock_list = sock_list->next)
    {

      rs_sock = list_entry (sock_list, struct rs_sock_list, rs_sock_list);

      sk = rs_sock->sk;

      if (sk != NULL)
	{
	sk->rk_net_reserve = NULL;
	sk->rcv_queue = NULL;
	}

    }
  rk_spin_unlock(flags);
}

static int
rcv_net_reserve_read_proc (rk_reserve_t rsv, char *buf)
{
  char *p = buf;
  rcv_net_reserve_t netrsv;
  net_capacity_t ave;

  netrsv = rsv->rsv_rsv;
  if (netrsv->average.total_count)
    {
      ave = netrsv->average.total_utils / netrsv->average.total_count;
    }
  else
    {
      if (netrsv->available_amount)
	{
	  ave = CAPACITY_OF (netrsv->used_amount, netrsv->period_ticks);
	}
      else
	{
	  ave = CAPACITY_OF (netrsv->used_amount, 1);
	}
    }


  p += sprintf (p,
		"utilization (ave max min): %lu.%02lu %lu.%02lu %lu.%02lu\n",
		CAPACITY_INT (ave), CAPACITY_FRAC (ave),
		CAPACITY_INT (netrsv->max_utilization),
		CAPACITY_FRAC (netrsv->max_utilization),
		CAPACITY_INT (netrsv->min_utilization),
		CAPACITY_FRAC (netrsv->min_utilization));
  p +=
    sprintf (p, "last used |used | available: %d | %d |%d\n",
	     netrsv->prev_used_amount, netrsv->used_amount,
	     netrsv->available_amount);
  p += sprintf (p, "count: %lu\n", netrsv->average.total_count);
  p += sprintf (p, "reserved: %lu.%02lu\n",
		CAPACITY_INT (netrsv->capacity),
		CAPACITY_FRAC (netrsv->capacity));

  return (p - buf);
}

int
rcv_net_reserve_status_proc (char *buf)
{
  char *p = buf;

  p += sprintf (p, "rcv_net_reserve_current_capacity: %lu.%02lu\n rcv_net_bw %u\n",
		CAPACITY_INT (rcv_net_reserve_current_capacity),
		CAPACITY_FRAC (rcv_net_reserve_current_capacity), rcv_net_bandwidth);
  
  return (p - buf);
}


int
admit_reserve_request (rcv_net_reserve_t net)
{
  struct timespec completion_time, prev_completion_time;
  struct timespec result;
  rcv_net_reserve_t curr, r;
  int ceil_value;
  net_reserve_attr_t attr = &(net->net_res_attr);
  struct list_head *ptr, *p2;

#ifdef DEBUG_RK
  printk ("admit_reserve_request: ");
#endif /* DEBUG_RK */

  /* the admission control policy for a reserve is as follows.
   * We check the completion times of the incoming reserve and ALL
   * lower priority reserves assuming that the reserve is admitted.
   * If the completion times of all these reserves are less than their
   * respective deadlines, then the incoming reserve can be admitted.
   */

#ifdef LOG_RESERVES
  if (log_messages)
    {
      log_start = clock_ttime (clockrt);
    }
#endif /* LOG_RESERVES */

  /* do basic checks quickly */
  if (timespec_gt (attr->net_time, attr->period) ||
      timespec_gt (attr->net_time, attr->deadline))
    {
#ifdef DEBUG_RK
      printk ("false (0)\n");
#endif /* DEBUG_RK */
      return FALSE;
    }

  /* perform the "completion time test" */
  for (ptr = rcv_net_reserve_head.next; ptr != &rcv_net_reserve_head; ptr = ptr->next)
    {
      net_reserve_attr_t curr_attr;

      curr = rcv_net_reserve_entry (ptr);
      curr_attr = &(curr->net_res_attr);

      /* repeat for each reserve in the current set of reserves */

      /* Optimization: skip reserves with shorter deadlines for
       *   deadline-monotonic scheduling policy or with shorter periods for
       *   rate-monotonic scheduling.
       */
#ifdef SUPER_CHARGED
      {
	int cont = FALSE;
	switch (rcv_net_reserves_scheduling_policy)
	  {
	  case RATE_MONOTONIC:
	    if (timespec_lt (curr_attr->period, attr->period))
	      {
		/* shorter period reservation: must have been tested earlier */
		cont = TRUE;
	      }
	    break;
	  case DEADLINE_MONOTONIC:
	    if (timespec_lt (curr_attr->deadline, attr->deadline))
	      {
		/* shorter deadline reservation: must have been tested earlier */
		cont = TRUE;
	      }
	    break;
	  default:


	    break;
	  }
	if (cont)
	  continue;
      }
#else /* SUPER_CHARGED */
      if (timespec_lt (curr_attr->period, attr->period))
	{
	  /* shorter period reservation: must have been tested earlier */
	  continue;
	}
#endif /* SUPER_CHARGED */

      timespec_zero (prev_completion_time);
      timespec_set (completion_time, curr_attr->net_time);
#if 0
      timespec_add (completion_time, curr_attr->blocking_time);
#endif
      /* calculate the worst-case completion time */
      while (timespec_le (prev_completion_time, curr_attr->deadline) &&
	     timespec_lt (prev_completion_time, completion_time))
	{
	  timespec_set (prev_completion_time, completion_time);
	  timespec_zero (completion_time);

	  for (p2 = rcv_net_reserve_head.next;
	       p2 != &rcv_net_reserve_head; p2 = p2->next)
	    {
	      net_reserve_attr_t r_attr;

	      r = rcv_net_reserve_entry (p2);

	      /* We compute preemption time from the HIGHER priority reserves and
	       * any EQUAL priority reserves.  This is necessary because the
	       * deadlines can be different for reserves with the same period.
	       */
	      if (r == curr)
		{
		  /* self */
		  continue;
		}

	      r_attr = &(r->net_res_attr);

#ifdef SUPER_CHARGED
	      {
		int done = FALSE;
		switch (rcv_net_reserves_scheduling_policy)
		  {
		  case RATE_MONOTONIC:
		    if (timespec_gt (r_attr->period, curr_attr->period))
		      {
			done = TRUE;
		      }
		    break;
		  case DEADLINE_MONOTONIC:
		    if (timespec_gt (r_attr->deadline, curr_attr->deadline))
		      {
			/* we have found a reserve with a longer period/deadline and
			 * therefore a lower priority, break from loop */
			done = TRUE;
		      }
		    break;
		  }
		if (done)
		  break;
	      }
#else /* SUPER_CHARGED */
	      if (timespec_gt (r_attr->period, curr_attr->period))
		break;
#endif /* SUPER_CHARGED */

	      ceil_value = efficient_timespec_ceil (prev_completion_time,
						    r_attr->period);
	      result = timespec_mult (r_attr->net_time, ceil_value);
	      timespec_add (completion_time, result);
	    }

	  /* add computation time and blocking time of self */
	  timespec_add (completion_time, curr_attr->net_time);
	  //   timespec_add(completion_time, curr_attr->blocking_time);
	}			/* end while */

      if (timespec_gt (completion_time, curr_attr->period) ||
	  timespec_gt (completion_time, curr_attr->deadline))
	{
	  /* deadline already missed; return failure */
#ifdef DEBUG_RK
	  printk ("false\n");
#endif /* DEBUG_RK */
	  return FALSE;
	}
    }

#ifdef LOG_RESERVES
  if (log_messages)
    {
      log_end = clock_ttime (clockrt);
      timespec_sub (log_end, log_start);
      sprintf (LINEA, " admission control %d %d \n", log_end.seconds,
	       log_end.nanoseconds);
      kern_msg_log (LINEA);
    }
#endif /* LOG_RESERVES */

  /* everything seems fine */
#ifdef DEBUG_RK
  printk ("true\n");
#endif /* DEBUG_RK */

  return TRUE;
}

/* this ceiling computation works faster by assuming that the seconds
 * field is less than 1000 seconds, and by truncating the nanoseconds field.
 * If the seconds field is greater than 1000 seconds, a valid but VERY 
 * inefficient response will result!
 */
int
efficient_timespec_ceil (struct timespec dividend, struct timespec divider)
{
  unsigned long dividend_microsecs, divider_microsecs;

  if ((divider.tv_sec == 0) && (divider.tv_nsec == 0))
    {
      return -1;
    }
  if ((dividend.tv_sec >= 1000) || (divider.tv_sec >= 1000))
    {
      /* be ready to pay a BIG penalty now! */
      return (timespec_ceiling (dividend, divider));
    }
#define    MICROSECS_PER_SECOND          1000000

  /* truncate nanoseconds */
  dividend_microsecs = (dividend.tv_sec % 1000) * MICROSECS_PER_SECOND +
    (dividend.tv_nsec / 1000);
  divider_microsecs = (divider.tv_sec % 1000) * MICROSECS_PER_SECOND +
    (divider.tv_nsec / 1000);
  return (ceiling (dividend_microsecs, divider_microsecs));
}


int
ceiling (unsigned long dividend, unsigned long divider)
{
  int quotient;
  quotient = dividend / divider;

  if (divider * quotient == dividend)
    return (quotient);
  else
    return (++quotient);
}

int
timespec_ceiling (struct timespec dividend, struct timespec divider)
{
  int quotient = 1;
  struct timespec divider1;

  divider1 = divider;
  while (timespec_gt (dividend, divider1))
    {
      timespec_add (divider1, divider);
      quotient++;
    }
  return (quotient);
}

struct timespec
timespec_mult (struct timespec multiplicand, int multiplier)
{
  struct timespec result;

  result.tv_sec = 0;
  result.tv_nsec = 0;

  do
    {
      timespec_add (result, multiplicand);
    }
  while (--multiplier);

  return (result);
}

void rcv_priority_list_add(rcv_net_reserve_t net, struct list_head *head)
{
  rcv_net_reserve_t r;
  int done = FALSE;
  struct list_head *ptr;

  if (head->next == head) {
    /* insert at the head */
//    net->net_priority_index = 0;
     list_add(&(net->rcv_net_link), head);
    return;
  }

  for (ptr = head->next; ptr != head; ptr = ptr->next) {
    r = rcv_net_reserve_entry(ptr); 
//    i = r->net_priority_index + 1;
    //  i = r->queue_number + 1;

    
#ifdef SUPER_CHARGED
    switch (rcv_net_reserves_scheduling_policy) {
    case RATE_MONOTONIC:
      if (timespec_lt(net->net_res_attr.period, r->net_res_attr.period)) {
	done = TRUE;
      }
      break;
    case DEADLINE_MONOTONIC:
       if (timespec_lt(net->net_res_attr.deadline, r->net_res_attr.deadline)) {
	 done = TRUE;
       }
       break;
    }
#else SUPER_CHARGED
    if (timespec_lt(net->net_res_attr.period, r->net_res_attr.period)) {
      done = TRUE;
    }
#endif SUPER_CHARGED

    if ((done) || (ptr == head)) {
      /* insert reservation here: subsequent indices will be fine as is! */
//      net->net_priority_index = i;
      //net->queue_number = i;
      list_add(&(net->rcv_net_link), ptr->prev);
      break;
    } 
    //else {
	/* this increments the priority index of this entry */
//      r->net_priority_index = i;
	//r->queue_number = i;
    //    }
  }
  
  if (!done)
    list_add(&net->rcv_net_link, ptr->prev);
}


int rcv_priority_list_remove(rcv_net_reserve_t net, struct list_head *head)
{
  rcv_net_reserve_t r;
  int i;
  struct list_head *ptr;

  if (head->next == head) {
    /* empty list */
    return -1;
  }
  if (head->next == &(net->rcv_net_link)) {
    /* remove item to make empty list */
    list_del(&(net->rcv_net_link));
    return 0;
  }
  

  /* search through list to find item */
  for (ptr = head->next; ptr != head; ptr = ptr->next) {
    r = rcv_net_reserve_entry(ptr);
//    i = r->net_priority_index - 1;
    //i = r->queue_number - 1;

    if (r == net) {
      /* delete reservation */
      list_del(&(net->rcv_net_link));

      /* we are done; subsequent entries already have valid priority indices */
      return 0;
    }	       
    else {
      /* this decrements the priority index of this entry */
//      r->net_priority_index = i;
      //r->queue_number = i;
    }
  }
 
  /* we should not reach here, but just in case, we set the priority 
   * index correctly.
   */
  for (ptr = head->prev, i = 0; ptr != head; ptr = ptr->prev, i++) {
    r = rcv_net_reserve_entry(ptr);
//    r->net_priority_index = i;  
    //r->queue_number = i;  
  }

  return(-1);
}

/*******************System calls ***********************************/

asmlinkage rk_reserve_t
sys_rk_rnet_reserve_create (rk_resource_set_t rs, net_reserve_attr_t uattr)
{
  net_reserve_attr_data_t attr;
  rk_reserve_t rsv;
  rcv_net_reserve_t netrsv;
  //struct timespec t;
  //struct rk_reserve_param p;
  struct device *netdev=dev_base->next;
  
#ifndef THREADED_NET
  
  return NULL;
#endif

  copy_from_user (&attr, uattr, sizeof(net_reserve_attr_data_t));

  

  /*      
     Now, we must use a net_reserve_attr structure!!!
     rsv = net_reserve_create(rs, ub, &t, &p, netdev);
   */

  rsv = rcv_net_reserve_create (rs, &attr, netdev);

  if (rsv)
    {
      /* */
      netrsv = rsv->rsv_rsv;
      //netrsv->netdev = netdev;

     
    }




  return rsv;



}
asmlinkage int
sys_rk_rnet_reserve_ctl (rk_reserve_t rsv, net_reserve_attr_t net_attr)
{

  net_reserve_attr_data_t local_attr;

  if (copy_from_user
      (&local_attr, net_attr, sizeof (net_reserve_attr_data_t)))
    {
      return -EFAULT;
    }

  return rcv_net_reserve_ctl (rsv, &local_attr);
}
