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

 Message Types:
	@User:  Document messages (requests and replies) here
	Op	Short Descr	Request			Reply
	-----------------------------------------------------------
	0	Hello		[0]  instance #		plugin id
				[1]  command = 0	instance #
 Notation:
	- this:  struct rp_instance * (ptr to plugin instance)
 Post-Conditions:
   stringSub_load
	- Plugin class (stringSub_class) structure is initialized
	- stringSub_get_class() is registered with PCU
   stringSub_create_instance
	- Plugin instance memory is allocated and initialized
	  (base class and its extension):
	  this->rpclass = &stringSub_class
	  ... other members of base class ...
   stringSub_bind_instance
   
   stringSub_handle_packet
   
   stringSub_handle_message
   
   stringSub_unbind_instance
   
   stringSub_free_instance
	- Plugin instance memory is free
   stringSub_unload
	- All instances are free
	- Class is not registered with PCU
*/

#include "stdinc.h"

#include "stringSub.h"

MOD_MISC("stringSub")

// 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 stringSub_class;

// @User:  Add class-wide global variables, new constants and functions here

#define EOS '\0'

int prefix(char* s1, char* s2) {	// Return 1 if s1 is a prefix of s2.
  while (*s1 != EOS) {
    if (*s1++ != *s2++) return 0;
  }
  return 1;
}
void copy(char* s1, char* s2) {		// Copy s1 to s2, omitting EOS.
  while (*s1 != EOS) *s2++ = *s1++;
}

void
stringSub_init_class() {		// initialize plugin class
//
// Initialize class struct:
//   classid - user defined
//   itype   - RP_INTERFACE_TYPE_PKT - for read-only plugins. The handle packet
//             signature is <handle_packet(struct rp_instance *this, void *pkt)>
//             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.

  stringSub_class.classid = stringSub_ID;
  stringSub_class.itype   = RP_INTERFACE_TYPE_HLIST;
  stringSub_class.create_instance = stringSub_create_instance;
  return;
}

// --| create and initialize an instance of stringSub |--
struct rp_instance *
stringSub_create_instance(
  struct rp_class *myclass,		// points to class structure
  u_int32_t instanceid)			// new instance identifier
{
  struct stringSub_instance *myinst; 

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

  // fill in instance pointers to local methods
  myinst->rootinstance.rpclass         = &stringSub_class;
  myinst->rootinstance.handle_packet   = stringSub_handle_packet;
  myinst->rootinstance.free_instance   = stringSub_free_instance;
  myinst->rootinstance.bind_instance   = stringSub_bind_instance;
  myinst->rootinstance.unbind_instance = stringSub_unbind_instance;
  myinst->rootinstance.handle_msg      = stringSub_handle_msg;

  myinst->rootinstance.instanceid = instanceid;

  // @User:  Initialize instance variables here
  myinst->pktCount = 0;
  myinst->count = 0;

  return (struct rp_instance *)myinst;
}

void
stringSub_handle_packet(
  struct rp_instance *this,		// points to instance structure
  void *bufferList)			// points to list of pkt buffers
{
  struct stringSub_instance *inst = (struct stringSub_instance *)this;
  msr_bufhdr_t	*buffer = msr_firstBuffer(bufferList);
  struct ip	*iph = msr_pkt_iph(buffer);
  int		len = msr_iplen(iph);
  int		proto = msr_ipproto(iph);
  char		*p, *end;

  // @User:  Add code to handle packets here

  // initialize p to point to first byte of the IP payload
  // initialize end to point to fifth byte from end of payload

  p = ((char *) iph) + msr_iphlen(iph);
  end = ((char *) iph) + len - 5;
  inst->pktCount++;

  while (p < end) {	// replace "HELLO" with "adieu" everywhere
    if (prefix("HELLO",p)) {
      copy("adieu",p);
      inst->count++;
      p += 5;
    } else {
      p++;
    }
  }
  // recompute the TCP checksum
  assign_tcpCksums((iphdr_t *) iph);

  // Note: this plugin is a little dangerous, since it
  // scans the transport and application level protocol
  // headers in addition to the true payload. A more
  // careful implementation would check for TCP and
  // higher level headers, operate only on packets
  // with appropriate payloads and initialize p to
  // the first byte of the actual data portion of the
  // packet.
}

/*
 @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 reply 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 plugin id and the instance number.  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' which are
		passed to this routine.
 @User: Append request codes and reply args to the list below.
 Request Codes:		Reply (#: args):
	0: Hello	2: stringSub_ID, id
	*: Hello	2: stringSub_ID, id
*/
int
stringSub_handle_msg(
  struct rp_instance *this,	// points to instance structure
  void *buf,			// points to request/reply buffer
  u_int8_t flags,		// flags
  u_int8_t seq,			// sequence number
  u_int8_t *len)		// IN:  request is in buf[0] thru buf[*len/4-1]
				// OUT:	reply is in buf[0] thru buf[*len/4-1]
{
  struct stringSub_instance *inst = (struct stringSub_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;

  *vals	= (u_int32_t)htonl(stringSub_ID);
  *(vals + 1)	= (u_int32_t)htonl(id);

  switch (cmnd) {
    case 0:	// Hello
      *len = 2 * sizeof(u_int32_t);
      break;
    case 1:
      // @User:  Add code to handle other messages here
      vals[0] = (u_int32_t) htonl(inst->count);
      vals[1] = (u_int32_t) htonl(inst->pktCount);
      *len = 2*sizeof(u_int32_t);
      break;
    default:
      // @User:  Usually, a copy of the most common command reply
      vals[0] = (u_int32_t) htonl(inst->count);
      vals[1] = (u_int32_t) htonl(inst->pktCount);
      *len = 2 * sizeof(u_int32_t);
      break;
  }

  return 0;
}

// --| Free instance structure |--
void
stringSub_free_instance(
  struct rp_instance *this)	// points to instance structure
{
  if (this) {
    MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_INFO,
          "stringSub_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,
          "stringSub_free_instance: Passing a NULL this pointer\n"));
  }
}

// --| Bind plugin instance to filter |--
void
stringSub_bind_instance(
  struct rp_instance *this)	// points to instance structure
{
  struct stringSub_instance *inst = (struct stringSub_instance *)this;

  MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_INFO,
	"stringSub_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
}

// --| Unbind plugin instance from filter
void
stringSub_unbind_instance(
  struct rp_instance *this)	// points to instance structure
{
  struct stringSub_instance *inst = (struct stringSub_instance *)this;

  MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_INFO,
	"stringSub_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
}

/**
	----------------------------------------------------------------
 @User: YOU SHOULD NOT NEED TO MAKE ANY CHANGES TO THE REST OF THIS FILE
	----------------------------------------------------------------
*/

struct rp_class *
stringSub_get_class() {	// return class structure
  return &stringSub_class;
}

// 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().
//

int
stringSub  (
  struct lkm_table *lkmtp,	// points to loadable kernel module table
  int cmd,			// command:  load or unload
  int ver,			// version
  struct kernel_plugin_fct_struct *fctPtr)
				// points to table of kernel functions
{
  // 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,
        "stringSub: Entry function -- initialized plugin_fcts pointers\n"));

  MSR_PLUGIN_DISPATCH(lkmtp, cmd, ver, stringSub_load, stringSub_unload,
							PLUGIN_LKM_NOFUNC_FCT);
}

// This function is called each time the module is loaded
int
stringSub_load(
  struct lkm_table *lkmtp,	// points to loadable kernel module table
  int cmd)			// command (should be load)
{
  int err;

  MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_VERBOSE,
        "stringSub_load: Loading stringSub ...\n"));

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

  err = PLUGIN_PCU_REGISTER_CLASS_FCT(stringSub_get_class());
  if (err != RP_OK) {
    MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_ERROR,
	"stringSub_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
stringSub_unload(
  struct lkm_table *lkmtp,	// points to loadable kernel module table
  int cmd)			// command (should beunload)
{
  struct rp_class *rpclass;
  u_int32_t cid;

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

  MSR_DEBUG((MSR_DEBUG_PLUGIN | MSR_DEBUG_LEVEL_VERBOSE,
        "stringSub_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,
          "stringSub_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,
          "stringSub_unload: Error deregistering class %d\n", cid));
  }

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

  return 0;
}

