ubuntu14.04LTS安装vmware10.0.1

因为所用Ubuntu系统是32位,而VMware最新版本又不支持32位,只好下载以前版本vmware10.0.1。

vmware10.0.1下载地址:  http://down.it168.com/114/130/14858/index.shtml

附上一组序列号:

0F63E-20HEM-4ZC49-RKC5M-A22HY
4F2A2-ARHEK-MZJJ0-JH8EH-C2GQG
1U64X-AA351-KZ519-4R85M-A2KJR
HU03A-F83EM-9Z7L8-LT974-3CE7V
1A46W-AHL9H-FZ7Z8-ETC50-0CK4P
1U2WF-64K91-EZQU9-T195H-0A34K
JZ2Q8-DZJ5L-VZWG8-ZH0NH-A3ZNR
NU4KA-48JDM-LZUV9-3J27P-AAJLZ
NU0FD-0C10L-UZJ48-U18XK-2AX4J
1Z01F-2FL11-RZUU8-ZV254-12CP0

 

修改下载文件的权限以及用户的权限后, 

在ubuntu14.04LTS下面安装完成后启动(可在终端运行vmware)报错, 在日志中可以看到,主要是filter.c的一个文件


一.修改方法: 

修改方法如下,但不是下面方法中的 vnetUserListener.c文件,是filter.c文件
$ cd /tmp

$ tar xf /usr/lib/vmware/modules/source/vmnet.tar
$ cd vmnet-only
$ vi vnetUserListener.c
go to line 37 (after the last include), add this line:  #include “compat_sched.h” then save and exit
$ cd /tmp
$ sudo tar cf /usr/lib/vmware/modules/source/vmnet.tar vmnet-only

$  vmware

二.修改内容:

可直接替换(以下是filter.c的全部内容)

可以参考:http://forum.ubuntu.org.cn/viewtopic.php?p=3075443 

 

/*********************************************************
 * Copyright (C) 2006 VMware, Inc. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation version 2 and no later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 *
 *********************************************************/
#include "driver-config.h"

#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/socket.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/ip.h>
#include "compat_skbuff.h"
#include "compat_module.h"
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/version.h>
#if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0)
#   include <linux/module.h>
#else
#   include <linux/export.h>
#endif


/*
 * All this makes sense only if NETFILTER support is configured in our kernel.
 */
#ifdef CONFIG_NETFILTER

#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/poll.h>

#include "vnetFilter.h"
#include "vnetFilterInt.h"
#include "vnetInt.h"
#include "vmnetInt.h"

// VNet_FilterLogPacket.action for dropped packets
#define VNET_FILTER_ACTION_DRP         (1)
#define VNET_FILTER_ACTION_DRP_SHORT   (2)
#define VNET_FILTER_ACTION_DRP_MATCH   (3)
#define VNET_FILTER_ACTION_DRP_DEFAULT (4)

// VNet_FilterLogPacket.action for forwarded packets
#define VNET_FILTER_ACTION_FWD         (1<<8 | 1)
#define VNET_FILTER_ACTION_FWD_LOOP    (1<<8 | 5)
#define VNET_FILTER_ACTION_FWD_MATCH   (1<<8 | 6)
#define VNET_FILTER_ACTION_FWD_DEFAULT (1<<8 | 7)

/* netfilter hooks for filtering. */
static nf_hookfn VNetFilterHookFn;

static struct nf_hook_ops vmnet_nf_ops[] = {
   {  .hook = VNetFilterHookFn,
      .owner = THIS_MODULE,
      .pf = PF_INET,
      .hooknum = VMW_NF_INET_LOCAL_IN,
      .priority = NF_IP_PRI_FILTER - 1, },
   {  .hook = VNetFilterHookFn,
      .owner = THIS_MODULE,
      .pf = PF_INET,
      .hooknum = VMW_NF_INET_POST_ROUTING,
      .priority = NF_IP_PRI_FILTER - 1, }
};

/* track if we actually set a callback in IP's filter driver */
static Bool installedFilterCallback = FALSE;

/* rules to use for filtering */
RuleSet *ruleSetHead = NULL;  /* linked list of all rules */
int32 numRuleSets = 0;        /* number of rule sets in ruleSetHead's linked list */
RuleSet *activeRule = NULL;   /* actual rule set for filter callback to use */

/* locks to protect against concurrent accesses. */
static DEFINE_MUTEX(filterIoctlMutex); /* serialize ioctl()s from user space. */
/*
 * user/netfilter hook concurrency lock.
 * This spinlock doesn't scale well if/when in the future the netfilter
 * callbacks can be concurrently executing on multiple threads on multiple
 * CPUs, so we should revisit locking for allowing for that in the future.
 */
static DEFINE_SPINLOCK(activeRuleLock);

/*
 * Logging.
 * 
 * All logging for development build uses LOG(2, (KERN_INFO ...)) because the default
 * log level is set to 1 (vnetInt.h). All ACE logging, i.e. policy driven logging, uses
 * printk(KERN_INFO ...).
 */
static uint32 logLevel = VNET_FILTER_LOGLEVEL_NORMAL; /* the current log level */

static void LogPacket(uint16 action, void *header, void *data,
                      uint32 length, Bool drop);
static int InsertHostFilterCallback(void);
static void RemoveHostFilterCallback(void);
static RuleSet *FindRuleSetById(uint32 id, RuleSet ***prevPtr);
static int CreateRuleSet(uint32 id, uint32 defaultAction);
static void DeleteRule(Rule *rule);
static int DeleteRuleSet(uint32 id);
static int ChangeRuleSet(uint32 id, Bool enable, Bool disable, uint32 action);
static int AddIPv4Rule(uint32 id, VNet_AddIPv4Rule *rule,
                       VNet_IPv4Address *addressList,
                       VNet_IPv4Port *portList);


/*
 *----------------------------------------------------------------------
 *
 * DropPacket --
 *
 *      Function is used to record information regarding a packet
 *      being dropped.
 *
 * Results:
 *      void
 *
 * Side effects:
 *      Might store information regarding the packet.
 *
 *----------------------------------------------------------------------
 */

static INLINE void
DropPacket(uint16 action,  // IN: reason code
           void *header,   // IN: packet header
           void *data,     // IN: packet data
           uint32 length)  // IN: packet length
{
   LogPacket(action, header, data, length, TRUE);
}


/*
 *----------------------------------------------------------------------
 *
 * ForwardPacket --
 *
 *      Function is used to record information regarding a packet
 *      being forwarded.
 *
 * Results:
 *      void
 *
 * Side effects:
 *      Might store information regarding the packet.
 *
 *----------------------------------------------------------------------
 */

static INLINE void
ForwardPacket(uint16 action,  // IN: reason code
              void *header,   // IN: packet header
              void *data,     // IN: packet data
              uint32 length)  // IN: packet length
{
#ifdef DBG
   LogPacket(action, header, data, length, FALSE);
#endif
}


/*
 *----------------------------------------------------------------------
 *
 * VNetFilterHookFn --
 *
 *      Function is registered as a callback function with the host's
 *      IP stack.  This function can be used to filter on specified protocols
 *      IP addresses, and/or local and remote ports. It makes use of the Linux
 *      netfilter infrastructure, by inserting this function in netfilter at a
 *      priority 1 higher than iptables, so that we don't have to worry about
 *      any existing iptables based firewall rules on the Linux hosts.
 *
 * Results:
 *      NF_ACCEPT or NF_DROP.
 *
 * Side effects:
 *      None besides those described above.
 *
 *----------------------------------------------------------------------
 */

#define DEBUG_HOST_FILTER 0

#if DEBUG_HOST_FILTER
#define HostFilterPrint(a) printk a
#else
#define HostFilterPrint(a)
#endif

static unsigned int
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
VNetFilterHookFn(unsigned int hooknum,                 // IN:
#else
VNetFilterHookFn(const struct nf_hook_ops *ops, // IN:
#endif
#ifdef VMW_NFHOOK_USES_SKB
                 struct sk_buff *skb,                  // IN:
#else
                 struct sk_buff **pskb,                // IN:
#endif
                 const struct net_device *in,          // IN:
                 const struct net_device *out,         // IN:
                 int (*okfn)(struct sk_buff *))        // IN:
{
#ifndef VMW_NFHOOK_USES_SKB
   struct sk_buff *skb = *pskb;
#endif
   struct iphdr *ip;
   uint32 remoteAddr;
   uint16 localPort;
   uint16 remotePort;
   uint8 *packet;
   uint8 *packetHeader;
   int packetLength;
   RuleSet *currRuleSet;
   Bool blockByDefault;
   Bool transmit; /* TRUE if transmitting, FALSE is receiving */
   Rule *currRule;
   unsigned int verdict = NF_ACCEPT;
   unsigned long flags;


   /* Early checks to see  we should even care. */
   if (skb->protocol != htons(ETH_P_IP)) {
      return verdict;
   }

   spin_lock_irqsave(&activeRuleLock, flags);

   currRuleSet = activeRule;
   // ASSERT(currRuleSet);

   /*
    * Function uses a local copy of ruleSetHead so that we're
    * not adversely affected by any rule changes that might occur
    * while this function is running.
    */

   blockByDefault = currRuleSet->action == VNET_FILTER_RULE_BLOCK;


   /* When the host transmits, hooknum is VMW_NF_INET_POST_ROUTING. */
   /* When the host receives, hooknum is VMW_NF_INET_LOCAL_IN. */

#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
 transmit = (hooknum == VMW_NF_INET_POST_ROUTING);
#else
 transmit = (ops->hooknum == VMW_NF_INET_POST_ROUTING);
#endif

   packetHeader = compat_skb_network_header(skb);
   ip = (struct iphdr*)packetHeader;

   if (transmit) {
      /* skb all set up for us. */
      packet = compat_skb_transport_header(skb);
   } else {
      /* skb hasn't had a chance to be processed by TCP yet. */
      packet = compat_skb_network_header(skb) + (ip->ihl << 2);
   }

   HostFilterPrint(("PacketFilter: IP ver %d ihl %d tos %d len %d id %d\n"
                    "              offset %d ttl %d proto %d xsum %d\n"
                    "              src 0x%08x dest 0x%08x %s\n",
                    ip->version, ip->ihl, ip->tos, ip->tot_len, ip->id,
          ip->frag_off, ip->ttl, ip->protocol, ip->check,
                    ip->saddr, ip->daddr, transmit ? "OUTGOING":"INCOMING"));

   /*
    * For incoming packets, there should be a skb->dev associated with it, with
    * a populated L2 address length.
    */
   if (skb->dev && skb->dev->hard_header_len) {
      packetLength = skb->len - skb->dev->hard_header_len - (ip->ihl << 2);
   } else {
      /*
       * In certain cases, compat_skb_mac_header() has been observed to be NULL. Don't
       * know why, but in such cases, this calculation will lead to a negative
       * packetLength, and the packet to be dropped.
       */
      packetLength = skb->len - 
                     (compat_skb_network_header(skb) - compat_skb_mac_header(skb)) - 
                     (ip->ihl << 2);
   }

   if (packetLength < 0) {
      HostFilterPrint(("PacketFilter: ill formed packet for IPv4\n"));
      HostFilterPrint(("skb: len %d h.raw %p nh.raw %p mac.raw %p, packetLength %d\n",
                       skb->len, compat_skb_transport_header(skb),
                       compat_skb_network_header(skb),
                       compat_skb_mac_header(skb), packetLength));
      verdict = NF_DROP;
      DropPacket(VNET_FILTER_ACTION_DRP_SHORT, packetHeader, packet, 0);
      goto out_unlock;
   }

   remoteAddr = transmit ? ip->daddr : ip->saddr;

   /* always allow 127/8. */
   if ((remoteAddr & 0xff) == 127) {
      HostFilterPrint(("PacketFilter: allowing %s loopback 0x%08x\n",
                       transmit ? "outgoing" : "incoming",
                       remoteAddr));
      ForwardPacket(VNET_FILTER_ACTION_FWD_LOOP,
                    packetHeader, packet, packetLength);
      goto out_unlock;
   }

   /* If we're dealing with TCP or UDP, then extract the port information */
   if (ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) {
      uint16 srcPort, dstPort; /* used to extract port information from packet */

      if (packetLength < 4) {
         HostFilterPrint(("PacketFilter: payload too short for "
                          "TCP or UDP: %d\n", packetLength));
         verdict = NF_DROP;
         DropPacket(VNET_FILTER_ACTION_DRP_SHORT,
                    packetHeader, packet, packetLength);
         goto out_unlock;
      }

      /* Retrieve UDP/TCP port info */
      srcPort = *((uint16*)&packet[0]);
      dstPort = *((uint16*)&packet[2]);

      if (transmit) { /* transmit */
         localPort = ntohs(srcPort);
         remotePort = ntohs(dstPort);
      } else { /* receive */
         localPort = ntohs(dstPort);
         remotePort = ntohs(srcPort);
      }

      HostFilterPrint(("PacketFilter: got local port %d remote port %d\n",
                       localPort, remotePort));
   } else {
      /* these mostly exist to silence compiler warning about uninit variables */
      localPort = 0;
      remotePort = 0;
   }

   currRule = currRuleSet->list;

   /* traverse all the rules in the rule set */
   while (currRule != NULL) {
      uint32 i;
      Bool matchedAddress;

      /* if direction doesn't match rule, then skip */
      if ((currRule->direction == VNET_FILTER_DIRECTION_IN && transmit) ||
          (currRule->direction == VNET_FILTER_DIRECTION_OUT && !transmit)) {
         HostFilterPrint(("PacketFilter: didn't match direction\n"));
         /* wrong direction */
         goto skipRule;
      }

      /*
       * Check if the packet's address matches the rule.  If the list is empty
       * then this means we don't care about address and it's considered a match.
       */

      matchedAddress = (currRule->addressListLen == 0); /* empty list means don't care */
      for (i = 0; i < currRule->addressListLen; ++i) {
         if ((remoteAddr & currRule->addressList[i].ipv4Mask) ==
             currRule->addressList[i].ipv4Addr) {
            matchedAddress = TRUE;
            HostFilterPrint(("PacketFilter: rule matched ip addr %u: "
                             "0x%08x == 0x%08x\n", i, remoteAddr,
                             currRule->addressList[i].ipv4Addr));
            break;
         } else {
            HostFilterPrint(("PacketFilter: rule not match ip addr %u: "
                             "0x%08x != 0x%08x\n", i, remoteAddr,
                             currRule->addressList[i].ipv4Addr));
         }
      }
      if (!matchedAddress) {
         HostFilterPrint(("PacketFilter: rule didn't match ip addr 0x%08x\n",
                          remoteAddr));
         /* ip addr doesn't match */
         goto skipRule;
      }

      /*
       * Check the protocol. ~0 (0xffff) means we don't care about the
       * protocol and it's considered a match.
       */

      if (currRule->proto != 0xffff && currRule->proto != ip->protocol) {
         HostFilterPrint(("PacketFilter: didn't match protocol: %u != %u\n",
                          ip->protocol, currRule->proto));
         /* protocol doesn't match */
         goto skipRule;
      }

      /*
       * If the protocol is TCP or UDP then check the port list.  If the list is empty
       * then this means we don't care about ports and it's considered a match.
       */

      if (currRule->proto == IPPROTO_TCP || currRule->proto == IPPROTO_UDP) {

         /* An empty list means the rule don't care about port numbers*/
         Bool matchedPort = (currRule->portListLen == 0);

         for (i = 0; i < currRule->portListLen; ++i) {
            RulePort *portRule = currRule->portList + i;
            Bool matchedLocal, matchedRemote; /* improves readability */

            /*
             * It's presumed that if portRule->localPortLow == ~0 then
             * portRule->localPortHigh == ~0.  Similiar story for the
             * remote ports.
             */
            matchedLocal = (localPort >= portRule->localPortLow &&
                            localPort <= portRule->localPortHigh) ||
                           portRule->localPortLow == ~0;
            matchedRemote = (remotePort >= portRule->remotePortLow &&
                             remotePort <= portRule->remotePortHigh) ||
                            portRule->remotePortLow == ~0;

            if (matchedLocal && matchedRemote) {
               HostFilterPrint(("PacketFilter: matched rule's "
                                "port element %u\n", i));
               matchedPort = TRUE;
               break;
            }
            HostFilterPrint(("PacketFilter: didn't match rule's "
                             "port element %u\n", i));
            HostFilterPrint(("-- local  %4u not in range [%4u, %4u] or \n",
                             localPort, portRule->localPortLow,
                             portRule->localPortHigh));
            HostFilterPrint(("-- remote %4u not in range [%4u, %4u]\n",
                             remotePort, portRule->remotePortLow,
                             portRule->remotePortHigh));
         }
         if (!matchedPort) {
            HostFilterPrint(("PacketFilter: rule didn't match port "
                             "(local %u remote %u)\n", localPort, remotePort));
            /* port doesn't match */
            goto skipRule;
         }
      }

      /* rule matches so follow orders */

      if (currRule->action == VNET_FILTER_RULE_ALLOW) {
         HostFilterPrint(("PacketFilter: found match, forwarding\n"));
         ForwardPacket(VNET_FILTER_ACTION_FWD_MATCH,
                       packetHeader, packet, packetLength);
         goto out_unlock;
      } else {
         HostFilterPrint(("PacketFilter: found match, dropping\n"));
         verdict = NF_DROP;
         DropPacket(VNET_FILTER_ACTION_DRP_MATCH,
                    packetHeader, packet, packetLength);
         goto out_unlock;
      }

skipRule:
      currRule = currRule->next;
   }

   /* Forward or drop packet based on the default rule */
   HostFilterPrint(("PacketFilter: Didn't find match for %s "
                    "%u.%u.%u.%u, %s packet\n",
                    transmit ? "outgoing" : "incoming",
                    remoteAddr & 0xff, (remoteAddr >> 8) & 0xff,
                    (remoteAddr >> 16) & 0xff, (remoteAddr >> 24) & 0xff,
                    blockByDefault ? "drop" : "forward"));

   if (blockByDefault) {
      verdict = NF_DROP;
      DropPacket(VNET_FILTER_ACTION_DRP_DEFAULT,
                 packetHeader, packet, packetLength);
   } else {
      ForwardPacket(VNET_FILTER_ACTION_FWD_DEFAULT,
                    packetHeader, packet, packetLength);
   }
out_unlock:
   spin_unlock_irqrestore(&activeRuleLock, flags);
   return verdict;
}


/*
 *----------------------------------------------------------------------
 *
 * InsertHostFilterCallback --
 *
 *      Function registers a hook in the host's IP stack.
 *
 * Results:
 *      0 on success (or if hook already installed),
 *      errno on failure.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static int
InsertHostFilterCallback(void)
{
   uint32 i;
   int retval = 0;

   LOG(2, (KERN_INFO "vnet filter inserting callback\n"));

   if (installedFilterCallback) {
      LOG(2, (KERN_INFO "vnet filter callback already registered\n"));
      goto end;
   }

   /* Register netfilter hooks. */
   for (i = 0; i < ARRAY_SIZE(vmnet_nf_ops); i++) {
      if ((retval = nf_register_hook(&vmnet_nf_ops[i])) >= 0) {
         continue;
      }
      /* Encountered an error, back out. */
      LOG(2, (KERN_INFO "vnet filter failed to register callback %d: %d\n",
              i, retval));
      while (i--) {
         nf_unregister_hook(&vmnet_nf_ops[i]);
      }
      goto end;
   }
   installedFilterCallback = TRUE;
   LOG(2, (KERN_INFO "Successfully set packet filter function\n"));

end:
   return retval;
}


/*
 *----------------------------------------------------------------------
 *
 * RemoveHostFilterCallback --
 *
 *      Function deregisters a hook in the host's IP stack.
 *
 * Results:
 *      void
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static void
RemoveHostFilterCallback(void)
{
   int i;

   LOG(2, (KERN_INFO "vnet filter removing callback\n"));

   if (installedFilterCallback) {
      LOG(2, (KERN_INFO "filter callback was installed: removing filter\n"));
      for (i = ARRAY_SIZE(vmnet_nf_ops) - 1; i >= 0; i--) {
         nf_unregister_hook(&vmnet_nf_ops[i]);
      }
      installedFilterCallback = FALSE;
   }
   LOG(2, (KERN_INFO "vnet filter remove callback done\n"));
}


/*
 *----------------------------------------------------------------------
 *
 * FindRuleSetById --
 *
 *      Function is given an ID for a rule set, and returns a
 *      pointer to the ruleset with that ID.  The function can
 *      optionally report what pointer is pointing to this item
 *      (suitable for removing the item from the linked list -- the
 *      result might be the prior item's next pointer, or the head).
 *
 * Results:
 *      NULL if rule set not found, otherwise pointer to rule set.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static RuleSet *
FindRuleSetById(uint32 id,          // IN: id to locate
                RuleSet ***prevPtr) // OUT: pointer to the ->next pointer
                                    //      (or head) that points to the
                                    //      returned item (optional)
{
   RuleSet *curr;
   RuleSet **prev = NULL;
   // ASSERT(id != 0);

   curr = ruleSetHead;
   prev = &ruleSetHead;
   while (curr != NULL) {
      if (curr->id == id) {
         LOG(2, (KERN_INFO "Found id %u at %p\n", id, curr));
         if (prevPtr != NULL) {
            *prevPtr = prev;
         }
         return curr;
      }
      prev = &curr->next;
      curr = curr->next;
   }
   LOG(2, (KERN_INFO "Didn't find ruleset with id %u\n", id));
   /* won't overwrite *prevPtr with NULL */
   return NULL;
}


/*
 *----------------------------------------------------------------------
 *
 * CreateRuleSet --
 *
 *      Function creates a new rule set with a specified ID and
 *      default action.  Call will fail if failed to alloc memory,
 *      or if ID is already in use, or if maximum number of
 *      rule sets have already been created.
 *
 * Results:
 *      Returns 0 on success, and otherwise returns errno.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static int
CreateRuleSet(uint32 id,            // IN: requested ID for new rule set
              uint32 defaultAction) // IN: default action for rule set
{
   RuleSet *newRuleSet;
   RuleSet *curr;

   /* check if too many rule sets already exist */
   if (numRuleSets >= MAX_RULE_SETS) {
      LOG(2, (KERN_INFO "filter already has all rules (%u of %u) allocated\n",
              numRuleSets, MAX_RULE_SETS));
      return -EOVERFLOW;
   }

   /* check if ID is already in use */
   curr = FindRuleSetById(id, NULL);
   if (curr != NULL) {
      LOG(2, (KERN_INFO "filter already has id %u\n", id));
      return -EEXIST;
   }

   /* allocate and init new rule set */
   newRuleSet = kmalloc(sizeof *newRuleSet, GFP_USER);
   if (newRuleSet == NULL) {
      LOG(2, (KERN_INFO "filter mem alloc failed\n"));
      return -ENOMEM;
   }

   memset(newRuleSet, 0, sizeof *newRuleSet);
   newRuleSet->next = ruleSetHead;
   newRuleSet->id = id;
   newRuleSet->enabled = FALSE;
   newRuleSet->action = (uint16)defaultAction;
   newRuleSet->list = NULL;
   newRuleSet->numRules = 0;
   newRuleSet->tail = &newRuleSet->list;

   /* add new rule set to head of linked list */
   numRuleSets++;
   ruleSetHead = newRuleSet;
   LOG(2, (KERN_INFO "filter created ruleset with id %u\n", id));
   return 0;
}


/*
 *----------------------------------------------------------------------
 *
 * DeleteRule --
 *
 *      Function frees the memory in a Rule object.  This function
 *      frees the arrays in the Rule, but not an elements that
 *      are chained on the linked-list via 'next'.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static void
DeleteRule(Rule *rule)          // IN: Rule to delete.
{
   // ASSERT(rule);

   if (!rule) {
      return;
   }
   if (rule->addressList) {
      kfree(rule->addressList);
      rule->addressList = NULL;
   }
   if (rule->portList) {
      kfree(rule->portList);
      rule->portList = NULL;
   }
   kfree(rule);
}


/*
 *----------------------------------------------------------------------
 *
 * DeleteRuleSet --
 *
 *      Function deletes a rule set with a specified ID. Call will fail
 *      if ID not found or if the current rule set is being used for
 *      filtering.
 *
 * Results:
 *      Returns 0 on success, errno on failure.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static int
DeleteRuleSet(uint32 id) // IN: ID of new rule set to delete
{
   RuleSet **prev = NULL;
   RuleSet *curr;
   Rule *currRule;

   /* locate the ruleset with the specified ID */
   curr = FindRuleSetById(id, &prev);
   if (curr == NULL) {
      LOG(2, (KERN_INFO "filter did not find id %u to delete\n", id));
      return -ESRCH;
   }

   LOG(2, (KERN_INFO "found id %u\n", id));

   /* check if in use */
   if (curr->enabled) {
      LOG(2, (KERN_INFO "Can't delete id %u since enabled\n", id));
      return -EBUSY;
   }

   /* remove item from linked list */
   *prev = curr->next;

   /* free rules in rule set */
   currRule = curr->list;
   curr->list = NULL; /* help mitigate any bugs or races */
   while (currRule) {
      Rule *temp = currRule->next;
      currRule->next = NULL; /* help mitigate any bugs or races */
      DeleteRule(currRule);
      currRule = temp;
   }

   kfree(curr);
   numRuleSets--;
   // ASSERT(numRuleSets >= 0);
   return 0;
}


/*
 *----------------------------------------------------------------------
 *
 * ChangeRuleSet --
 *
 *      This function is used to specify which rule set is to be used
 *      for filtering (or stop using for filtering).  If another
 *      rule set is currently used for filtering then the specified
 *      rule set will replace it.  This funciton can also be used to
 *      change the default action for any rule set, but this option
 *      should not be used when disabling a rule set.
 *
 *      Call will fail if ID can't be found, or when attempting to
 *      disable a rule set that's not enabled.
 *
 * Results:
 *      Returns 0 on success, errno on failure.
 *
 * Side effects:
 *      May add/remove filter callback.
 *
 *----------------------------------------------------------------------
 */

static int
ChangeRuleSet(uint32 id,     // IN: requested ID of rule set
              Bool enable,   // IN: TRUE says start using this rule for filtering
              Bool disable,  // IN: TRUE says stop using this rule for filtering
              uint32 action) // IN: default action for rule set
{
   RuleSet *curr;
   int retval;
   unsigned long flags;

   // ASSERT(!enable || !disable); /* at most one can be set */

   LOG(2, (KERN_INFO "changeruleset %d enable %d disable %d action %x\n", id,
           enable, disable, action));
   /* locate the specified rule set */
   curr = FindRuleSetById(id, NULL);
   if (curr == NULL) {
      LOG(2, (KERN_INFO "vnet filter can't find ruleset: %u\n", id));
      return -ESRCH;
   }

   if (enable) {
      RuleSet *oldActive;

      if (action != VNET_FILTER_RULE_NO_CHANGE) {
         LOG(2, (KERN_INFO "vnet filter changing default action "
                 "of active rule set: %u (id %u)\n", action, id));
         curr->action = (uint16)action;
      }

      /* enable new rule */
      curr->enabled = TRUE;

      /* Grab activeRule spinlock. */
      spin_lock_irqsave(&activeRuleLock, flags);

      LOG(2, (KERN_INFO "changing active rule from "
              "%p (%u) to %p (%u)\n", activeRule,
              activeRule ? activeRule->id : 0,
              curr, curr->id));

      /* make rule active */
      oldActive = activeRule;
      activeRule = curr;

      /* Safe to release activeRule spinlock now. */
      spin_unlock_irqrestore(&activeRuleLock, flags);

      /*
       * Mark old rule as not enabled, except if it's the same
       * as the newly enabled rule set.
       */

      if (oldActive == NULL) {
         // 1) activate (no current active)
         LOG(2, (KERN_INFO "No prior rule was active\n"));
      } else if (oldActive == curr) {
         // 2) activate (current active, and same as this one)
         LOG(2, (KERN_INFO "Activated rule that was already active\n"));
      } else { /* oldActive != NULL && oldActive != curr */
         // 3) activate (current active, and different than this one)
         LOG(2, (KERN_INFO "Deactivating old rule: %p (id %u)\n",
                 oldActive, oldActive->id));
         oldActive->enabled = FALSE;
      }
      if ((retval = InsertHostFilterCallback()) != 0) {
         LOG(2, (KERN_INFO "Failed to insert filter in IP\n"));
      }

   } else if (disable) {

      if (!curr->enabled) {
         // 4) deactive (but not currently active)
         LOG(2, (KERN_INFO "vnet filter tried to deactive a "
                 "non-active rule: %u\n", id));
         if (activeRule) {
            // ASSERT(activeRule != curr);
            LOG(2, (KERN_INFO "-- current active is %p (id %u)\n",
                    activeRule, activeRule->id));
         } else {
            LOG(2, (KERN_INFO "-- no rule is currently active\n"));
         }
         /* in this case we'll also not change the default action */
         return -EINVAL;
      }

      // 5) deactive (and currently active)
      LOG(2, (KERN_INFO "vnet filter deactivating %p (id %u)\n",
              curr, id));

      RemoveHostFilterCallback();

      // ASSERT(activeRule == curr);
      /* Grab activeRule spinlock. */
      spin_lock_irqsave(&activeRuleLock, flags);
      activeRule = NULL;
      /* Safe to release activeRule spinlock now. */
      spin_unlock_irqrestore(&activeRuleLock, flags);
      curr->enabled = FALSE;
      if (action != VNET_FILTER_RULE_NO_CHANGE) {
         LOG(2, (KERN_INFO "vnet filter changing default action: "
                 "%u (id %u)\n", action, id));
         curr->action = (uint16)action;
      }
      retval = 0;

   } else { /* !enable && !disable */

      if (action == VNET_FILTER_RULE_NO_CHANGE) {
         // 6) no activate change (and default not changed)
         LOG(2, (KERN_INFO "vnet filter got nothing to change\n"));
         retval = 0;
      }

      // 7) no activate change (but default action changed)
      curr->action = (uint16)action;
      LOG(2, (KERN_INFO "vnet filter changed action: %u\n", action));
      retval = 0;
   }

   return retval;
}


/*
 *----------------------------------------------------------------------
 *
 * AddIPv4Rule --
 *
 *      Function is used to add an IPv4 rule to a rule set.
 *      Call will fail if failed to alloc memory, or if specified
 *      ID was not found.  The actual rule is not sanity checked,
 *      as it's presumed the caller did this.
 *
 * Results:
 *      Returns 0 on success, errno on failure.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static int
AddIPv4Rule(uint32 id,                       // IN: requested ID of rule set
            VNet_AddIPv4Rule *rule,          // IN: rule to add
            VNet_IPv4Address *addressList,   // IN: list of addresses
            VNet_IPv4Port *portList)         // IN: list of ports
{
   Rule *newRule;
   RuleSet *curr;

   // ASSERT(rule && addressList && portList);

   /* locate the rule set with the specified ID */
   curr = FindRuleSetById(id, NULL);
   if (curr == NULL) {
      LOG(2, (KERN_INFO "vnet filter can't find ruleset: %u\n", id));
      return -ESRCH;
   }

   /* make sure that we don't have too many rules already */
   if (curr->numRules >= MAX_RULES_PER_SET) {
      LOG(2, (KERN_INFO "vnet filter has too many rules in ruleset: %u >= %u\n",
              curr->numRules, MAX_RULES_PER_SET));
      return -EOVERFLOW;
   }

   /* allocate and init rule */
   newRule = kmalloc(sizeof *newRule, GFP_USER);
   if (newRule == NULL) {
      LOG(2, (KERN_INFO "vnet filter mem alloc failed for rule\n"));
      return -ENOMEM;
   }
   memset(newRule, 0, sizeof *newRule);

   newRule->action = (uint16)rule->action;
   newRule->direction = (uint16)rule->direction;
   newRule->proto = (uint16)rule->proto;

   // ASSERT(rule->addressListLen <= 255); /* double-check for data truncation */
   newRule->addressListLen = (uint8)rule->addressListLen;
   if (newRule->addressListLen == 1 &&
       addressList[0].ipv4RemoteAddr == 0 &&
       addressList[0].ipv4RemoteMask == 0) {
      newRule->addressListLen = 0;
      LOG(2, (KERN_INFO "vnet filter address has single don't care rule\n"));
   }

   // ASSERT(rule->portListLen <= 255); /* double-check for data truncation */
   newRule->portListLen = (uint8)rule->portListLen;
   if (newRule->portListLen == 1 &&
       portList[0].localPortLow == ~0 &&
       portList[0].localPortHigh == ~0 &&
       portList[0].remotePortLow == ~0 &&
       portList[0].remotePortHigh == ~0) {
      newRule->portListLen = 0;
      LOG(2, (KERN_INFO "vnet filter port has single don't care rule\n"));
   }

   if (newRule->addressListLen > 0) {
      uint32 i;

      newRule->addressList =
         kmalloc(sizeof(*newRule->addressList) * newRule->addressListLen,
                 GFP_USER);
      if (newRule->addressList == NULL) {
         LOG(2, (KERN_INFO "vnet filter mem alloc failed for rule address\n"));
         DeleteRule(newRule);
         return -ENOMEM;
      }

      /* could use memcpy(), but this insulates against API changes */
      for (i = 0; i < newRule->addressListLen; ++i) {
         newRule->addressList[i].ipv4Addr = addressList[i].ipv4RemoteAddr;
         newRule->addressList[i].ipv4Mask = addressList[i].ipv4RemoteMask;
      }
   }

   if (newRule->portListLen > 0) {
      uint32 i;

      newRule->portList =
         kmalloc(sizeof(*newRule->portList) * newRule->portListLen, GFP_USER);
      if (newRule->portList == NULL) {
         LOG(2, (KERN_INFO "vnet filter mem alloc failed for rule port\n"));
         DeleteRule(newRule);
         return -ENOMEM;
      }

      /* could use memcpy(), but this insulates against API changes */
      for (i = 0; i < newRule->portListLen; ++i) {
         newRule->portList[i].localPortLow   = portList[i].localPortLow;
         newRule->portList[i].localPortHigh  = portList[i].localPortHigh;
         newRule->portList[i].remotePortLow  = portList[i].remotePortLow;
         newRule->portList[i].remotePortHigh = portList[i].remotePortHigh;
      }
   }

   LOG(2, (KERN_INFO "adding rule with %u addresses and %u ports\n",
           newRule->addressListLen, newRule->portListLen));

   /* add rule to rule set */
   newRule->next = NULL;
   *(curr->tail) = newRule;
   curr->tail = &(newRule->next);
   ++curr->numRules;

   LOG(2, (KERN_INFO "Added rule %p to set %p, count now %u\n",
           newRule, curr, curr->numRules));

   return 0;
}


/*
 *----------------------------------------------------------------------------
 *
 * VNetFilter_HandleUserCall --
 *
 *      Handle the subcommands from the SIOCSFILTERRULES ioctl command.
 *      We end up copying the VNet_RuleHeader bytes twice from userland,
 *      once from the calling function, and once here after we've figured out
 *      what sub-command we are dealing with.
 *
 * Returns:
 *      0 on success.
 *      errno on failure.
 *
 * Side effects:
 *      May add/remove filter callback.
 *
 *----------------------------------------------------------------------------
 */

int
VNetFilter_HandleUserCall(VNet_RuleHeader *ruleHeader,      // IN: command header
                          unsigned long ioarg)              // IN: ptr to user data
{
   int retval = 0;

   /* Serialize all ioctl()s. */
   retval = mutex_lock_interruptible(&filterIoctlMutex);
   if (retval != 0) {
      return retval;
   }

   switch (ruleHeader->type) {

      case VNET_FILTER_CMD_CREATE_RULE_SET: {
         VNet_CreateRuleSet createRequest;
         if (copy_from_user(&createRequest, (void *)ioarg, sizeof createRequest)) {
            retval = -EFAULT;
            goto out_unlock;
         }
         /* Validate size. */
         if (createRequest.header.len != sizeof createRequest) {
            LOG(2, (KERN_INFO "invalid length %d/%zd for create filter "
                    "request\n", createRequest.header.len,
                    sizeof createRequest));
            retval = -EINVAL;
            goto out_unlock;
         }
         if (createRequest.ruleSetId == 0) {
            LOG(2, (KERN_INFO "invalid id %u for create filter request\n",
                    createRequest.ruleSetId));
            retval = -EINVAL;
            goto out_unlock;
         }
         if (createRequest.defaultAction != VNET_FILTER_RULE_BLOCK &&
             createRequest.defaultAction != VNET_FILTER_RULE_ALLOW) {
            LOG(2, (KERN_INFO "invalid action %u for create filter request\n",
                    createRequest.defaultAction));
            retval = -EINVAL;
            goto out_unlock;
         }
         retval = CreateRuleSet(createRequest.ruleSetId,
                                createRequest.defaultAction);
         goto out_unlock;
      }

      case VNET_FILTER_CMD_DELETE_RULE_SET: {
         VNet_DeleteRuleSet deleteRequest;
         if (copy_from_user(&deleteRequest, (void *)ioarg, sizeof deleteRequest)) {
            retval = -EFAULT;
            goto out_unlock;
         }
         /* Validate size. */
         if (deleteRequest.header.len != sizeof deleteRequest) {
            LOG(2, (KERN_INFO "invalid length %d/%zd for delete filter "
                    "request\n", deleteRequest.header.len,
                    sizeof deleteRequest));
            retval = -EINVAL;
            goto out_unlock;
         }
         if (deleteRequest.ruleSetId == 0) {
            LOG(2, (KERN_INFO "invalid id %u for delete filter request\n",
                    deleteRequest.ruleSetId));
            retval = -EINVAL;
            goto out_unlock;
         }
         retval = DeleteRuleSet(deleteRequest.ruleSetId);
         goto out_unlock;
      }

      case VNET_FILTER_CMD_CHANGE_RULE_SET: {
         VNet_ChangeRuleSet changeRequest;

         if (copy_from_user(&changeRequest, (void *)ioarg, sizeof changeRequest)) {
            retval = -EFAULT;
            goto out_unlock;
         }
         /* Validate size. */
         if (changeRequest.header.len != sizeof changeRequest) {
            LOG(2, (KERN_INFO "invalid length %d/%zd for change filter "
                    "request\n", changeRequest.header.len,
                    sizeof changeRequest));
            retval = -EINVAL;
            goto out_unlock;
         }
         if (changeRequest.ruleSetId == 0) {
            LOG(2, (KERN_INFO "invalid id %u for change filter request\n",
                    changeRequest.ruleSetId));
            retval = -EINVAL;
            goto out_unlock;
         }
         if (changeRequest.defaultAction != VNET_FILTER_RULE_NO_CHANGE &&
             changeRequest.defaultAction != VNET_FILTER_RULE_BLOCK &&
             changeRequest.defaultAction != VNET_FILTER_RULE_ALLOW) {
            LOG(2, (KERN_INFO "invalid default action %u for change "
                    "filter request\n", changeRequest.defaultAction));
            retval = -EINVAL;
            goto out_unlock;
         }
         if (changeRequest.activate != VNET_FILTER_STATE_NO_CHANGE &&
             changeRequest.activate != VNET_FILTER_STATE_ENABLE &&
             changeRequest.activate != VNET_FILTER_STATE_DISABLE) {
            LOG(2, (KERN_INFO "invalid activate %u for change filter "
                    "request\n", changeRequest.activate));
            retval = -EINVAL;
            goto out_unlock;
         }
         retval = ChangeRuleSet(changeRequest.ruleSetId,
                                changeRequest.activate == VNET_FILTER_STATE_ENABLE,
                                changeRequest.activate == VNET_FILTER_STATE_DISABLE,
                                changeRequest.defaultAction);
         goto out_unlock;

      }

      case VNET_FILTER_CMD_ADD_IPV4_RULE: {
         VNet_AddIPv4Rule *addRequest;
         VNet_IPv4Address *addressList = NULL;
         VNet_IPv4Port *portList = NULL;
         int error = -EINVAL;
         uint32 i;

         /* Validate size. */
         if (ruleHeader->len < sizeof *addRequest) {
            LOG(2, (KERN_INFO "short length %d/%zd for add filter rule "
                    "request\n", ruleHeader->len,
                    sizeof *addRequest));
            retval = -EINVAL;
            goto out_unlock;
         }
         if (ruleHeader->len > (sizeof *addRequest +
                                (sizeof *addressList * MAX_ADDR_PER_RULE) +
                                (sizeof *portList * MAX_PORT_PER_RULE))) {
            LOG(2, (KERN_INFO "long length %d for add filter rule "
                    "request\n", ruleHeader->len));
            retval = -EINVAL;
            goto out_unlock;
         }
         addRequest = kmalloc(ruleHeader->len, GFP_USER);
         if (!addRequest) {
            LOG(2, (KERN_INFO "couldn't allocate memory to add filter rule\n"));
            retval = -ENOMEM;
            goto out_unlock;
         }

         if (copy_from_user(addRequest, (void *)ioarg, ruleHeader->len)) {
            error = -EFAULT;
            goto out_error;
         }
         if (addRequest->addressListLen <= 0 ||
             addRequest->addressListLen > MAX_ADDR_PER_RULE) {
            LOG(2, (KERN_INFO "add filter rule: invalid addr list length: %u\n",
                    addRequest->addressListLen));
            goto out_error;
         }
         if (addRequest->portListLen <= 0 ||
             addRequest->portListLen > MAX_PORT_PER_RULE) {
            LOG(2, (KERN_INFO "add filter rule: invalid port list length: %u\n",
                    addRequest->portListLen));
            goto out_error;
         }
         if (addRequest->header.len !=
             (sizeof *addRequest +
              addRequest->addressListLen * sizeof(VNet_IPv4Address) +
              addRequest->portListLen * sizeof(VNet_IPv4Port))) {
            LOG(2, (KERN_INFO "add filter rule: invalid length: %u != %zu\n",
                    addRequest->header.len, sizeof *addRequest +
                    addRequest->addressListLen * sizeof(VNet_IPv4Address) +
                    addRequest->portListLen * sizeof(VNet_IPv4Port)));
            goto out_error;
         }

         /*
          * The address list comes after initial struct, and port
          * list follows the address list.
          */
         addressList = (VNet_IPv4Address *)(addRequest + 1);
         portList = (VNet_IPv4Port *)(addressList + addRequest->addressListLen);

         if (addRequest->ruleSetId == 0) {
            LOG(2, (KERN_INFO "add filter rule: invalid request id %u\n",
                    addRequest->ruleSetId));
            goto out_error;
         }
         if (addRequest->action != VNET_FILTER_RULE_BLOCK &&
             addRequest->action != VNET_FILTER_RULE_ALLOW) {
            LOG(2, (KERN_INFO "add filter rule: invalid action %u\n",
                    addRequest->action));
            goto out_error;
         }

         if (addRequest->direction != VNET_FILTER_DIRECTION_IN &&
             addRequest->direction != VNET_FILTER_DIRECTION_OUT &&
             addRequest->direction != VNET_FILTER_DIRECTION_BOTH) {
            LOG(2, (KERN_INFO "add filter rule: invalid direction %u\n",
                    addRequest->direction));
            goto out_error;
         }

         /*
          * Make sure addr is sane for given mask.  Also verify that the address
          * and mask, if both zero, are in the first element and the array only
          * has one element. This also means that a 0 mask is not allowed in any
          * element besides the first.
          */
         for (i = 0; i < addRequest->addressListLen; i++) {
            if (addressList[i].ipv4RemoteAddr !=
                (addressList[i].ipv4RemoteAddr & addressList[i].ipv4RemoteMask)) {
               LOG(2, (KERN_INFO "add filter rule got address 0x%08x mask "
                       "0x%08x for %u\n", addressList[i].ipv4RemoteAddr,
                       addressList[i].ipv4RemoteMask, i));
               addressList[i].ipv4RemoteAddr &= addressList[i].ipv4RemoteMask;
               LOG(2, (KERN_INFO "-- changed address to 0x%08x\n",
                       addressList[i].ipv4RemoteAddr));
            }

            /*
             * If addr==mask==0, then it must be in the first element of the
             * address list, and the address list should have only one element.
             */
            if (addressList[i].ipv4RemoteAddr == 0 &&
                addressList[i].ipv4RemoteMask == 0 &&
                (i > 0 || addRequest->addressListLen > 1)) {
               LOG(2, (KERN_INFO "add filter rule got violation for zero IP "
                       "addr/mask\n"));
               goto out_error;
            }
         }

         if (addRequest->proto > 0xFF && addRequest->proto != (uint16)~0) {
            LOG(2, (KERN_INFO "add filter rule got invalid proto %u\n",
                    addRequest->proto));
            goto out_error;
         }

         if (addRequest->proto == IPPROTO_TCP ||
             addRequest->proto == IPPROTO_UDP) {

            for (i = 0; i < addRequest->portListLen; i++) {

               if (portList[i].localPortLow > 0xFFFF &&
                   portList[i].localPortLow != ~0) {
                  LOG(2, (KERN_INFO "add filter rule invalid localPortLow %u\n",
                          portList[i].localPortLow));
                  goto out_error;
               }
               if (portList[i].localPortHigh > 0xFFFF &&
                   portList[i].localPortHigh != ~0) {
                  LOG(2, (KERN_INFO "add filter rule invalid localPortHigh %u\n",
                          portList[i].localPortHigh));
                  goto out_error;
               }
               if (portList[i].remotePortLow > 0xFFFF &&
                   portList[i].remotePortLow != ~0) {
                  LOG(2, (KERN_INFO "add filter rule invalid remotePortLow %u\n",
                          portList[i].remotePortLow));
                  goto out_error;
               }
               if (portList[i].remotePortHigh > 0xFFFF &&
                   portList[i].remotePortHigh != ~0) {
                  LOG(2, (KERN_INFO "add filter rule invalid remotePortHigh %u\n",
                          portList[i].remotePortHigh));
                  goto out_error;
               }

               /*
                * Make sure both low and high ports of a port range specify don't
                * care ports.
                */
               if ((portList[i].localPortLow   == ~0 && portList[i].localPortHigh  != ~0) ||
                   (portList[i].localPortLow   != ~0 && portList[i].localPortHigh  == ~0) ||
                   (portList[i].remotePortLow  == ~0 && portList[i].remotePortHigh != ~0) ||
                   (portList[i].remotePortLow  != ~0 && portList[i].remotePortHigh == ~0)) {
                  LOG(2, (KERN_INFO "add filter rule mismatch in don't care "
                          "status of ports\n"));
                  LOG(2, (KERN_INFO " -- srcLow %u srcHigh %u dstLow %u dstHigh %u\n",
                          portList[i].localPortLow, portList[i].localPortHigh,
                          portList[i].remotePortLow, portList[i].remotePortHigh));
                  goto out_error;
               }
               if (portList[i].localPortHigh  < portList[i].localPortLow ||
                   portList[i].remotePortHigh < portList[i].remotePortLow) {
                  LOG(2, (KERN_INFO "add filter rule high < low on ports\n"));
                  LOG(2, (KERN_INFO " -- srcLow %u srcHigh %u dstLow %u dstHigh %u\n",
                          portList[i].localPortLow,  portList[i].localPortHigh,
                          portList[i].remotePortLow, portList[i].remotePortHigh));
                  goto out_error;
               }
               /*
                * Only allow a don't care on port ranges when it is the only port
                * range specified.
                */
               if (portList[i].localPortLow   == ~0 && portList[i].localPortHigh  == ~0 &&
                   portList[i].remotePortLow  == ~0 && portList[i].remotePortHigh == ~0 &&
                   (i > 0 || addRequest->portListLen > 1)) {
                  LOG(2, (KERN_INFO "add filter rule incorrect don't "
                          "care on port list\n"));
                  goto out_error;
               }
            }

         } else {                  // proto not TCP or UDP
            if (addRequest->portListLen != 1 ||
                (portList[0].localPortLow   !=  0 &&
                 portList[0].localPortLow   != ~0) ||
                (portList[0].localPortHigh  !=  0 &&
                 portList[0].localPortHigh  != ~0) ||
                (portList[0].remotePortLow  !=  0 &&
                 portList[0].remotePortLow  != ~0) ||
                (portList[0].remotePortHigh !=  0 &&
                 portList[0].remotePortHigh != ~0)) {
               LOG(2, (KERN_INFO "add filter rule missing/unnecessary port "
                       "information\n"));
               for (i = 0; i < addRequest->portListLen; i++) {
                  LOG(2, (KERN_INFO " -- srcLow %u srcHigh %u dstLow %u dstHigh %u\n",
                          portList[i].localPortLow,  portList[i].localPortHigh,
                          portList[i].remotePortLow, portList[i].remotePortHigh));
               }
               goto out_error;
            }
         }
         retval = AddIPv4Rule(addRequest->ruleSetId, addRequest,
                              addressList, portList);
         goto out_unlock;
out_error:
         kfree(addRequest);
         retval = error;
         goto out_unlock;
      }

      case VNET_FILTER_CMD_ADD_IPV6_RULE:
         LOG(2, (KERN_INFO "add filter rule IPv6 not supported\n"));
         retval = -EPROTONOSUPPORT;
         goto out_unlock;
         
      case VNET_FILTER_CMD_SET_LOG_LEVEL: {
         VNet_SetLogLevel setLogLevel;
         
         if (copy_from_user(&setLogLevel, (void *)ioarg, sizeof setLogLevel)) {
            retval = -EFAULT;
         } else if (setLogLevel.header.len != sizeof setLogLevel) {
            LOG(2, (KERN_INFO "set log level invalid header length %u\n",
                    setLogLevel.header.len));
            retval = -EINVAL;
         } else if (VNET_FILTER_LOGLEVEL_NONE > setLogLevel.logLevel ||
                    setLogLevel.logLevel > VNET_FILTER_LOGLEVEL_MAXIMUM) {
            LOG(2, (KERN_INFO "set log level invalid value %u\n",
                    setLogLevel.logLevel));
            retval = -EINVAL;
         } else {
            logLevel = setLogLevel.logLevel;
         }
         goto out_unlock;
      }

      default:
         LOG(2, (KERN_INFO "add filter rule invalid command %u\n",
                 ruleHeader->type));
         retval = -EINVAL;
         goto out_unlock;
   }
out_unlock:
   mutex_unlock(&filterIoctlMutex);
   return retval;
}


/*
 *----------------------------------------------------------------------
 *
 * VNetFilter_Shutdown --
 *
 *      Function is called when the driver is being unloaded.
 *      This function is responsible for removing the callback
 *      function from the IP stack and deallocating any remaining
 *      state.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *
 *----------------------------------------------------------------------
 */

void
VNetFilter_Shutdown(void)
{
   LOG(2, (KERN_INFO "shutting down vnet filter\n"));

   RemoveHostFilterCallback();

   if (activeRule != NULL) {
      LOG(2, (KERN_INFO "disabling the active rule %u\n", activeRule->id));
      ChangeRuleSet(activeRule->id, FALSE, TRUE, VNET_FILTER_RULE_NO_CHANGE);
      // ASSERT(activeRule == NULL);
   }
   while (ruleSetHead != NULL) {
      LOG(2, (KERN_INFO "Deleteing rule set %u\n", ruleSetHead->id));
      DeleteRuleSet(ruleSetHead->id);
   }
   // ASSERT(numRuleSets == 0);

   LOG(2, (KERN_INFO "shut down vnet filter\n"));
}

/*
 *----------------------------------------------------------------------
 *
 * LogPacket --
 *
 *      This function logs a dropped or forwarded packet.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

#define LOGPACKET_HEADER_LEN (20) /* presumed length of 'header': IP (20) */
#define LOGPACKET_DATA_LEN   (28) /* TCP/UDP header (20) + 8 payload = 28 */

static void
LogPacket(uint16 action,  // IN: reason for packet drop/forward
          void *header,   // IN: packet header
          void *data,     // IN: packet data
          uint32 length,  // IN: packet length (of 'data', not including 'header')
          Bool drop)      // IN: drop versus forward
{
   char packet[(LOGPACKET_HEADER_LEN + LOGPACKET_DATA_LEN) * 3 + 1];
   int i, n;
   
   /* something to do? */
   if (VNET_FILTER_LOGLEVEL_VERBOSE > logLevel) {
      return;
   }
   
   /* cap packet length */
   if (length > LOGPACKET_DATA_LEN) {
      length = LOGPACKET_DATA_LEN;
   }
   
   /* build packet string */
   n = 0;
   if (header) {
      for (i = 0; i < LOGPACKET_HEADER_LEN; i++) {
         sprintf(&packet[n], "%02x ", ((uint8 *)header)[i]);
         n += 3;
      }
   }
   for (i = 0; i < length; i++) {
      sprintf(&packet[n], "%02x ", ((uint8 *)data)[i]);
      n += 3;
   }
   
   /* log packet */
   printk(KERN_INFO "packet %s: %s\n", drop ? "dropped" : "forwarded", packet);
}

#endif // CONFIG_NETFILTER


 


 

posted @ 2015-12-07 14:56  kobe8  Views(1158)  Comments(0Edit  收藏  举报