
/**
 @Name:		mytest.c
 @Purpose:	@User:  Fill in purpose

 Notation:
	- this:  struct rp_instance * (ptr to plugin instance)
 Post-Conditions:
   mytest_load
	- Plugin class (mytest_class) structure is initialized
	- mytest_get_class() is registered with PCU
   mytest_create_instance
	- Plugin instance memory is allocated and initialized
	  (base class and its extension):
	  this->rpclass = &mytest_class
	  ... other members of base class ...
   mytest_bind_instance
   
   mytest_handle_packet
   
   mytest_unbind_instance
   
   mytest_free_instance
	- Plugin instance memory is free
   mytest_unload
	- All instances are free
	- Class is not registered with PCU
*/

#include "stdinc.h"

#include "mytest.h"

MOD_MISC("mytest")

// Static plugin class structure.
// Each kernel module has one class structure that is initialized by
// the plugin and a pointer to it is returned. The class structure can then
// be used to create plugin instances. Note that this is a structure and 
// not a pointer.
static struct rp_class mytest_class;

/*
 @User:  Add class-wide global variables here
*/

void
mytest_init_class() {		// initialize plugin class
//
// Initialize class struct:
//   classid - user defined
//   itype   - RP_INTERFACE_TYPE_HLIST for plugins that will modify pkts or want
//             to source or sink data. The signature is
//              <handle_packet(struct rp_instance *this, void *plist)>
//   create_instance = function pointer to your create instance method.
//
  mytest_class.classid = mytest_ID;
  mytest_class.itype   = RP_INTERFACE_TYPE_HLIST;
  mytest_class.create_instance = mytest_create_instance;
  return;
}

struct rp_class *
mytest_get_class() {	// return class structure
  return &mytest_class;
}

// --| create and initialize an instance of mytest |--
struct rp_instance *
mytest_create_instance(struct rp_class *myclass, u_int32_t instanceid) {
  struct mytest_instance *myinst; 

  // allocate memory for local instance struct
  MSR_PLUGIN_MALLOC(myinst,struct mytest_instance *, 
                    sizeof(struct mytest_instance),
                    M_MSR, 
                    M_WAITOK);
  if (myinst == NULL)	return NULL;

  // fill in instance pointers to local methods
  myinst->rootinstance.rpclass         = &mytest_class;
  myinst->rootinstance.handle_packet   = mytest_handle_packet;
  myinst->rootinstance.free_instance   = mytest_free_instance;
  myinst->rootinstance.bind_instance   = mytest_bind_instance;
  myinst->rootinstance.unbind_instance = mytest_unbind_instance;
  myinst->rootinstance.handle_msg      = mytest_handle_msg;

  myinst->rootinstance.instanceid = instanceid;

  /**
   @User:  Initialize instance variables here
  */

  return (struct rp_instance *)myinst;
}

void
mytest_handle_packet(struct rp_instance *this, void *plist) {
  struct mytest_instance *inst = (struct mytest_instance *)this;

  /**
   @User:  Add code to handle packets here
  */

}

void
mytest_free_instance(struct rp_instance *this) {
  if (this) {
    MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_INFO,
          "mytest_free_instance: Freeing instance id %d ((class id %d)\n",
          this->instanceid, this->rpclass->classid));
    MSR_PLUGIN_FREE(this, M_MSR);
  } else {
    MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_WARNING,
          "mytest_free_instance: Passing a NULL this pointer\n"));
  }
}

void
mytest_bind_instance(struct rp_instance *this) {
  struct mytest_instance *inst = (struct mytest_instance *)this;

  MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_INFO,
	"mytest_bind_instance: Binding instance id %d (class id %d, type %d) to filter id %d\n",
        this->instanceid, this->rpclass->classid,
	this->rpclass->itype, this->bound_fid));

  /**
   @User:  Define what occurs when binding your plugin here
  */
}

void
mytest_unbind_instance(struct rp_instance *this) {
  struct mytest_instance *inst = (struct mytest_instance *)this;

  MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_INFO,
	"mytest_unbind_instance: Unbinding instance id %d (class id %d, Type %d) to filter id %d\n",
        this->instanceid, this->rpclass->classid,
	this->rpclass->itype, this->bound_fid));

  /**
   @User:  Define what occurs when unbinding your plugin here
  */
}

// External kernel module entry point.
//
// This function must match the name of the .o file.
// It is called each time the module is loaded or unloaded.
// The stat information is not needed here, so we will 
// leave it lkm_nofunc().
//

#ifdef PLUGIN_DEBUG
int
mytest  (struct lkm_table *lkmtp, int cmd, int ver) {
  struct kernel_plugin_fct_struct *fctPtr;
  extern struct kernel_plugin_fct_struct  MSR_kernel_plugin_fcts;
  fctPtr = &MSR_kernel_plugin_fcts;
#else
int
mytest  (struct lkm_table *lkmtp, int cmd, int ver,
				struct kernel_plugin_fct_struct *fctPtr) {
#endif
  // Do NOT put anything before the kernel_plugin_fcts is set, especially if
  // it uses any of the MSR_ macros!!!
  if (kernel_plugin_fcts == NULL) {
    kernel_plugin_fcts = fctPtr;
    kernel_plugin_variables = fctPtr->pluginVariables;
  }

  MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_VERBOSE,
        "mytest: Entry function -- initialized plugin_fcts pointers\n"));

  MSR_PLUGIN_DISPATCH(lkmtp, cmd, ver, mytest_load, mytest_unload,
							PLUGIN_LKM_NOFUNC_FCT);
}

// This function is called each time the module is loaded
int
mytest_load(struct lkm_table *lkmtp, int cmd) {
  int err;

  MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_VERBOSE,
        "mytest_load: Loading mytest ...\n"));

  if (PLUGIN_LKM_EXISTS_FCT(lkmtp)) {	// avoid loading twice
    MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_INFO,
      "mytest_load: plugin already exists! Returing EEXIST\n"));
    return (EEXIST);
  }
  mytest_init_class();

  err = PLUGIN_PCU_REGISTER_CLASS_FCT(mytest_get_class());
  if (err != RP_OK) {
    MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_ERROR,
	"mytest_load: Error (err = %d) encountered registering class.\n",
	err));
    return -1;
  }

  return 0;
}

// This function is called each time the module is unloaded.
// Remove all existing instances and then remove class.
int
mytest_unload(struct lkm_table *lkmtp, int cmd) {
  struct rp_class *rpclass;
  u_int32_t cid;

  rpclass = mytest_get_class();
  cid = rpclass->classid;

  MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_VERBOSE,
        "mytest_unload: my rpclass id = %d, Struct Address = 0x%08x\n",
        cid, (u_int32_t)rpclass));

  if (PLUGIN_PCU_FREE_ALL_INSTANCES_FCT(rpclass) != RP_OK) {
    MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_ERROR,
          "mytest_unload: Error freeing all instances for class %d\n", cid));
    return -1;
  }

  if (PLUGIN_PCU_DEREGISTER_CLASS_FCT(rpclass) != RP_OK) {
    MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_ERROR,
          "mytest_unload: Error deregistering class %d\n", cid));
  }

  MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_VERBOSE,
        "mytest_unload: Unloaded class %d\n", cid));

  return 0;
}

/*
 @Purpose: Handle control messages.
	The request buffer 'buf' is 44 Bytes (11 ints) long. The same array
	will be used for the reply msg (i.e., request buffer is reused for
	the replay buffer and is overwritten).
 	Request Buffer (1 word = 1 int):
		Word 0	Instance number of receiver
		Word 1	Command (Operation Code)
		Word 2	Arg 0 (if any)
		...
		Word 10	Arg 8 (if any)
	Note 1:	By convention, command 0 is the 'hello' command which returns
		the instance id and command number (0) followed by the
		arguments flags, seq, and *len.  All other commands are
		at the discretion of the user.
	Note 2: The word preceding buf[0] contains the message header and
		contains the values of 'flags', 'seq' and '*len'.
 Args:	this	Addr of this instance
	buf	Request/Reply buffer
	flags	Flags
	seq	Sequence number
	len	IN	request is in buf[0] thru buf[*len/4-1]
		OUT	reply   is in buf[0] thru buf[*len/4-1]
 @User: Append request codes and reply args to the list below.
 Request Codes:		Reply (#: args):
	0: Hello	5: id, cmnd, flags, seq, *len
	*: Hello	5: id, cmnd, flags, seq, *len
*/
int
mytest_handle_msg(struct rp_instance *this, void *buf, u_int8_t flags,
						u_int8_t seq, u_int8_t *len) {
  struct mytest_instance *inst = (struct mytest_instance *)this;
  u_int32_t *vals	= (u_int32_t *)buf;
  u_int32_t id		= (u_int32_t)ntohl(*vals);
  u_int32_t cmnd	= (u_int32_t)ntohl(*(vals + 1));
  struct msr_bufhdr_t *hdr;

  switch (cmnd) {
  case 0:	// Hello
    *vals	= (u_int32_t)htonl(id);
    *(vals + 1)	= (u_int32_t)htonl(cmnd);
    *(vals + 2)	= (u_int32_t)htonl((u_int32_t)flags);
    *(vals + 3)	= (u_int32_t)htonl((u_int32_t)seq);
    *(vals + 4)	= (u_int32_t)htonl((u_int32_t)*len);
    *len = 5 * sizeof(u_int32_t);
    break;
  case 1:	// Fake
    *vals	= (u_int32_t)htonl(id);
    *(vals + 1)	= (u_int32_t)htonl(cmnd);
    *(vals + 2)	= (u_int32_t)htonl(999);
    *len = 3 * sizeof(u_int32_t);
    break;
    /**
     @User:  Add code to handle other messages here
  */
  default:	// Hello
    *vals	= (u_int32_t)htonl(id);
    *(vals + 1)	= (u_int32_t)htonl(cmnd);
    *(vals + 2)	= (u_int32_t)htonl((u_int32_t)flags);
    *(vals + 3)	= (u_int32_t)htonl((u_int32_t)seq);
    *(vals + 4)	= (u_int32_t)htonl((u_int32_t)*len);
    *len = 5 * sizeof(u_int32_t);
    break;
  }

  return 0;
}

