diff -Nrup source/vmnet-only/bridge.c source.edited/vmnet-only/bridge.c --- source/vmnet-only/bridge.c 2010-05-09 20:08:42.000000000 -0700 +++ source.edited/vmnet-only/bridge.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1651 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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" - -#define EXPORT_SYMTAB - -#include -#include -#include -#ifdef KERNEL_2_2 -# include -#else -# include -#endif -#include - -#include -#include -#include -#include "compat_skbuff.h" -#include -#include "compat_sock.h" - -#define __KERNEL_SYSCALLS__ -#include - -#include -#include -#include -#include -#include - -#ifdef CONFIG_NET_RADIO -# include -#endif -#include "vmnetInt.h" -#include "compat_spinlock.h" -#include "compat_netdevice.h" -#include "vnetInt.h" -#include "smac.h" - -#define VNET_BRIDGE_HISTORY 48 - -/* - * Bytes reserved before start of packet. As Ethernet header has 14 bytes, - * to get aligned IP header we must skip 2 bytes before packet. Not that it - * matters a lot for us, but using 2 is compatible with what newer 2.6.x - * kernels do. - */ -#ifndef NET_IP_ALIGN -#define NET_IP_ALIGN 2 -#endif - -#if LOGLEVEL >= 4 -static struct timeval vnetTime; -#endif - -typedef struct VNetBridge VNetBridge; - -struct VNetBridge { - struct notifier_block notifier; // for device state changes - char name[VNET_NAME_LEN]; // name of net device (e.g., "eth0") - struct net_device *dev; // device structure for 'name' - struct sock *sk; // socket associated with skb's - struct packet_type pt; // used to add packet handler - Bool enabledPromisc; // track if promisc enabled - Bool warnPromisc; // tracks if warning has been logged - struct sk_buff *history[VNET_BRIDGE_HISTORY]; // avoid duplicate packets - spinlock_t historyLock; // protects 'history' - VNetPort port; // connection to virtual hub - Bool wirelessAdapter; // connected to wireless adapter? - struct SMACState *smac; // device structure for wireless - VNetEvent_Sender *eventSender; // event sender -}; - -typedef PacketStatus (* SMACINT SMACFunc)(struct SMACState *, SMACPackets *); - -static int VNetBridgeUp(VNetBridge *bridge, Bool rtnlLock); -static void VNetBridgeDown(VNetBridge *bridge, Bool rtnlLock); - -static int VNetBridgeNotify(struct notifier_block *this, u_long msg, - void *data); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) && \ - !defined(VMW_TL10S64_WORKAROUND) -static int VNetBridgeReceiveFromDev(struct sk_buff *skb, - struct net_device *dev, - struct packet_type *pt); -#else -static int VNetBridgeReceiveFromDev(struct sk_buff *skb, - struct net_device *dev, - struct packet_type *pt, - struct net_device *real_dev); -#endif - -static void VNetBridgeFree(VNetJack *this); -static void VNetBridgeReceiveFromVNet(VNetJack *this, struct sk_buff *skb); -static Bool VNetBridgeCycleDetect(VNetJack *this, int generation); -static Bool VNetBridgeIsDeviceWireless(struct net_device *dev); -static void VNetBridgePortsChanged(VNetJack *this); -static int VNetBridgeIsBridged(VNetJack *this); -static int VNetBridgeProcRead(char *page, char **start, off_t off, - int count, int *eof, void *data); - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeStartPromisc -- - * - * Set IFF_PROMISC on the peer interface. - * - * Results: - * None. - * - * Side effects: - * The peer interface IFF_PROMISC flag may be changed. - * - *---------------------------------------------------------------------- - */ - -static void -VNetBridgeStartPromisc(VNetBridge *bridge, // IN: - Bool rtnlLock) // IN: Acquire RTNL lock -{ - struct net_device *dev = bridge->dev; - - /* - * Disable wireless cards from going into promiscous mode because those - * cards which do support RF monitoring would not be able to function - * correctly i.e. they would not be able to send data packets. - */ - if (rtnlLock) { - rtnl_lock(); - } - if (!bridge->enabledPromisc && !bridge->wirelessAdapter) { - dev_set_promiscuity(dev, 1); - bridge->enabledPromisc = TRUE; - bridge->warnPromisc = FALSE; - LOG(0, (KERN_NOTICE "bridge-%s: enabled promiscuous mode\n", - bridge->name)); - } - if (rtnlLock) { - rtnl_unlock(); - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeStopPromisc -- - * - * Restore saved IFF_PROMISC on the peer interface. - * - * Results: - * None. - * - * Side effects: - * The peer interface IFF_PROMISC flag may be changed. - * - *---------------------------------------------------------------------- - */ - -static void -VNetBridgeStopPromisc(VNetBridge *bridge, // IN: - Bool rtnlLock) // IN: Acquire RTNL lock -{ - struct net_device *dev = bridge->dev; - - if (rtnlLock) { - rtnl_lock(); - } - if (bridge->enabledPromisc && !bridge->wirelessAdapter) { - dev_set_promiscuity(dev, -1); - bridge->enabledPromisc = FALSE; - LOG(0, (KERN_NOTICE "bridge-%s: disabled promiscuous mode\n", - bridge->name)); - } - if (rtnlLock) { - rtnl_unlock(); - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeCheckPromisc -- - * - * Make sure IFF_PROMISC on the peer interface is set. - * - * This can be called periodically. - * - * Results: - * None. - * - * Side effects: - * Hopefully enables promiscuous mode again if it should have been enabled. - * - *---------------------------------------------------------------------- - */ - -static INLINE_SINGLE_CALLER void -VNetBridgeCheckPromisc(VNetBridge *bridge) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) - if (bridge->enabledPromisc && !bridge->wirelessAdapter) { - struct net_device *dev = bridge->dev; - Bool devPromisc = (dev->flags & IFF_PROMISC) != 0; - - if (!devPromisc) { - if (!bridge->warnPromisc) { - bridge->warnPromisc = TRUE; - LOG(0, (KERN_NOTICE "bridge-%s: someone disabled promiscuous mode\n" - "Your Ethernet driver is not compatible with VMware's bridged networking.\n", - bridge->name)); - } - rtnl_lock(); - dev_set_promiscuity(dev, 0); - rtnl_unlock(); - } - } -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeDevCompatible -- - * - * Check whether bridge and network device are compatible. - * - * Results: - * Non-zero if device is good enough for bridge. Zero otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE_SINGLE_CALLER int -VNetBridgeDevCompatible(VNetBridge *bridge, // IN: Bridge - struct net_device *net) // IN: Network device -{ -#ifdef VMW_NETDEV_HAS_NET - if (compat_dev_net(net) != &init_net) { - return 0; - } -#endif - return strcmp(net->name, bridge->name) == 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridge_Create -- - * - * Creates a bridge. Allocates struct, allocates internal device, - * initializes port/jack, and creates a proc entry. Finally, creates an - * event sender and register itself with the kernel for device state - * change notifications. - * - * At this time the bridge is not yet plugged into the hub, because this - * will be done by the caller, i.e. the driver. But we need to know the - * hub in order to create an event sender. This allows for enabling - * the notification mechanism, which will instantly start firing, which in - * turn will bring up the bridge (if present), which eventually will - * inject bridge events. Moreover, the bridge will start injecting - * packets, which will be dropped on the floor. All in all, this is not - * that elegant. Alternatively, we could (i) plug into the hub inside of - * this function, which would require adding a few parameters, (ii) split - * the function into a create part and a registration part. Both ways are - * not consistent with how driver.c plugs the ports into the hub. - * - * Results: - * Errno. Also returns an allocated jack to connect to, - * NULL on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetBridge_Create(const char *devName, // IN: name of device (e.g., "eth0") - VNetJack *hubJack, // IN: the future hub - VNetPort **ret) // OUT: port to virtual hub -{ - VNetBridge *bridge = NULL; - static unsigned id = 0; - int retval = 0; - - *ret = NULL; - - /* - * Its an error if device name is empty. - */ - - if (devName[0] == '\0') { - retval = -EINVAL; - goto out; - } - - /* - * Allocate bridge structure - */ - - bridge = kmalloc(sizeof *bridge, GFP_USER); - if (bridge == NULL) { - retval = -ENOMEM; - goto out; - } - memset(bridge, 0, sizeof *bridge); - spin_lock_init(&bridge->historyLock); - memcpy(bridge->name, devName, sizeof bridge->name); - NULL_TERMINATE_STRING(bridge->name); - - /* - * Initialize jack. - */ - - bridge->port.id = id++; - bridge->port.next = NULL; - - bridge->port.jack.peer = NULL; - bridge->port.jack.numPorts = 1; - VNetSnprintf(bridge->port.jack.name, sizeof bridge->port.jack.name, - "bridge%u", bridge->port.id); - bridge->port.jack.private = bridge; - bridge->port.jack.index = 0; - bridge->port.jack.procEntry = NULL; - bridge->port.jack.free = VNetBridgeFree; - bridge->port.jack.rcv = VNetBridgeReceiveFromVNet; - bridge->port.jack.cycleDetect = VNetBridgeCycleDetect; - bridge->port.jack.portsChanged = VNetBridgePortsChanged; - bridge->port.jack.isBridged = VNetBridgeIsBridged; - - /* - * Make proc entry for this jack. - */ - - retval = VNetProc_MakeEntry(bridge->port.jack.name, S_IFREG, - &bridge->port.jack.procEntry); - if (retval) { - if (retval == -ENXIO) { - bridge->port.jack.procEntry = NULL; - } else { - goto out; - } - } else { - bridge->port.jack.procEntry->read_proc = VNetBridgeProcRead; - bridge->port.jack.procEntry->data = bridge; - } - - /* - * Rest of fields. - */ - - bridge->port.flags = IFF_RUNNING; - - memset(bridge->port.paddr, 0, sizeof bridge->port.paddr); - memset(bridge->port.ladrf, 0, sizeof bridge->port.ladrf); - - bridge->port.paddr[0] = VMX86_STATIC_OUI0; - bridge->port.paddr[1] = VMX86_STATIC_OUI1; - bridge->port.paddr[2] = VMX86_STATIC_OUI2; - - bridge->port.fileOpRead = NULL; - bridge->port.fileOpWrite = NULL; - bridge->port.fileOpIoctl = NULL; - bridge->port.fileOpPoll = NULL; - - /* create event sender */ - retval = VNetHub_CreateSender(hubJack, &bridge->eventSender); - if (retval != 0) { - goto out; - } - - /* - * on RHEL3 Linux 2.4.21-47 (others maybe too) the notifier does not fire - * and bring up the bridge as expected, thus we bring it up manually - * *before* registering the notifier (PR306435) - */ - VNetBridgeUp(bridge, TRUE); - - /* - * register notifier for network device state change notifications, the - * notifier will fire right away, and the notifier handler will bring up - * the bridge (see exception above) - */ - bridge->notifier.notifier_call = VNetBridgeNotify; - bridge->notifier.priority = 0; - register_netdevice_notifier(&bridge->notifier); - - /* return bridge */ - *ret = &bridge->port; - LOG(1, (KERN_DEBUG "bridge-%s: attached\n", bridge->name)); - return 0; - -out: - if (bridge != NULL) { - kfree(bridge); - } - return retval; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeFree -- - * - * Unregister from device state notifications, disable the bridge, - * destroy sender, remove proc entry, cleanup smac, and deallocate - * struct. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VNetBridgeFree(VNetJack *this) // IN: jack to free -{ - VNetBridge *bridge = (VNetBridge*)this->private; - - /* unregister notifier */ - if (bridge->notifier.notifier_call != NULL) { - int err; - - err = compat_unregister_netdevice_notifier(&bridge->notifier); - if (err != 0) { - LOG(0, (KERN_NOTICE "Can't unregister netdevice notifier (%d)\n", - err)); - } - bridge->notifier.notifier_call = NULL; - } - - /* disable bridge */ - if (bridge->dev != NULL) { - LOG(1, (KERN_DEBUG "bridge-%s: disabling the bridge\n", bridge->name)); - VNetBridgeDown(bridge, TRUE); - } - - /* destroy event sender */ - VNetEvent_DestroySender(bridge->eventSender); - bridge->eventSender = NULL; - - /* remove /proc entry */ - if (this->procEntry) { - VNetProc_RemoveEntry(this->procEntry); - } - - if (bridge->smac){ - SMAC_CleanupState(&(bridge->smac)); - } - - /* free bridge */ - LOG(1, (KERN_DEBUG "bridge-%s: detached\n", bridge->name)); - kfree(bridge); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetCallSMACFunc -- - * - * Wrapper for SMAC functions. - * - * Results: - * Packet Status. - * - * Side effects: - * The skb buffer is freed if not successful otherwise it points to - * the clone. - * - *---------------------------------------------------------------------- - */ - -PacketStatus -VNetCallSMACFunc(struct SMACState *state, // IN: pointer to state - struct sk_buff **skb, // IN/OUT: packet to process - void *startOfData, // IN: points to start of data - SMACFunc func) // IN: function to be called -{ - SMACPackets packets = { {0} }; - PacketStatus status; - - packets.orig.skb = *skb; - packets.orig.startOfData = startOfData; - - status = func(state, &packets); - if (status != PacketStatusForwardPacket) { - dev_kfree_skb(*skb); - return status; - } - - if (packets.clone.skb) { - dev_kfree_skb(*skb); - *skb = packets.clone.skb; - } - return status; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeReceiveFromVNet -- - * - * This jack is receiving a packet from a vnet. This function - * sends down (i.e., out on the host net device) if the packet - * isn't destined for the host, and it sends up (i.e., - * simulates a receive for the host) if the packet - * satisfies the host's packet filter. - * - * When the function sends up it keeps a reference to the - * packet in a history list so that we can avoid handing - * a VM a copy of its own packet. - * - * Results: - * None. - * - * Side effects: - * Frees skb. Checks if host device is still using - * promiscuous mode. - * - *---------------------------------------------------------------------- - */ - -void -VNetBridgeReceiveFromVNet(VNetJack *this, // IN: jack - struct sk_buff *skb) // IN: pkt to receive -{ - VNetBridge *bridge = (VNetBridge*)this->private; - struct net_device *dev = bridge->dev; - uint8 dest[ETH_ALEN]; - struct sk_buff *clone; - - LOG(3, (KERN_DEBUG "bridge-%s: transmit %d\n", - bridge->name, (int) skb->len)); - - if (!dev) { - dev_kfree_skb(skb); - return; - } - - /* - * skb might be freed by wireless code, so need to keep - * a local copy of the MAC rather than a pointer to it. - */ - - memcpy(dest, SKB_2_DESTMAC(skb), ETH_ALEN); - - /* - * Check promiscuous bit periodically - */ - - VNetBridgeCheckPromisc(bridge); - -#ifdef notdef - // xxx; - /* - * We need to send the packet both up to the host and down - * to the interface. - * However, we ignore packets destined only for this hub. - */ - - for (i = 0; i < VNET_PORTS_PER_HUB; i++) { - VNetPort *p = &port->hub->port[i]; - if (UP_AND_RUNNING(p->flags) && MAC_EQ(dest, p->paddr)) { - return; - } - } -#endif - - /* - * Wireless processing - */ - - if (bridge->smac) { - if (VNetCallSMACFunc(bridge->smac, &skb, skb->data, - SMAC_CheckPacketToHost) != - PacketStatusForwardPacket) { - LOG(4, (KERN_NOTICE "bridge-%s: packet dropped .\n", - bridge->name)); - return; - } - } - - /* - * Send down (imitate packet_sendmsg) - * - * Do this only if the packet is not addressed to the peer, - * and the packet size is not too big. - */ - - dev_lock_list(); - if (MAC_EQ(dest, dev->dev_addr) || - skb->len > dev->mtu + dev->hard_header_len) { - dev_unlock_list(); - } else { -# if 0 // XXX we should do header translation - if ((dev->flags & IFF_SOFTHEADERS) != 0) { - if (skb->len > dev->mtu) { - clone = NULL; - } else { - clone = dev_alloc_skb(skb->len + dev->hard_header_len, GFP_ATOMIC); - } - if (clone != NULL) { - skb_reserve(clone, dev->hard_header_len); - if (dev->hard_header != NULL) { - dev->hard_header(clone, dev, ETH_P_IP, NULL, NULL, skb->len); - } - memcpy(skb_put(clone, skb->len), skb->data, skb->len); - } - } -# endif - clone = skb_clone(skb, GFP_ATOMIC); - if (clone == NULL) { - dev_unlock_list(); - } else { - struct sock *sk = bridge->sk; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) - atomic_add(skb->truesize, &sk->sk_wmem_alloc); -#else -#warning EHUD gotta figure out what this does and how to fix it: atomic_add(skb->truesize, &sk->sk_wmem_alloc); -#endif /* 2.6.29 */ - clone->sk = sk; - clone->protocol = ((struct ethhdr *)skb->data)->h_proto; // XXX - if ((dev->flags & IFF_UP) != 0) { - dev_unlock_list(); - DEV_QUEUE_XMIT(clone, dev, 0); - } else { - dev_unlock_list(); - dev_kfree_skb(clone); - } - } - } - - /* - * Send up (imitate Ethernet receive) - * - * Do this if the packet is addressed to the peer (or is broadcast, etc.). - * - * This packet will get back to us, via VNetBridgeReceive. - * We save it so we can recognize it (and its clones) again. - */ - - if (VNetPacketMatch(dest, dev->dev_addr, allMultiFilter, dev->flags)) { - clone = skb_clone(skb, GFP_ATOMIC); - if (clone) { - unsigned long flags; - int i; - - atomic_inc(&clone->users); - - clone->dev = dev; - clone->protocol = eth_type_trans(clone, dev); - spin_lock_irqsave(&bridge->historyLock, flags); - for (i = 0; i < VNET_BRIDGE_HISTORY; i++) { - if (bridge->history[i] == NULL) { - bridge->history[i] = clone; -# if LOGLEVEL >= 3 - { - int j; - int count = 0; - for (j = 0; j < VNET_BRIDGE_HISTORY; j++) { - if (bridge->history[j] != NULL) { - count++; - } - } - LOG(3, (KERN_DEBUG "bridge-%s: host slot %d history %d\n", - bridge->name, i, count)); - } -# endif - break; - } - } - if (i >= VNET_BRIDGE_HISTORY) { - LOG(1, (KERN_NOTICE "bridge-%s: history full\n", - bridge->name)); - - for (i = 0; i < VNET_BRIDGE_HISTORY; i++) { - struct sk_buff *s = bridge->history[i]; - - /* - * We special case 0 to avoid races with another thread on - * another cpu wanting to use the 0 entry. This could happen - * when we release the lock to free the former entry. - * See bug 11231 for details. - */ - if (i == 0) { - bridge->history[0] = clone; - } else { - bridge->history[i] = NULL; - } - if (s) { - spin_unlock_irqrestore(&bridge->historyLock, flags); - dev_kfree_skb(s); - spin_lock_irqsave(&bridge->historyLock, flags); - } - } - } - spin_unlock_irqrestore(&bridge->historyLock, flags); - - /* - * We used to cli() before calling netif_rx() here. It was probably - * unneeded (as we never did it in netif.c, and the code worked). In - * any case, now that we are using netif_rx_ni(), we should certainly - * not do it, or netif_rx_ni() will deadlock on the cli() lock --hpreg - */ - - netif_rx_ni(clone); -# if LOGLEVEL >= 4 - do_gettimeofday(&vnetTime); -# endif - } - } - - // xxx; - dev_kfree_skb(skb); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeCycleDetect -- - * - * Cycle detection algorithm. - * - * Results: - * TRUE if a cycle was detected, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -VNetBridgeCycleDetect(VNetJack *this, // IN: jack - int generation) // IN: generation -{ - VNetBridge *bridge = (VNetBridge*)this->private; - return VNetCycleDetectIf(bridge->name, generation); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgePortsChanged -- - * - * The number of ports connected to this jack has change, react - * accordingly by starting/stopping promiscuous mode based on - * whether any peers exist. - * - * Results: - * None. - * - * Side effects: - * Promiscuous mode may be started or stopped. - * - *---------------------------------------------------------------------- - */ - -void -VNetBridgePortsChanged(VNetJack *this) // IN: jack -{ - VNetBridge *bridge = (VNetBridge*)this->private; - if (bridge->dev) { - if (VNetGetAttachedPorts(this)) { - VNetBridgeStartPromisc(bridge, TRUE); - } else { - VNetBridgeStopPromisc(bridge, TRUE); - } - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeIsBridged -- - * - * Reports if the bridged interface is up or down. - * - * Results: - * 1 - we are bridged but the interface is not up - * 2 - we are bridged and the interface is up - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetBridgeIsBridged(VNetJack *this) // IN: jack -{ - VNetBridge *bridge = (VNetBridge*)this->private; - if (bridge->dev) { - return 2; - } else { - return 1; - } -} - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeIsDeviceWireless -- - * - * Check if the device is a wireless adapter, depending on the version - * of the wireless extension present in the kernel. - * - * Results: - * TRUE if the device is wireless, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static Bool -VNetBridgeIsDeviceWireless(struct net_device *dev) //IN: sock -{ -#ifdef CONFIG_WIRELESS_EXT - return dev->wireless_handlers != NULL; -#elif !defined(CONFIG_NET_RADIO) - return FALSE; -#elif defined(WIRELESS_EXT) && WIRELESS_EXT > 19 - return dev->wireless_handlers != NULL; -#elif defined(WIRELESS_EXT) && WIRELESS_EXT > 12 - return dev->wireless_handlers != NULL || dev->get_wireless_stats != NULL; -#else - return dev->get_wireless_stats != NULL; -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeSendLinkStateEvent -- - * - * Sends a link state event. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ -static int -VNetBridgeSendLinkStateEvent(VNetBridge *bridge, // IN: the bridge - uint32 adapter, // IN: the adapter - Bool up) // IN: the link state -{ - VNet_LinkStateEvent event; - int res; - - event.header.size = sizeof event; - res = VNetEvent_GetSenderId(bridge->eventSender, &event.header.senderId); - if (res != 0) { - LOG(1, (KERN_NOTICE "bridge-%s: can't send link state event, " - "getSenderId failed (%d)\n", bridge->name, res)); - return res; - } - event.header.eventId = 0; - event.header.classSet = VNET_EVENT_CLASS_BRIDGE; - event.header.type = VNET_EVENT_TYPE_LINK_STATE; - event.adapter = adapter; - event.up = up; - res = VNetEvent_Send(bridge->eventSender, &event.header); - if (res != 0) { - LOG(1, (KERN_NOTICE "bridge-%s: can't send link state event, send " - "failed (%d)\n", bridge->name, res)); - } - return res; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeUp -- - * - * Bring a bridge up. Gets peer's device structure, verifies - * that interface is up, checks the header length, - * allocates a socket, adds a packet handler to the network - * stack, and then places the peer's device in promiscuous - * mode. - * - * Results: - * errno. - * - * Side effects: - * Bridging may be brought up with a peer interface. - * - *---------------------------------------------------------------------- - */ - -static int -VNetBridgeUp(VNetBridge *bridge, // IN: bridge struct - Bool rtnlLock) // IN: acquire RTNL lock -{ - int retval = 0; - - if (bridge->dev != NULL) { - LOG(0, (KERN_NOTICE "bridge-%s: already up\n", bridge->name)); - goto out; - } - - /* - * Get peer device structure - */ - - dev_lock_list(); - bridge->dev = DEV_GET(bridge); - LOG(2, (KERN_DEBUG "bridge-%s: got dev %p\n", - bridge->name, bridge->dev)); - if (bridge->dev == NULL) { - dev_unlock_list(); - retval = -ENODEV; - goto out; - } - if (!(bridge->dev->flags & IFF_UP)) { - LOG(2, (KERN_DEBUG "bridge-%s: interface %s is not up\n", - bridge->name, bridge->dev->name)); - dev_unlock_list(); - retval = -ENODEV; - goto out; - } - - /* - * At a minimum, the header size should be the same as ours. - * - * XXX we should either do header translation or ensure this - * is an Ethernet. - */ - - if (bridge->dev->hard_header_len != ETH_HLEN) { - LOG(1, (KERN_DEBUG "bridge-%s: can't bridge with %s, bad header length %d\n", - bridge->name, bridge->dev->name, bridge->dev->hard_header_len)); - dev_unlock_list(); - retval = -EINVAL; - goto out; - } - - /* - * Get a socket to play with - * - * We set the dead field so we don't get a call back from dev_kfree_skb(). - * (The alternative is to support the callback.) - */ - - bridge->sk = compat_sk_alloc(bridge, GFP_ATOMIC); - if (bridge->sk == NULL) { - dev_unlock_list(); - retval = -ENOMEM; - goto out; - } - SET_SK_DEAD(bridge->sk); - - bridge->wirelessAdapter = VNetBridgeIsDeviceWireless(bridge->dev); - - /* - * If it is a wireless adapter initialize smac struct. - */ - - if (bridge->wirelessAdapter) { - - LOG(1, (KERN_NOTICE "bridge-%s: is a Wireless Adapter\n", bridge->name)); - SMAC_InitState(&(bridge->smac)); - if (bridge->smac) { - /* - * Store the MAC address of the adapter - */ - - SMAC_SetMac(bridge->smac, bridge->dev->dev_addr); - } - } - - /* - * Link up with the peer device by adding a - * packet handler to the networking stack. - */ - - bridge->pt.func = VNetBridgeReceiveFromDev; - bridge->pt.type = htons(ETH_P_ALL); - bridge->pt.dev = bridge->dev; - - /* - * TurboLinux10 uses 2.6.0-test5, which we do not support, so special case it, - * 2.6.0 with tl_kernel_version_h is 2.6.0-pre5... - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 0) && defined(__tl_kernel_version_h__)) - bridge->pt.data = bridge->sk; -#else - bridge->pt.af_packet_priv = bridge->sk; -#endif - bridge->enabledPromisc = FALSE; - bridge->warnPromisc = FALSE; - dev_add_pack(&bridge->pt); - dev_unlock_list(); - - /* - * Put in promiscuous mode if need be. - */ - - down(&vnetStructureSemaphore); - if (VNetGetAttachedPorts(&bridge->port.jack)) { - VNetBridgeStartPromisc(bridge, rtnlLock); - } - up(&vnetStructureSemaphore); - - /* send link state up event */ - retval = VNetBridgeSendLinkStateEvent(bridge, bridge->dev->ifindex, TRUE); - if (retval != 0) { - LOG(1, (KERN_NOTICE "bridge-%s: can't send link state event (%d)\n", - bridge->name, retval)); - goto out; - } - - LOG(1, (KERN_DEBUG "bridge-%s: up\n", bridge->name)); - - /* - * Return - */ - -out: - if (retval != 0) { - if (bridge->sk != NULL) { - sk_free(bridge->sk); - bridge->sk = NULL; - } - bridge->dev = NULL; - } - return retval; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeDown -- - * - * Bring a bridge down. Stops promiscuous mode, removes the - * packet handler from the network stack, and frees the - * socket. - * - * Results: - * None. - * - * Side effects: - * Bridging is brought down. - * - *---------------------------------------------------------------------- - */ - -static void -VNetBridgeDown(VNetBridge *bridge, // IN: bridge - Bool rtnlLock) // IN: acquire RTNL lock -{ - int retval; - - if (bridge->dev == NULL) { - LOG(0, (KERN_NOTICE "bridge-%s: already down\n", bridge->name)); - return; - } - - /* send link state down event */ - retval = VNetBridgeSendLinkStateEvent(bridge, bridge->dev->ifindex, FALSE); - if (retval != 0) { - LOG(1, (KERN_NOTICE "bridge-%s: can't send link state event (%d)\n", - bridge->name, retval)); - } - - VNetBridgeStopPromisc(bridge, rtnlLock); - if (bridge->smac){ - SMAC_SetMac(bridge->smac, NULL); - } - bridge->dev = NULL; - dev_remove_pack(&bridge->pt); - sk_free(bridge->sk); - bridge->sk = NULL; - - LOG(1, (KERN_DEBUG "bridge-%s: down\n", bridge->name)); -} - - -/* - *----------------------------------------------------------------------------- - * - * VNetBridgeNotifyLogBridgeUpError -- - * - * Logs a bridge up error for the notify function following this function. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VNetBridgeNotifyLogBridgeUpError(int errno, // IN: the error number - char *bridgeName, // IN: the bridge name - char *devName) // IN: the device name -{ - switch (errno) { - case -ENODEV: - LOG(0, (KERN_WARNING "bridge-%s: interface %s not found or not " - "up\n", bridgeName, devName)); - break; - case -EINVAL: - LOG(0, (KERN_WARNING "bridge-%s: interface %s is not a valid " - "Ethernet interface\n", bridgeName, devName)); - break; - case -ENOMEM: - LOG(0, (KERN_WARNING "bridge-%s: failed to allocate memory\n", - bridgeName)); - break; - default: - /* This should never happen --hpreg */ - LOG(0, (KERN_WARNING "bridge-%s: failed to enable the bridge to " - "interface %s (error %d)\n", bridgeName, devName, - -errno)); - break; - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VNetBridgeNotify -- - * - * Callback on peer device state change. The function brings - * the bridge up/down in response to changes in the peer device. - * - * Results: - * NOTIFY_DONE - * - * Side effects: - * Promiscuous mode is changed when bridge brought up/down. - * - *----------------------------------------------------------------------------- - */ - -static int -VNetBridgeNotify(struct notifier_block *this, // IN: callback data (bridge) - u_long msg, // IN: type of event - void *data) // IN: device pertaining to event -{ - VNetBridge *bridge = list_entry(this, VNetBridge, notifier); - struct net_device *dev = (struct net_device *) data; - - switch (msg) { - case NETDEV_UNREGISTER: - LOG(2, (KERN_DEBUG "bridge-%s: interface %s is unregistering\n", - bridge->name, dev->name)); - if (dev == bridge->dev) { - /* This should never happen --hpreg */ - LOG(0, (KERN_WARNING "bridge-%s: interface %s unregistered without " - "going down! Disabling the bridge\n", bridge->name, - dev->name)); - VNetBridgeDown(bridge, FALSE); - } - break; - - case NETDEV_DOWN: - LOG(2, (KERN_DEBUG "bridge-%s: interface %s is going down\n", - bridge->name, dev->name)); - if (dev == bridge->dev) { - LOG(1, (KERN_DEBUG "bridge-%s: disabling the bridge\n", - bridge->name)); - VNetBridgeDown(bridge, FALSE); - } - break; - - case NETDEV_CHANGE: - LOG(2, (KERN_DEBUG "bridge-%s: interface %s is changing\n", - bridge->name, dev->name)); - if (dev == bridge->dev) { - LOG(1, (KERN_DEBUG "bridge-%s: disabling the bridge\n", - bridge->name)); - VNetBridgeDown(bridge, FALSE); - } else if (bridge->dev == NULL && VNetBridgeDevCompatible(bridge, dev)) { - int errno; - - LOG(1, (KERN_DEBUG "bridge-%s: enabling the bridge\n", bridge->name)); - errno = VNetBridgeUp(bridge, FALSE); - if (errno != 0) { - VNetBridgeNotifyLogBridgeUpError(errno, bridge->name, dev->name); - } - } - break; - - - case NETDEV_UP: - LOG(2, (KERN_DEBUG "bridge-%s: interface %s is going up\n", - bridge->name, dev->name)); - if (bridge->dev == NULL && VNetBridgeDevCompatible(bridge, dev)) { - int errno; - - LOG(1, (KERN_DEBUG "bridge-%s: enabling the bridge\n", bridge->name)); - errno = VNetBridgeUp(bridge, FALSE); - if (errno != 0) { - VNetBridgeNotifyLogBridgeUpError(errno, bridge->name, dev->name); - } - } - break; - - default: - LOG(2, (KERN_DEBUG "bridge-%s: interface %s is sending notification " - "0x%lx\n", bridge->name, dev->name, msg)); - break; - } - - return NOTIFY_DONE; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeComputeHeaderPos -- - * - * Compute correct position for UDP/TCP header. - * - * Results: - * None. - * - * Side effects: - * transport header pointer updated to point to the tcp/udp header. - * - *---------------------------------------------------------------------- - */ - -static INLINE_SINGLE_CALLER void -VNetBridgeComputeHeaderPos(struct sk_buff *skb) // IN: buffer to examine -{ - /* Maybe some kernel gets it right... */ - if (compat_skb_network_header_len(skb)) { - return; - } - switch (be16_to_cpu(skb->protocol)) { - case ETH_P_IP: { - struct iphdr *ipHdr = compat_skb_ip_header(skb); - - compat_skb_set_transport_header(skb, compat_skb_network_offset(skb) + - ipHdr->ihl * 4); - } - return; - default: - LOG(3, (KERN_DEBUG "Unknown EII protocol %04X: csum at %d\n", - be16_to_cpu(skb->protocol), compat_skb_csum_offset(skb))); - break; - } - return; -} - - -/* - * We deal with three types of kernels: - * New kernels: skb_shinfo() has gso_size member, and there is - * skb_gso_segment() helper to split GSO skb into flat ones. - * Older kernels: skb_shinfo() has tso_size member, and there is - * no helper. - * Oldest kernels: without any segmentation offload support. - */ -#if defined(NETIF_F_GSO) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) -#define VNetBridgeIsGSO(skb) skb_shinfo(skb)->gso_size -#define VNetBridgeGSOSegment(skb) skb_gso_segment(skb, 0) -#elif defined(NETIF_F_TSO) -#define VNetBridgeIsGSO(skb) skb_shinfo(skb)->tso_size - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeGSOSegment -- - * - * Split a large TCP/IPv4 sk_buff into multiple sk_buffs of - * size skb_shinfo(skb)->tso_size - * Called from VNetBridgeSendLargePacket(). - * - * Results: - * List of skbs created. - * - * Side effects: - * The incoming packet is split into multiple packets. - * - *---------------------------------------------------------------------- - */ - -static struct sk_buff * -VNetBridgeGSOSegment(struct sk_buff *skb) // IN: packet to split -{ - struct sk_buff *segs = NULL; - struct sk_buff **next = &segs; - int bytesPerPacket, bytesLeft; - int macHdrLen, ipHdrLen, tcpHdrLen, allHdrLen; - int curByteOffset; - uint16 ipID; - uint32 seqNo; - - if (((struct ethhdr *)compat_skb_mac_header(skb))->h_proto != htons(ETH_P_IP)) { - return ERR_PTR(-EPFNOSUPPORT); - } - - if (compat_skb_ip_header(skb)->protocol != IPPROTO_TCP) { - return ERR_PTR(-EPROTONOSUPPORT); - } - - macHdrLen = compat_skb_network_header(skb) - compat_skb_mac_header(skb); - ipHdrLen = compat_skb_ip_header(skb)->ihl << 2; - tcpHdrLen = compat_skb_tcp_header(skb)->doff << 2; - allHdrLen = macHdrLen + ipHdrLen + tcpHdrLen; - - ipID = ntohs(compat_skb_ip_header(skb)->id); - seqNo = ntohl(compat_skb_tcp_header(skb)->seq); - - /* Host TCP stack populated this (MSS) for the host NIC driver */ - bytesPerPacket = skb_shinfo(skb)->tso_size; - - bytesLeft = skb->len - allHdrLen; - curByteOffset = allHdrLen; - - while (bytesLeft) { - struct sk_buff *newSkb; - int payloadSize = (bytesLeft < bytesPerPacket) ? bytesLeft : bytesPerPacket; - - newSkb = dev_alloc_skb(payloadSize + allHdrLen + NET_IP_ALIGN); - if (!newSkb) { - while (segs) { - newSkb = segs; - segs = segs->next; - newSkb->next = NULL; - dev_kfree_skb(newSkb); - } - return ERR_PTR(-ENOMEM); - } - skb_reserve(newSkb, NET_IP_ALIGN); - newSkb->dev = skb->dev; - newSkb->protocol = skb->protocol; - newSkb->pkt_type = skb->pkt_type; - newSkb->ip_summed = VM_TX_CHECKSUM_PARTIAL; - - /* - * MAC+IP+TCP copy - * This implies that ALL fields in the IP and TCP headers are copied from - * the original skb. This is convenient: we'll only fix up fields that - * need to be changed below - */ - memcpy(skb_put(newSkb, allHdrLen), skb->data, allHdrLen); - - /* Fix up pointers to different layers */ - compat_skb_reset_mac_header(newSkb); - compat_skb_set_network_header(newSkb, macHdrLen); - compat_skb_set_transport_header(newSkb, macHdrLen + ipHdrLen); - - /* Payload copy */ - skb_copy_bits(skb, curByteOffset, compat_skb_tail_pointer(newSkb), payloadSize); - skb_put(newSkb, payloadSize); - - curByteOffset+=payloadSize; - bytesLeft -= payloadSize; - - /* Fix up IP hdr */ - compat_skb_ip_header(newSkb)->tot_len = htons(payloadSize + tcpHdrLen + ipHdrLen); - compat_skb_ip_header(newSkb)->id = htons(ipID); - compat_skb_ip_header(newSkb)->check = 0; - /* Recompute new IP checksum */ - compat_skb_ip_header(newSkb)->check = - ip_fast_csum(compat_skb_network_header(newSkb), - compat_skb_ip_header(newSkb)->ihl); - - /* Fix up TCP hdr */ - compat_skb_tcp_header(newSkb)->seq = htonl(seqNo); - /* Clear FIN/PSH if not last packet */ - if (bytesLeft > 0) { - compat_skb_tcp_header(newSkb)->fin = 0; - compat_skb_tcp_header(newSkb)->psh = 0; - } - /* Recompute partial TCP checksum */ - compat_skb_tcp_header(newSkb)->check = - ~csum_tcpudp_magic(compat_skb_ip_header(newSkb)->saddr, - compat_skb_ip_header(newSkb)->daddr, - payloadSize+tcpHdrLen, IPPROTO_TCP, 0); - - /* Offset of field */ - newSkb->csum = offsetof(struct tcphdr, check); - - /* Join packet to the list of segments */ - *next = newSkb; - next = &newSkb->next; - - /* Bump up our counters */ - ipID++; - seqNo += payloadSize; - - } - return segs; -} -#else -#define VNetBridgeIsGSO(skb) (0) -#define VNetBridgeGSOSegment(skb) ERR_PTR(-ENOSYS) -#endif - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeSendLargePacket -- - * - * Split and send a large TCP/IPv4 sk_buff into multiple sk_buffs which - * fits on wire. Called from VNetBridgeReceiveFromDev(), which is a - * protocol handler called from the bottom half, so steady as she - * goes... - * - * skb passed in is deallocated by function. - * - * Results: - * None. - * - * Side effects: - * The incoming packet is split into multiple packets and sent to the - * vnet. - * - *---------------------------------------------------------------------- - */ - -void -VNetBridgeSendLargePacket(struct sk_buff *skb, // IN: packet to split - VNetBridge *bridge) // IN: bridge -{ - struct sk_buff *segs; - - segs = VNetBridgeGSOSegment(skb); - dev_kfree_skb(skb); - if (IS_ERR(segs)) { - LOG(1, (KERN_DEBUG "bridge-%s: cannot segment packet: error %ld\n", - bridge->name, PTR_ERR(segs))); - return; - } - - while (segs) { - struct sk_buff *newSkb; - - newSkb = segs; - segs = newSkb->next; - newSkb->next = NULL; - /* Send it along */ - skb = newSkb; - VNetSend(&bridge->port.jack, newSkb); - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeReceiveFromDev -- - * - * Receive a packet from a bridged peer device - * - * This is called from the bottom half. Must be careful. - * - * Results: - * errno. - * - * Side effects: - * A packet may be sent to the vnet. - * - *---------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) && \ - !defined(VMW_TL10S64_WORKAROUND) -int -VNetBridgeReceiveFromDev(struct sk_buff *skb, // IN: packet to receive - struct net_device *dev, // IN: unused - struct packet_type *pt) // IN: pt (pointer to bridge) -#else -int -VNetBridgeReceiveFromDev(struct sk_buff *skb, // IN: packet to receive - struct net_device *dev, // IN: unused - struct packet_type *pt, // IN: pt (pointer to bridge) - struct net_device *real_dev) // IN: real device, unused -#endif -{ - VNetBridge *bridge = list_entry(pt, VNetBridge, pt); - int i; - unsigned long flags; - - if (bridge->dev == NULL) { - LOG(3, (KERN_DEBUG "bridge-%s: received %d closed\n", - bridge->name, (int) skb->len)); - dev_kfree_skb(skb); - return -EIO; // value is ignored anyway - } - - /* - * Check is this is a packet that we sent up to the host, and if - * so then don't bother to receive the packet. - */ - - spin_lock_irqsave(&bridge->historyLock, flags); - for (i = 0; i < VNET_BRIDGE_HISTORY; i++) { - struct sk_buff *s = bridge->history[i]; - if (s != NULL && - (s == skb || SKB_IS_CLONE_OF(skb, s))) { - bridge->history[i] = NULL; - spin_unlock_irqrestore(&bridge->historyLock, flags); - dev_kfree_skb(s); - LOG(3, (KERN_DEBUG "bridge-%s: receive %d self %d\n", - bridge->name, (int) skb->len, i)); - dev_kfree_skb(skb); - return 0; - } - } - spin_unlock_irqrestore(&bridge->historyLock, flags); - -# if LOGLEVEL >= 4 - { - struct timeval now; - do_gettimeofday(&now); - LOG(3, (KERN_DEBUG "bridge-%s: time %d\n", - bridge->name, - (int)((now.tv_sec * 1000000 + now.tv_usec) - - (vnetTime.tv_sec * 1000000 + vnetTime.tv_usec)))); - } -# endif - - if (bridge->smac) { - if (VNetCallSMACFunc(bridge->smac, &skb, compat_skb_mac_header(skb), - SMAC_CheckPacketFromHost) != - PacketStatusForwardPacket) { - LOG(4, (KERN_NOTICE "bridge-%s: packet dropped .\n", - bridge->name)); - return 0; - } - } - -#ifdef KERNEL_2_3_15 - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) { - return 0; - } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) - /* - * Unbelievable... Caller sets h.raw = nh.raw before invoking us... - */ - VNetBridgeComputeHeaderPos(skb); -#endif -#endif - - skb_push(skb, skb->data - compat_skb_mac_header(skb)); - LOG(3, (KERN_DEBUG "bridge-%s: receive %d\n", - bridge->name, (int) skb->len)); - - /* - * If this is a large packet, chop chop chop (if supported)... - */ - if (VNetBridgeIsGSO(skb)) { - VNetBridgeSendLargePacket(skb, bridge); - } else { - VNetSend(&bridge->port.jack, skb); - } - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetBridgeProcRead -- - * - * Callback for read operation on this bridge entry in vnets proc fs. - * - * Results: - * Length of read operation. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetBridgeProcRead(char *page, // IN/OUT: buffer to write into - char **start, // OUT: 0 if file < 4k, else offset into page - off_t off, // IN: (unused) offset of read into the file - int count, // IN: (unused) maximum number of bytes to read - int *eof, // OUT: TRUE if there is nothing more to read - void *data) // IN: client data - pointer to bridge -{ - VNetBridge *bridge = (VNetBridge*)data; - int len = 0; - - if (!bridge) { - return len; - } - - len += VNetPrintPort(&bridge->port, page+len); - - len += sprintf(page+len, "dev %s ", bridge->name); - - len += sprintf(page+len, "\n"); - - *start = 0; - *eof = 1; - return len; -} diff -Nrup source/vmnet-only/compat_file.h source.edited/vmnet-only/compat_file.h --- source/vmnet-only/compat_file.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_file.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,56 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_FILE_H__ -# define __COMPAT_FILE_H__ - - -/* The fput() API is modified in 2.2.0 --hpreg */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) -# define compat_fput(_file) fput(_file) -#else -# define compat_fput(_file) fput(_file, (_file)->f_inode) -#endif - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) -# define compat_get_file(_file) get_file(_file) -# define compat_file_count(_file) file_count(_file) -#else -# define compat_get_file(_file) (_file)->f_count++ -# define compat_file_count(_file) (_file)->f_count -#endif - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 4) -# define compat_filp_close(_file, _files) filp_close(_file, _files) -#else -static inline void compat_filp_close(struct file* filp, fl_owner_t files) { - if (filp->f_op && filp->f_op->flush) { - filp->f_op->flush(filp); - } - /* - * Hopefully there are no locks to release on this filp. - * locks_remove_posix is not exported so we cannot use it... - */ - fput(filp); -} -#endif - - -#endif /* __COMPAT_FILE_H__ */ diff -Nrup source/vmnet-only/compat_highmem.h source.edited/vmnet-only/compat_highmem.h --- source/vmnet-only/compat_highmem.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_highmem.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,40 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_HIGHMEM_H__ -# define __COMPAT_HIGHMEM_H__ - - -/* - * BIGMEM (4 GB) support appeared in 2.3.16: kmap() API added - * HIGHMEM (4 GB + 64 GB) support appeared in 2.3.23: kmap() API modified - * In 2.3.27, kmap() API modified again - * - * --hpreg - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 27) -# include -#else -/* For page_address --hpreg */ -# include - -# define kmap(_page) (void*)page_address(_page) -# define kunmap(_page) -#endif - -#endif /* __COMPAT_HIGHMEM_H__ */ diff -Nrup source/vmnet-only/compat_kdev_t.h source.edited/vmnet-only/compat_kdev_t.h --- source/vmnet-only/compat_kdev_t.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_kdev_t.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,33 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_KDEV_T_H__ -# define __COMPAT_KDEV_T_H__ - - -#include - - -/* The major() API appeared in 2.5.2 --hpreg */ -#ifndef major -# define major MAJOR -# define minor MINOR -#endif - - -#endif /* __COMPAT_KDEV_T_H__ */ diff -Nrup source/vmnet-only/compat_mm.h source.edited/vmnet-only/compat_mm.h --- source/vmnet-only/compat_mm.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_mm.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,134 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_MM_H__ -# define __COMPAT_MM_H__ - - -#include - - -/* The get_page() API appeared in 2.3.7 --hpreg */ -/* Sometime during development it became function instead of macro --petr */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) && !defined(get_page) -# define get_page(_page) atomic_inc(&(_page)->count) -/* The __free_page() API is exported in 2.1.67 --hpreg */ -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 67) -# define put_page __free_page -# else -# include "compat_page.h" - -# define page_to_phys(_page) (page_to_pfn(_page) << PAGE_SHIFT) -# define put_page(_page) free_page(page_to_phys(_page)) -# endif -#endif - - -/* page_count() is 2.4.0 invention. Unfortunately unavailable in some RedHat - * kernels (for example 2.4.21-4-RHEL3). */ -/* It is function since 2.6.0, and hopefully RedHat will not play silly games - * with mm_inline.h again... */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(page_count) -# define page_count(page) atomic_read(&(page)->count) -#endif - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) -# define compat_vm_pgoff(vma) ((vma)->vm_offset >> PAGE_SHIFT) - -static inline unsigned long compat_do_mmap_pgoff(struct file *file, unsigned long addr, - unsigned long len, unsigned long prot, - unsigned long flag, unsigned long pgoff) -{ - unsigned long ret = -EINVAL; - - if (pgoff < 1 << (32 - PAGE_SHIFT)) { - ret = do_mmap(file, addr, len, prot, flag, pgoff << PAGE_SHIFT); - } - return ret; -} - -#else -# define compat_vm_pgoff(vma) (vma)->vm_pgoff -# ifdef VMW_SKAS_MMAP -# define compat_do_mmap_pgoff(f, a, l, p, g, o) \ - do_mmap_pgoff(current->mm, f, a, l, p, g, o) -# else -# define compat_do_mmap_pgoff(f, a, l, p, g, o) \ - do_mmap_pgoff(f, a, l, p, g, o) -# endif -#endif - - -/* 2.2.x uses 0 instead of some define */ -#ifndef NOPAGE_SIGBUS -#define NOPAGE_SIGBUS (0) -#endif - - -/* 2.2.x does not have HIGHMEM support */ -#ifndef GFP_HIGHUSER -#define GFP_HIGHUSER (GFP_USER) -#endif - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) - -#include "compat_page.h" - -static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order) -{ - unsigned long addr; - - addr = __get_free_pages(gfp_mask, order); - if (!addr) { - return NULL; - } - return virt_to_page(addr); -} -#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) - -#endif - -/* - * In 2.4.14, the logic behind the UnlockPage macro was moved to the - * unlock_page() function. Later (in 2.5.12), the UnlockPage macro was removed - * altogether, and nowadays everyone uses unlock_page(). - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 14) -#define compat_unlock_page(page) UnlockPage(page) -#else -#define compat_unlock_page(page) unlock_page(page) -#endif - -/* - * In 2.4.10, vmtruncate was changed from returning void to returning int. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) -#define compat_vmtruncate(inode, size) \ -({ \ - int result = 0; \ - vmtruncate(inode, size); \ - result; \ -}) -#else -#define compat_vmtruncate(inode, size) vmtruncate(inode, size) -#endif - - -#endif /* __COMPAT_MM_H__ */ diff -Nrup source/vmnet-only/compat_module.h source.edited/vmnet-only/compat_module.h --- source/vmnet-only/compat_module.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_module.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,72 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 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 - * - *********************************************************/ - -/* - * compat_module.h -- - */ - -#ifndef __COMPAT_MODULE_H__ -# define __COMPAT_MODULE_H__ - - -#include - - -/* - * Modules wishing to use the GPL license are required to include a - * MODULE_LICENSE definition in their module source as of 2.4.10. - */ -#ifndef MODULE_LICENSE -#define MODULE_LICENSE(license) -#endif - -/* - * To make use of our own home-brewed MODULE_INFO, we need macros to - * concatenate two expressions to "__mod_", and and to convert an - * expression into a string. I'm sure we've got these in our codebase, - * but I'd rather not introduce such a dependency in a compat header. - */ -#ifndef __module_cat -#define __module_cat_1(a, b) __mod_ ## a ## b -#define __module_cat(a, b) __module_cat_1(a, b) -#endif - -#ifndef __stringify -#define __stringify_1(x) #x -#define __stringify(x) __stringify_1(x) -#endif - -/* - * MODULE_INFO was born in 2.5.69. - */ -#ifndef MODULE_INFO -#define MODULE_INFO(tag, info) \ -static const char __module_cat(tag, __LINE__)[] \ - __attribute__((section(".modinfo"), unused)) = __stringify(tag) "=" info -#endif - -/* - * MODULE_VERSION was born in 2.6.4. The earlier form appends a long "\0xxx" - * string to the module's version, but that was removed in 2.6.10, so we'll - * ignore it in our wrapper. - */ -#ifndef MODULE_VERSION -#define MODULE_VERSION(_version) MODULE_INFO(version, _version) -#endif - -#endif /* __COMPAT_MODULE_H__ */ diff -Nrup source/vmnet-only/compat_netdevice.h source.edited/vmnet-only/compat_netdevice.h --- source/vmnet-only/compat_netdevice.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_netdevice.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,287 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_NETDEVICE_H__ -# define __COMPAT_NETDEVICE_H__ - - -#include -#include -#include -#include - -/* - * The enet_statistics structure moved from linux/if_ether.h to - * linux/netdevice.h and is renamed net_device_stats in 2.1.25 --hpreg - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 1, 25) -# include - -# define net_device_stats enet_statistics -#endif - - -/* The netif_rx_ni() API appeared in 2.4.8 --hpreg */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 8) -# define netif_rx_ni netif_rx -#endif - - -/* The device struct was renamed net_device in 2.3.14 --hpreg */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14) -# define net_device device -#endif - - -/* - * SET_MODULE_OWNER appeared sometime during 2.3.x. It was setting - * dev->owner = THIS_MODULE until 2.5.70, where netdevice refcounting - * was completely changed. SET_MODULE_OWNER was nop for whole - * 2.6.x series, and finally disappeared in 2.6.24. - * - * MOD_xxx_USE_COUNT wrappers are here, as they must be mutually - * exclusive with SET_MODULE_OWNER call. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) -# define COMPAT_SET_MODULE_OWNER(dev) do {} while (0) -# define COMPAT_NETDEV_MOD_INC_USE_COUNT MOD_INC_USE_COUNT -# define COMPAT_NETDEV_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT -#else -# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -# define COMPAT_SET_MODULE_OWNER(dev) SET_MODULE_OWNER(dev) -# else -# define COMPAT_SET_MODULE_OWNER(dev) do {} while (0) -# endif -# define COMPAT_NETDEV_MOD_INC_USE_COUNT do {} while (0) -# define COMPAT_NETDEV_MOD_DEC_USE_COUNT do {} while (0) -#endif - -/* - * SET_NETDEV_DEV appeared sometime during 2.5.x, and later was - * crossported to various 2.4.x kernels (as dummy macro). - */ -#ifdef SET_NETDEV_DEV -# define COMPAT_SET_NETDEV_DEV(dev, pdev) SET_NETDEV_DEV(dev, pdev) -#else -# define COMPAT_SET_NETDEV_DEV(dev, pdev) do {} while (0) -#endif - -/* - * Build alloc_etherdev API on the top of init_etherdev. For 2.0.x kernels - * we must provide dummy init method, otherwise register_netdev does - * nothing. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) -int -vmware_dummy_init(struct net_device *dev) -{ - return 0; -} -#endif - - -static inline struct net_device* -compat_alloc_etherdev(int priv_size) -{ - struct net_device* dev; - int size = sizeof *dev + priv_size; - - /* - * The name is dynamically allocated before 2.4.0, but - * is an embedded array in later kernels. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) - size += sizeof("ethXXXXXXX"); -#endif - dev = kmalloc(size, GFP_KERNEL); - if (dev) { - memset(dev, 0, size); - if (priv_size) { - dev->priv = dev + 1; - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) - dev->name = (char *)(dev + 1) + priv_size; -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) - dev->init = vmware_dummy_init; -#endif - if (init_etherdev(dev, 0) != dev) { - kfree(dev); - dev = NULL; - } - } - return dev; -} -#else -#define compat_alloc_etherdev(sz) alloc_etherdev(sz) -#endif - - -/* - * alloc_netdev and free_netdev are there since 2.4.23. Their use is mandatory - * since 2.6.24. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23) -static inline struct net_device * -compat_alloc_netdev(int priv_size, - const char *mask, - void (*setup)(struct net_device *)) -{ - struct net_device *dev; - int netdev_size = sizeof *dev; - int alloc_size; - -# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) - netdev_size += IFNAMSIZ; -# endif - - alloc_size = netdev_size + priv_size; - dev = kmalloc(alloc_size, GFP_KERNEL); - if (dev) { - memset(dev, 0, alloc_size); - dev->priv = (char*)dev + netdev_size; - setup(dev); -# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) - dev->name = (char*)(dev + 1); -# endif - strcpy(dev->name, mask); - } - return dev; -} -# define compat_free_netdev(dev) kfree(dev) -#else -# define compat_alloc_netdev(size, mask, setup) alloc_netdev(size, mask, setup) -# define compat_free_netdev(dev) free_netdev(dev) -#endif - -/* netdev_priv() appeared in 2.6.3 */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3) -# define compat_netdev_priv(netdev) (netdev)->priv -#else -# define compat_netdev_priv(netdev) netdev_priv(netdev) -#endif - -#if defined(NETDEV_TX_OK) -# define COMPAT_NETDEV_TX_OK NETDEV_TX_OK -# define COMPAT_NETDEV_TX_BUSY NETDEV_TX_BUSY -#else -# define COMPAT_NETDEV_TX_OK 0 -# define COMPAT_NETDEV_TX_BUSY 1 -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)) -static inline void -compat_netif_start_queue(struct device *dev) -{ - clear_bit(0, &dev->tbusy); -} - -static inline void -compat_netif_stop_queue(struct device *dev) -{ - set_bit(0, &dev->tbusy); -} - -static inline int -compat_netif_queue_stopped(struct device *dev) -{ - return test_bit(0, &dev->tbusy); -} - -static inline void -compat_netif_wake_queue(struct device *dev) -{ - clear_bit(0, &dev->tbusy); - mark_bh(NET_BH); -} - -static inline int -compat_netif_running(struct device *dev) -{ - return dev->start == 0; -} - -static inline int -compat_netif_carrier_ok(struct device *dev) -{ - return 1; -} - -static inline void -compat_netif_carrier_on(struct device *dev) -{ -} - -static inline void -compat_netif_carrier_off(struct device *dev) -{ -} - -#else -#define compat_netif_start_queue(dev) netif_start_queue(dev) -#define compat_netif_stop_queue(dev) netif_stop_queue(dev) -#define compat_netif_queue_stopped(dev) netif_queue_stopped(dev) -#define compat_netif_wake_queue(dev) netif_wake_queue(dev) -#define compat_netif_running(dev) netif_running(dev) -#define compat_netif_carrier_ok(dev) netif_carrier_ok(dev) -#define compat_netif_carrier_on(dev) netif_carrier_on(dev) -#define compat_netif_carrier_off(dev) netif_carrier_off(dev) -#endif - -/* unregister_netdevice_notifier was not safe prior to 2.6.17 */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) && \ - !defined(ATOMIC_NOTIFIER_INIT) -/* pre 2.6.17 and not patched */ -static inline int compat_unregister_netdevice_notifier(struct notifier_block *nb) { - int err; - - rtnl_lock(); - err = unregister_netdevice_notifier(nb); - rtnl_unlock(); - return err; -} -#else -/* post 2.6.17 or patched */ -#define compat_unregister_netdevice_notifier(_nb) \ - unregister_netdevice_notifier(_nb); -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -#define compat_netif_napi_add(dev, napi, poll, quota) \ - netif_napi_add(dev, napi, poll, quota) -#define compat_netif_rx_schedule(dev, napi) netif_rx_schedule(dev, napi) -#define compat_napi_enable(dev, napi) napi_enable(napi) -#define compat_napi_disable(dev, napi) napi_disable(napi) -#else -struct napi_struct { - int dummy; -}; - -#define compat_netif_napi_add(dev, napi, pollcb, quota) \ - do { \ - (dev)->poll = (pollcb); \ - (dev)->weight = (quota);\ - } while (0) -#define compat_netif_rx_schedule(dev, napi) netif_rx_schedule(dev) -#define compat_napi_enable(dev, napi) netif_poll_enable(dev) -#define compat_napi_disable(dev, napi) netif_poll_disable(dev) -#endif - -#endif /* __COMPAT_NETDEVICE_H__ */ diff -Nrup source/vmnet-only/compat_page.h source.edited/vmnet-only/compat_page.h --- source/vmnet-only/compat_page.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_page.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,75 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_PAGE_H__ -# define __COMPAT_PAGE_H__ - - -#include -#include - - -/* The pfn_to_page() API appeared in 2.5.14 and changed to function during 2.6.x */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pfn_to_page) -# define pfn_to_page(_pfn) (mem_map + (_pfn)) -# define page_to_pfn(_page) ((_page) - mem_map) -#endif - - -/* The virt_to_page() API appeared in 2.4.0 --hpreg */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) && !defined(virt_to_page) -# define virt_to_page(_kvAddr) pfn_to_page(MAP_NR(_kvAddr)) -#endif - - -/* - * The get_order() API appeared at some point in 2.3.x, and was then backported - * in 2.2.17-21mdk and in the stock 2.2.18. Because we can only detect its - * definition through makefile tricks, we provide our own for now --hpreg - */ -static inline int -compat_get_order(unsigned long size) // IN -{ - int order; - - size = (size - 1) >> (PAGE_SHIFT - 1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - - return order; -} - -/* - * BUG() was added to in 2.2.18, and was moved to - * in 2.5.58. - * - * XXX: Technically, this belongs in some sort of "compat_asm_page.h" file, but - * since our compatibility wrappers don't distinguish between and - * , putting it here is reasonable. - */ -#ifndef BUG -#define BUG() do { \ - printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ - __asm__ __volatile__(".byte 0x0f,0x0b"); \ -} while (0) -#endif - -#endif /* __COMPAT_PAGE_H__ */ diff -Nrup source/vmnet-only/compat_pgtable.h source.edited/vmnet-only/compat_pgtable.h --- source/vmnet-only/compat_pgtable.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_pgtable.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,139 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_PGTABLE_H__ -# define __COMPAT_PGTABLE_H__ - - -#if defined(CONFIG_PARAVIRT) && defined(CONFIG_HIGHPTE) -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) -# include -# undef paravirt_map_pt_hook -# define paravirt_map_pt_hook(type, va, pfn) do {} while (0) -# endif -#endif -#include - - -/* pte_page() API modified in 2.3.23 to return a struct page * --hpreg */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 23) -# define compat_pte_page pte_page -#else -# include "compat_page.h" - -# define compat_pte_page(_pte) virt_to_page(pte_page(_pte)) -#endif - - -/* Appeared in 2.5.5 --hpreg */ -#ifndef pte_offset_map -/* Appeared in SuSE 8.0's 2.4.18 --hpreg */ -# ifdef pte_offset_atomic -# define pte_offset_map pte_offset_atomic -# define pte_unmap pte_kunmap -# else -# define pte_offset_map pte_offset -# define pte_unmap(_pte) -# endif -#endif - - -/* Appeared in 2.5.74-mmX --petr */ -#ifndef pmd_offset_map -# define pmd_offset_map(pgd, address) pmd_offset(pgd, address) -# define pmd_unmap(pmd) -#endif - - -/* - * Appeared in 2.6.10-rc2-mm1. Older kernels did L4 page tables as - * part of pgd_offset, or they did not have L4 page tables at all. - * In 2.6.11 pml4 -> pgd -> pmd -> pte hierarchy was replaced by - * pgd -> pud -> pmd -> pte hierarchy. - */ -#ifdef PUD_MASK -# define compat_pgd_offset(mm, address) pgd_offset(mm, address) -# define compat_pgd_present(pgd) pgd_present(pgd) -# define compat_pud_offset(pgd, address) pud_offset(pgd, address) -# define compat_pud_present(pud) pud_present(pud) -typedef pgd_t compat_pgd_t; -typedef pud_t compat_pud_t; -#elif defined(pml4_offset) -# define compat_pgd_offset(mm, address) pml4_offset(mm, address) -# define compat_pgd_present(pml4) pml4_present(pml4) -# define compat_pud_offset(pml4, address) pml4_pgd_offset(pml4, address) -# define compat_pud_present(pgd) pgd_present(pgd) -typedef pml4_t compat_pgd_t; -typedef pgd_t compat_pud_t; -#else -# define compat_pgd_offset(mm, address) pgd_offset(mm, address) -# define compat_pgd_present(pgd) pgd_present(pgd) -# define compat_pud_offset(pgd, address) (pgd) -# define compat_pud_present(pud) (1) -typedef pgd_t compat_pgd_t; -typedef pgd_t compat_pud_t; -#endif - - -#define compat_pgd_offset_k(mm, address) pgd_offset_k(address) - - -/* Introduced somewhere in 2.6.0, + backported to some 2.4 RedHat kernels */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pte_pfn) -# define pte_pfn(pte) page_to_pfn(compat_pte_page(pte)) -#endif - - -/* A page_table_lock field is added to struct mm_struct in 2.3.10 --hpreg */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 10) -# define compat_get_page_table_lock(_mm) (&(_mm)->page_table_lock) -#else -# define compat_get_page_table_lock(_mm) NULL -#endif - - -/* - * Define VM_PAGE_KERNEL_EXEC for vmapping executable pages. - * - * On ia32 PAGE_KERNEL_EXEC was introduced in 2.6.8.1. Unfortunately it accesses - * __PAGE_KERNEL_EXEC which is not exported for modules. So we use - * __PAGE_KERNEL and just cut _PAGE_NX bit from it. - * - * For ia32 kernels before 2.6.8.1 we use PAGE_KERNEL directly, these kernels - * do not have noexec support. - * - * On x86-64 situation is a bit better: they always supported noexec, but - * before 2.6.8.1 flag was named PAGE_KERNEL_EXECUTABLE, and it was renamed - * to PAGE_KERNEL_EXEC when ia32 got noexec too (see above). - */ -#ifdef CONFIG_X86 -#ifdef _PAGE_NX -#define VM_PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL & ~_PAGE_NX) -#else -#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL -#endif -#else -#ifdef PAGE_KERNEL_EXECUTABLE -#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL_EXECUTABLE -#else -#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL_EXEC -#endif -#endif - - -#endif /* __COMPAT_PGTABLE_H__ */ diff -Nrup source/vmnet-only/compat_sched.h source.edited/vmnet-only/compat_sched.h --- source/vmnet-only/compat_sched.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_sched.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,291 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_SCHED_H__ -# define __COMPAT_SCHED_H__ - - -#include - -/* CLONE_KERNEL available in 2.5.35 and higher. */ -#ifndef CLONE_KERNEL -#define CLONE_KERNEL CLONE_FILES | CLONE_FS | CLONE_SIGHAND -#endif - -/* TASK_COMM_LEN become available in 2.6.11. */ -#ifndef TASK_COMM_LEN -#define TASK_COMM_LEN 16 -#endif - -/* The capable() API appeared in 2.1.92 --hpreg */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 1, 92) -# define capable(_capability) suser() -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) -# define need_resched() need_resched -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 3) -# define need_resched() (current->need_resched) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 3) -# define cond_resched() (need_resched() ? schedule() : (void) 0) -#endif - -/* Oh well. We need yield... Happy us! */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) -# ifdef __x86_64__ -# define compat_yield() there_is_nothing_like_yield() -# else -# include -# include - -/* - * Used by _syscallX macros. Note that this is global variable, so - * do not rely on its contents too much. As exit() is only function - * we use, and we never check return value from exit(), we have - * no problem... - */ -extern int errno; - -/* - * compat_exit() provides an access to the exit() function. It must - * be named compat_exit(), as exit() (with different signature) is - * provided by x86-64, arm and other (but not by i386). - */ -# define __NR_compat_yield __NR_sched_yield -static inline _syscall0(int, compat_yield); -# endif -#else -# define compat_yield() yield() -#endif - - -/* - * Since 2.5.34 there are two methods to enumerate tasks: - * for_each_process(p) { ... } which enumerates only tasks and - * do_each_thread(g,t) { ... } while_each_thread(g,t) which enumerates - * also threads even if they share same pid. - */ -#ifndef for_each_process -# define for_each_process(p) for_each_task(p) -#endif - -#ifndef do_each_thread -# define do_each_thread(g, t) for_each_task(g) { t = g; do -# define while_each_thread(g, t) while (0) } -#endif - - -/* - * Lock for signal mask is moving target... - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 40) && defined(CLONE_PID) -/* 2.4.x without NPTL patches or early 2.5.x */ -#define compat_sigmask_lock sigmask_lock -#define compat_dequeue_signal_current(siginfo_ptr) \ - dequeue_signal(¤t->blocked, (siginfo_ptr)) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 60) && !defined(INIT_SIGHAND) -/* RedHat's 2.4.x with first version of NPTL support, or 2.5.40 to 2.5.59 */ -#define compat_sigmask_lock sig->siglock -#define compat_dequeue_signal_current(siginfo_ptr) \ - dequeue_signal(¤t->blocked, (siginfo_ptr)) -#else -/* RedHat's 2.4.x with second version of NPTL support, or 2.5.60+. */ -#define compat_sigmask_lock sighand->siglock -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) -#define compat_dequeue_signal_current(siginfo_ptr) \ - dequeue_signal(¤t->blocked, (siginfo_ptr)) -#else -#define compat_dequeue_signal_current(siginfo_ptr) \ - dequeue_signal(current, ¤t->blocked, (siginfo_ptr)) -#endif -#endif - -/* - * recalc_sigpending() had task argument in the past - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 29) && defined(CLONE_PID) -/* 2.4.x without NPTL patches or early 2.5.x */ -#define compat_recalc_sigpending() recalc_sigpending(current) -#else -/* RedHat's 2.4.x with NPTL support, or 2.5.29+ */ -#define compat_recalc_sigpending() recalc_sigpending() -#endif - - -/* - * reparent_to_init() was introduced in 2.4.8. In 2.5.38 (or possibly - * earlier, but later than 2.5.31) a call to it was added into - * daemonize(), so compat_daemonize no longer needs to call it. - * - * In 2.4.x kernels reparent_to_init() forgets to do correct refcounting - * on current->user. It is better to count one too many than one too few... - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 38) -#define compat_reparent_to_init() do { \ - reparent_to_init(); \ - atomic_inc(¤t->user->__count); \ - } while (0) -#else -#define compat_reparent_to_init() do {} while (0) -#endif - - -/* - * daemonize appeared in 2.2.18. Except 2.2.17-4-RH7.0, which has it too. - * Fortunately 2.2.17-4-RH7.0 uses versioned symbols, so we can check - * its existence with defined(). - */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) && !defined(daemonize) -static inline void daemonize(void) { - struct fs_struct *fs; - - exit_mm(current); - current->session = 1; - current->pgrp = 1; - exit_fs(current); - fs = init_task.fs; - current->fs = fs; - atomic_inc(&fs->count); -} -#endif - - -/* - * flush_signals acquires sighand->siglock since 2.5.61... Verify RH's kernels! - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) -#define compat_flush_signals(task) do { \ - spin_lock_irq(&task->compat_sigmask_lock); \ - flush_signals(task); \ - spin_unlock_irq(&task->compat_sigmask_lock); \ - } while (0) -#else -#define compat_flush_signals(task) flush_signals(task) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) -#define compat_allow_signal(signr) do { \ - spin_lock_irq(¤t->compat_sigmask_lock); \ - sigdelset(¤t->blocked, signr); \ - compat_recalc_sigpending(); \ - spin_unlock_irq(¤t->compat_sigmask_lock); \ - } while (0) -#else -#define compat_allow_signal(signr) allow_signal(signr) -#endif - -/* - * daemonize can set process name since 2.5.61. Prior to 2.5.61, daemonize - * didn't block signals on our behalf. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) -#define compat_daemonize(x...) \ -({ \ - /* Beware! No snprintf here, so verify arguments! */ \ - sprintf(current->comm, x); \ - \ - /* Block all signals. */ \ - spin_lock_irq(¤t->compat_sigmask_lock); \ - sigfillset(¤t->blocked); \ - compat_recalc_sigpending(); \ - spin_unlock_irq(¤t->compat_sigmask_lock); \ - compat_flush_signals(current); \ - \ - daemonize(); \ - compat_reparent_to_init(); \ -}) -#else -#define compat_daemonize(x...) daemonize(x) -#endif - - -/* - * set priority for specified thread. Exists on 2.6.x kernels and some - * 2.4.x vendor's kernels. - */ -#if defined(VMW_HAVE_SET_USER_NICE) -#define compat_set_user_nice(task, n) set_user_nice((task), (n)) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) -#define compat_set_user_nice(task, n) do { (task)->priority = 20 - (n); } while (0) -#elif !defined(VMW_HAVE_SET_USER_NICE) -#define compat_set_user_nice(task, n) do { (task)->nice = (n); } while (0) -#endif - -/* - * try to freeze a process. For kernels 2.6.11 or newer, we know how to choose - * the interface. The problem is that the oldest interface, introduced in - * 2.5.18, was backported to 2.4.x kernels. So if we're older than 2.6.11, - * we'll decide what to do based on whether or not swsusp was configured - * for the kernel. For kernels 2.6.20 and newer, we'll also need to include - * freezer.h since the try_to_freeze definition was pulled out of sched.h. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -#include -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) || defined(VMW_TL10S64_WORKAROUND) -#define compat_try_to_freeze() try_to_freeze() -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) -#define compat_try_to_freeze() try_to_freeze(PF_FREEZE) -#elif defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_SOFTWARE_SUSPEND2) -#include "compat_mm.h" -#include -#include -static inline int compat_try_to_freeze(void) { - if (current->flags & PF_FREEZE) { - refrigerator(PF_FREEZE); - return 1; - } else { - return 0; - } -} -#else -static inline int compat_try_to_freeze(void) { return 0; } -#endif - -/* - * As of 2.6.23-rc1, kernel threads are no longer freezable by - * default. Instead, kernel threads that need to be frozen must opt-in - * by calling set_freezable() as soon as the thread is created. - */ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) -#define compat_set_freezable() do { set_freezable(); } while (0) -#else -#define compat_set_freezable() do {} while (0) -#endif - -/* - * Since 2.6.27-rc2 kill_proc() is gone... Replacement (GPL-only!) - * API is available since 2.6.19. Use them from 2.6.27-rc1 up. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -typedef int compat_pid; -#define compat_find_get_pid(pid) (pid) -#define compat_put_pid(pid) do { } while (0) -#define compat_kill_pid(pid, sig, flag) kill_proc(pid, sig, flag) -#else -typedef struct pid * compat_pid; -#define compat_find_get_pid(pid) find_get_pid(pid) -#define compat_put_pid(pid) put_pid(pid) -#define compat_kill_pid(pid, sig, flag) kill_pid(pid, sig, flag) -#endif - - -#endif /* __COMPAT_SCHED_H__ */ diff -Nrup source/vmnet-only/compat_semaphore.h source.edited/vmnet-only/compat_semaphore.h --- source/vmnet-only/compat_semaphore.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_semaphore.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,49 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_SEMAPHORE_H__ -# define __COMPAT_SEMAPHORE_H__ - - -/* <= 2.6.25 have asm only, 2.6.26 has both, and 2.6.27-rc2+ has linux only. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -# include -#else -# include -#endif - - -/* -* The init_MUTEX_LOCKED() API appeared in 2.2.18, and is also in -* 2.2.17-21mdk --hpreg -*/ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) - #ifndef init_MUTEX_LOCKED - #define init_MUTEX_LOCKED(_sem) *(_sem) = MUTEX_LOCKED - #endif - #ifndef DECLARE_MUTEX - #define DECLARE_MUTEX(name) struct semaphore name = MUTEX - #endif - #ifndef DECLARE_MUTEX_LOCKED - #define DECLARE_MUTEX_LOCKED(name) struct semaphore name = MUTEX_LOCKED - #endif -#endif - - -#endif /* __COMPAT_SEMAPHORE_H__ */ diff -Nrup source/vmnet-only/compat_skbuff.h source.edited/vmnet-only/compat_skbuff.h --- source/vmnet-only/compat_skbuff.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_skbuff.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,156 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 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 - * - *********************************************************/ - -#ifndef __COMPAT_SKBUFF_H__ -# define __COMPAT_SKBUFF_H__ - -#include - -/* - * When transition from mac/nh/h to skb_* accessors was made, also SKB_WITH_OVERHEAD - * was introduced. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 21) && defined(SKB_WITH_OVERHEAD)) -#define compat_skb_mac_header(skb) skb_mac_header(skb) -#define compat_skb_network_header(skb) skb_network_header(skb) -#define compat_skb_network_offset(skb) skb_network_offset(skb) -#define compat_skb_transport_header(skb) skb_transport_header(skb) -#define compat_skb_transport_offset(skb) skb_transport_offset(skb) -#define compat_skb_network_header_len(skb) skb_network_header_len(skb) -#define compat_skb_tail_pointer(skb) skb_tail_pointer(skb) -#define compat_skb_end_pointer(skb) skb_end_pointer(skb) -#define compat_skb_ip_header(skb) ((struct iphdr *)skb_network_header(skb)) -#define compat_skb_tcp_header(skb) ((struct tcphdr *)skb_transport_header(skb)) -#define compat_skb_reset_mac_header(skb) skb_reset_mac_header(skb) -#define compat_skb_set_network_header(skb, off) skb_set_network_header(skb, off) -#define compat_skb_set_transport_header(skb, off) skb_set_transport_header(skb, off) -#else -#define compat_skb_mac_header(skb) (skb)->mac.raw -#define compat_skb_network_header(skb) (skb)->nh.raw -#define compat_skb_network_offset(skb) ((skb)->nh.raw - (skb)->data) -#define compat_skb_transport_header(skb) (skb)->h.raw -#define compat_skb_transport_offset(skb) ((skb)->h.raw - (skb)->data) -#define compat_skb_network_header_len(skb) ((skb)->h.raw - (skb)->nh.raw) -#define compat_skb_tail_pointer(skb) (skb)->tail -#define compat_skb_end_pointer(skb) (skb)->end -#define compat_skb_ip_header(skb) (skb)->nh.iph -#define compat_skb_tcp_header(skb) (skb)->h.th -#define compat_skb_reset_mac_header(skb) ((skb)->mac.raw = (skb)->data) -#define compat_skb_set_network_header(skb, off) ((skb)->nh.raw = (skb)->data + (off)) -#define compat_skb_set_transport_header(skb, off) ((skb)->h.raw = (skb)->data + (off)) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) || defined(VMW_SKB_LINEARIZE_2618) -# define compat_skb_linearize(skb) skb_linearize((skb)) -#else - -# if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 0) -# define compat_skb_linearize(skb) __skb_linearize((skb), GFP_ATOMIC) -# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) -# define compat_skb_linearize(skb) skb_linearize((skb), GFP_ATOMIC) -# else -static inline int -compat_skb_linearize(struct sk_buff *skb) -{ - return 0; -} -# endif - -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -#define compat_skb_csum_offset(skb) (skb)->csum_offset -#else -#define compat_skb_csum_offset(skb) (skb)->csum -#endif - -/* - * Note that compat_skb_csum_start() has semantic different from kernel's csum_start: - * kernel's skb->csum_start is offset between start of checksummed area and start of - * complete skb buffer, while our compat_skb_csum_start(skb) is offset from start - * of packet itself. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -#define compat_skb_csum_start(skb) ((skb)->csum_start - skb_headroom(skb)) -#else -#define compat_skb_csum_start(skb) compat_skb_transport_offset(skb) -#endif - -#if defined(NETIF_F_GSO) /* 2.6.18 and upwards */ -#define compat_skb_mss(skb) (skb_shinfo(skb)->gso_size) -#else -#define compat_skb_mss(skb) (skb_shinfo(skb)->tso_size) -#endif - -/* used by both received pkts and outgoing ones */ -#define VM_CHECKSUM_UNNECESSARY CHECKSUM_UNNECESSARY - -/* csum status of received pkts */ -#if defined(CHECKSUM_COMPLETE) -# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_COMPLETE -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW) -# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_HW -#else -# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_PARTIAL -#endif - -/* csum status of outgoing pkts */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW) -# define VM_TX_CHECKSUM_PARTIAL CHECKSUM_HW -#else -# define VM_TX_CHECKSUM_PARTIAL CHECKSUM_PARTIAL -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)) -# define compat_kfree_skb(skb, type) kfree_skb(skb, type) -# define compat_dev_kfree_skb(skb, type) dev_kfree_skb(skb, type) -# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb(skb, type) -# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb(skb, type) -#else -# define compat_kfree_skb(skb, type) kfree_skb(skb) -# define compat_dev_kfree_skb(skb, type) dev_kfree_skb(skb) -# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)) -# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb(skb) -# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb(skb) -# else -# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb_any(skb) -# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb_irq(skb) -# endif -#endif - -#ifndef NET_IP_ALIGN -# define COMPAT_NET_IP_ALIGN 2 -#else -# define COMPAT_NET_IP_ALIGN NET_IP_ALIGN -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) -# define compat_skb_headlen(skb) skb_headlen(skb) -# define compat_pskb_may_pull(skb, len) pskb_may_pull(skb, len) -#else -# define compat_skb_headlen(skb) (skb)->len -# define compat_pskb_may_pull(skb, len) 1 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) -# define compat_skb_header_cloned(skb) skb_header_cloned(skb) -#else -# define compat_skb_header_cloned(skb) 0 -#endif -#endif /* __COMPAT_SKBUFF_H__ */ diff -Nrup source/vmnet-only/compat_slab.h source.edited/vmnet-only/compat_slab.h --- source/vmnet-only/compat_slab.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_slab.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,85 +0,0 @@ -/********************************************************* - * Copyright (C) 2005 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 - * - *********************************************************/ - -#ifndef __COMPAT_SLAB_H__ -# define __COMPAT_SLAB_H__ - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) -# include -#else -# include -#endif - -/* - * Before 2.6.20, kmem_cache_t was the accepted way to refer to a kmem_cache - * structure. Prior to 2.6.15, this structure was called kmem_cache_s, and - * afterwards it was renamed to kmem_cache. Here we keep things simple and use - * the accepted typedef until it became deprecated, at which point we switch - * over to the kmem_cache name. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -# define compat_kmem_cache struct kmem_cache -#else -# define compat_kmem_cache kmem_cache_t -#endif - -/* - * Up to 2.6.22 kmem_cache_create has 6 arguments - name, size, alignment, flags, - * constructor, and destructor. Then for some time kernel was asserting that - * destructor is NULL, and since 2.6.23-pre1 kmem_cache_create takes only 5 - * arguments - destructor is gone. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) || defined(VMW_KMEMCR_HAS_DTOR) -#define compat_kmem_cache_create(name, size, align, flags, ctor) \ - kmem_cache_create(name, size, align, flags, ctor, NULL) -#else -#define compat_kmem_cache_create(name, size, align, flags, ctor) \ - kmem_cache_create(name, size, align, flags, ctor) -#endif - -/* - * Up to 2.6.23 kmem_cache constructor has three arguments - pointer to block to - * prepare (aka "this"), from which cache it came, and some unused flags. After - * 2.6.23 flags were removed, and order of "this" and cache parameters was swapped... - * Since 2.6.27-rc2 everything is different again, and ctor has only one argument. - * - * HAS_3_ARGS has precedence over HAS_2_ARGS if both are defined. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) && !defined(VMW_KMEMCR_CTOR_HAS_3_ARGS) -# define VMW_KMEMCR_CTOR_HAS_3_ARGS -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) && !defined(VMW_KMEMCR_CTOR_HAS_2_ARGS) -# define VMW_KMEMCR_CTOR_HAS_2_ARGS -#endif - -#if defined(VMW_KMEMCR_CTOR_HAS_3_ARGS) -typedef void compat_kmem_cache_ctor(void *, compat_kmem_cache *, unsigned long); -#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) void *arg, \ - compat_kmem_cache *cache, \ - unsigned long flags -#elif defined(VMW_KMEMCR_CTOR_HAS_2_ARGS) -typedef void compat_kmem_cache_ctor(compat_kmem_cache *, void *); -#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) compat_kmem_cache *cache, \ - void *arg -#else -typedef void compat_kmem_cache_ctor(void *); -#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) void *arg -#endif - -#endif /* __COMPAT_SLAB_H__ */ diff -Nrup source/vmnet-only/compat_sock.h source.edited/vmnet-only/compat_sock.h --- source/vmnet-only/compat_sock.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_sock.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,169 +0,0 @@ -/********************************************************* - * Copyright (C) 2003 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 - * - *********************************************************/ - -#ifndef __COMPAT_SOCK_H__ -# define __COMPAT_SOCK_H__ - -#include /* for NULL */ -#include - - -/* - * Between 2.5.70 and 2.5.71 all sock members were renamed from XXX to sk_XXX. - * - * VMW_HAVE_SK_WMEM_ALLOC is defined in module Makefile if kernel's struct sock - * has sk_wmem_alloc member. See vmnet's Makefile.kernel for details. - * It also means that all modules including this file should do - * - * EXTRA_CFLAGS += $(call vm_check_build, $(SRCROOT)/socket.c, -DVMW_HAVE_SK_WMEM_ALLOC, ) - * - * in their Makefiles. - */ -#ifndef VMW_HAVE_SK_WMEM_ALLOC -# define sk_wmem_alloc wmem_alloc -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 71) -# define compat_sk_backlog_rcv backlog_rcv -# define compat_sk_destruct destruct -# define compat_sk_shutdown shutdown -# define compat_sk_receive_queue receive_queue -# define compat_sk_sleep sleep -# define compat_sk_err err -# define compat_sk_state_change state_change -# define compat_sk_data_ready data_ready -# define compat_sk_write_space write_space -# define compat_sk_error_report error_report -# define compat_sk_type type -# define compat_sk_refcnt refcnt -# define compat_sk_state state -# define compat_sk_error_report error_report -# define compat_sk_socket socket -# define compat_sk_ack_backlog ack_backlog -# define compat_sk_max_ack_backlog max_ack_backlog -#else -# define compat_sk_backlog_rcv sk_backlog_rcv -# define compat_sk_destruct sk_destruct -# define compat_sk_shutdown sk_shutdown -# define compat_sk_receive_queue sk_receive_queue -# define compat_sk_sleep sk_sleep -# define compat_sk_err sk_err -# define compat_sk_state_change sk_state_change -# define compat_sk_data_ready sk_data_ready -# define compat_sk_write_space sk_write_space -# define compat_sk_error_report sk_error_report -# define compat_sk_type sk_type -# define compat_sk_refcnt sk_refcnt -# define compat_sk_state sk_state -# define compat_sk_error_report sk_error_report -# define compat_sk_socket sk_socket -# define compat_sk_ack_backlog sk_ack_backlog -# define compat_sk_max_ack_backlog sk_max_ack_backlog -#endif - - -/* - * Prior to 2.6.24, there was no sock network namespace member. In 2.6.26, it - * was hidden behind accessor functions so that its behavior could vary - * depending on the value of CONFIG_NET_NS. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) -# define compat_sock_net(sk) sock_net(sk) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -# define compat_sock_net(sk) sk->sk_net -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 42) -# define compat_sock_owned_by_user(sk) ((sk)->lock.users != 0) -#else -# define compat_sock_owned_by_user(sk) sock_owned_by_user(sk) -#endif - -/* - * Up until 2.4.21 for the 2.4 series and 2.5.60 for the 2.5 series, - * sk_filter() calls were protected with CONFIG_FILTER. Wrapping our compat - * definition in a similar check allows us to build on those kernels. - * - */ -#ifdef CONFIG_FILTER -/* - * Unfortunately backports for certain kernels require the use of an autoconf - * program to check the interface for sk_filter(). - */ -# ifndef VMW_HAVE_NEW_SKFILTER -# define compat_sk_filter(sk, skb, needlock) sk_filter(skb, (sk)->filter) -# else -# define compat_sk_filter(sk, skb, needlock) sk_filter(sk, skb, needlock) -# endif -#else -# define compat_sk_filter(sk, skb, needlock) 0 -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) -/* Taken from 2.6.16's sock.h and modified for macro. */ -# define compat_sk_receive_skb(sk, skb, nested) \ - ({ \ - int rc = NET_RX_SUCCESS; \ - \ - if (compat_sk_filter(sk, skb, 0)) { \ - kfree_skb(skb); \ - sock_put(sk); \ - } else { \ - skb->dev = NULL; \ - bh_lock_sock(sk); \ - if (!compat_sock_owned_by_user(sk)) { \ - rc = (sk)->compat_sk_backlog_rcv(sk, skb); \ - } else { \ - sk_add_backlog(sk, skb); \ - } \ - bh_unlock_sock(sk); \ - sock_put(sk); \ - } \ - \ - rc; \ - }) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -# define compat_sk_receive_skb(sk, skb, nested) sk_receive_skb(sk, skb) -#else -# define compat_sk_receive_skb(sk, skb, nested) sk_receive_skb(sk, skb, nested) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 72) -/* - * Before 2.5.72, the helper socket functions for hlist management did not - * exist, so we use the sklist_ functions instead. These are not ideal since - * they grab a system-wide sklist lock despite not needing it since we provide - * our own list. - */ -#define compat_sk_next next /* for when we find out it became sk_next */ -# define compat_sklist_table struct sock * -/* This isn't really used in the iterator, but we need something. */ -# define compat_sklist_table_entry struct sock -# define compat_sk_for_each(sk, node, list) \ - for (sk = *(list), node = NULL; sk != NULL; sk = (sk)->compat_sk_next) -# define compat_sk_add_node(sk, list) sklist_insert_socket(list, sk) -# define compat_sk_del_node_init(sk, list) sklist_remove_socket(list, sk) -#else -# define compat_sklist_table struct hlist_head -# define compat_sklist_table_entry struct hlist_node -# define compat_sk_for_each(sk, node, list) sk_for_each(sk, node, list) -# define compat_sk_add_node(sk, list) sk_add_node(sk, list) -# define compat_sk_del_node_init(sk, list) sk_del_node_init(sk) -#endif - -#endif /* __COMPAT_SOCK_H__ */ diff -Nrup source/vmnet-only/compat_spinlock.h source.edited/vmnet-only/compat_spinlock.h --- source/vmnet-only/compat_spinlock.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_spinlock.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,68 +0,0 @@ -/********************************************************* - * Copyright (C) 2005 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 - * - *********************************************************/ - -#ifndef __COMPAT_SPINLOCK_H__ -# define __COMPAT_SPINLOCK_H__ - - -/* - * The spin_lock() API appeared in 2.1.25 in asm/smp_lock.h - * It moved in 2.1.30 to asm/spinlock.h - * It moved again in 2.3.18 to linux/spinlock.h - * - * --hpreg - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 18) -# include -#else -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 30) -# include -# else -typedef struct {} spinlock_t; -# define spin_lock_init(lock) -# define spin_lock(lock) -# define spin_unlock(lock) -# define spin_lock_irqsave(lock, flags) do { \ - save_flags(flags); \ - cli(); \ - spin_lock(lock); \ - } while (0) -# define spin_unlock_irqrestore(lock, flags) do { \ - spin_unlock(lock); \ - restore_flags(flags); \ - } while (0) -# endif -#endif - - -/* - * Preempt support was added during 2.5.x development cycle, and later - * it was backported to 2.4.x. In 2.4.x backport these definitions - * live in linux/spinlock.h, that's why we put them here (in 2.6.x they - * are defined in linux/preempt.h which is included by linux/spinlock.h). - */ -#ifdef CONFIG_PREEMPT -#define compat_preempt_disable() preempt_disable() -#define compat_preempt_enable() preempt_enable() -#else -#define compat_preempt_disable() do { } while (0) -#define compat_preempt_enable() do { } while (0) -#endif - - -#endif /* __COMPAT_SPINLOCK_H__ */ diff -Nrup source/vmnet-only/compat_uaccess.h source.edited/vmnet-only/compat_uaccess.h --- source/vmnet-only/compat_uaccess.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_uaccess.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,79 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_UACCESS_H__ -# define __COMPAT_UACCESS_H__ - - -/* User space access functions moved in 2.1.7 to asm/uaccess.h --hpreg */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 7) -# include -#else -# include -#endif - - -/* get_user() API modified in 2.1.4 to take 2 arguments --hpreg */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 4) -# define compat_get_user get_user -#else -/* - * We assign 0 to the variable in case of failure to prevent "`_var' might be - * used uninitialized in this function" compiler warnings. I think it is OK, - * because the hardware-based version in newer kernels probably has the same - * semantics and does not guarantee that the value of _var will not be - * modified, should the access fail --hpreg - */ -# define compat_get_user(_var, _uvAddr) ({ \ - int _status; \ - \ - _status = verify_area(VERIFY_READ, _uvAddr, sizeof(*(_uvAddr))); \ - if (_status == 0) { \ - (_var) = get_user(_uvAddr); \ - } else { \ - (_var) = 0; \ - } \ - _status; \ -}) -#endif - - -/* - * The copy_from_user() API appeared in 2.1.4 - * - * The emulation is not perfect here, but it is conservative: on failure, we - * always return the total size, instead of the potentially smaller faulty - * size --hpreg - * - * Since 2.5.55 copy_from_user() is no longer macro. - */ -#if !defined(copy_from_user) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) -# define copy_from_user(_to, _from, _size) ( \ - verify_area(VERIFY_READ, _from, _size) \ - ? (_size) \ - : (memcpy_fromfs(_to, _from, _size), 0) \ -) -# define copy_to_user(_to, _from, _size) ( \ - verify_area(VERIFY_WRITE, _to, _size) \ - ? (_size) \ - : (memcpy_tofs(_to, _from, _size), 0) \ -) -#endif - - -#endif /* __COMPAT_UACCESS_H__ */ diff -Nrup source/vmnet-only/compat_version.h source.edited/vmnet-only/compat_version.h --- source/vmnet-only/compat_version.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/compat_version.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,121 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -#ifndef __COMPAT_VERSION_H__ -# define __COMPAT_VERSION_H__ - -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMNIXMOD -#define INCLUDE_ALLOW_DISTRIBUTE -#include "includeCheck.h" - - -#ifndef __linux__ -# error "linux-version.h" -#endif - - -#include - -/* Appeared in 2.1.90 --hpreg */ -#ifndef KERNEL_VERSION -# define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) -#endif - - -/* - * Distinguish relevant classes of Linux kernels. - * - * The convention is that version X defines all - * the KERNEL_Y symbols where Y <= X. - * - * XXX Do not add more definitions here. This way of doing things does not - * scale, and we are going to phase it out soon --hpreg - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 0) -# define KERNEL_2_1 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) -# define KERNEL_2_2 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 1) -# define KERNEL_2_3_1 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 15) -/* new networking */ -# define KERNEL_2_3_15 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25) -/* new procfs */ -# define KERNEL_2_3_25 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29) -/* even newer procfs */ -# define KERNEL_2_3_29 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 43) -/* softnet changes */ -# define KERNEL_2_3_43 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 47) -/* more softnet changes */ -# define KERNEL_2_3_47 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 99) -/* name in netdevice struct is array and not pointer */ -# define KERNEL_2_3_99 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) -/* New 'owner' member at the beginning of struct file_operations */ -# define KERNEL_2_4_0 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) -/* New netif_rx_ni() --hpreg */ -# define KERNEL_2_4_8 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22) -/* New vmap() */ -# define KERNEL_2_4_22 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 2) -/* New kdev_t, major()/minor() API --hpreg */ -# define KERNEL_2_5_2 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) -/* New sk_alloc(), pte_offset_map()/pte_unmap() --hpreg */ -# define KERNEL_2_5_5 -#endif - - -#endif /* __COMPAT_VERSION_H__ */ diff -Nrup source/vmnet-only/compat_wait.h source.edited/vmnet-only/compat_wait.h --- source/vmnet-only/compat_wait.h 2010-05-09 20:06:53.000000000 -0700 +++ source.edited/vmnet-only/compat_wait.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,229 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_WAIT_H__ -# define __COMPAT_WAIT_H__ - - -#include -#include -#include - -#include "compat_file.h" - - -/* - * The DECLARE_WAITQUEUE() API appeared in 2.3.1 - * It was back ported in 2.2.18 - * - * --hpreg - */ - -#ifndef DECLARE_WAITQUEUE - -typedef struct wait_queue *wait_queue_head_t; -# define init_waitqueue_head(_headPtr) *(_headPtr) = NULL -# define DECLARE_WAITQUEUE(_var, _task) \ - struct wait_queue _var = {_task, NULL, } - -typedef struct wait_queue wait_queue_t; -# define init_waitqueue_entry(_wait, _task) ((_wait)->task = (_task)) - -#endif - -/* - * The 'struct poll_wqueues' appeared in 2.5.48, when global - * /dev/epoll interface was added. It was backported to the - * 2.4.20-wolk4.0s. - */ - -#ifdef VMW_HAVE_EPOLL // { -#define compat_poll_wqueues struct poll_wqueues -#else // } { -#define compat_poll_wqueues poll_table -#endif // } - -#ifdef VMW_HAVE_EPOLL // { - -/* If prototype does not match, build will abort here */ -extern void poll_initwait(compat_poll_wqueues *); - -#define compat_poll_initwait(wait, table) ( \ - poll_initwait((table)), \ - (wait) = &(table)->pt \ -) - -#define compat_poll_freewait(wait, table) ( \ - poll_freewait((table)) \ -) - -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) // { - -/* If prototype does not match, build will abort here */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) -extern void poll_initwait(compat_poll_wqueues *); -#else /* 2.6.29 */ -extern void poll_initwait(struct poll_wqueues *); -#endif /* 2.6.29 */ - -#define compat_poll_initwait(wait, table) ( \ - (wait) = (table), \ - poll_initwait(wait) \ -) - -#define compat_poll_freewait(wait, table) ( \ - poll_freewait((table)) \ -) - -#else // } { - -#define compat_poll_initwait(wait, table) ( \ - (wait) = (table), /* confuse compiler */ \ - (wait) = (poll_table *) __get_free_page(GFP_KERNEL), \ - (wait)->nr = 0, \ - (wait)->entry = (struct poll_table_entry *)((wait) + 1), \ - (wait)->next = NULL \ -) - -static inline void -poll_freewait(poll_table *wait) -{ - while (wait) { - struct poll_table_entry * entry; - poll_table *old; - - entry = wait->entry + wait->nr; - while (wait->nr > 0) { - wait->nr--; - entry--; - remove_wait_queue(entry->wait_address, &entry->wait); - compat_fput(entry->filp); - } - old = wait; - wait = wait->next; - free_page((unsigned long) old); - } -} - -#define compat_poll_freewait(wait, table) ( \ - poll_freewait((wait)) \ -) - -#endif // } - -/* - * The wait_event_interruptible_timeout() interface is not - * defined in pre-2.6 kernels. - */ -#ifndef wait_event_interruptible_timeout -#define __wait_event_interruptible_timeout(wq, condition, ret) \ -do { \ - wait_queue_t __wait; \ - init_waitqueue_entry(&__wait, current); \ - \ - add_wait_queue(&wq, &__wait); \ - for (;;) { \ - set_current_state(TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - if (!signal_pending(current)) { \ - ret = schedule_timeout(ret); \ - if (!ret) \ - break; \ - continue; \ - } \ - ret = -ERESTARTSYS; \ - break; \ - } \ - set_current_state(TASK_RUNNING); \ - remove_wait_queue(&wq, &__wait); \ -} while (0) - -#define wait_event_interruptible_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - if (!(condition)) \ - __wait_event_interruptible_timeout(wq, condition, __ret); \ - __ret; \ -}) -#endif - -/* - * The wait_event_timeout() interface is not - * defined in pre-2.6 kernels. - */ -#ifndef wait_event_timeout -#define __wait_event_timeout(wq, condition, ret) \ -do { \ - wait_queue_t __wait; \ - init_waitqueue_entry(&__wait, current); \ - \ - add_wait_queue(&wq, &__wait); \ - for (;;) { \ - set_current_state(TASK_UNINTERRUPTIBLE); \ - if (condition) \ - break; \ - ret = schedule_timeout(ret); \ - if (!ret) \ - break; \ - } \ - set_current_state(TASK_RUNNING); \ - remove_wait_queue(&wq, &__wait); \ -} while (0) - -#define wait_event_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - if (!(condition)) \ - __wait_event_timeout(wq, condition, __ret); \ - __ret; \ -}) -#endif - -/* - * DEFINE_WAIT() and friends were added in 2.5.39 and backported to 2.4.28. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 28) || \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 39)) -# define COMPAT_DEFINE_WAIT(_wait) \ - DECLARE_WAITQUEUE(_wait, current) -# define compat_init_prepare_to_wait(_sleep, _wait, _state) \ - do { \ - __set_current_state(_state); \ - add_wait_queue(_sleep, _wait); \ - } while (0) -# define compat_cont_prepare_to_wait(_sleep, _wait, _state) \ - set_current_state(_state) -# define compat_finish_wait(_sleep, _wait, _state) \ - do { \ - __set_current_state(_state); \ - remove_wait_queue(_sleep, _wait); \ - } while (0) -#else -# define COMPAT_DEFINE_WAIT(_wait) \ - DEFINE_WAIT(_wait) -# define compat_init_prepare_to_wait(_sleep, _wait, _state) \ - prepare_to_wait(_sleep, _wait, _state) -# define compat_cont_prepare_to_wait(_sleep, _wait, _state) \ - prepare_to_wait(_sleep, _wait, _state) -# define compat_finish_wait(_sleep, _wait, _state) \ - finish_wait(_sleep, _wait) -#endif - -#endif /* __COMPAT_WAIT_H__ */ diff -Nrup source/vmnet-only/driver.c source.edited/vmnet-only/driver.c --- source/vmnet-only/driver.c 2010-05-09 20:06:53.000000000 -0700 +++ source.edited/vmnet-only/driver.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1853 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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" - -#define EXPORT_SYMTAB - -#include -#include "compat_module.h" -#include -#include -#ifdef KERNEL_2_2 -# include -#else -# include -#endif -#include - -#include -#include - -#include -#include -#include -#include "compat_skbuff.h" -#include -#include -#include "compat_sock.h" - -#define __KERNEL_SYSCALLS__ -#include - -#include -#include -#if defined(__x86_64__) && !defined(HAVE_COMPAT_IOCTL) -#include -#endif - -#include "vnetInt.h" -#include "vnetFilter.h" - -#include "compat_uaccess.h" -#include "compat_kdev_t.h" -#include "compat_sched.h" -#include "compat_semaphore.h" -#include "vmnetInt.h" - -/* - * Initialization and creation routines from other files. - * Putting them here reduces the need for so many header files. - */ - -extern int VNetUserIf_Create(VNetPort **ret); -extern int VNetNetIf_Create(char *devName, VNetPort **ret, int hubNum); -extern int VNetBridge_Create(char *devName, VNetJack *hubJack, VNetPort **ret); -extern int VNetUserListener_Create(uint32 classMask, VNetJack *hubJack, VNetPort **ret); - -#ifdef CONFIG_NETFILTER -/* - * Filter routine from filter.c - */ -extern int VNetFilter_HandleUserCall(VNet_RuleHeader *ruleHeader, unsigned long ioarg); -extern void VNetFilter_Shutdown(void); -#endif - -/* - * Structure for cycle detection of host interfaces. This - * struct is only used by VNetCycleDetectIf(). - */ - -typedef struct VNetInterface { - char name[VNET_NAME_LEN]; - int myGeneration; - struct VNetInterface *next; -} VNetInterface; - -static VNetInterface *vnetInterfaces = NULL; - -/* this will let all multicast packets go through. */ -const uint8 allMultiFilter[VNET_LADRF_LEN] = { 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff }; - -/* broadcast MAC */ -const uint8 broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -/* - * All jack->peer accesses are guarded by this lock. - * - * This lock is acquired for read from interrupt context: - * use write_lock_irqsave() to gain write access. - * - * If you are acquiring this lock for write, and you do - * not have vnetStructureSemaphore already acquired, - * it is most certainly a bug. - */ -static rwlock_t vnetPeerLock = RW_LOCK_UNLOCKED; - -/* - * All concurrent changes to the network structure are - * guarded by this semaphore. - * - * For change to peer field you must own both - * vnetStructureSemaphore and vnetPeerLock for write. - */ -DECLARE_MUTEX(vnetStructureSemaphore); - -#if defined(VM_X86_64) && !defined(HAVE_COMPAT_IOCTL) -/* - * List of ioctl commands we translate 1:1 between 32bit - * userspace and 64bit kernel. - * - * Whole range is translated - * 1:1 in addition to the commands listed below. - */ -static const unsigned int ioctl32_cmds[] = { - SIOCGBRSTATUS, SIOCSPEER, SIOCSPEER2, SIOCSBIND, SIOCGETAPIVERSION2, - SIOCSFILTERRULES, 0, -}; -#endif - -/* - * List of known ports. Use vnetStructureSemaphore for locking. - */ - -static VNetPort *vnetAllPorts = NULL; - - -#ifdef VMW_HAVE_SK_ALLOC_WITH_PROTO -struct proto vmnet_proto = { - .name = "VMNET", - .owner = THIS_MODULE, - .obj_size = sizeof(struct sock), -}; -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -struct proto vmnet_proto = { - .name = "VMNET", - .owner = THIS_MODULE, - .obj_size = sizeof(struct sock), -}; - -#endif - -/* - * Device driver interface. - */ - -int VNetRegister(int value); -static int VNetFileOpOpen(struct inode *inode, struct file *filp); -static int VNetFileOpClose(struct inode *inode, struct file *filp); -static unsigned int VNetFileOpPoll(struct file *filp, poll_table *wait); -static ssize_t VNetFileOpRead(struct file *filp, char *buf, size_t count, - loff_t *ppos); -static ssize_t VNetFileOpWrite(struct file *filp, const char *buf, size_t count, - loff_t *ppos); -static int VNetFileOpIoctl(struct inode *inode, struct file *filp, - unsigned int iocmd, unsigned long ioarg); -#if defined(HAVE_UNLOCKED_IOCTL) || defined(HAVE_COPAT_IOCTL) -static long VNetFileOpUnlockedIoctl(struct file * filp, - unsigned int iocmd, unsigned long ioarg); -#endif - -static struct file_operations vnetFileOps; - -/* - * Utility functions - */ - -static void VNetFreeInterfaceList(void); -static int VNetSwitchToDifferentPeer(VNetJack *jack, VNetJack *newPeer, - Bool connectNewToPeer, - struct file *filp, VNetPort *jackPort, - VNetPort *newPeerPort); - -/* - *---------------------------------------------------------------------- - * - * VNetRegister -- - * - * (debugging support) Should be the first function of this file - * - * Results: - * - * Registers the module. - * /sbin/ksyms -a | grep VNetRegister will return the base - * address of that function as loaded in the kernel. - * - * Since this is the first function of the kernel module, - * every other symbol can be computing by adding the base - * to the output of nm. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetRegister(int value) // IN: unused -{ - LOG(0, (KERN_WARNING "/dev/vmnet: VNetRegister called\n")); - return 0; -} - -#ifdef VMW_HAVE_SK_ALLOC_WITH_PROTO - -/* - *---------------------------------------------------------------------- - * - * VNetProtoRegister -- - * VNetProtoUnregister -- - * - * Register or unregister the struct proto that we use for sk_alloc. - * - * Results: - * int. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -#define VNetProtoRegister() proto_register(&vmnet_proto, 0) -#define VNetProtoUnregister() \ - do { \ - proto_unregister(&vmnet_proto); \ - } while (0) - -#else - -#define VNetProtoRegister() 0 -#define VNetProtoUnregister() - -#endif - -#if defined(VM_X86_64) && !defined(HAVE_COMPAT_IOCTL) -/* - *---------------------------------------------------------------------- - * - * LinuxDriver_Ioctl32_Handler -- - * - * Wrapper for allowing 64-bit driver to handle ioctls() - * from 32-bit applications. - * - * Results: - * - * -ENOTTY, or result of call to VNetFileOpIoctl(). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -LinuxDriver_Ioctl32_Handler(unsigned int fd, // IN: (unused) - unsigned int iocmd, // IN: - unsigned long ioarg, // IN: - struct file * filp) // IN: -{ - int ret = -ENOTTY; - lock_kernel(); - if (filp && filp->f_op && filp->f_op->ioctl == VNetFileOpIoctl) { - ret = VNetFileOpIoctl(filp->f_dentry->d_inode, filp, iocmd, ioarg); - } - unlock_kernel(); - return ret; -} - - -/* - *---------------------------------------------------------------------- - * - * register_ioctl32_handlers -- - * - * Registers LinuxDriver_Ioctl32_Handler as the wrapper for - * allowing 64-bit driver to handle ioctls() - * from 32-bit applications. - * - * Does nothing on non-64bit systems. - * - * Results: - * - * errno (0 on success) - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -register_ioctl32_handlers(void) -{ - int i; - int retval; - - for (i = VNET_FIRST_CMD; i <= VNET_LAST_CMD; i++) { - retval = register_ioctl32_conversion(i, LinuxDriver_Ioctl32_Handler); - if (retval) { - int j; - LOG(0, (KERN_WARNING "Fail to register ioctl32 conversion for cmd %d\n", i)); - for (j = VNET_FIRST_CMD; j < i; ++j) { - unregister_ioctl32_conversion(j); - } - return retval; - } - } - for (i = 0; ioctl32_cmds[i]; i++) { - retval = register_ioctl32_conversion(ioctl32_cmds[i], LinuxDriver_Ioctl32_Handler); - if (retval) { - int j; - LOG(0, (KERN_WARNING "Fail to register ioctl32 conversion for cmd %08X\n", - ioctl32_cmds[i])); - for (j = VNET_FIRST_CMD; j < VNET_LAST_CMD; ++j) { - unregister_ioctl32_conversion(j); - } - for (j = 0; j < i; ++j) { - unregister_ioctl32_conversion(ioctl32_cmds[j]); - } - return retval; - } - } - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * unregister_ioctl32_handlers -- - * - * Unregisters the wrappers we specified for - * allowing a 64-bit driver to handle ioctls() - * from 32-bit applications. - * - * Does nothing on non-64bit systems. - * - * Results: - * - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -unregister_ioctl32_handlers(void) -{ - int i; - int retval; - - for (i = VNET_FIRST_CMD; i <= VNET_LAST_CMD; i++) { - retval = unregister_ioctl32_conversion(i); - if (retval) { - LOG(0, (KERN_WARNING "Fail to unregister ioctl32 conversion for cmd %d\n", i)); - } - } - for (i = 0; ioctl32_cmds[i]; i++) { - retval = unregister_ioctl32_conversion(ioctl32_cmds[i]); - if (retval) { - LOG(0, (KERN_WARNING "Fail to unregister ioctl32 conversion for cmd %08X\n", - ioctl32_cmds[i])); - } - } -} -#else -#define register_ioctl32_handlers() (0) -#define unregister_ioctl32_handlers() do { } while (0) -#endif - - -/* - *---------------------------------------------------------------------- - * - * VNetAddPortToList -- - * - * Add port to list of known ports. - * Caller must own vnetStructureSemaphore. - * - * Results: - * - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE void -VNetAddPortToList(VNetPort *port) // IN: port to add to list -{ - port->next = vnetAllPorts; - vnetAllPorts = port; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetRemovePortFromList -- - * - * Remove port from list of known ports. - * Caller must own vnetStructureSemaphore. - * - * Results: - * - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE void -VNetRemovePortFromList(const VNetPort *port) // IN: port to remove from list -{ - VNetPort **p; - - for (p = &vnetAllPorts; *p; p = &(*p)->next) { - if (*p == port) { - *p = port->next; - break; - } - } -} - - -/* - *---------------------------------------------------------------------- - * - * init_module -- - * - * linux module entry point. Called by /sbin/insmod command. - * Initializes module and Registers this driver for a - * vnet major #. The 64-bit version of this driver also - * registers handlers for 32-bit applications. - * - * Results: - * errno (0 on success). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -init_module(void) -{ - int retval; - - /* - * First initialize everything, and as a last step register - * vmnet device: immediately after registration anybody can - * ask driver for anything. - */ - - retval = VNetProc_Init(); - if (retval) { - LOG(0, (KERN_NOTICE "/dev/vmnet: could not register proc fs\n")); - return -ENOENT; - } - - retval = VNetProtoRegister(); - if (retval) { - goto err_proto; - } - - /* - * Initialize the file_operations structure. Because this code is always - * compiled as a module, this is fine to do it here and not in a static - * initializer. - */ - - memset(&vnetFileOps, 0, sizeof vnetFileOps); - compat_fop_set_owner(&vnetFileOps); - vnetFileOps.read = VNetFileOpRead; - vnetFileOps.write = VNetFileOpWrite; - vnetFileOps.poll = VNetFileOpPoll; -#ifdef HAVE_UNLOCKED_IOCTL - vnetFileOps.unlocked_ioctl = VNetFileOpUnlockedIoctl; -#else - vnetFileOps.ioctl = VNetFileOpIoctl; -#endif -#ifdef HAVE_COMPAT_IOCTL - vnetFileOps.compat_ioctl = VNetFileOpUnlockedIoctl; -#endif - vnetFileOps.open = VNetFileOpOpen; - vnetFileOps.release = VNetFileOpClose; - - retval = register_chrdev(VNET_MAJOR_NUMBER, "vmnet", &vnetFileOps); - if (retval) { - LOG(0, (KERN_NOTICE "/dev/vmnet: could not register major device %d\n", - VNET_MAJOR_NUMBER)); - goto err_chrdev; - } - - retval = register_ioctl32_handlers(); - if (retval) { - goto err_ioctl; - } - - return 0; - -err_ioctl: - unregister_chrdev(VNET_MAJOR_NUMBER, "vmnet"); -err_chrdev: - VNetProtoUnregister(); -err_proto: - VNetProc_Cleanup(); - return retval; -} - - -/* - *---------------------------------------------------------------------- - * - * cleanup_module -- - * - * Called by /sbin/rmmod. Unregisters this driver for a - * vnet major #, and deinitializes the modules. The 64-bit - * version of this driver also unregisters the handlers - * for 32-bit applications. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -cleanup_module(void) -{ - unregister_ioctl32_handlers(); - unregister_chrdev(VNET_MAJOR_NUMBER, "vmnet"); - VNetProtoUnregister(); - VNetProc_Cleanup(); -#ifdef CONFIG_NETFILTER - VNetFilter_Shutdown(); -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * VNetIncrModCount -- - * - * Increment or decrement the module use count. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VNetIncrModCount(int delta) // IN: delta (typically 1 or -1) -{ - if (delta > 0) { - compat_mod_inc_refcount; - } else if (delta < 0) { - compat_mod_dec_refcount; - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetFileOpOpen -- - * - * The virtual network's open file operation. Connects to (and - * potentially allocates) a hub, then opens a connection to - * this virtual network (i.e., plugs a cable into the virtual - * hub). - * - * Results: - * Errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetFileOpOpen(struct inode *inode, // IN: used to get hub number - struct file *filp) // IN: filp -{ - VNetPort *port; - VNetJack *hubJack; - int hubNum; - int retval; - - LOG(1, (KERN_DEBUG "/dev/vmnet: open called by PID %d (%s)\n", - current->pid, current->comm)); - - /* - * Sanity check the hub number. - */ - - hubNum = minor(inode->i_rdev); - if (hubNum < 0 || hubNum >= VNET_NUM_VNETS) { - return -ENODEV; - } - - /* - * Allocate port - */ - - retval = VNetUserIf_Create(&port); - if (retval) { - return -retval; - } - - /* - * Allocate and connect to hub. - */ - - hubJack = VNetHub_AllocVnet(hubNum); - if (!hubJack) { - VNetFree(&port->jack); - return -EBUSY; - } - - down(&vnetStructureSemaphore); - retval = VNetConnect(&port->jack, hubJack); - if (retval) { - up(&vnetStructureSemaphore); - VNetFree(&port->jack); - VNetFree(hubJack); - return retval; - } - - VNetAddPortToList(port); - up(&vnetStructureSemaphore); - - /* - * Store away jack in file pointer private field for later use. - */ - - filp->private_data = port; - - LOG(1, (KERN_DEBUG "/dev/vmnet: port on hub %d successfully opened\n", hubNum)); - - compat_mod_inc_refcount; - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetFileOpClose -- - * - * The virtual network's close file operation. Disconnects - * from the virtual hub (i.e., unplugs the cable). - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VNetFileOpClose(struct inode *inode, // IN: (unused) - struct file *filp) // IN: filp -{ - VNetPort *port = (VNetPort*)filp->private_data; - VNetJack *peer; - - if (!port) { - LOG(1, (KERN_DEBUG "/dev/vmnet: bad file pointer on close\n")); - return -EBADF; - } - - down(&vnetStructureSemaphore); - peer = VNetDisconnect(&port->jack); - VNetRemovePortFromList(port); - up(&vnetStructureSemaphore); - - VNetFree(&port->jack); - VNetFree(peer); - - compat_mod_dec_refcount; - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetFileOpRead -- - * - * The virtual network's read file operation. - * - * Results: - * On success the len of the packet received, - * else if no packet waiting and nonblocking 0, - * else -errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -ssize_t -VNetFileOpRead(struct file *filp, // IN: - char *buf, // OUT: - size_t count, // IN: - loff_t *ppos) // IN: (unused) -{ - VNetPort *port = (VNetPort*)filp->private_data; - - if (!port) { - LOG(1, (KERN_DEBUG "/dev/vmnet: bad file pointer on read\n")); - return -EBADF; - } - - if (!port->fileOpRead) { - return -EPERM; - } - - return port->fileOpRead(port, filp, buf, count); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetFileOpWrite -- - * - * The virtual network's write file operation. - * - * Results: - * On success the count of bytes written else errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -ssize_t -VNetFileOpWrite(struct file *filp, // IN: - const char *buf, // IN: - size_t count, // IN: - loff_t *ppos) // IN: (unused) -{ - VNetPort *port = (VNetPort*)filp->private_data; - - if (!port) { - LOG(1, (KERN_DEBUG "/dev/vmnet: bad file pointer on write\n")); - return -EBADF; - } - - if (!port->fileOpWrite) { - return -EPERM; - } - - return port->fileOpWrite(port, filp, buf, count); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetFileOpPoll -- - * - * The virtual network's file select operation. - * - * Results: - * Return 1 if success, else sleep and return 0. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static unsigned int -VNetFileOpPoll(struct file *filp, // IN: - poll_table *wait) // IN: -{ - VNetPort *port = (VNetPort*)filp->private_data; - - if (!port) { - LOG(1, (KERN_DEBUG "/dev/vmnet: bad file pointer on poll\n")); - return -EBADF; - } - - if (!port->fileOpPoll) { - return -EPERM; - } - - return port->fileOpPoll(port, filp, wait); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetFileOpIoctl -- - * - * The virtual network's ioctl file operation. This is used for - * setup of the connection. Currently supported commands are - * (taken from sockios.h): - * - * SIOCGIFADDR - get ethernet address - ioarg OUT: 6 bytes - * SIOCSIFADDR - set ethernet address - ioarg IN: 6 bytes -#ifdef VNET_API_DEPRECATED - * SIOCGIFFLAGS - get flags - ioarg OUT 4 bytes -#endif - * SIOCSIFFLAGS - set flags - ioarg IN: 4 bytes - * - * Private ioctl calls, taken from device-private ioctl space - * in sockios.h, and defined in includes/vm_oui.h: - * - * SIOCSLADRF (0x89F2) - set logical address filter (for - * filtering multicast packets) - ioarg IN: 8 bytes - * - * SIOCGBRSTATUS - get bridging status - ioarg OUT: 4 bytes - * SIOCSPEER - set bridge peer interface - ioarg IN: 8 bytes - * SIOCSPEER2 - set bridge peer interface - ioarg IN: 32 bytes - * SIOCSBIND - bind to a particular vnet/PVN - ioarg IN: VNet_Bind - * SIOCSFILTERRULES - set host filter rules - ioarg IN: VNet_Filter - * SIOCBRIDGE - (legacy see SIOCSPEER) - * SIOCSUSERLISTENER - set user listener - ioarg IN: VNet_SetUserListener - * - * Supported flags are (taken from if.h): - * - * IFF_UP - ready to receive packets - OFF by default - * IFF_BROADCAST - receive broadcast packets - OFF by default - * IFF_DEBUG - turn on debugging - OFF by default - * IFF_PROMISC - promiscuous mode - OFF by default - * IFF_MULTICAST - receive multicast packets - OFF by default - * IFF_ALLMULTI - receive all multicast packets - * (like IFF_PROMISC but with multicast) - OFF by default - * - * Results: - * On success 0 else errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetFileOpIoctl(struct inode *inode, // IN: - struct file *filp, // IN: - unsigned int iocmd, // IN: - unsigned long ioarg) // IN: -{ - VNetPort *port = (VNetPort*)filp->private_data; - VNetJack *hubJack; - VNetPort *new; - char name[32]; - int retval; - VNet_SetMacAddrIOCTL macAddr; - VNet_Bind newNetwork; -#ifdef CONFIG_NETFILTER - VNet_RuleHeader ruleHeader; -#endif - - if (!port) { - LOG(1, (KERN_DEBUG "/dev/vmnet: bad file pointer on ioctl\n")); - return -EBADF; - } - - // sprintf(vnetHub[hubNum]->devName, "vmnet%d", hubNum); - - switch (iocmd) { -#ifdef VNET_API_DEPRECATED - case SIOCSIFBR: -#endif - case SIOCSPEER: - case SIOCBRIDGE: - if (copy_from_user(name, (void *)ioarg, 8)) { - return -EFAULT; - } - name[8] = '\0'; /* allow 8-char unterminated string */ - - if (!capable(CAP_NET_RAW)) { - return -EACCES; - } - retval = VNetBridge_Create(name, port->jack.peer, &new); - - return retval ? retval : VNetSwitchToDifferentPeer(&port->jack, - &new->jack, TRUE, - filp, port, new); - break; - case SIOCSPEER2: - if (copy_from_user(name, (void *)ioarg, sizeof name)) { - return -EFAULT; - } - NULL_TERMINATE_STRING(name); - - if (!capable(CAP_NET_RAW)) { - return -EACCES; - } - retval = VNetBridge_Create(name, port->jack.peer, &new); - - return retval ? retval : VNetSwitchToDifferentPeer(&port->jack, - &new->jack, TRUE, - filp, port, new); - break; - case SIOCSUSERLISTENER: - { - VNet_SetUserListener param; - - /* copy parameters */ - if (copy_from_user(¶m, (void *)ioarg, sizeof param)) { - return -EFAULT; - } - - /* check version */ - if (param.version != VNET_EVENT_VERSION) { - return -EINVAL; - } - - /* create user listener */ - retval = VNetUserListener_Create(param.classMask, port->jack.peer, &new); - if (retval != 0) { - return retval; - } - - /* replace current port with user listener */ - retval = VNetSwitchToDifferentPeer(&port->jack, &new->jack, TRUE, - filp, port, new); - } - break; - case SIOCPORT: - retval = VNetUserIf_Create(&new); - - return retval ? retval : VNetSwitchToDifferentPeer(&port->jack, &new->jack, - TRUE, filp, port, new); - break; - case SIOCNETIF: - if (copy_from_user(name, (void *)ioarg, 8)) { - return -EFAULT; - } - name[8] = '\0'; /* allow 8-char unterminated string */ - - retval = VNetNetIf_Create(name, &new, minor(inode->i_rdev)); - - return retval ? retval : VNetSwitchToDifferentPeer(&port->jack, &new->jack, - TRUE, filp, port, new); - break; - - case SIOCSBIND: - if (copy_from_user(&newNetwork, (void *)ioarg, sizeof newNetwork)) { - return -EFAULT; - } - if (newNetwork.version != VNET_BIND_VERSION) { - LOG(1, (KERN_NOTICE "/dev/vmnet: bad bind version: %u %u\n", - newNetwork.version, VNET_BIND_VERSION)); - return -EINVAL; - } - switch (newNetwork.bindType) { - case VNET_BIND_TO_VNET: - if (newNetwork.number < 0 || newNetwork.number >= VNET_NUM_VNETS) { - LOG(1, (KERN_NOTICE "/dev/vmnet: invalid bind to vnet %d\n", - newNetwork.number)); - return -EINVAL; - } - hubJack = VNetHub_AllocVnet(newNetwork.number); - break; - case VNET_BIND_TO_PVN: - { - uint8 id[VNET_PVN_ID_LEN] = {0}; - - if (memcmp(id, newNetwork.id, sizeof id < sizeof newNetwork.id ? - sizeof id : sizeof newNetwork.id) == 0) { - LOG(0, (KERN_NOTICE "/dev/vmnet: invalid bind to pvn\n")); - return -EINVAL; - } - memcpy(id, newNetwork.id, sizeof id < sizeof newNetwork.id ? - sizeof id : sizeof newNetwork.id); - hubJack = VNetHub_AllocPvn(id); - } - break; - default: - LOG(1, (KERN_NOTICE "/dev/vmnet: bad bind type: %u\n", - newNetwork.bindType)); - return -EINVAL; - } - - return VNetSwitchToDifferentPeer(&port->jack, hubJack, FALSE, NULL, NULL, NULL); - break; - - case SIOCSFILTERRULES: -#ifdef CONFIG_NETFILTER - if (copy_from_user(&ruleHeader, (void *)ioarg, sizeof ruleHeader)) { - return -EFAULT; - } - - /* Verify the call is for a known type */ - if (ruleHeader.type < VNET_FILTER_CMD_MIN || - ruleHeader.type > VNET_FILTER_CMD_MAX) { - LOG(1, (KERN_NOTICE "/dev/vmnet: invalid filter command\n")); - return -EINVAL; - } - - /* - * Version check should be done on a per-sub-command basis, but every - * sub-command is currently using 1, so for now we globally check for - * all sub-commands here in one place. - */ - if (ruleHeader.ver != 1) { - LOG(1, (KERN_NOTICE "/dev/vmnet: invalid version for " - "filter command\n")); - return -EINVAL; - } - - /* - * Dispatch the sub-command. - */ - return VNetFilter_HandleUserCall(&ruleHeader, ioarg); -#else - LOG(0, (KERN_NOTICE "/dev/vmnet: kernel doesn't support netfilter\n")); - return -EINVAL; - break; -#endif - -#ifdef VNET_API_DEPRECATED - case SIOCGIFBR: -#endif - case SIOCGBRSTATUS: - { - uint32 flags; - - read_lock(&vnetPeerLock); - flags = VNetIsBridged(&port->jack); - read_unlock(&vnetPeerLock); - - if (copy_to_user((void *)ioarg, &flags, sizeof flags)) { - return -EFAULT; - } - } - break; - - case SIOCGIFADDR: - if (copy_to_user((void *)ioarg, port->paddr, ETH_ALEN)) { - return -EFAULT; - } - break; - - case SIOCSIFADDR: - return -EFAULT; - - case SIOCSLADRF: - if (copy_from_user(port->ladrf, (void *)ioarg, sizeof port->ladrf)) { - return -EFAULT; - } - break; - -#ifdef VNET_API_DEPRECATED - /* We can't think of a good reason to use this ioctl. --gustav,hpreg */ - case SIOCGIFFLAGS: - if (copy_to_user((void *)ioarg, &port->flags, sizeof port->flags)) { - return -EFAULT; - } - break; - -#endif - case SIOCSIFFLAGS: - if (copy_from_user(&port->flags, (void *)ioarg, sizeof port->flags)) { - return -EFAULT; - } - port->flags = ((port->flags - & (IFF_UP|IFF_BROADCAST|IFF_DEBUG - |IFF_PROMISC|IFF_MULTICAST|IFF_ALLMULTI)) - | IFF_RUNNING); - if (port->fileOpIoctl) { - - /* - * Userif ports have some postprocessing when the IFF_UP flags is - * changed. - */ - port->fileOpIoctl(port, filp, iocmd, ioarg); - } - break; - - case SIOCSETMACADDR: - if (copy_from_user(&macAddr, (void *)ioarg, sizeof macAddr)) { - return -EFAULT; - } - - switch (macAddr.version) { - case 1: - if (macAddr.flags & VNET_SETMACADDRF_UNIQUE) { - if (VMX86_IS_VIRT_ADAPTER_MAC(macAddr.addr)) { - return -EBUSY; - } - return VNetSetMACUnique(port, macAddr.addr); - } - memcpy(port->paddr, macAddr.addr, ETH_ALEN); - break; - default: - return -EINVAL; - break; - } - break; - case SIOCGETAPIVERSION2: - { - uint32 verFromUser; - if (copy_from_user(&verFromUser, (void *)ioarg, sizeof verFromUser)) { - return -EFAULT; - } - /* Should we require verFromUser == VNET_API_VERSION? */ - } - /* fall thru */ - case SIOCGETAPIVERSION: - { - uint32 verToUser = VNET_API_VERSION; - if (copy_to_user((void*)ioarg, &verToUser, sizeof verToUser)) { - return -EFAULT; - } - } - break; - default: - if (!port->fileOpIoctl) { - return -ENOIOCTLCMD; - } - return port->fileOpIoctl(port, filp, iocmd, ioarg); - break; - } - - return 0; -} - - -#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL) -/* - *---------------------------------------------------------------------- - * - * VNetFileOpUnlockedIoctl -- - * - * Wrapper around VNetFileOpIoctl. See VNetFileOpIoctl for - * supported arguments. Called without big kernel lock held. - * - * Results: - * On success 0 else errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static long -VNetFileOpUnlockedIoctl(struct file *filp, // IN: - unsigned int iocmd, // IN: - unsigned long ioarg) // IN: -{ - struct inode *inode = NULL; - long err; - - if (filp && filp->f_dentry) { - inode = filp->f_dentry->d_inode; - } - lock_kernel(); - err = VNetFileOpIoctl(inode, filp, iocmd, ioarg); - unlock_kernel(); - return err; -} -#endif - - -/* - *---------------------------------------------------------------------- - * - * VNetSwitchToDifferentPeer -- - * - * This function is used to disconnect from a one peer and - * connect to another peer. If the connect to the new peer - * fails (e.g., if the connect would create a cycle), then - * the function will reconnect back to the original peer. - * The function will deallocate the old or the new peer, - * whichever is the one that has been disconnected. - * - * optional behavior: - * - * For the case where the function was successful in switching - * to the new peer, the caller can optionally provide a 'filp' - * (private_data is set to the new port), and the caller - * can also provide one each of a port to be added to - * and/or removed from the port list. If the caller provides - * ports to add/remove from the list, then - * connectNewToPeerOfJack should be set to TRUE (otherwise - * inconsistencies in the port list are likely to occur). - * - * Results: - * errno (0 on success). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VNetSwitchToDifferentPeer(VNetJack *jack, // IN: jack whose peer is to be changed - VNetJack *newPeer, // IN: the new peer to try to switch to - Bool connectNewToPeerOfJack, // IN: connect new to peer of 'jack' or to 'jack' itself? - struct file *filp, // IN: (optional) set filp to 'newpeerPort' on success - VNetPort *jackPort, // IN: (optional) port to remove from list on success - VNetPort *newPeerPort) // IN: (optional) port to add to list on success -{ - VNetJack *oldPeer; - int retval; - - if (newPeer == NULL) { - LOG(0, (KERN_NOTICE "/dev/vmnet: failed to alloc new peer\n")); - return -EINVAL; - } - - /* - * OK this is tricky. Try and connect the new peer while saving - * enough information so that we can reconnect back to the - * old peer if a cycle is detected. - */ - - down(&vnetStructureSemaphore); - - /* Disconnect from the old peer */ - oldPeer = VNetDisconnect(jack); - - /* Try to connect to the new peer */ - if (connectNewToPeerOfJack) { - retval = VNetConnect(oldPeer, newPeer); - } else { - retval = VNetConnect(jack, newPeer); - } - if (retval) { - - /* Connect failed, so reconnect back to old peer */ - int retval2 = VNetConnect(jack, oldPeer); - up(&vnetStructureSemaphore); - - /* Free the new peer */ - VNetFree(newPeer); - if (retval2) { - // assert xxx redo this - LOG(1, (KERN_NOTICE "/dev/vmnet: cycle on connect failure\n")); - return -EBADF; - } - return retval; - } - - if (newPeerPort != NULL) { - VNetAddPortToList(newPeerPort); - } - if (filp != NULL) { - filp->private_data = newPeerPort; - } - if (jackPort != NULL) { - VNetRemovePortFromList(jackPort); - } - - up(&vnetStructureSemaphore); - - /* Connected to new peer, so dealloc the old peer */ - if (connectNewToPeerOfJack) { - VNetFree(jack); - } else { - VNetFree(oldPeer); - } - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetMulticastFilter -- - * - * Utility function that filters multicast packets according - * to a 64-bit logical address filter (like the one on the - * lance chipset). AllMultiFilter lets all packets through. - * - * We generate a hash value from the destination MAC address - * and see if it's in our filter. Broadcast packets have - * already OK'd by PacketMatch, so we don't have to worry - * about that. - * - * (This is in the green AMD "Ethernet Controllers" book, - * page 1-53.) - * - * Results: - * TRUE if packet is in filter, FALSE if not. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ - -static INLINE_SINGLE_CALLER Bool -VNetMulticastFilter(const uint8 *destAddr, // IN: multicast MAC - const uint8 *ladrf) // IN: multicast filter -{ - uint16 hashcode; - int32 crc; - int32 poly = CRC_POLYNOMIAL_BE; - int j; - int bit; - int byte; - - crc = 0xffffffff; /* init CRC for each address */ - for (byte = 0; byte < ETH_ALEN; byte++) { /* for each address byte */ - /* process each address bit */ - for (bit = *destAddr++, j = 0; - j < VNET_LADRF_LEN; - j++, bit >>= 1) { - crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0); - } - } - hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */ - for (j = 0; j < 5; j++) { /* ... in reverse order. */ - hashcode = (hashcode << 1) | ((crc>>=1) & 1); - } - - byte = hashcode >> 3; /* bit[3-5] -> byte in filter */ - bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ - if (ladrf[byte] & bit) { - return TRUE; - } else { - return FALSE; - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetPacketMatch -- - * - * Determines whether the packet should be given to the interface. - * - * Results: - * TRUE if the pasket is OK for this interface, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -VNetPacketMatch(const uint8 *destAddr, // IN: destination MAC - const uint8 *ifAddr, // IN: MAC of interface - const uint8 *ladrf, // IN: multicast filter - uint32 flags) // IN: filter flags -{ - /* - * Return TRUE if promiscuous requested, or unicast destined - * for interface, or broadcast (and broadcast requested), or - * if multicast (and all multicast, or this specific - * multicast MAC, was requested). - */ - - return ((flags & IFF_PROMISC) || MAC_EQ(destAddr, ifAddr) || - ((flags & IFF_BROADCAST) && MAC_EQ(destAddr, broadcast)) || - ((destAddr[0] & 0x1) && (flags & IFF_ALLMULTI || - (flags & IFF_MULTICAST && - VNetMulticastFilter(destAddr, ladrf))))); -} - - -/* - *---------------------------------------------------------------------- - * - * VNet_MakeMACAddress -- - * - * Generate a unique MAC address and assign it to the given port. - * The address will be in the range: - * - * VMX86_STATIC_OUI:e0:00:00 - VMX86_STATIC_OUI:ff:ff:ff - * - * Results: - * errno. - * - * Side effects: - * The address is changed. - * - *---------------------------------------------------------------------- - */ - -int -VNet_MakeMACAddress(VNetPort *port) // IN: port -{ - uint8 paddr[ETH_ALEN] = {0}; - int conflict; - int maxTries = 1000; - - do { - VMX86_GENERATE_RANDOM_MAC(paddr); - - conflict = VNetSetMACUnique(port, paddr); - - /* - * We don't have to check for conflicts with the virtual - * host adapters since they are in the range - * c0:00:00-c0:00:FF. - */ - - } while (maxTries-- > 0 && conflict); - - return conflict; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetConnect -- - * - * Connect 2 jacks. - * vnetStructureSemaphore must be held. - * - * Results: - * errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetConnect(VNetJack *jack1, // IN: jack - VNetJack *jack2) // IN: jack -{ - static int vnetGeneration = 0; - Bool foundCycle; - unsigned long flags; - - vnetGeneration++; - - foundCycle = VNetCycleDetect(jack1, vnetGeneration); - if (foundCycle) { - VNetFreeInterfaceList(); - return -EDEADLK; - } - - foundCycle = VNetCycleDetect(jack2, vnetGeneration); - if (foundCycle) { - VNetFreeInterfaceList(); - return -EDEADLK; - } - VNetFreeInterfaceList(); - - /* - * Synchronize with peer readers - */ - - write_lock_irqsave(&vnetPeerLock, flags); - jack1->peer = jack2; - jack2->peer = jack1; - write_unlock_irqrestore(&vnetPeerLock, flags); - - if (jack2->numPorts) { - VNetPortsChanged(jack1); - } - - if (jack1->numPorts) { - VNetPortsChanged(jack2); - } - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetDisconnect -- - * - * Disconnect 2 jacks. - * vnetStructureSemaphore must be held. - * - * Results: - * Return the peer jack (returns NULL on error, or if no peer) - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VNetJack * -VNetDisconnect(VNetJack *jack) // IN: jack -{ - VNetJack *peer; - unsigned long flags; - - write_lock_irqsave(&vnetPeerLock, flags); - peer = jack->peer; - if (!peer) { - write_unlock_irqrestore(&vnetPeerLock, flags); - return NULL; - } - jack->peer = NULL; - peer->peer = NULL; - write_unlock_irqrestore(&vnetPeerLock, flags); - - if (peer->numPorts) { - VNetPortsChanged(jack); - } - - if (jack->numPorts) { - VNetPortsChanged(peer); - } - - return peer; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetCycleDetectIf -- - * - * Perform the cycle detect alogorithm for this generation on a - * specific interface. This could be a bridged interface, host - * interface or both. - * vnetStructureSemaphore must be held. - * - * Results: - * TRUE if a cycle was detected, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -VNetCycleDetectIf(const char *name, // IN: - int generation) // IN: -{ - VNetInterface *p; - - for (p = vnetInterfaces; p != NULL; p = p->next) { - if (!strcmp(name, p->name)) { - if (p->myGeneration == generation) { - return TRUE; - } else { - p->myGeneration = generation; - return FALSE; - } - } - } - - p = kmalloc(sizeof *p, GFP_USER); - if (!p) { - // assert - return TRUE; - } - - memcpy(p->name, name, sizeof p->name); - NULL_TERMINATE_STRING(p->name); - p->myGeneration = generation; - p->next = vnetInterfaces; - vnetInterfaces = p; - - return FALSE; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetFreeInterfaceList -- - * - * Free's the linked list that may have been constructed - * during a recent run on the cycle detect alogorithm. - * vnetStructureSemaphore must be held. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VNetFreeInterfaceList() -{ - while (vnetInterfaces != NULL) { - VNetInterface *next = vnetInterfaces->next; - kfree(vnetInterfaces); - vnetInterfaces = next; - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetSend -- - * - * Send a packet through this jack. Note, the packet goes to the - * jacks peer. - * - * Results: - * None. - * - * Side effects: - * The skb is no longer owned by us. - * - *---------------------------------------------------------------------- - */ - -void -VNetSend(const VNetJack *jack, // IN: jack - struct sk_buff *skb) // IN: packet -{ - read_lock(&vnetPeerLock); - if (jack && jack->peer && jack->peer->rcv) { - jack->peer->rcv(jack->peer, skb); - } else { - dev_kfree_skb(skb); - } - read_unlock(&vnetPeerLock); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetSetMACUnique -- - * - * Verify that MAC address is not used by other ports. - * Function grabs semaphore, so caller shouldn't hold any - * locks. - * - * Results: - * - * 0 if address is unique. Port's paddr is updated. - * -EBUSY if address is already in use. Port's paddr is unchanged. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetSetMACUnique(VNetPort *port, // IN: - const uint8 mac[ETH_ALEN]) // IN: -{ - VNetPort *p; - - down(&vnetStructureSemaphore); - for (p = vnetAllPorts; p != NULL; p = p->next) { - if (p != port && MAC_EQ(p->paddr, mac)) { - up(&vnetStructureSemaphore); - return -EBUSY; - } - } - memcpy(port->paddr, mac, ETH_ALEN); - up(&vnetStructureSemaphore); - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetPrintJack -- - * - * Print info about the jack to a buffer. - * - * Results: - * Length of the write. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetPrintJack(const VNetJack *jack, // IN: jack - char *buf) // OUT: info about jack -{ - int len = 0; - - read_lock(&vnetPeerLock); - if (!jack->peer) { - len += sprintf(buf+len, "connected not "); - } else { - len += sprintf(buf+len, "connected %s ", jack->peer->name); - } - read_unlock(&vnetPeerLock); - - return len; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetPrintPort -- - * - * Print info about the port to a buffer. - * - * Results: - * Length of the write. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetPrintPort(const VNetPort *port, // IN: port - char *buf) // OUT: info about port -{ - int len = 0; - - len += VNetPrintJack(&port->jack, buf+len); - - len += sprintf(buf+len, "mac %02x:%02x:%02x:%02x:%02x:%02x ", - port->paddr[0], port->paddr[1], port->paddr[2], - port->paddr[3], port->paddr[4], port->paddr[5]); - - len += sprintf(buf+len, "ladrf %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ", - port->ladrf[0], port->ladrf[1], port->ladrf[2], - port->ladrf[3], port->ladrf[4], port->ladrf[5], - port->ladrf[6], port->ladrf[7]); - - len += sprintf(buf+len, "flags IFF_RUNNING"); - - if (port->flags & IFF_UP) { - len += sprintf(buf+len, ",IFF_UP"); - } - - if (port->flags & IFF_BROADCAST) { - len += sprintf(buf+len, ",IFF_BROADCAST"); - } - - if (port->flags & IFF_DEBUG) { - len += sprintf(buf+len, ",IFF_DEBUG"); - } - - if (port->flags & IFF_PROMISC) { - len += sprintf(buf+len, ",IFF_PROMISC"); - } - - if (port->flags & IFF_MULTICAST) { - len += sprintf(buf+len, ",IFF_MULTICAST"); - } - - if (port->flags & IFF_ALLMULTI) { - len += sprintf(buf+len, ",IFF_ALLMULTI"); - } - - len += sprintf(buf+len, " "); - - return len; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetSnprintf -- - * - * Wrapper to account for lack of snprintf() in older kernels, - * where 'old' appears to be older than 2.4.8. - * - * Results: - * Refer to docs for snprintf() and / or sprintf(). This - * version unconditionally adds NULL termination to the end - * of the string. - * - * Side effects: - * Might overrun buffer on older kernels. - * - *---------------------------------------------------------------------- - */ - -int -VNetSnprintf(char *str, // OUT: resulting string - size_t size, // IN: length of 'result' in bytes - const char *format, // IN: format string - ...) // IN: (optional) -{ - int length; - va_list args; - - va_start(args, format); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) - length = vsnprintf(str, size, format, args); -#else - length = vsprintf(str, format, args); -#endif - - va_end(args); - - str[size - 1] = '\0'; - - return length; -} - - -MODULE_AUTHOR("VMware, Inc."); -MODULE_DESCRIPTION("VMware Virtual Networking Driver."); -MODULE_LICENSE("GPL v2"); diff -Nrup source/vmnet-only/driver-config.h source.edited/vmnet-only/driver-config.h --- source/vmnet-only/driver-config.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/driver-config.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,78 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -/* - * Sets the proper defines from the Linux header files - * - * This file must be included before the inclusion of any kernel header file, - * with the exception of linux/autoconf.h and linux/version.h --hpreg - */ - -#ifndef __VMX_CONFIG_H__ -#define __VMX_CONFIG_H__ - -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMNIXMOD -#include "includeCheck.h" - -#include -#include "compat_version.h" - -/* - * We rely on Kernel Module support. Check here. - */ -#ifndef CONFIG_MODULES -# error "No Module support in this kernel. Please configure with CONFIG_MODULES" -#endif - -/* - * 2.2 kernels still use __SMP__ (derived from CONFIG_SMP - * in the main Makefile), so we do it here. - */ - -#ifdef CONFIG_SMP -# define __SMP__ 1 -#endif - -#if defined(CONFIG_MODVERSIONS) && defined(KERNEL_2_1) -# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) -/* - * MODVERSIONS might be already defined when using kernel's Makefiles. - */ -# ifndef MODVERSIONS -# define MODVERSIONS -# endif -# include -# endif -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -/* - * Force the uintptr_t definition to come from linux/types.h instead of vm_basic_types.h. - */ -# include -# define _STDINT_H 1 -#endif - -#ifndef __KERNEL__ -# define __KERNEL__ -#endif - -#endif diff -Nrup source/vmnet-only/epoll.c source.edited/vmnet-only/epoll.c --- source/vmnet-only/epoll.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/epoll.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,36 +0,0 @@ -/********************************************************* - * Copyright (C) 2004 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 - * - *********************************************************/ - -/* - * Detect whether we have 'struct poll_wqueues' - * 2.6.x kernels always had this struct. Stock 2.4.x kernels - * never had it, but some distros backported epoll patch. - */ - -#include -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -#include - -void poll_test(void) { - struct poll_wqueues test; - - return poll_initwait(&test); -} -#endif diff -Nrup source/vmnet-only/filter.c source.edited/vmnet-only/filter.c --- source/vmnet-only/filter.c 2009-10-20 17:31:32.000000000 -0700 +++ source.edited/vmnet-only/filter.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1540 +0,0 @@ -/********************************************************* - * 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 -#include -#include -#include -#include -#include -#include "compat_skbuff.h" -#include -/* - * All this makes sense only if NETFILTER support is configured in our kernel. - */ -#ifdef CONFIG_NETFILTER - -#include -#include -#include - -#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, - compat_nf_hook_owner - .pf = PF_INET, - .hooknum = VMW_NF_INET_LOCAL_IN, - .priority = NF_IP_PRI_FILTER - 1, }, - { .hook = VNetFilterHookFn, - compat_nf_hook_owner - .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 DECLARE_MUTEX(filterIoctlSem); /* 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. - */ -spinlock_t activeRuleLock = SPIN_LOCK_UNLOCKED; - -/* - * 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 -VNetFilterHookFn(unsigned int hooknum, // IN: -#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. */ - transmit = (hooknum == VMW_NF_INET_POST_ROUTING); - - 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 = down_interruptible(&filterIoctlSem); - 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: - up(&filterIoctlSem); - 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 diff -Nrup source/vmnet-only/geninclude.c source.edited/vmnet-only/geninclude.c --- source/vmnet-only/geninclude.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/geninclude.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,40 +0,0 @@ -/********************************************************* - * Copyright (C) 2003 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 - -#ifdef CONFIG_X86_VOYAGER -APATH/mach-voyager -#endif -#ifdef CONFIG_X86_VISWS -APATH/mach-visws -#endif -#ifdef CONFIG_X86_NUMAQ -APATH/mach-numaq -#endif -#ifdef CONFIG_X86_BIGSMP -APATH/mach-bigsmp -#endif -#ifdef CONFIG_X86_SUMMIT -APATH/mach-summit -#endif -#ifdef CONFIG_X86_GENERICARCH -APATH/mach-generic -#endif -APATH/mach-default - diff -Nrup source/vmnet-only/hub.c source.edited/vmnet-only/hub.c --- source/vmnet-only/hub.c 2009-10-20 17:31:32.000000000 -0700 +++ source.edited/vmnet-only/hub.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,741 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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" - -#define EXPORT_SYMTAB - -#include -#include -#include -#ifdef KERNEL_2_2 -# include -#else -# include -#endif -#include - -#include -#include -#include -#include "compat_skbuff.h" -#include -#include -#include "compat_sock.h" - -#define __KERNEL_SYSCALLS__ -#include - -#include -#include - -#include "vnetInt.h" - -#define HUB_TYPE_VNET 0x1 -#define HUB_TYPE_PVN 0x2 - -typedef struct VNetHubStats { - unsigned tx; -} VNetHubStats; - -typedef struct VNetHub { - uint32 hubType; // HUB_TYPE_xxx - union { - int vnetNum; // vnet number (HUB_TYPE_VNET) - uint8 pvnID[VNET_PVN_ID_LEN]; // PVN ID (HUB_TYPE_PVN) - } id; - Bool used[NUM_JACKS_PER_HUB]; // tracks which jacks in use - VNetJack jack[NUM_JACKS_PER_HUB]; // jacks for the hub - VNetHubStats stats[NUM_JACKS_PER_HUB]; // stats for the jacks - int totalPorts; // num devices reachable from hub - int myGeneration; // used for cycle detection - struct VNetHub *next; // next hub in linked list - VNetEvent_Mechanism *eventMechanism; // event notification mechanism -} VNetHub; - -static VNetJack *VNetHubAlloc(Bool allocPvn, int hubNum, - uint8 id[VNET_PVN_ID_LEN]); -static void VNetHubFree(VNetJack *this); -static void VNetHubReceive(VNetJack *this, struct sk_buff *skb); -static Bool VNetHubCycleDetect(VNetJack *this, int generation); -static void VNetHubPortsChanged(VNetJack *this); -static int VNetHubIsBridged(VNetJack *this); -static int VNetHubProcRead(char *page, char **start, off_t off, - int count, int *eof, void *data); - -static VNetHub *vnetHub = NULL; - -/* - * UP spin_lock_irqsave() doesn't actually use the lock variable, - * so we use __attribute__((unused)) to quiet the compiler. - */ - -static spinlock_t vnetHubLock __attribute__((unused)) = SPIN_LOCK_UNLOCKED; - - -/* - *---------------------------------------------------------------------- - * - * VNetHubFindHubByNum -- - * - * Find a hub for a specified vnet number. - * Caller must be holding vnetHubLock. - * - * Results: - * Pointer to hub, or NULL if not found. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static VNetHub * -VNetHubFindHubByNum(int hubNum) // IN: vnet number to find -{ - VNetHub *currHub = vnetHub; - while (currHub && (currHub->hubType != HUB_TYPE_VNET || - currHub->id.vnetNum != hubNum)) { - currHub = currHub->next; - } - return currHub; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetHubFindHubByID -- - * - * Find a hub for a specified PVN id. - * Caller must be holding vnetHubLock. - * - * Results: - * Pointer to hub, or NULL if not found. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static VNetHub * -VNetHubFindHubByID(uint8 idNum[VNET_PVN_ID_LEN]) // IN: PVN id to find -{ - VNetHub *currHub = vnetHub; - while (currHub && (currHub->hubType != HUB_TYPE_PVN || - memcmp(idNum, currHub->id.pvnID, sizeof idNum))) { - currHub = currHub->next; - } - return currHub; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetHubAddHubToList -- - * - * Add hub to list of known hubs. - * Caller must be holding vnetHubLock. - * - * Results: - * - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE void -VNetHubAddHubToList(VNetHub *hub) // IN: hub to add to list -{ - hub->next = vnetHub; - vnetHub = hub; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetHubRemoveHubFromList -- - * - * Remove hub from list of known hubs. - * Caller must be holding vnetHubLock. - * - * Results: - * - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE void -VNetHubRemoveHubFromList(VNetHub *hub) // IN: hub to remove from list -{ - VNetHub **h; - - for (h = &vnetHub; *h; h = &(*h)->next) { - if (*h == hub) { - *h = hub->next; - break; - } - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetHub_AllocVnet -- - * - * Allocate a jack on a hub for a vnet. - * - * Results: - * The jack to connect to, NULL on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VNetJack * -VNetHub_AllocVnet(int hubNum) // IN: the vnet number to alloc on -{ - return VNetHubAlloc(FALSE, hubNum, NULL); -} - -/* - *---------------------------------------------------------------------- - * - * VNetHub_AllocPvn -- - * - * Allocate a jack on a hub for a PVN. - * - * Results: - * The jack to connect to, NULL on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VNetJack * -VNetHub_AllocPvn(uint8 id[]) // IN: the PVN ID to alloc on -{ - return VNetHubAlloc(TRUE, -1, id); -} - -/* - *---------------------------------------------------------------------- - * - * VNetHubAlloc -- - * - * Allocate a jack on this hub. - * - * Results: - * The jack to connect to, NULL on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VNetJack * -VNetHubAlloc(Bool allocPvn, // IN: TRUE for PVN, FALSE for vnet - int hubNum, // IN: vnet # to use (-1 if allocPvn == TRUE) - uint8 id[]) // IN: PVN ID to use (NULL if allocPvn == FALSE) -{ - VNetHub *hub; - VNetJack *jack; - int i; - int retval; - unsigned long flags; - static uint32 pvnInstance = 0; - - spin_lock_irqsave(&vnetHubLock, flags); - - hub = allocPvn ? VNetHubFindHubByID(id) : VNetHubFindHubByNum(hubNum); - if (!hub) { - spin_unlock_irqrestore(&vnetHubLock, flags); - LOG(1, (KERN_DEBUG "/dev/vmnet: hub %d does not exist, allocating memory.\n", - hubNum)); - - hub = kmalloc(sizeof *hub, GFP_KERNEL); - if (hub == NULL) { - LOG(1, (KERN_DEBUG "/dev/vmnet: no memory to allocate hub %d\n", hubNum)); - return NULL; - } - for (i = 0; i < NUM_JACKS_PER_HUB; i++) { - jack = &hub->jack[i]; - - /* - * The private field indicates if this jack is allocated. - * NULL means free, otherwise the jack is allocated and it - * should point back to the hub. - */ - - jack->peer = NULL; - jack->numPorts = 0; - if (allocPvn) { - VNetSnprintf(jack->name, sizeof jack->name, "pvn%d.%d", - pvnInstance, i); - } else { - VNetSnprintf(jack->name, sizeof jack->name, "hub%d.%d", hubNum, i); - } - jack->private = NULL; - jack->index = i; - jack->procEntry = NULL; - jack->free = VNetHubFree; - jack->rcv = VNetHubReceive; - jack->cycleDetect = VNetHubCycleDetect; - jack->portsChanged = VNetHubPortsChanged; - jack->isBridged = VNetHubIsBridged; - - memset(&hub->stats[i], 0, sizeof hub->stats[i]); - - hub->used[i] = FALSE; - } - - if (allocPvn) { - hub->hubType = HUB_TYPE_PVN; - memcpy(hub->id.pvnID, id, sizeof id); - ++pvnInstance; - } else { - hub->hubType = HUB_TYPE_VNET; - hub->id.vnetNum = hubNum; - } - hub->next = NULL; - hub->totalPorts = 0; - hub->myGeneration = 0; - - /* create event mechanism */ - retval = VNetEvent_CreateMechanism(&hub->eventMechanism); - if (retval != 0) { - LOG(1, (KERN_DEBUG "can't create event mechanism (%d)\n", retval)); - kfree(hub); - return NULL; - } - - spin_lock_irqsave(&vnetHubLock, flags); - if (allocPvn ? VNetHubFindHubByID(id) : VNetHubFindHubByNum(hubNum)) { - /* - * Someone else just allocated this hub. Free our structure - * and use already present hub. - */ - - kfree(hub); - hub = allocPvn ? VNetHubFindHubByID(id) : VNetHubFindHubByNum(hubNum); - } else { - VNetHubAddHubToList(hub); - } - } - - for (i = 0; i < NUM_JACKS_PER_HUB; i++) { - jack = &hub->jack[i]; - if (!hub->used[i]) { - hub->used[i] = TRUE; - spin_unlock_irqrestore(&vnetHubLock, flags); - - /* - * Make proc entry for this jack. - */ - - retval = VNetProc_MakeEntry(jack->name, S_IFREG, &jack->procEntry); - if (retval) { - if (retval == -ENXIO) { - jack->procEntry = NULL; - } else { - hub->used[i] = FALSE; - return NULL; - } - } else { - jack->procEntry->read_proc = VNetHubProcRead; - jack->procEntry->data = jack; - } - - /* - * OK, now allocate this jack. - */ - - jack->numPorts = hub->totalPorts; - jack->peer = NULL; - jack->private = hub; - - return jack; - } - } - spin_unlock_irqrestore(&vnetHubLock, flags); - - return NULL; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetHubFree -- - * - * Free the jack on this hub. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VNetHubFree(VNetJack *this) -{ - VNetHub *hub = (VNetHub*)this->private; - int i = 0; - int retval; - unsigned long flags; - - if (this != &hub->jack[this->index]) { - LOG(1, (KERN_DEBUG "/dev/vmnet: bad free of hub jack\n")); - return; - } - - if (this->procEntry) { - VNetProc_RemoveEntry(this->procEntry); - this->procEntry = NULL; - } - - this->private = NULL; - - spin_lock_irqsave(&vnetHubLock, flags); - - hub->used[this->index] = FALSE; - - for (i = 0; i < NUM_JACKS_PER_HUB; i++) { - if (hub->used[i]) { - spin_unlock_irqrestore(&vnetHubLock, flags); - return; - } - } - VNetHubRemoveHubFromList(hub); - - spin_unlock_irqrestore(&vnetHubLock, flags); - - /* destroy event mechanism */ - retval = VNetEvent_DestroyMechanism(hub->eventMechanism); - if (retval != 0) { - LOG(1, (KERN_DEBUG "can't destroy event mechanism (%d)\n", retval)); - } - hub->eventMechanism = NULL; - - kfree(hub); -} - - -/* - *----------------------------------------------------------------------------- - * - * VNetHub_CreateSender -- - * - * Creates an event sender for the mechanism of this hub. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VNetHub_CreateSender(VNetJack *jack, // IN: a jack to a hub - VNetEvent_Sender **s) // OUT: the new sender -{ - if (jack != NULL && jack->private != NULL) { - VNetHub *hub = (VNetHub*)jack->private; - return VNetEvent_CreateSender(hub->eventMechanism, s); - } else { - return -EINVAL; - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VNetHub_CreateListener -- - * - * Creates an event listener for the mechanism of this hub. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VNetHub_CreateListener(VNetJack *jack, // IN: a jack to a hub - VNetEvent_Handler h, // IN: a handler - void *data, // IN: the handler's data - uint32 classMask, // IN: a class mask - VNetEvent_Listener **l) // OUT: the new listener -{ - if (jack != NULL && jack->private != NULL) { - VNetHub *hub = (VNetHub*)jack->private; - return VNetEvent_CreateListener(hub->eventMechanism, h, data, classMask, - l); - } else { - return -EINVAL; - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetHubReceive -- - * - * This jack is receiving a packet. Take appropriate action. - * - * Results: - * None. - * - * Side effects: - * Frees skb. - * - *---------------------------------------------------------------------- - */ - -void -VNetHubReceive(VNetJack *this, // IN: - struct sk_buff *skb) // IN: -{ - VNetHub *hub = (VNetHub*)this->private; - VNetJack *jack; - struct sk_buff *clone; - int i; - - hub->stats[this->index].tx++; - - for (i = 0; i < NUM_JACKS_PER_HUB; i++) { - jack = &hub->jack[i]; - if (jack->private && /* allocated */ - jack->peer && /* and connected */ - jack->peer->rcv && /* and has a receiver */ - (jack != this)) { /* and not a loop */ - clone = skb_clone(skb, GFP_ATOMIC); - if (clone) { - VNetSend(jack, clone); - } - } - } - - dev_kfree_skb(skb); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetHubCycleDetect -- - * - * Cycle detection algorithm. - * - * Results: - * TRUE if a cycle was detected, FALSE otherwise. - * - * Side effects: - * Will generate other cycleDetect events to other jacks on hub. - * - *---------------------------------------------------------------------- - */ - -Bool -VNetHubCycleDetect(VNetJack *this, - int generation) -{ - VNetHub *hub = (VNetHub *)this->private; - Bool foundCycle; - int i; - - if (hub->myGeneration == generation) { - return TRUE; - } - - hub->myGeneration = generation; - - for (i = 0; i < NUM_JACKS_PER_HUB; i++) { - if (hub->jack[i].private && (i != this->index)) { - foundCycle = VNetCycleDetect(hub->jack[i].peer, generation); - if (foundCycle) { - return TRUE; - } - } - } - - return FALSE; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetHubPortsChanged -- - * - * The number of ports connected to this jack has change, react - * accordingly. - * This function presumes that the caller has the semaphore. - * - * Results: - * None. - * - * Side effects: - * May generate other portsChanged events to other jacks on hub. - * - *---------------------------------------------------------------------- - */ - -void -VNetHubPortsChanged(VNetJack *this) -{ - VNetHub *hub = (VNetHub *)this->private; - int num, new; - int i; - - hub->totalPorts = 0; - - for (i=0; ijack[i].private) { - hub->totalPorts += VNetGetAttachedPorts(&hub->jack[i]); - } - } - - for (i=0; ijack[i].private) { - num = VNetGetAttachedPorts(&hub->jack[i]); - new = hub->totalPorts - num; - if (i == this->index) { - if (new != hub->jack[i].numPorts) { - /* basically an assert failure */ - LOG(0, (KERN_DEBUG "/dev/vmnet: numPorts mismatch.\n")); - } - } else { - hub->jack[i].numPorts = new; - VNetPortsChanged(hub->jack[i].peer); - } - } - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetHubIsBridged -- - * - * Check whether we are bridged. - * - * Results: - * 0 - not bridged - * 1 - we are bridged but the interface is not up - * 2 - we are bridged and the interface is up - * 3 - some bridges are down - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetHubIsBridged(VNetJack *this) -{ - VNetHub *hub = (VNetHub*)this->private; - int ret = 0; - int num; - int i; - - for (i=0; ijack[i].private) && (i != this->index)) { - num = VNetIsBridged(&hub->jack[i]); - ret = MAX(ret, num); - if ((num == 1) && (ret == 2)) { - ret = 3; - } - } - } - - return ret; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetHubProcRead -- - * - * Callback for read operation on hub entry in vnets proc fs. - * - * Results: - * Length of read operation. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetHubProcRead(char *page, // IN/OUT: buffer to write into - char **start, // OUT: 0 if file < 4k, else offset into page - off_t off, // IN: offset of read into the file - int count, // IN: maximum number of bytes to read - int *eof, // OUT: TRUE if there is nothing more to read - void *data) // IN: client data - not used -{ - VNetJack *jack = (VNetJack*)data; - VNetHub *hub; - int len = 0; - - if (!jack || !jack->private) { - return len; - } - hub = (VNetHub*)jack->private; - - len += VNetPrintJack(jack, page+len); - - len += sprintf(page+len, "tx %u ", hub->stats[jack->index].tx); - - len += sprintf(page+len, "\n"); - - *start = 0; - *eof = 1; - return len; -} diff -Nrup source/vmnet-only/include/compat_file.h source.edited/vmnet-only/include/compat_file.h --- source/vmnet-only/include/compat_file.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_file.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,56 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_FILE_H__ +# define __COMPAT_FILE_H__ + + +/* The fput() API is modified in 2.2.0 --hpreg */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) +# define compat_fput(_file) fput(_file) +#else +# define compat_fput(_file) fput(_file, (_file)->f_inode) +#endif + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) +# define compat_get_file(_file) get_file(_file) +# define compat_file_count(_file) file_count(_file) +#else +# define compat_get_file(_file) (_file)->f_count++ +# define compat_file_count(_file) (_file)->f_count +#endif + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 4) +# define compat_filp_close(_file, _files) filp_close(_file, _files) +#else +static inline void compat_filp_close(struct file* filp, fl_owner_t files) { + if (filp->f_op && filp->f_op->flush) { + filp->f_op->flush(filp); + } + /* + * Hopefully there are no locks to release on this filp. + * locks_remove_posix is not exported so we cannot use it... + */ + fput(filp); +} +#endif + + +#endif /* __COMPAT_FILE_H__ */ diff -Nrup source/vmnet-only/include/compat_highmem.h source.edited/vmnet-only/include/compat_highmem.h --- source/vmnet-only/include/compat_highmem.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_highmem.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,40 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_HIGHMEM_H__ +# define __COMPAT_HIGHMEM_H__ + + +/* + * BIGMEM (4 GB) support appeared in 2.3.16: kmap() API added + * HIGHMEM (4 GB + 64 GB) support appeared in 2.3.23: kmap() API modified + * In 2.3.27, kmap() API modified again + * + * --hpreg + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 27) +# include +#else +/* For page_address --hpreg */ +# include + +# define kmap(_page) (void*)page_address(_page) +# define kunmap(_page) +#endif + +#endif /* __COMPAT_HIGHMEM_H__ */ diff -Nrup source/vmnet-only/include/compat_kdev_t.h source.edited/vmnet-only/include/compat_kdev_t.h --- source/vmnet-only/include/compat_kdev_t.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_kdev_t.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,33 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_KDEV_T_H__ +# define __COMPAT_KDEV_T_H__ + + +#include + + +/* The major() API appeared in 2.5.2 --hpreg */ +#ifndef major +# define major MAJOR +# define minor MINOR +#endif + + +#endif /* __COMPAT_KDEV_T_H__ */ diff -Nrup source/vmnet-only/include/compat_mm.h source.edited/vmnet-only/include/compat_mm.h --- source/vmnet-only/include/compat_mm.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_mm.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,134 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_MM_H__ +# define __COMPAT_MM_H__ + + +#include + + +/* The get_page() API appeared in 2.3.7 --hpreg */ +/* Sometime during development it became function instead of macro --petr */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) && !defined(get_page) +# define get_page(_page) atomic_inc(&(_page)->count) +/* The __free_page() API is exported in 2.1.67 --hpreg */ +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 67) +# define put_page __free_page +# else +# include "compat_page.h" + +# define page_to_phys(_page) (page_to_pfn(_page) << PAGE_SHIFT) +# define put_page(_page) free_page(page_to_phys(_page)) +# endif +#endif + + +/* page_count() is 2.4.0 invention. Unfortunately unavailable in some RedHat + * kernels (for example 2.4.21-4-RHEL3). */ +/* It is function since 2.6.0, and hopefully RedHat will not play silly games + * with mm_inline.h again... */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(page_count) +# define page_count(page) atomic_read(&(page)->count) +#endif + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +# define compat_vm_pgoff(vma) ((vma)->vm_offset >> PAGE_SHIFT) + +static inline unsigned long compat_do_mmap_pgoff(struct file *file, unsigned long addr, + unsigned long len, unsigned long prot, + unsigned long flag, unsigned long pgoff) +{ + unsigned long ret = -EINVAL; + + if (pgoff < 1 << (32 - PAGE_SHIFT)) { + ret = do_mmap(file, addr, len, prot, flag, pgoff << PAGE_SHIFT); + } + return ret; +} + +#else +# define compat_vm_pgoff(vma) (vma)->vm_pgoff +# ifdef VMW_SKAS_MMAP +# define compat_do_mmap_pgoff(f, a, l, p, g, o) \ + do_mmap_pgoff(current->mm, f, a, l, p, g, o) +# else +# define compat_do_mmap_pgoff(f, a, l, p, g, o) \ + do_mmap_pgoff(f, a, l, p, g, o) +# endif +#endif + + +/* 2.2.x uses 0 instead of some define */ +#ifndef NOPAGE_SIGBUS +#define NOPAGE_SIGBUS (0) +#endif + + +/* 2.2.x does not have HIGHMEM support */ +#ifndef GFP_HIGHUSER +#define GFP_HIGHUSER (GFP_USER) +#endif + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + +#include "compat_page.h" + +static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order) +{ + unsigned long addr; + + addr = __get_free_pages(gfp_mask, order); + if (!addr) { + return NULL; + } + return virt_to_page(addr); +} +#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) + +#endif + +/* + * In 2.4.14, the logic behind the UnlockPage macro was moved to the + * unlock_page() function. Later (in 2.5.12), the UnlockPage macro was removed + * altogether, and nowadays everyone uses unlock_page(). + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 14) +#define compat_unlock_page(page) UnlockPage(page) +#else +#define compat_unlock_page(page) unlock_page(page) +#endif + +/* + * In 2.4.10, vmtruncate was changed from returning void to returning int. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) +#define compat_vmtruncate(inode, size) \ +({ \ + int result = 0; \ + vmtruncate(inode, size); \ + result; \ +}) +#else +#define compat_vmtruncate(inode, size) vmtruncate(inode, size) +#endif + + +#endif /* __COMPAT_MM_H__ */ diff -Nrup source/vmnet-only/include/compat_module.h source.edited/vmnet-only/include/compat_module.h --- source/vmnet-only/include/compat_module.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_module.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,72 @@ +/********************************************************* + * Copyright (C) 2007 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 + * + *********************************************************/ + +/* + * compat_module.h -- + */ + +#ifndef __COMPAT_MODULE_H__ +# define __COMPAT_MODULE_H__ + + +#include + + +/* + * Modules wishing to use the GPL license are required to include a + * MODULE_LICENSE definition in their module source as of 2.4.10. + */ +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(license) +#endif + +/* + * To make use of our own home-brewed MODULE_INFO, we need macros to + * concatenate two expressions to "__mod_", and and to convert an + * expression into a string. I'm sure we've got these in our codebase, + * but I'd rather not introduce such a dependency in a compat header. + */ +#ifndef __module_cat +#define __module_cat_1(a, b) __mod_ ## a ## b +#define __module_cat(a, b) __module_cat_1(a, b) +#endif + +#ifndef __stringify +#define __stringify_1(x) #x +#define __stringify(x) __stringify_1(x) +#endif + +/* + * MODULE_INFO was born in 2.5.69. + */ +#ifndef MODULE_INFO +#define MODULE_INFO(tag, info) \ +static const char __module_cat(tag, __LINE__)[] \ + __attribute__((section(".modinfo"), unused)) = __stringify(tag) "=" info +#endif + +/* + * MODULE_VERSION was born in 2.6.4. The earlier form appends a long "\0xxx" + * string to the module's version, but that was removed in 2.6.10, so we'll + * ignore it in our wrapper. + */ +#ifndef MODULE_VERSION +#define MODULE_VERSION(_version) MODULE_INFO(version, _version) +#endif + +#endif /* __COMPAT_MODULE_H__ */ diff -Nrup source/vmnet-only/include/compat_netdevice.h source.edited/vmnet-only/include/compat_netdevice.h --- source/vmnet-only/include/compat_netdevice.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_netdevice.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,287 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_NETDEVICE_H__ +# define __COMPAT_NETDEVICE_H__ + + +#include +#include +#include +#include + +/* + * The enet_statistics structure moved from linux/if_ether.h to + * linux/netdevice.h and is renamed net_device_stats in 2.1.25 --hpreg + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 1, 25) +# include + +# define net_device_stats enet_statistics +#endif + + +/* The netif_rx_ni() API appeared in 2.4.8 --hpreg */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 8) +# define netif_rx_ni netif_rx +#endif + + +/* The device struct was renamed net_device in 2.3.14 --hpreg */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14) +# define net_device device +#endif + + +/* + * SET_MODULE_OWNER appeared sometime during 2.3.x. It was setting + * dev->owner = THIS_MODULE until 2.5.70, where netdevice refcounting + * was completely changed. SET_MODULE_OWNER was nop for whole + * 2.6.x series, and finally disappeared in 2.6.24. + * + * MOD_xxx_USE_COUNT wrappers are here, as they must be mutually + * exclusive with SET_MODULE_OWNER call. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +# define COMPAT_SET_MODULE_OWNER(dev) do {} while (0) +# define COMPAT_NETDEV_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +# define COMPAT_NETDEV_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +# define COMPAT_SET_MODULE_OWNER(dev) SET_MODULE_OWNER(dev) +# else +# define COMPAT_SET_MODULE_OWNER(dev) do {} while (0) +# endif +# define COMPAT_NETDEV_MOD_INC_USE_COUNT do {} while (0) +# define COMPAT_NETDEV_MOD_DEC_USE_COUNT do {} while (0) +#endif + +/* + * SET_NETDEV_DEV appeared sometime during 2.5.x, and later was + * crossported to various 2.4.x kernels (as dummy macro). + */ +#ifdef SET_NETDEV_DEV +# define COMPAT_SET_NETDEV_DEV(dev, pdev) SET_NETDEV_DEV(dev, pdev) +#else +# define COMPAT_SET_NETDEV_DEV(dev, pdev) do {} while (0) +#endif + +/* + * Build alloc_etherdev API on the top of init_etherdev. For 2.0.x kernels + * we must provide dummy init method, otherwise register_netdev does + * nothing. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) +int +vmware_dummy_init(struct net_device *dev) +{ + return 0; +} +#endif + + +static inline struct net_device* +compat_alloc_etherdev(int priv_size) +{ + struct net_device* dev; + int size = sizeof *dev + priv_size; + + /* + * The name is dynamically allocated before 2.4.0, but + * is an embedded array in later kernels. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + size += sizeof("ethXXXXXXX"); +#endif + dev = kmalloc(size, GFP_KERNEL); + if (dev) { + memset(dev, 0, size); + if (priv_size) { + dev->priv = dev + 1; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + dev->name = (char *)(dev + 1) + priv_size; +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) + dev->init = vmware_dummy_init; +#endif + if (init_etherdev(dev, 0) != dev) { + kfree(dev); + dev = NULL; + } + } + return dev; +} +#else +#define compat_alloc_etherdev(sz) alloc_etherdev(sz) +#endif + + +/* + * alloc_netdev and free_netdev are there since 2.4.23. Their use is mandatory + * since 2.6.24. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23) +static inline struct net_device * +compat_alloc_netdev(int priv_size, + const char *mask, + void (*setup)(struct net_device *)) +{ + struct net_device *dev; + int netdev_size = sizeof *dev; + int alloc_size; + +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + netdev_size += IFNAMSIZ; +# endif + + alloc_size = netdev_size + priv_size; + dev = kmalloc(alloc_size, GFP_KERNEL); + if (dev) { + memset(dev, 0, alloc_size); + dev->priv = (char*)dev + netdev_size; + setup(dev); +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + dev->name = (char*)(dev + 1); +# endif + strcpy(dev->name, mask); + } + return dev; +} +# define compat_free_netdev(dev) kfree(dev) +#else +# define compat_alloc_netdev(size, mask, setup) alloc_netdev(size, mask, setup) +# define compat_free_netdev(dev) free_netdev(dev) +#endif + +/* netdev_priv() appeared in 2.6.3 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3) +# define compat_netdev_priv(netdev) (netdev)->priv +#else +# define compat_netdev_priv(netdev) netdev_priv(netdev) +#endif + +#if defined(NETDEV_TX_OK) +# define COMPAT_NETDEV_TX_OK NETDEV_TX_OK +# define COMPAT_NETDEV_TX_BUSY NETDEV_TX_BUSY +#else +# define COMPAT_NETDEV_TX_OK 0 +# define COMPAT_NETDEV_TX_BUSY 1 +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)) +static inline void +compat_netif_start_queue(struct device *dev) +{ + clear_bit(0, &dev->tbusy); +} + +static inline void +compat_netif_stop_queue(struct device *dev) +{ + set_bit(0, &dev->tbusy); +} + +static inline int +compat_netif_queue_stopped(struct device *dev) +{ + return test_bit(0, &dev->tbusy); +} + +static inline void +compat_netif_wake_queue(struct device *dev) +{ + clear_bit(0, &dev->tbusy); + mark_bh(NET_BH); +} + +static inline int +compat_netif_running(struct device *dev) +{ + return dev->start == 0; +} + +static inline int +compat_netif_carrier_ok(struct device *dev) +{ + return 1; +} + +static inline void +compat_netif_carrier_on(struct device *dev) +{ +} + +static inline void +compat_netif_carrier_off(struct device *dev) +{ +} + +#else +#define compat_netif_start_queue(dev) netif_start_queue(dev) +#define compat_netif_stop_queue(dev) netif_stop_queue(dev) +#define compat_netif_queue_stopped(dev) netif_queue_stopped(dev) +#define compat_netif_wake_queue(dev) netif_wake_queue(dev) +#define compat_netif_running(dev) netif_running(dev) +#define compat_netif_carrier_ok(dev) netif_carrier_ok(dev) +#define compat_netif_carrier_on(dev) netif_carrier_on(dev) +#define compat_netif_carrier_off(dev) netif_carrier_off(dev) +#endif + +/* unregister_netdevice_notifier was not safe prior to 2.6.17 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) && \ + !defined(ATOMIC_NOTIFIER_INIT) +/* pre 2.6.17 and not patched */ +static inline int compat_unregister_netdevice_notifier(struct notifier_block *nb) { + int err; + + rtnl_lock(); + err = unregister_netdevice_notifier(nb); + rtnl_unlock(); + return err; +} +#else +/* post 2.6.17 or patched */ +#define compat_unregister_netdevice_notifier(_nb) \ + unregister_netdevice_notifier(_nb); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +#define compat_netif_napi_add(dev, napi, poll, quota) \ + netif_napi_add(dev, napi, poll, quota) +#define compat_netif_rx_schedule(dev, napi) netif_rx_schedule(dev, napi) +#define compat_napi_enable(dev, napi) napi_enable(napi) +#define compat_napi_disable(dev, napi) napi_disable(napi) +#else +struct napi_struct { + int dummy; +}; + +#define compat_netif_napi_add(dev, napi, pollcb, quota) \ + do { \ + (dev)->poll = (pollcb); \ + (dev)->weight = (quota);\ + } while (0) +#define compat_netif_rx_schedule(dev, napi) netif_rx_schedule(dev) +#define compat_napi_enable(dev, napi) netif_poll_enable(dev) +#define compat_napi_disable(dev, napi) netif_poll_disable(dev) +#endif + +#endif /* __COMPAT_NETDEVICE_H__ */ diff -Nrup source/vmnet-only/include/compat_page.h source.edited/vmnet-only/include/compat_page.h --- source/vmnet-only/include/compat_page.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_page.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,75 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_PAGE_H__ +# define __COMPAT_PAGE_H__ + + +#include +#include + + +/* The pfn_to_page() API appeared in 2.5.14 and changed to function during 2.6.x */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pfn_to_page) +# define pfn_to_page(_pfn) (mem_map + (_pfn)) +# define page_to_pfn(_page) ((_page) - mem_map) +#endif + + +/* The virt_to_page() API appeared in 2.4.0 --hpreg */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) && !defined(virt_to_page) +# define virt_to_page(_kvAddr) pfn_to_page(MAP_NR(_kvAddr)) +#endif + + +/* + * The get_order() API appeared at some point in 2.3.x, and was then backported + * in 2.2.17-21mdk and in the stock 2.2.18. Because we can only detect its + * definition through makefile tricks, we provide our own for now --hpreg + */ +static inline int +compat_get_order(unsigned long size) // IN +{ + int order; + + size = (size - 1) >> (PAGE_SHIFT - 1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + + return order; +} + +/* + * BUG() was added to in 2.2.18, and was moved to + * in 2.5.58. + * + * XXX: Technically, this belongs in some sort of "compat_asm_page.h" file, but + * since our compatibility wrappers don't distinguish between and + * , putting it here is reasonable. + */ +#ifndef BUG +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + __asm__ __volatile__(".byte 0x0f,0x0b"); \ +} while (0) +#endif + +#endif /* __COMPAT_PAGE_H__ */ diff -Nrup source/vmnet-only/include/compat_pgtable.h source.edited/vmnet-only/include/compat_pgtable.h --- source/vmnet-only/include/compat_pgtable.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_pgtable.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,139 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_PGTABLE_H__ +# define __COMPAT_PGTABLE_H__ + + +#if defined(CONFIG_PARAVIRT) && defined(CONFIG_HIGHPTE) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) +# include +# undef paravirt_map_pt_hook +# define paravirt_map_pt_hook(type, va, pfn) do {} while (0) +# endif +#endif +#include + + +/* pte_page() API modified in 2.3.23 to return a struct page * --hpreg */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 23) +# define compat_pte_page pte_page +#else +# include "compat_page.h" + +# define compat_pte_page(_pte) virt_to_page(pte_page(_pte)) +#endif + + +/* Appeared in 2.5.5 --hpreg */ +#ifndef pte_offset_map +/* Appeared in SuSE 8.0's 2.4.18 --hpreg */ +# ifdef pte_offset_atomic +# define pte_offset_map pte_offset_atomic +# define pte_unmap pte_kunmap +# else +# define pte_offset_map pte_offset +# define pte_unmap(_pte) +# endif +#endif + + +/* Appeared in 2.5.74-mmX --petr */ +#ifndef pmd_offset_map +# define pmd_offset_map(pgd, address) pmd_offset(pgd, address) +# define pmd_unmap(pmd) +#endif + + +/* + * Appeared in 2.6.10-rc2-mm1. Older kernels did L4 page tables as + * part of pgd_offset, or they did not have L4 page tables at all. + * In 2.6.11 pml4 -> pgd -> pmd -> pte hierarchy was replaced by + * pgd -> pud -> pmd -> pte hierarchy. + */ +#ifdef PUD_MASK +# define compat_pgd_offset(mm, address) pgd_offset(mm, address) +# define compat_pgd_present(pgd) pgd_present(pgd) +# define compat_pud_offset(pgd, address) pud_offset(pgd, address) +# define compat_pud_present(pud) pud_present(pud) +typedef pgd_t compat_pgd_t; +typedef pud_t compat_pud_t; +#elif defined(pml4_offset) +# define compat_pgd_offset(mm, address) pml4_offset(mm, address) +# define compat_pgd_present(pml4) pml4_present(pml4) +# define compat_pud_offset(pml4, address) pml4_pgd_offset(pml4, address) +# define compat_pud_present(pgd) pgd_present(pgd) +typedef pml4_t compat_pgd_t; +typedef pgd_t compat_pud_t; +#else +# define compat_pgd_offset(mm, address) pgd_offset(mm, address) +# define compat_pgd_present(pgd) pgd_present(pgd) +# define compat_pud_offset(pgd, address) (pgd) +# define compat_pud_present(pud) (1) +typedef pgd_t compat_pgd_t; +typedef pgd_t compat_pud_t; +#endif + + +#define compat_pgd_offset_k(mm, address) pgd_offset_k(address) + + +/* Introduced somewhere in 2.6.0, + backported to some 2.4 RedHat kernels */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pte_pfn) +# define pte_pfn(pte) page_to_pfn(compat_pte_page(pte)) +#endif + + +/* A page_table_lock field is added to struct mm_struct in 2.3.10 --hpreg */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 10) +# define compat_get_page_table_lock(_mm) (&(_mm)->page_table_lock) +#else +# define compat_get_page_table_lock(_mm) NULL +#endif + + +/* + * Define VM_PAGE_KERNEL_EXEC for vmapping executable pages. + * + * On ia32 PAGE_KERNEL_EXEC was introduced in 2.6.8.1. Unfortunately it accesses + * __PAGE_KERNEL_EXEC which is not exported for modules. So we use + * __PAGE_KERNEL and just cut _PAGE_NX bit from it. + * + * For ia32 kernels before 2.6.8.1 we use PAGE_KERNEL directly, these kernels + * do not have noexec support. + * + * On x86-64 situation is a bit better: they always supported noexec, but + * before 2.6.8.1 flag was named PAGE_KERNEL_EXECUTABLE, and it was renamed + * to PAGE_KERNEL_EXEC when ia32 got noexec too (see above). + */ +#ifdef CONFIG_X86 +#ifdef _PAGE_NX +#define VM_PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL & ~_PAGE_NX) +#else +#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL +#endif +#else +#ifdef PAGE_KERNEL_EXECUTABLE +#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL_EXECUTABLE +#else +#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL_EXEC +#endif +#endif + + +#endif /* __COMPAT_PGTABLE_H__ */ diff -Nrup source/vmnet-only/include/compat_sched.h source.edited/vmnet-only/include/compat_sched.h --- source/vmnet-only/include/compat_sched.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_sched.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,291 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_SCHED_H__ +# define __COMPAT_SCHED_H__ + + +#include + +/* CLONE_KERNEL available in 2.5.35 and higher. */ +#ifndef CLONE_KERNEL +#define CLONE_KERNEL CLONE_FILES | CLONE_FS | CLONE_SIGHAND +#endif + +/* TASK_COMM_LEN become available in 2.6.11. */ +#ifndef TASK_COMM_LEN +#define TASK_COMM_LEN 16 +#endif + +/* The capable() API appeared in 2.1.92 --hpreg */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 1, 92) +# define capable(_capability) suser() +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) +# define need_resched() need_resched +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 3) +# define need_resched() (current->need_resched) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 3) +# define cond_resched() (need_resched() ? schedule() : (void) 0) +#endif + +/* Oh well. We need yield... Happy us! */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) +# ifdef __x86_64__ +# define compat_yield() there_is_nothing_like_yield() +# else +# include +# include + +/* + * Used by _syscallX macros. Note that this is global variable, so + * do not rely on its contents too much. As exit() is only function + * we use, and we never check return value from exit(), we have + * no problem... + */ +extern int errno; + +/* + * compat_exit() provides an access to the exit() function. It must + * be named compat_exit(), as exit() (with different signature) is + * provided by x86-64, arm and other (but not by i386). + */ +# define __NR_compat_yield __NR_sched_yield +static inline _syscall0(int, compat_yield); +# endif +#else +# define compat_yield() yield() +#endif + + +/* + * Since 2.5.34 there are two methods to enumerate tasks: + * for_each_process(p) { ... } which enumerates only tasks and + * do_each_thread(g,t) { ... } while_each_thread(g,t) which enumerates + * also threads even if they share same pid. + */ +#ifndef for_each_process +# define for_each_process(p) for_each_task(p) +#endif + +#ifndef do_each_thread +# define do_each_thread(g, t) for_each_task(g) { t = g; do +# define while_each_thread(g, t) while (0) } +#endif + + +/* + * Lock for signal mask is moving target... + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 40) && defined(CLONE_PID) +/* 2.4.x without NPTL patches or early 2.5.x */ +#define compat_sigmask_lock sigmask_lock +#define compat_dequeue_signal_current(siginfo_ptr) \ + dequeue_signal(¤t->blocked, (siginfo_ptr)) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 60) && !defined(INIT_SIGHAND) +/* RedHat's 2.4.x with first version of NPTL support, or 2.5.40 to 2.5.59 */ +#define compat_sigmask_lock sig->siglock +#define compat_dequeue_signal_current(siginfo_ptr) \ + dequeue_signal(¤t->blocked, (siginfo_ptr)) +#else +/* RedHat's 2.4.x with second version of NPTL support, or 2.5.60+. */ +#define compat_sigmask_lock sighand->siglock +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) +#define compat_dequeue_signal_current(siginfo_ptr) \ + dequeue_signal(¤t->blocked, (siginfo_ptr)) +#else +#define compat_dequeue_signal_current(siginfo_ptr) \ + dequeue_signal(current, ¤t->blocked, (siginfo_ptr)) +#endif +#endif + +/* + * recalc_sigpending() had task argument in the past + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 29) && defined(CLONE_PID) +/* 2.4.x without NPTL patches or early 2.5.x */ +#define compat_recalc_sigpending() recalc_sigpending(current) +#else +/* RedHat's 2.4.x with NPTL support, or 2.5.29+ */ +#define compat_recalc_sigpending() recalc_sigpending() +#endif + + +/* + * reparent_to_init() was introduced in 2.4.8. In 2.5.38 (or possibly + * earlier, but later than 2.5.31) a call to it was added into + * daemonize(), so compat_daemonize no longer needs to call it. + * + * In 2.4.x kernels reparent_to_init() forgets to do correct refcounting + * on current->user. It is better to count one too many than one too few... + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 38) +#define compat_reparent_to_init() do { \ + reparent_to_init(); \ + atomic_inc(¤t->user->__count); \ + } while (0) +#else +#define compat_reparent_to_init() do {} while (0) +#endif + + +/* + * daemonize appeared in 2.2.18. Except 2.2.17-4-RH7.0, which has it too. + * Fortunately 2.2.17-4-RH7.0 uses versioned symbols, so we can check + * its existence with defined(). + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) && !defined(daemonize) +static inline void daemonize(void) { + struct fs_struct *fs; + + exit_mm(current); + current->session = 1; + current->pgrp = 1; + exit_fs(current); + fs = init_task.fs; + current->fs = fs; + atomic_inc(&fs->count); +} +#endif + + +/* + * flush_signals acquires sighand->siglock since 2.5.61... Verify RH's kernels! + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) +#define compat_flush_signals(task) do { \ + spin_lock_irq(&task->compat_sigmask_lock); \ + flush_signals(task); \ + spin_unlock_irq(&task->compat_sigmask_lock); \ + } while (0) +#else +#define compat_flush_signals(task) flush_signals(task) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) +#define compat_allow_signal(signr) do { \ + spin_lock_irq(¤t->compat_sigmask_lock); \ + sigdelset(¤t->blocked, signr); \ + compat_recalc_sigpending(); \ + spin_unlock_irq(¤t->compat_sigmask_lock); \ + } while (0) +#else +#define compat_allow_signal(signr) allow_signal(signr) +#endif + +/* + * daemonize can set process name since 2.5.61. Prior to 2.5.61, daemonize + * didn't block signals on our behalf. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) +#define compat_daemonize(x...) \ +({ \ + /* Beware! No snprintf here, so verify arguments! */ \ + sprintf(current->comm, x); \ + \ + /* Block all signals. */ \ + spin_lock_irq(¤t->compat_sigmask_lock); \ + sigfillset(¤t->blocked); \ + compat_recalc_sigpending(); \ + spin_unlock_irq(¤t->compat_sigmask_lock); \ + compat_flush_signals(current); \ + \ + daemonize(); \ + compat_reparent_to_init(); \ +}) +#else +#define compat_daemonize(x...) daemonize(x) +#endif + + +/* + * set priority for specified thread. Exists on 2.6.x kernels and some + * 2.4.x vendor's kernels. + */ +#if defined(VMW_HAVE_SET_USER_NICE) +#define compat_set_user_nice(task, n) set_user_nice((task), (n)) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#define compat_set_user_nice(task, n) do { (task)->priority = 20 - (n); } while (0) +#elif !defined(VMW_HAVE_SET_USER_NICE) +#define compat_set_user_nice(task, n) do { (task)->nice = (n); } while (0) +#endif + +/* + * try to freeze a process. For kernels 2.6.11 or newer, we know how to choose + * the interface. The problem is that the oldest interface, introduced in + * 2.5.18, was backported to 2.4.x kernels. So if we're older than 2.6.11, + * we'll decide what to do based on whether or not swsusp was configured + * for the kernel. For kernels 2.6.20 and newer, we'll also need to include + * freezer.h since the try_to_freeze definition was pulled out of sched.h. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) || defined(VMW_TL10S64_WORKAROUND) +#define compat_try_to_freeze() try_to_freeze() +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) +#define compat_try_to_freeze() try_to_freeze(PF_FREEZE) +#elif defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_SOFTWARE_SUSPEND2) +#include "compat_mm.h" +#include +#include +static inline int compat_try_to_freeze(void) { + if (current->flags & PF_FREEZE) { + refrigerator(PF_FREEZE); + return 1; + } else { + return 0; + } +} +#else +static inline int compat_try_to_freeze(void) { return 0; } +#endif + +/* + * As of 2.6.23-rc1, kernel threads are no longer freezable by + * default. Instead, kernel threads that need to be frozen must opt-in + * by calling set_freezable() as soon as the thread is created. + */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) +#define compat_set_freezable() do { set_freezable(); } while (0) +#else +#define compat_set_freezable() do {} while (0) +#endif + +/* + * Since 2.6.27-rc2 kill_proc() is gone... Replacement (GPL-only!) + * API is available since 2.6.19. Use them from 2.6.27-rc1 up. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) +typedef int compat_pid; +#define compat_find_get_pid(pid) (pid) +#define compat_put_pid(pid) do { } while (0) +#define compat_kill_pid(pid, sig, flag) kill_proc(pid, sig, flag) +#else +typedef struct pid * compat_pid; +#define compat_find_get_pid(pid) find_get_pid(pid) +#define compat_put_pid(pid) put_pid(pid) +#define compat_kill_pid(pid, sig, flag) kill_pid(pid, sig, flag) +#endif + + +#endif /* __COMPAT_SCHED_H__ */ diff -Nrup source/vmnet-only/include/compat_semaphore.h source.edited/vmnet-only/include/compat_semaphore.h --- source/vmnet-only/include/compat_semaphore.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_semaphore.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,49 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_SEMAPHORE_H__ +# define __COMPAT_SEMAPHORE_H__ + + +/* <= 2.6.25 have asm only, 2.6.26 has both, and 2.6.27-rc2+ has linux only. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) +# include +#else +# include +#endif + + +/* +* The init_MUTEX_LOCKED() API appeared in 2.2.18, and is also in +* 2.2.17-21mdk --hpreg +*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) + #ifndef init_MUTEX_LOCKED + #define init_MUTEX_LOCKED(_sem) *(_sem) = MUTEX_LOCKED + #endif + #ifndef DECLARE_MUTEX + #define DECLARE_MUTEX(name) struct semaphore name = MUTEX + #endif + #ifndef DECLARE_MUTEX_LOCKED + #define DECLARE_MUTEX_LOCKED(name) struct semaphore name = MUTEX_LOCKED + #endif +#endif + + +#endif /* __COMPAT_SEMAPHORE_H__ */ diff -Nrup source/vmnet-only/include/compat_skbuff.h source.edited/vmnet-only/include/compat_skbuff.h --- source/vmnet-only/include/compat_skbuff.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_skbuff.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,156 @@ +/********************************************************* + * Copyright (C) 2007 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 + * + *********************************************************/ + +#ifndef __COMPAT_SKBUFF_H__ +# define __COMPAT_SKBUFF_H__ + +#include + +/* + * When transition from mac/nh/h to skb_* accessors was made, also SKB_WITH_OVERHEAD + * was introduced. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) || \ + (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 21) && defined(SKB_WITH_OVERHEAD)) +#define compat_skb_mac_header(skb) skb_mac_header(skb) +#define compat_skb_network_header(skb) skb_network_header(skb) +#define compat_skb_network_offset(skb) skb_network_offset(skb) +#define compat_skb_transport_header(skb) skb_transport_header(skb) +#define compat_skb_transport_offset(skb) skb_transport_offset(skb) +#define compat_skb_network_header_len(skb) skb_network_header_len(skb) +#define compat_skb_tail_pointer(skb) skb_tail_pointer(skb) +#define compat_skb_end_pointer(skb) skb_end_pointer(skb) +#define compat_skb_ip_header(skb) ((struct iphdr *)skb_network_header(skb)) +#define compat_skb_tcp_header(skb) ((struct tcphdr *)skb_transport_header(skb)) +#define compat_skb_reset_mac_header(skb) skb_reset_mac_header(skb) +#define compat_skb_set_network_header(skb, off) skb_set_network_header(skb, off) +#define compat_skb_set_transport_header(skb, off) skb_set_transport_header(skb, off) +#else +#define compat_skb_mac_header(skb) (skb)->mac.raw +#define compat_skb_network_header(skb) (skb)->nh.raw +#define compat_skb_network_offset(skb) ((skb)->nh.raw - (skb)->data) +#define compat_skb_transport_header(skb) (skb)->h.raw +#define compat_skb_transport_offset(skb) ((skb)->h.raw - (skb)->data) +#define compat_skb_network_header_len(skb) ((skb)->h.raw - (skb)->nh.raw) +#define compat_skb_tail_pointer(skb) (skb)->tail +#define compat_skb_end_pointer(skb) (skb)->end +#define compat_skb_ip_header(skb) (skb)->nh.iph +#define compat_skb_tcp_header(skb) (skb)->h.th +#define compat_skb_reset_mac_header(skb) ((skb)->mac.raw = (skb)->data) +#define compat_skb_set_network_header(skb, off) ((skb)->nh.raw = (skb)->data + (off)) +#define compat_skb_set_transport_header(skb, off) ((skb)->h.raw = (skb)->data + (off)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) || defined(VMW_SKB_LINEARIZE_2618) +# define compat_skb_linearize(skb) skb_linearize((skb)) +#else + +# if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 0) +# define compat_skb_linearize(skb) __skb_linearize((skb), GFP_ATOMIC) +# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) +# define compat_skb_linearize(skb) skb_linearize((skb), GFP_ATOMIC) +# else +static inline int +compat_skb_linearize(struct sk_buff *skb) +{ + return 0; +} +# endif + +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +#define compat_skb_csum_offset(skb) (skb)->csum_offset +#else +#define compat_skb_csum_offset(skb) (skb)->csum +#endif + +/* + * Note that compat_skb_csum_start() has semantic different from kernel's csum_start: + * kernel's skb->csum_start is offset between start of checksummed area and start of + * complete skb buffer, while our compat_skb_csum_start(skb) is offset from start + * of packet itself. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#define compat_skb_csum_start(skb) ((skb)->csum_start - skb_headroom(skb)) +#else +#define compat_skb_csum_start(skb) compat_skb_transport_offset(skb) +#endif + +#if defined(NETIF_F_GSO) /* 2.6.18 and upwards */ +#define compat_skb_mss(skb) (skb_shinfo(skb)->gso_size) +#else +#define compat_skb_mss(skb) (skb_shinfo(skb)->tso_size) +#endif + +/* used by both received pkts and outgoing ones */ +#define VM_CHECKSUM_UNNECESSARY CHECKSUM_UNNECESSARY + +/* csum status of received pkts */ +#if defined(CHECKSUM_COMPLETE) +# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_COMPLETE +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW) +# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_HW +#else +# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_PARTIAL +#endif + +/* csum status of outgoing pkts */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW) +# define VM_TX_CHECKSUM_PARTIAL CHECKSUM_HW +#else +# define VM_TX_CHECKSUM_PARTIAL CHECKSUM_PARTIAL +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)) +# define compat_kfree_skb(skb, type) kfree_skb(skb, type) +# define compat_dev_kfree_skb(skb, type) dev_kfree_skb(skb, type) +# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb(skb, type) +# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb(skb, type) +#else +# define compat_kfree_skb(skb, type) kfree_skb(skb) +# define compat_dev_kfree_skb(skb, type) dev_kfree_skb(skb) +# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)) +# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb(skb) +# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb(skb) +# else +# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb_any(skb) +# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb_irq(skb) +# endif +#endif + +#ifndef NET_IP_ALIGN +# define COMPAT_NET_IP_ALIGN 2 +#else +# define COMPAT_NET_IP_ALIGN NET_IP_ALIGN +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) +# define compat_skb_headlen(skb) skb_headlen(skb) +# define compat_pskb_may_pull(skb, len) pskb_may_pull(skb, len) +#else +# define compat_skb_headlen(skb) (skb)->len +# define compat_pskb_may_pull(skb, len) 1 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) +# define compat_skb_header_cloned(skb) skb_header_cloned(skb) +#else +# define compat_skb_header_cloned(skb) 0 +#endif +#endif /* __COMPAT_SKBUFF_H__ */ diff -Nrup source/vmnet-only/include/compat_slab.h source.edited/vmnet-only/include/compat_slab.h --- source/vmnet-only/include/compat_slab.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_slab.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,85 @@ +/********************************************************* + * Copyright (C) 2005 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 + * + *********************************************************/ + +#ifndef __COMPAT_SLAB_H__ +# define __COMPAT_SLAB_H__ + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) +# include +#else +# include +#endif + +/* + * Before 2.6.20, kmem_cache_t was the accepted way to refer to a kmem_cache + * structure. Prior to 2.6.15, this structure was called kmem_cache_s, and + * afterwards it was renamed to kmem_cache. Here we keep things simple and use + * the accepted typedef until it became deprecated, at which point we switch + * over to the kmem_cache name. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +# define compat_kmem_cache struct kmem_cache +#else +# define compat_kmem_cache kmem_cache_t +#endif + +/* + * Up to 2.6.22 kmem_cache_create has 6 arguments - name, size, alignment, flags, + * constructor, and destructor. Then for some time kernel was asserting that + * destructor is NULL, and since 2.6.23-pre1 kmem_cache_create takes only 5 + * arguments - destructor is gone. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) || defined(VMW_KMEMCR_HAS_DTOR) +#define compat_kmem_cache_create(name, size, align, flags, ctor) \ + kmem_cache_create(name, size, align, flags, ctor, NULL) +#else +#define compat_kmem_cache_create(name, size, align, flags, ctor) \ + kmem_cache_create(name, size, align, flags, ctor) +#endif + +/* + * Up to 2.6.23 kmem_cache constructor has three arguments - pointer to block to + * prepare (aka "this"), from which cache it came, and some unused flags. After + * 2.6.23 flags were removed, and order of "this" and cache parameters was swapped... + * Since 2.6.27-rc2 everything is different again, and ctor has only one argument. + * + * HAS_3_ARGS has precedence over HAS_2_ARGS if both are defined. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) && !defined(VMW_KMEMCR_CTOR_HAS_3_ARGS) +# define VMW_KMEMCR_CTOR_HAS_3_ARGS +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) && !defined(VMW_KMEMCR_CTOR_HAS_2_ARGS) +# define VMW_KMEMCR_CTOR_HAS_2_ARGS +#endif + +#if defined(VMW_KMEMCR_CTOR_HAS_3_ARGS) +typedef void compat_kmem_cache_ctor(void *, compat_kmem_cache *, unsigned long); +#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) void *arg, \ + compat_kmem_cache *cache, \ + unsigned long flags +#elif defined(VMW_KMEMCR_CTOR_HAS_2_ARGS) +typedef void compat_kmem_cache_ctor(compat_kmem_cache *, void *); +#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) compat_kmem_cache *cache, \ + void *arg +#else +typedef void compat_kmem_cache_ctor(void *); +#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) void *arg +#endif + +#endif /* __COMPAT_SLAB_H__ */ diff -Nrup source/vmnet-only/include/compat_sock.h source.edited/vmnet-only/include/compat_sock.h --- source/vmnet-only/include/compat_sock.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_sock.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,169 @@ +/********************************************************* + * Copyright (C) 2003 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 + * + *********************************************************/ + +#ifndef __COMPAT_SOCK_H__ +# define __COMPAT_SOCK_H__ + +#include /* for NULL */ +#include + + +/* + * Between 2.5.70 and 2.5.71 all sock members were renamed from XXX to sk_XXX. + * + * VMW_HAVE_SK_WMEM_ALLOC is defined in module Makefile if kernel's struct sock + * has sk_wmem_alloc member. See vmnet's Makefile.kernel for details. + * It also means that all modules including this file should do + * + * EXTRA_CFLAGS += $(call vm_check_build, $(SRCROOT)/socket.c, -DVMW_HAVE_SK_WMEM_ALLOC, ) + * + * in their Makefiles. + */ +#ifndef VMW_HAVE_SK_WMEM_ALLOC +# define sk_wmem_alloc wmem_alloc +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 71) +# define compat_sk_backlog_rcv backlog_rcv +# define compat_sk_destruct destruct +# define compat_sk_shutdown shutdown +# define compat_sk_receive_queue receive_queue +# define compat_sk_sleep sleep +# define compat_sk_err err +# define compat_sk_state_change state_change +# define compat_sk_data_ready data_ready +# define compat_sk_write_space write_space +# define compat_sk_error_report error_report +# define compat_sk_type type +# define compat_sk_refcnt refcnt +# define compat_sk_state state +# define compat_sk_error_report error_report +# define compat_sk_socket socket +# define compat_sk_ack_backlog ack_backlog +# define compat_sk_max_ack_backlog max_ack_backlog +#else +# define compat_sk_backlog_rcv sk_backlog_rcv +# define compat_sk_destruct sk_destruct +# define compat_sk_shutdown sk_shutdown +# define compat_sk_receive_queue sk_receive_queue +# define compat_sk_sleep sk_sleep +# define compat_sk_err sk_err +# define compat_sk_state_change sk_state_change +# define compat_sk_data_ready sk_data_ready +# define compat_sk_write_space sk_write_space +# define compat_sk_error_report sk_error_report +# define compat_sk_type sk_type +# define compat_sk_refcnt sk_refcnt +# define compat_sk_state sk_state +# define compat_sk_error_report sk_error_report +# define compat_sk_socket sk_socket +# define compat_sk_ack_backlog sk_ack_backlog +# define compat_sk_max_ack_backlog sk_max_ack_backlog +#endif + + +/* + * Prior to 2.6.24, there was no sock network namespace member. In 2.6.26, it + * was hidden behind accessor functions so that its behavior could vary + * depending on the value of CONFIG_NET_NS. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +# define compat_sock_net(sk) sock_net(sk) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +# define compat_sock_net(sk) sk->sk_net +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 42) +# define compat_sock_owned_by_user(sk) ((sk)->lock.users != 0) +#else +# define compat_sock_owned_by_user(sk) sock_owned_by_user(sk) +#endif + +/* + * Up until 2.4.21 for the 2.4 series and 2.5.60 for the 2.5 series, + * sk_filter() calls were protected with CONFIG_FILTER. Wrapping our compat + * definition in a similar check allows us to build on those kernels. + * + */ +#ifdef CONFIG_FILTER +/* + * Unfortunately backports for certain kernels require the use of an autoconf + * program to check the interface for sk_filter(). + */ +# ifndef VMW_HAVE_NEW_SKFILTER +# define compat_sk_filter(sk, skb, needlock) sk_filter(skb, (sk)->filter) +# else +# define compat_sk_filter(sk, skb, needlock) sk_filter(sk, skb, needlock) +# endif +#else +# define compat_sk_filter(sk, skb, needlock) 0 +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) +/* Taken from 2.6.16's sock.h and modified for macro. */ +# define compat_sk_receive_skb(sk, skb, nested) \ + ({ \ + int rc = NET_RX_SUCCESS; \ + \ + if (compat_sk_filter(sk, skb, 0)) { \ + kfree_skb(skb); \ + sock_put(sk); \ + } else { \ + skb->dev = NULL; \ + bh_lock_sock(sk); \ + if (!compat_sock_owned_by_user(sk)) { \ + rc = (sk)->compat_sk_backlog_rcv(sk, skb); \ + } else { \ + sk_add_backlog(sk, skb); \ + } \ + bh_unlock_sock(sk); \ + sock_put(sk); \ + } \ + \ + rc; \ + }) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +# define compat_sk_receive_skb(sk, skb, nested) sk_receive_skb(sk, skb) +#else +# define compat_sk_receive_skb(sk, skb, nested) sk_receive_skb(sk, skb, nested) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 72) +/* + * Before 2.5.72, the helper socket functions for hlist management did not + * exist, so we use the sklist_ functions instead. These are not ideal since + * they grab a system-wide sklist lock despite not needing it since we provide + * our own list. + */ +#define compat_sk_next next /* for when we find out it became sk_next */ +# define compat_sklist_table struct sock * +/* This isn't really used in the iterator, but we need something. */ +# define compat_sklist_table_entry struct sock +# define compat_sk_for_each(sk, node, list) \ + for (sk = *(list), node = NULL; sk != NULL; sk = (sk)->compat_sk_next) +# define compat_sk_add_node(sk, list) sklist_insert_socket(list, sk) +# define compat_sk_del_node_init(sk, list) sklist_remove_socket(list, sk) +#else +# define compat_sklist_table struct hlist_head +# define compat_sklist_table_entry struct hlist_node +# define compat_sk_for_each(sk, node, list) sk_for_each(sk, node, list) +# define compat_sk_add_node(sk, list) sk_add_node(sk, list) +# define compat_sk_del_node_init(sk, list) sk_del_node_init(sk) +#endif + +#endif /* __COMPAT_SOCK_H__ */ diff -Nrup source/vmnet-only/include/compat_spinlock.h source.edited/vmnet-only/include/compat_spinlock.h --- source/vmnet-only/include/compat_spinlock.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_spinlock.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,68 @@ +/********************************************************* + * Copyright (C) 2005 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 + * + *********************************************************/ + +#ifndef __COMPAT_SPINLOCK_H__ +# define __COMPAT_SPINLOCK_H__ + + +/* + * The spin_lock() API appeared in 2.1.25 in asm/smp_lock.h + * It moved in 2.1.30 to asm/spinlock.h + * It moved again in 2.3.18 to linux/spinlock.h + * + * --hpreg + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 18) +# include +#else +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 30) +# include +# else +typedef struct {} spinlock_t; +# define spin_lock_init(lock) +# define spin_lock(lock) +# define spin_unlock(lock) +# define spin_lock_irqsave(lock, flags) do { \ + save_flags(flags); \ + cli(); \ + spin_lock(lock); \ + } while (0) +# define spin_unlock_irqrestore(lock, flags) do { \ + spin_unlock(lock); \ + restore_flags(flags); \ + } while (0) +# endif +#endif + + +/* + * Preempt support was added during 2.5.x development cycle, and later + * it was backported to 2.4.x. In 2.4.x backport these definitions + * live in linux/spinlock.h, that's why we put them here (in 2.6.x they + * are defined in linux/preempt.h which is included by linux/spinlock.h). + */ +#ifdef CONFIG_PREEMPT +#define compat_preempt_disable() preempt_disable() +#define compat_preempt_enable() preempt_enable() +#else +#define compat_preempt_disable() do { } while (0) +#define compat_preempt_enable() do { } while (0) +#endif + + +#endif /* __COMPAT_SPINLOCK_H__ */ diff -Nrup source/vmnet-only/include/compat_uaccess.h source.edited/vmnet-only/include/compat_uaccess.h --- source/vmnet-only/include/compat_uaccess.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_uaccess.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,79 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_UACCESS_H__ +# define __COMPAT_UACCESS_H__ + + +/* User space access functions moved in 2.1.7 to asm/uaccess.h --hpreg */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 7) +# include +#else +# include +#endif + + +/* get_user() API modified in 2.1.4 to take 2 arguments --hpreg */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 4) +# define compat_get_user get_user +#else +/* + * We assign 0 to the variable in case of failure to prevent "`_var' might be + * used uninitialized in this function" compiler warnings. I think it is OK, + * because the hardware-based version in newer kernels probably has the same + * semantics and does not guarantee that the value of _var will not be + * modified, should the access fail --hpreg + */ +# define compat_get_user(_var, _uvAddr) ({ \ + int _status; \ + \ + _status = verify_area(VERIFY_READ, _uvAddr, sizeof(*(_uvAddr))); \ + if (_status == 0) { \ + (_var) = get_user(_uvAddr); \ + } else { \ + (_var) = 0; \ + } \ + _status; \ +}) +#endif + + +/* + * The copy_from_user() API appeared in 2.1.4 + * + * The emulation is not perfect here, but it is conservative: on failure, we + * always return the total size, instead of the potentially smaller faulty + * size --hpreg + * + * Since 2.5.55 copy_from_user() is no longer macro. + */ +#if !defined(copy_from_user) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) +# define copy_from_user(_to, _from, _size) ( \ + verify_area(VERIFY_READ, _from, _size) \ + ? (_size) \ + : (memcpy_fromfs(_to, _from, _size), 0) \ +) +# define copy_to_user(_to, _from, _size) ( \ + verify_area(VERIFY_WRITE, _to, _size) \ + ? (_size) \ + : (memcpy_tofs(_to, _from, _size), 0) \ +) +#endif + + +#endif /* __COMPAT_UACCESS_H__ */ diff -Nrup source/vmnet-only/include/compat_version.h source.edited/vmnet-only/include/compat_version.h --- source/vmnet-only/include/compat_version.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_version.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,121 @@ +/********************************************************* + * Copyright (C) 1998 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 + * + *********************************************************/ + +#ifndef __COMPAT_VERSION_H__ +# define __COMPAT_VERSION_H__ + +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_DISTRIBUTE +#include "includeCheck.h" + + +#ifndef __linux__ +# error "linux-version.h" +#endif + + +#include + +/* Appeared in 2.1.90 --hpreg */ +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) +#endif + + +/* + * Distinguish relevant classes of Linux kernels. + * + * The convention is that version X defines all + * the KERNEL_Y symbols where Y <= X. + * + * XXX Do not add more definitions here. This way of doing things does not + * scale, and we are going to phase it out soon --hpreg + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 0) +# define KERNEL_2_1 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) +# define KERNEL_2_2 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 1) +# define KERNEL_2_3_1 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 15) +/* new networking */ +# define KERNEL_2_3_15 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25) +/* new procfs */ +# define KERNEL_2_3_25 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29) +/* even newer procfs */ +# define KERNEL_2_3_29 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 43) +/* softnet changes */ +# define KERNEL_2_3_43 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 47) +/* more softnet changes */ +# define KERNEL_2_3_47 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 99) +/* name in netdevice struct is array and not pointer */ +# define KERNEL_2_3_99 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) +/* New 'owner' member at the beginning of struct file_operations */ +# define KERNEL_2_4_0 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) +/* New netif_rx_ni() --hpreg */ +# define KERNEL_2_4_8 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22) +/* New vmap() */ +# define KERNEL_2_4_22 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 2) +/* New kdev_t, major()/minor() API --hpreg */ +# define KERNEL_2_5_2 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) +/* New sk_alloc(), pte_offset_map()/pte_unmap() --hpreg */ +# define KERNEL_2_5_5 +#endif + + +#endif /* __COMPAT_VERSION_H__ */ diff -Nrup source/vmnet-only/include/compat_wait.h source.edited/vmnet-only/include/compat_wait.h --- source/vmnet-only/include/compat_wait.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/compat_wait.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,229 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __COMPAT_WAIT_H__ +# define __COMPAT_WAIT_H__ + + +#include +#include +#include + +#include "compat_file.h" + + +/* + * The DECLARE_WAITQUEUE() API appeared in 2.3.1 + * It was back ported in 2.2.18 + * + * --hpreg + */ + +#ifndef DECLARE_WAITQUEUE + +typedef struct wait_queue *wait_queue_head_t; +# define init_waitqueue_head(_headPtr) *(_headPtr) = NULL +# define DECLARE_WAITQUEUE(_var, _task) \ + struct wait_queue _var = {_task, NULL, } + +typedef struct wait_queue wait_queue_t; +# define init_waitqueue_entry(_wait, _task) ((_wait)->task = (_task)) + +#endif + +/* + * The 'struct poll_wqueues' appeared in 2.5.48, when global + * /dev/epoll interface was added. It was backported to the + * 2.4.20-wolk4.0s. + */ + +#ifdef VMW_HAVE_EPOLL // { +#define compat_poll_wqueues struct poll_wqueues +#else // } { +#define compat_poll_wqueues poll_table +#endif // } + +#ifdef VMW_HAVE_EPOLL // { + +/* If prototype does not match, build will abort here */ +extern void poll_initwait(compat_poll_wqueues *); + +#define compat_poll_initwait(wait, table) ( \ + poll_initwait((table)), \ + (wait) = &(table)->pt \ +) + +#define compat_poll_freewait(wait, table) ( \ + poll_freewait((table)) \ +) + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) // { + +/* If prototype does not match, build will abort here */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) +extern void poll_initwait(compat_poll_wqueues *); +#else /* 2.6.29 */ +extern void poll_initwait(struct poll_wqueues *); +#endif /* 2.6.29 */ + +#define compat_poll_initwait(wait, table) ( \ + (wait) = (table), \ + poll_initwait(wait) \ +) + +#define compat_poll_freewait(wait, table) ( \ + poll_freewait((table)) \ +) + +#else // } { + +#define compat_poll_initwait(wait, table) ( \ + (wait) = (table), /* confuse compiler */ \ + (wait) = (poll_table *) __get_free_page(GFP_KERNEL), \ + (wait)->nr = 0, \ + (wait)->entry = (struct poll_table_entry *)((wait) + 1), \ + (wait)->next = NULL \ +) + +static inline void +poll_freewait(poll_table *wait) +{ + while (wait) { + struct poll_table_entry * entry; + poll_table *old; + + entry = wait->entry + wait->nr; + while (wait->nr > 0) { + wait->nr--; + entry--; + remove_wait_queue(entry->wait_address, &entry->wait); + compat_fput(entry->filp); + } + old = wait; + wait = wait->next; + free_page((unsigned long) old); + } +} + +#define compat_poll_freewait(wait, table) ( \ + poll_freewait((wait)) \ +) + +#endif // } + +/* + * The wait_event_interruptible_timeout() interface is not + * defined in pre-2.6 kernels. + */ +#ifndef wait_event_interruptible_timeout +#define __wait_event_interruptible_timeout(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + set_current_state(TASK_RUNNING); \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_interruptible_timeout(wq, condition, __ret); \ + __ret; \ +}) +#endif + +/* + * The wait_event_timeout() interface is not + * defined in pre-2.6 kernels. + */ +#ifndef wait_event_timeout +#define __wait_event_timeout(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + if (condition) \ + break; \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + } \ + set_current_state(TASK_RUNNING); \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_timeout(wq, condition, __ret); \ + __ret; \ +}) +#endif + +/* + * DEFINE_WAIT() and friends were added in 2.5.39 and backported to 2.4.28. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 28) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 39)) +# define COMPAT_DEFINE_WAIT(_wait) \ + DECLARE_WAITQUEUE(_wait, current) +# define compat_init_prepare_to_wait(_sleep, _wait, _state) \ + do { \ + __set_current_state(_state); \ + add_wait_queue(_sleep, _wait); \ + } while (0) +# define compat_cont_prepare_to_wait(_sleep, _wait, _state) \ + set_current_state(_state) +# define compat_finish_wait(_sleep, _wait, _state) \ + do { \ + __set_current_state(_state); \ + remove_wait_queue(_sleep, _wait); \ + } while (0) +#else +# define COMPAT_DEFINE_WAIT(_wait) \ + DEFINE_WAIT(_wait) +# define compat_init_prepare_to_wait(_sleep, _wait, _state) \ + prepare_to_wait(_sleep, _wait, _state) +# define compat_cont_prepare_to_wait(_sleep, _wait, _state) \ + prepare_to_wait(_sleep, _wait, _state) +# define compat_finish_wait(_sleep, _wait, _state) \ + finish_wait(_sleep, _wait) +#endif + +#endif /* __COMPAT_WAIT_H__ */ diff -Nrup source/vmnet-only/include/driver-config.h source.edited/vmnet-only/include/driver-config.h --- source/vmnet-only/include/driver-config.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/driver-config.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,78 @@ +/********************************************************* + * Copyright (C) 1998 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 + * + *********************************************************/ + +/* + * Sets the proper defines from the Linux header files + * + * This file must be included before the inclusion of any kernel header file, + * with the exception of linux/autoconf.h and linux/version.h --hpreg + */ + +#ifndef __VMX_CONFIG_H__ +#define __VMX_CONFIG_H__ + +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMNIXMOD +#include "includeCheck.h" + +#include +#include "compat_version.h" + +/* + * We rely on Kernel Module support. Check here. + */ +#ifndef CONFIG_MODULES +# error "No Module support in this kernel. Please configure with CONFIG_MODULES" +#endif + +/* + * 2.2 kernels still use __SMP__ (derived from CONFIG_SMP + * in the main Makefile), so we do it here. + */ + +#ifdef CONFIG_SMP +# define __SMP__ 1 +#endif + +#if defined(CONFIG_MODVERSIONS) && defined(KERNEL_2_1) +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) +/* + * MODVERSIONS might be already defined when using kernel's Makefiles. + */ +# ifndef MODVERSIONS +# define MODVERSIONS +# endif +# include +# endif +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +/* + * Force the uintptr_t definition to come from linux/types.h instead of vm_basic_types.h. + */ +# include +# define _STDINT_H 1 +#endif + +#ifndef __KERNEL__ +# define __KERNEL__ +#endif + +#endif diff -Nrup source/vmnet-only/include/includeCheck.h source.edited/vmnet-only/include/includeCheck.h --- source/vmnet-only/include/includeCheck.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/includeCheck.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,17 @@ +/********************************************************* + * Copyright (C) 2008 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 + * + *********************************************************/ diff -Nrup source/vmnet-only/include/net.h source.edited/vmnet-only/include/net.h --- source/vmnet-only/include/net.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/net.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,136 @@ +/********************************************************* + * Copyright (C) 1998 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 + * + *********************************************************/ + +/************************************************************ + * + * net.h + * + * This file should contain all network global defines. + * No vlance/vmxnet/vnet/vmknet specific stuff should be + * put here only defines used/usable by all network code. + * --gustav + * + ************************************************************/ + +#ifndef VMWARE_DEVICES_NET_H +#define VMWARE_DEVICES_NET_H + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMMEXT +#include "includeCheck.h" +#include "vm_device_version.h" + +#define ETHERNET_MTU 1518 +#define ETH_MIN_FRAME_LEN 60 + +#ifndef ETHER_ADDR_LEN +#define ETHER_ADDR_LEN 6 /* length of MAC address */ +#endif +#define ETH_HEADER_LEN 14 /* length of Ethernet header */ +#define IP_ADDR_LEN 4 /* length of IPv4 address */ +#define IP_HEADER_LEN 20 /* minimum length of IPv4 header */ + +#define ETHER_MAX_QUEUED_PACKET 1600 + + +/* + * State's that a NIC can be in currently we only use this + * in VLance but if we implement/emulate new adapters that + * we also want to be able to morph a new corresponding + * state should be added. + */ + +#define LANCE_CHIP 0x2934 +#define VMXNET_CHIP 0x4392 + +/* + * Size of reserved IO space needed by the LANCE adapter and + * the VMXNET adapter. If you add more ports to Vmxnet than + * there is reserved space you must bump VMXNET_CHIP_IO_RESV_SIZE. + * The sizes must be powers of 2. + */ + +#define LANCE_CHIP_IO_RESV_SIZE 0x20 +#define VMXNET_CHIP_IO_RESV_SIZE 0x40 + +#define MORPH_PORT_SIZE 4 + + +#ifdef USERLEVEL + +/* + *---------------------------------------------------------------------------- + * + * Net_AddAddrToLADRF -- + * + * Given a MAC address, sets the corresponding bit in the LANCE style + * Logical Address Filter 'ladrf'. + * The caller should have initialized the ladrf to all 0's, as this + * function only ORs on a bit in the array. + * 'addr' is presumed to be ETHER_ADDR_LEN in size; + * 'ladrf' is presumed to point to a 64-bit vector. + * + * Derived from a long history of derivations, originally inspired by + * sample code from the AMD "Network Products: Ethernet Controllers 1998 + * Data Book, Book 2", pages 1-53..1-55. + * + * Returns: + * None. + * + * Side effects: + * Updates 'ladrf'. + * + *---------------------------------------------------------------------------- + */ + +static INLINE void +Net_AddAddrToLadrf(const uint8 *addr, // IN: pointer to MAC address + uint8 *ladrf) // IN/OUT: pointer to ladrf +{ +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ + + uint16 hashcode; + int32 crc = 0xffffffff; /* init CRC for each address */ + int32 j; + int32 bit; + int32 byte; + + ASSERT(addr); + ASSERT(ladrf); + + for (byte = 0; byte < ETHER_ADDR_LEN; byte++) { /* for each address byte */ + /* process each address bit */ + for (bit = *addr++, j = 0; + j < 8; + j++, bit >>= 1) { + crc = (crc << 1) ^ ((((crc < 0 ? 1 : 0) ^ bit) & 0x01) ? + CRC_POLYNOMIAL_BE : 0); + } + } + hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */ + for (j = 0; j < 5; j++) { /* ... in reverse order. */ + hashcode = (hashcode << 1) | ((crc>>=1) & 1); + } + + ladrf[hashcode >> 3] |= 1 << (hashcode & 0x07); +} + +#endif // USERLEVEL + +#endif // VMWARE_DEVICES_NET_H diff -Nrup source/vmnet-only/include/pgtbl.h source.edited/vmnet-only/include/pgtbl.h --- source/vmnet-only/include/pgtbl.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/pgtbl.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,385 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __PGTBL_H__ +# define __PGTBL_H__ + + +#include "compat_highmem.h" +#include "compat_pgtable.h" +#include "compat_spinlock.h" +#include "compat_page.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 11) +# define compat_active_mm mm +#else +# define compat_active_mm active_mm +#endif + + +/* + *----------------------------------------------------------------------------- + * + * PgtblPte2MPN -- + * + * Returns the page structure associated to a Page Table Entry. + * + * This function is not allowed to schedule() because it can be called while + * holding a spinlock --hpreg + * + * Results: + * INVALID_MPN on failure + * mpn on success + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE MPN +PgtblPte2MPN(pte_t *pte) // IN +{ + if (pte_present(*pte) == 0) { + return INVALID_MPN; + } + return pte_pfn(*pte); +} + + +/* + *----------------------------------------------------------------------------- + * + * PgtblPte2Page -- + * + * Returns the page structure associated to a Page Table Entry. + * + * This function is not allowed to schedule() because it can be called while + * holding a spinlock --hpreg + * + * Results: + * The page structure if the page table entry points to a physical page + * NULL if the page table entry does not point to a physical page + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE struct page * +PgtblPte2Page(pte_t *pte) // IN +{ + if (pte_present(*pte) == 0) { + return NULL; + } + + return compat_pte_page(*pte); +} + + +/* + *----------------------------------------------------------------------------- + * + * PgtblPGD2PTELocked -- + * + * Walks through the hardware page tables to try to find the pte + * associated to a virtual address. + * + * Results: + * pte. Caller must call pte_unmap if valid pte returned. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE pte_t * +PgtblPGD2PTELocked(compat_pgd_t *pgd, // IN: PGD to start with + VA addr) // IN: Address in the virtual address + // space of that process +{ + compat_pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + if (compat_pgd_present(*pgd) == 0) { + return NULL; + } + + pud = compat_pud_offset(pgd, addr); + if (compat_pud_present(*pud) == 0) { + return NULL; + } + + pmd = pmd_offset_map(pud, addr); + if (pmd_present(*pmd) == 0) { + pmd_unmap(pmd); + return NULL; + } + + pte = pte_offset_map(pmd, addr); + pmd_unmap(pmd); + return pte; +} + + +/* + *----------------------------------------------------------------------------- + * + * PgtblVa2PTELocked -- + * + * Walks through the hardware page tables to try to find the pte + * associated to a virtual address. + * + * Results: + * pte. Caller must call pte_unmap if valid pte returned. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE pte_t * +PgtblVa2PTELocked(struct mm_struct *mm, // IN: Mm structure of a process + VA addr) // IN: Address in the virtual address + // space of that process +{ + return PgtblPGD2PTELocked(compat_pgd_offset(mm, addr), addr); +} + + +/* + *----------------------------------------------------------------------------- + * + * PgtblVa2MPNLocked -- + * + * Retrieve MPN for a given va. + * + * Caller must call pte_unmap if valid pte returned. The mm->page_table_lock + * must be held, so this function is not allowed to schedule() --hpreg + * + * Results: + * INVALID_MPN on failure + * mpn on success + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE MPN +PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process + VA addr) // IN: Address in the virtual address +{ + pte_t *pte; + + pte = PgtblVa2PTELocked(mm, addr); + if (pte != NULL) { + MPN mpn = PgtblPte2MPN(pte); + pte_unmap(pte); + return mpn; + } + return INVALID_MPN; +} + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +/* + *----------------------------------------------------------------------------- + * + * PgtblKVa2MPNLocked -- + * + * Retrieve MPN for a given kernel va. + * + * Caller must call pte_unmap if valid pte returned. The mm->page_table_lock + * must be held, so this function is not allowed to schedule() --hpreg + * + * Results: + * INVALID_MPN on failure + * mpn on success + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE MPN +PgtblKVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a caller + VA addr) // IN: Address in the virtual address +{ + pte_t *pte; + + pte = PgtblPGD2PTELocked(compat_pgd_offset_k(mm, addr), addr); + if (pte != NULL) { + MPN mpn = PgtblPte2MPN(pte); + pte_unmap(pte); + return mpn; + } + return INVALID_MPN; +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * PgtblVa2PageLocked -- + * + * Return the "page" struct for a given va. + * + * Results: + * struct page or NULL. The mm->page_table_lock must be held, so this + * function is not allowed to schedule() --hpreg + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE struct page * +PgtblVa2PageLocked(struct mm_struct *mm, // IN: Mm structure of a process + VA addr) // IN: Address in the virtual address +{ + pte_t *pte; + + pte = PgtblVa2PTELocked(mm, addr); + if (pte != NULL) { + struct page *page = PgtblPte2Page(pte); + pte_unmap(pte); + return page; + } else { + return NULL; + } +} + + +/* + *----------------------------------------------------------------------------- + * + * PgtblVa2MPN -- + * + * Walks through the hardware page tables of the current process to try to + * find the page structure associated to a virtual address. + * + * Results: + * Same as PgtblVa2MPNLocked() + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE int +PgtblVa2MPN(VA addr) // IN +{ + struct mm_struct *mm; + MPN mpn; + + /* current->mm is NULL for kernel threads, so use active_mm. */ + mm = current->compat_active_mm; + if (compat_get_page_table_lock(mm)) { + spin_lock(compat_get_page_table_lock(mm)); + } + mpn = PgtblVa2MPNLocked(mm, addr); + if (compat_get_page_table_lock(mm)) { + spin_unlock(compat_get_page_table_lock(mm)); + } + return mpn; +} + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +/* + *----------------------------------------------------------------------------- + * + * PgtblKVa2MPN -- + * + * Walks through the hardware page tables of the current process to try to + * find the page structure associated to a virtual address. + * + * Results: + * Same as PgtblVa2MPNLocked() + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE int +PgtblKVa2MPN(VA addr) // IN +{ + struct mm_struct *mm; + MPN mpn; + + mm = current->compat_active_mm; + if (compat_get_page_table_lock(mm)) { + spin_lock(compat_get_page_table_lock(mm)); + } + mpn = PgtblKVa2MPNLocked(mm, addr); + if (compat_get_page_table_lock(mm)) { + spin_unlock(compat_get_page_table_lock(mm)); + } + return mpn; +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * PgtblVa2Page -- + * + * Walks through the hardware page tables of the current process to try to + * find the page structure associated to a virtual address. + * + * Results: + * Same as PgtblVa2PageLocked() + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE struct page * +PgtblVa2Page(VA addr) // IN +{ + struct mm_struct *mm; + struct page *page; + + mm = current->compat_active_mm; + if (compat_get_page_table_lock(mm)) { + spin_lock(compat_get_page_table_lock(mm)); + } + page = PgtblVa2PageLocked(mm, addr); + if (compat_get_page_table_lock(mm)) { + spin_unlock(compat_get_page_table_lock(mm)); + } + return page; +} + + +#endif /* __PGTBL_H__ */ diff -Nrup source/vmnet-only/include/smac_compat.h source.edited/vmnet-only/include/smac_compat.h --- source/vmnet-only/include/smac_compat.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/smac_compat.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,63 @@ +/********************************************************* + * Copyright (C) 2005 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 + * + *********************************************************/ + +/* + * smac_compat.h -- + * + * This file defines an abstraction layer to handling + * differences among the Linux kernel and avoiding + * symbol match issues. + */ + +#ifndef _SMAC_COMPAT_H_ +#define _SMAC_COMPAT_H_ + +#include "vm_basic_types.h" + +#if defined(__x86_64__) +#define SMACINT +#else +#define SMACINT __attribute__((cdecl, regparm(3))) +#endif + +void SMACINT SMACL_Memcpy(void *d, const void *s, size_t l); +int SMACINT SMACL_Memcmp(const void *p1, const void *p2, size_t l); +void SMACINT SMACL_Memset(void *p1, int val, size_t l); +void* SMACINT SMACL_Alloc(size_t s); +void SMACINT SMACL_Free(void *p); + +unsigned long SMACINT SMACL_GetUptime(void); + +void SMACINT SMACL_InitSpinlock(void **s); +void SMACINT SMACL_AcquireSpinlock(void **s, unsigned long *flags); +void SMACINT SMACL_ReleaseSpinlock(void **s, unsigned long *flags); + + +struct sk_buff* SMACINT SMACL_DupPacket(struct sk_buff *skb); +void* SMACINT SMACL_PacketData(struct sk_buff *skb); +unsigned int SMACINT SMACL_PacketLength(struct sk_buff *skb); +int SMACINT SMACL_LinearizeSkb(struct sk_buff *skb); +int SMACINT SMACL_IsSkbHostBound(struct sk_buff *skb); +#ifdef DBG +void SMACINT SMACL_Print(const char *m, ...); +void SMACINT SMACL_PrintSkb(struct sk_buff *skb, char *type); +int SMACINT SMACL_Snprintf(char *str, size_t size, const char *format, ...); +#endif /* DBG */ + +#endif /* _SMAC_COMPAT_H */ + diff -Nrup source/vmnet-only/include/smac.h source.edited/vmnet-only/include/smac.h --- source/vmnet-only/include/smac.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/smac.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,109 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +/* + * smac.h -- + * + * This file declares functionality that allows the + * bridge to be used across links that do + * not support promiscuous mode, nor provide the + * ability to transmit ethernet frames whose MAC source + * address does not match the hardware's MAC address. + */ + +#ifndef _SMAC_H_ +#define _SMAC_H_ + +#ifdef _WIN32 +#include "vnetInt.h" +#else /* _WIN32 */ + +#include "vm_basic_types.h" + +/* linux header files include too much garbage, so just define if needed */ +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif /* ETH_ALEN */ + +#ifndef ETH_HLEN +#define ETH_HLEN 14 +#endif /* ETH_HLEN */ + +#endif /* _WIN32 */ + +#if defined __linux__ && !defined __x86_64__ +#define SMACINT __attribute__((cdecl, regparm(3))) +#else +#define SMACINT +#endif + +typedef enum { + PacketStatusTooShort = 0x4546, // insuficient data to process packet + PacketStatusDropPacket, // bridge should drop packet + PacketStatusForwardPacket // bridge should accept/process/forward packet +} PacketStatus; + +struct SMACState; + +void SMACINT +SMAC_InitState(struct SMACState **ptr); // IN: state to alloc/init +void SMACINT +SMAC_SetMac(struct SMACState *state, uint8 *mac); // IN: state, and host MAC +void SMACINT +SMAC_CleanupState(struct SMACState **ptr); // IN: state to cleanup/dealloc + +/* + * Structure is used to separate out differences + * between packets on different OSes. + */ + +#ifdef _WIN32 +/* defines Windows versions of SMACPacket and SMACPackets */ +#include "smac_win.h" +#else /* _WIN32 */ +/* non-WIN32 versions of these structs */ +typedef struct SMACPacket { +#ifdef __linux__ + struct sk_buff *skb; // packet + void *startOfData; // handles non-uniform start of data in sk_buff +#else + mbuf_t m; // packet +#endif +} SMACPacket; + +typedef struct SMACPackets { + SMACPacket orig; // IN: packet + SMACPacket clone; // OUT: packet +} SMACPackets; +#endif /* _WIN32 */ + +PacketStatus SMACINT +SMAC_CheckPacketFromHost(struct SMACState *state, // IN: pointer to smac state + SMACPackets *packets); // IN/OUT: packet(s) to process + +PacketStatus SMACINT +SMAC_CheckPacketToHost(struct SMACState *state, // IN: pointer to smac state + SMACPackets *packets); // IN/OUT: packet(s) to process + +void SMACINT +SMAC_SetForwardUnknownPackets(struct SMACState *state, // IN: pointer to smac state + Bool forwardUnknown); // IN: T/F to forward + +#endif // _SMAC_H_ + + diff -Nrup source/vmnet-only/include/vm_atomic.h source.edited/vmnet-only/include/vm_atomic.h --- source/vmnet-only/include/vm_atomic.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vm_atomic.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,2049 @@ +/********************************************************* + * Copyright (C) 1998 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 + * + *********************************************************/ + +/* + * vm_atomic.h -- + * + * Atomic power + */ + +#ifndef _ATOMIC_H_ +#define _ATOMIC_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMMEXT +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_VMKDRIVERS +#define INCLUDE_ALLOW_VMK_MODULE +#define INCLUDE_ALLOW_VMKERNEL +#define INCLUDE_ALLOW_DISTRIBUTE +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMIROM +#include "includeCheck.h" + +#include "vm_basic_types.h" + + +/* Basic atomic type: 32 bits */ +typedef struct Atomic_uint32 { + volatile uint32 value; +} Atomic_uint32; + + +/* Basic atomic type: 64 bits */ +typedef struct Atomic_uint64 { + volatile uint64 value; +} Atomic_uint64 ALIGNED(8); + + +/* + * Prototypes for msft atomics. These are defined & inlined by the + * compiler so no function definition is needed. The prototypes are + * needed for c++. Since amd64 compiler doesn't support inline asm we + * have to use these. Unfortunately, we still have to use some inline asm + * for the 32 bit code since the and/or/xor implementations didn't show up + * untill xp or 2k3. + * + * The declarations for the intrinsic functions were taken from ntddk.h + * in the DDK. The declarations must match otherwise the 64-bit c++ + * compiler will complain about second linkage of the intrinsic functions. + * We define the intrinsic using the basic types corresponding to the + * Windows typedefs. This avoids having to include windows header files + * to get to the windows types. + */ +#if defined(_MSC_VER) && _MSC_VER >= 1310 +#ifdef __cplusplus +extern "C" { +#endif +long _InterlockedExchange(long volatile*, long); +long _InterlockedCompareExchange(long volatile*, long, long); +long _InterlockedExchangeAdd(long volatile*, long); +long _InterlockedDecrement(long volatile*); +long _InterlockedIncrement(long volatile*); +#pragma intrinsic(_InterlockedExchange, _InterlockedCompareExchange) +#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedDecrement) +#pragma intrinsic(_InterlockedIncrement) + +#if defined(VM_X86_64) +long _InterlockedAnd(long volatile*, long); +__int64 _InterlockedAnd64(__int64 volatile*, __int64); +long _InterlockedOr(long volatile*, long); +__int64 _InterlockedOr64(__int64 volatile*, __int64); +long _InterlockedXor(long volatile*, long); +__int64 _InterlockedXor64(__int64 volatile*, __int64); +__int64 _InterlockedExchangeAdd64(__int64 volatile*, __int64); +__int64 _InterlockedIncrement64(__int64 volatile*); +__int64 _InterlockedDecrement64(__int64 volatile*); +__int64 _InterlockedExchange64(__int64 volatile*, __int64); +__int64 _InterlockedCompareExchange64(__int64 volatile*, __int64, __int64); +#if !defined(_WIN64) +#pragma intrinsic(_InterlockedAnd, _InterlockedAnd64) +#pragma intrinsic(_InterlockedOr, _InterlockedOr64) +#pragma intrinsic(_InterlockedXor, _InterlockedXor64) +#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedIncrement64) +#pragma intrinsic(_InterlockedDecrement64, _InterlockedExchange64) +#pragma intrinsic(_InterlockedCompareExchange64) +#endif /* !_WIN64 */ +#endif /* __x86_64__ */ + +#ifdef __cplusplus +} +#endif +#endif /* _MSC_VER */ + + +/* Convert a volatile int to Atomic_uint32. */ +static INLINE Atomic_uint32 * +Atomic_VolatileToAtomic(volatile uint32 *var) +{ + return (Atomic_uint32 *)var; +} + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Init, Atomic_SetFence, AtomicUseFence -- + * + * Determine whether an lfence intruction is executed after + * every locked instruction. + * + * Certain AMD processes have a bug (see bug 107024) that + * requires an lfence after every locked instruction. + * + * The global variable AtomicUseFence controls whether lfence + * is used (see AtomicEpilogue). + * + * Atomic_SetFence sets AtomicUseFence to the given value. + * + * Atomic_Init computes and sets AtomicUseFence. + * It does not take into account the number of processors. + * + * The rationale for all this complexity is that Atomic_Init + * is the easy-to-use interface. It can be called a number + * of times cheaply, and does not depend on other libraries. + * However, because the number of CPUs is difficult to compute, + * it does without it and always assumes there are more than one. + * + * For programs that care or have special requirements, + * Atomic_SetFence can be called directly, in addition to Atomic_Init. + * It overrides the effect of Atomic_Init, and can be called + * before, after, or between calls to Atomic_Init. + * + *----------------------------------------------------------------------------- + */ + +// The freebsd assembler doesn't know the lfence instruction +#if defined(__GNUC__) && \ + __GNUC__ >= 3 && \ + !defined(BSD_VERSION) && \ + (!defined(MODULE) || defined(__VMKERNEL_MODULE__)) && \ + !defined(__APPLE__) /* PR136775 */ +#define ATOMIC_USE_FENCE +#endif + +#if defined(VMATOMIC_IMPORT_DLLDATA) +VMX86_EXTERN_DATA Bool AtomicUseFence; +#else +EXTERN Bool AtomicUseFence; +#endif + +EXTERN Bool atomicFenceInitialized; + +void AtomicInitFence(void); + +static INLINE void +Atomic_Init(void) +{ +#ifdef ATOMIC_USE_FENCE + if (!atomicFenceInitialized) { + AtomicInitFence(); + } +#endif +} + +static INLINE void +Atomic_SetFence(Bool fenceAfterLock) /* IN: TRUE to enable lfence */ + /* FALSE to disable. */ +{ + AtomicUseFence = fenceAfterLock; +#if defined(__VMKERNEL__) + extern void Atomic_SetFenceVMKAPI(Bool fenceAfterLock); + Atomic_SetFenceVMKAPI(fenceAfterLock); +#endif + atomicFenceInitialized = TRUE; +} + + +/* Conditionally execute fence after interlocked instruction. */ +static INLINE void +AtomicEpilogue(void) +{ +#ifdef ATOMIC_USE_FENCE + if (UNLIKELY(AtomicUseFence)) { + asm volatile ("lfence" ::: "memory"); + } +#endif +} + + +/* + * All the assembly code is tricky and written conservatively. + * For example, to make sure gcc won't introduce copies, + * we force the addressing mode like this: + * + * "xchgl %0, (%1)" + * : "=r" (val) + * : "r" (&var->value), + * "0" (val) + * : "memory" + * + * - edward + * + * Actually - turns out that gcc never generates memory aliases (it + * still does generate register aliases though), so we can be a bit + * more agressive with the memory constraints. The code above can be + * modified like this: + * + * "xchgl %0, %1" + * : "=r" (val), + * "=m" (var->value), + * : "0" (val), + * "1" (var->value) + * + * The advantages are that gcc can use whatever addressing mode it + * likes to access the memory value, and that we dont have to use a + * way-too-generic "memory" clobber as there is now an explicit + * declaration that var->value is modified. + * + * see also /usr/include/asm/atomic.h to convince yourself this is a + * valid optimization. + * + * - walken + */ + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Read -- + * + * Read + * + * Results: + * The value of the atomic variable. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint32 +Atomic_Read(Atomic_uint32 const *var) // IN +{ + return var->value; +} +#define Atomic_Read32 Atomic_Read + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Write -- + * + * Write + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Write(Atomic_uint32 *var, // IN + uint32 val) // IN +{ + var->value = val; +} +#define Atomic_Write32 Atomic_Write + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_ReadWrite -- + * + * Read followed by write + * + * Results: + * The value of the atomic variable before the write. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint32 +Atomic_ReadWrite(Atomic_uint32 *var, // IN + uint32 val) // IN +#ifdef __GNUC__ +{ + /* Checked against the Intel manual and GCC --walken */ + __asm__ __volatile__( + "xchgl %0, %1" +# if VM_ASM_PLUS + : "=r" (val), + "+m" (var->value) + : "0" (val) +# else + : "=r" (val), + "=m" (var->value) + : "0" (val), + "1" (var->value) +# endif + ); + AtomicEpilogue(); + return val; +} +#elif defined(_MSC_VER) && _MSC_VER >= 1310 +{ + return _InterlockedExchange((long *)&var->value, (long)val); +} +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4035) // disable no-return warning +{ + __asm mov eax, val + __asm mov ebx, var + __asm xchg [ebx]Atomic_uint32.value, eax + // eax is the return value, this is documented to work - edward +} +#pragma warning(pop) +#else +#error No compiler defined for Atomic_ReadWrite +#endif +#define Atomic_ReadWrite32 Atomic_ReadWrite + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_ReadIfEqualWrite -- + * + * Compare exchange: Read variable, if equal to oldVal, write newVal + * + * Results: + * The value of the atomic variable before the write. + * + * Side effects: + * The variable may be modified. + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint32 +Atomic_ReadIfEqualWrite(Atomic_uint32 *var, // IN + uint32 oldVal, // IN + uint32 newVal) // IN +#ifdef __GNUC__ +{ + uint32 val; + + /* Checked against the Intel manual and GCC --walken */ + __asm__ __volatile__( + "lock; cmpxchgl %2, %1" +# if VM_ASM_PLUS + : "=a" (val), + "+m" (var->value) + : "r" (newVal), + "0" (oldVal) +# else + : "=a" (val), + "=m" (var->value) + : "r" (newVal), + "0" (oldVal) + /* + * "1" (var->value): results in inconsistent constraints on gcc 2.7.2.3 + * when compiling enterprise-2.2.17-14-RH7.0-update. + * The constraint has been commented out for now. We may consider doing + * this systematically, but we need to be sure it is the right thing to + * do. However, it is also possible that the offending use of this asm + * function will be removed in the near future in which case we may + * decide to reintroduce the constraint instead. hpreg & agesen. + */ +# endif + : "cc" + ); + AtomicEpilogue(); + return val; +} +#elif defined(_MSC_VER) && _MSC_VER >= 1310 +{ + return _InterlockedCompareExchange((long *)&var->value, + (long)newVal, + (long)oldVal); +} +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4035) // disable no-return warning +{ + __asm mov eax, oldVal + __asm mov ebx, var + __asm mov ecx, newVal + __asm lock cmpxchg [ebx]Atomic_uint32.value, ecx + // eax is the return value, this is documented to work - edward +} +#pragma warning(pop) +#else +#error No compiler defined for Atomic_ReadIfEqualWrite +#endif +#define Atomic_ReadIfEqualWrite32 Atomic_ReadIfEqualWrite + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_ReadIfEqualWrite64 -- + * + * Compare exchange: Read variable, if equal to oldVal, write newVal + * + * Results: + * The value of the atomic variable before the write. + * + * Side effects: + * The variable may be modified. + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint64 +Atomic_ReadIfEqualWrite64(Atomic_uint64 *var, // IN + uint64 oldVal, // IN + uint64 newVal) // IN +{ +#if defined(__GNUC__) + uint64 val; + + /* Checked against the AMD manual and GCC --hpreg */ + __asm__ __volatile__( + "lock; cmpxchgq %2, %1" + : "=a" (val), + "+m" (var->value) + : "r" (newVal), + "0" (oldVal) + : "cc" + ); + AtomicEpilogue(); + return val; +#elif defined(_MSC_VER) + return _InterlockedCompareExchange64((__int64 *)&var->value, + (__int64)newVal, + (__int64)oldVal); +#else +#error No compiler defined for Atomic_ReadIfEqualWrite64 +#endif +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_And -- + * + * Atomic read, bitwise AND with a value, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_And(Atomic_uint32 *var, // IN + uint32 val) // IN +{ +#ifdef __GNUC__ + /* Checked against the Intel manual and GCC --walken */ + __asm__ __volatile__( + "lock; andl %1, %0" +# if VM_ASM_PLUS + : "+m" (var->value) + : "ri" (val) +# else + : "=m" (var->value) + : "ri" (val), + "0" (var->value) +# endif + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) +#if defined(__x86_64__) + _InterlockedAnd((long *)&var->value, (long)val); +#else + __asm mov eax, val + __asm mov ebx, var + __asm lock and [ebx]Atomic_uint32.value, eax +#endif +#else +#error No compiler defined for Atomic_And +#endif +} +#define Atomic_And32 Atomic_And + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_And64 -- + * + * Atomic read, bitwise AND with a value, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_And64(Atomic_uint64 *var, // IN + uint64 val) // IN +{ +#if defined(__GNUC__) + /* Checked against the AMD manual and GCC --hpreg */ + __asm__ __volatile__( + "lock; andq %1, %0" + : "+m" (var->value) + : "ri" (val) + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) + _InterlockedAnd64((__int64 *)&var->value, (__int64)val); +#else +#error No compiler defined for Atomic_And64 +#endif +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Or -- + * + * Atomic read, bitwise OR with a value, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Or(Atomic_uint32 *var, // IN + uint32 val) // IN +{ +#ifdef __GNUC__ + /* Checked against the Intel manual and GCC --walken */ + __asm__ __volatile__( + "lock; orl %1, %0" +# if VM_ASM_PLUS + : "+m" (var->value) + : "ri" (val) +# else + : "=m" (var->value) + : "ri" (val), + "0" (var->value) +# endif + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) +#if defined(__x86_64__) + _InterlockedOr((long *)&var->value, (long)val); +#else + __asm mov eax, val + __asm mov ebx, var + __asm lock or [ebx]Atomic_uint32.value, eax +#endif +#else +#error No compiler defined for Atomic_Or +#endif +} +#define Atomic_Or32 Atomic_Or + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_Or64 -- + * + * Atomic read, bitwise OR with a value, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Or64(Atomic_uint64 *var, // IN + uint64 val) // IN +{ +#if defined(__GNUC__) + /* Checked against the AMD manual and GCC --hpreg */ + __asm__ __volatile__( + "lock; orq %1, %0" + : "+m" (var->value) + : "ri" (val) + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) + _InterlockedOr64((__int64 *)&var->value, (__int64)val); +#else +#error No compiler defined for Atomic_Or64 +#endif +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Xor -- + * + * Atomic read, bitwise XOR with a value, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Xor(Atomic_uint32 *var, // IN + uint32 val) // IN +{ +#ifdef __GNUC__ + /* Checked against the Intel manual and GCC --walken */ + __asm__ __volatile__( + "lock; xorl %1, %0" +# if VM_ASM_PLUS + : "+m" (var->value) + : "ri" (val) +# else + : "=m" (var->value) + : "ri" (val), + "0" (var->value) +# endif + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) +#if defined(__x86_64__) + _InterlockedXor((long *)&var->value, (long)val); +#else + __asm mov eax, val + __asm mov ebx, var + __asm lock xor [ebx]Atomic_uint32.value, eax +#endif +#else +#error No compiler defined for Atomic_Xor +#endif +} +#define Atomic_Xor32 Atomic_Xor + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_Xor64 -- + * + * Atomic read, bitwise XOR with a value, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Xor64(Atomic_uint64 *var, // IN + uint64 val) // IN +{ +#if defined(__GNUC__) + /* Checked against the AMD manual and GCC --hpreg */ + __asm__ __volatile__( + "lock; xorq %1, %0" + : "+m" (var->value) + : "ri" (val) + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) + _InterlockedXor64((__int64 *)&var->value, (__int64)val); +#else +#error No compiler defined for Atomic_Xor64 +#endif +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Add -- + * + * Atomic read, add a value, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Add(Atomic_uint32 *var, // IN + uint32 val) // IN +{ +#ifdef __GNUC__ + /* Checked against the Intel manual and GCC --walken */ + __asm__ __volatile__( + "lock; addl %1, %0" +# if VM_ASM_PLUS + : "+m" (var->value) + : "ri" (val) +# else + : "=m" (var->value) + : "ri" (val), + "0" (var->value) +# endif + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) && _MSC_VER >= 1310 + _InterlockedExchangeAdd((long *)&var->value, (long)val); +#elif defined(_MSC_VER) + __asm mov eax, val + __asm mov ebx, var + __asm lock add [ebx]Atomic_uint32.value, eax +#else +#error No compiler defined for Atomic_Add +#endif +} +#define Atomic_Add32 Atomic_Add + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_Add64 -- + * + * Atomic read, add a value, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Add64(Atomic_uint64 *var, // IN + uint64 val) // IN +{ +#if defined(__GNUC__) + /* Checked against the AMD manual and GCC --hpreg */ + __asm__ __volatile__( + "lock; addq %1, %0" + : "+m" (var->value) + : "ri" (val) + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) + _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)val); +#else +#error No compiler defined for Atomic_Add64 +#endif +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Sub -- + * + * Atomic read, subtract a value, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Sub(Atomic_uint32 *var, // IN + uint32 val) // IN +{ +#ifdef __GNUC__ + /* Checked against the Intel manual and GCC --walken */ + __asm__ __volatile__( + "lock; subl %1, %0" +# if VM_ASM_PLUS + : "+m" (var->value) + : "ri" (val) +# else + : "=m" (var->value) + : "ri" (val), + "0" (var->value) +# endif + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) && _MSC_VER >= 1310 + _InterlockedExchangeAdd((long *)&var->value, (long)-val); +#elif defined(_MSC_VER) + __asm mov eax, val + __asm mov ebx, var + __asm lock sub [ebx]Atomic_uint32.value, eax +#else +#error No compiler defined for Atomic_Sub +#endif +} +#define Atomic_Sub32 Atomic_Sub + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_Sub64 -- + * + * Atomic read, subtract a value, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Sub64(Atomic_uint64 *var, // IN + uint64 val) // IN +{ +#ifdef __GNUC__ + /* Checked against the AMD manual and GCC --hpreg */ + __asm__ __volatile__( + "lock; subq %1, %0" + : "+m" (var->value) + : "ri" (val) + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) + _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)-val); +#else +#error No compiler defined for Atomic_Sub64 +#endif +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Inc -- + * + * Atomic read, increment, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Inc(Atomic_uint32 *var) // IN +{ +#ifdef __GNUC__ + /* Checked against the Intel manual and GCC --walken */ + __asm__ __volatile__( + "lock; incl %0" +# if VM_ASM_PLUS + : "+m" (var->value) + : +# else + : "=m" (var->value) + : "0" (var->value) +# endif + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) && _MSC_VER >= 1310 + _InterlockedIncrement((long *)&var->value); +#elif defined(_MSC_VER) + __asm mov ebx, var + __asm lock inc [ebx]Atomic_uint32.value +#else +#error No compiler defined for Atomic_Inc +#endif +} +#define Atomic_Inc32 Atomic_Inc + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_Inc64 -- + * + * Atomic read, increment, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Inc64(Atomic_uint64 *var) // IN +{ +#if defined(__GNUC__) + /* Checked against the AMD manual and GCC --hpreg */ + __asm__ __volatile__( + "lock; incq %0" + : "+m" (var->value) + : + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) + _InterlockedIncrement64((__int64 *)&var->value); +#else +#error No compiler defined for Atomic_Inc64 +#endif +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Dec -- + * + * Atomic read, decrement, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Dec(Atomic_uint32 *var) // IN +{ +#ifdef __GNUC__ + /* Checked against the Intel manual and GCC --walken */ + __asm__ __volatile__( + "lock; decl %0" +# if VM_ASM_PLUS + : "+m" (var->value) + : +# else + : "=m" (var->value) + : "0" (var->value) +# endif + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) && _MSC_VER >= 1310 + _InterlockedDecrement((long *)&var->value); +#elif defined(_MSC_VER) + __asm mov ebx, var + __asm lock dec [ebx]Atomic_uint32.value +#else +#error No compiler defined for Atomic_Dec +#endif +} +#define Atomic_Dec32 Atomic_Dec + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_Dec64 -- + * + * Atomic read, decrement, write. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Dec64(Atomic_uint64 *var) // IN +{ +#if defined(__GNUC__) + /* Checked against the AMD manual and GCC --hpreg */ + __asm__ __volatile__( + "lock; decq %0" + : "+m" (var->value) + : + : "cc" + ); + AtomicEpilogue(); +#elif defined(_MSC_VER) + _InterlockedDecrement64((__int64 *)&var->value); +#else +#error No compiler defined for Atomic_Dec64 +#endif +} +#endif + + +/* + * Note that the technique below can be used to implement ReadX(), where X is + * an arbitrary mathematical function. + */ + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_FetchAndOr -- + * + * Atomic read (returned), bitwise OR with a value, write. + * + * Results: + * The value of the variable before the operation. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint32 +Atomic_FetchAndOr(Atomic_uint32 *var, // IN + uint32 val) // IN +{ + uint32 res; + + do { + res = var->value; + } while (res != Atomic_ReadIfEqualWrite(var, res, res | val)); + + return res; +} + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_FetchAndAnd -- + * + * Atomic read (returned), bitwise And with a value, write. + * + * Results: + * The value of the variable before the operation. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint32 +Atomic_FetchAndAnd(Atomic_uint32 *var, // IN + uint32 val) // IN +{ + uint32 res; + + do { + res = var->value; + } while (res != Atomic_ReadIfEqualWrite(var, res, res & val)); + + return res; +} +#define Atomic_ReadOr32 Atomic_FetchAndOr + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_ReadOr64 -- + * + * Atomic read (returned), bitwise OR with a value, write. + * + * Results: + * The value of the variable before the operation. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint64 +Atomic_ReadOr64(Atomic_uint64 *var, // IN + uint64 val) // IN +{ + uint64 res; + + do { + res = var->value; + } while (res != Atomic_ReadIfEqualWrite64(var, res, res | val)); + + return res; +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_FetchAndAddUnfenced -- + * + * Atomic read (returned), add a value, write. + * + * If you have to implement FetchAndAdd() on an architecture other than + * x86 or x86-64, you might want to consider doing something similar to + * Atomic_FetchAndOr(). + * + * The "Unfenced" version of Atomic_FetchAndInc never executes + * "lfence" after the interlocked operation. + * + * Results: + * The value of the variable before the operation. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint32 +Atomic_FetchAndAddUnfenced(Atomic_uint32 *var, // IN + uint32 val) // IN +#ifdef __GNUC__ +{ + /* Checked against the Intel manual and GCC --walken */ + __asm__ __volatile__( +# if VM_ASM_PLUS + "lock; xaddl %0, %1" + : "=r" (val), + "+m" (var->value) + : "0" (val) + : "cc" +# else + "lock; xaddl %0, (%1)" + : "=r" (val) + : "r" (&var->value), + "0" (val) + : "cc", "memory" +# endif + ); + return val; +} +#elif defined(_MSC_VER) && _MSC_VER >= 1310 +{ + return _InterlockedExchangeAdd((long *)&var->value, (long)val); +} +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4035) // disable no-return warning +{ + __asm mov eax, val + __asm mov ebx, var + __asm lock xadd [ebx]Atomic_uint32.value, eax +} +#pragma warning(pop) +#else +#error No compiler defined for Atomic_FetchAndAdd +#endif +#define Atomic_ReadAdd32 Atomic_FetchAndAdd + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_FetchAndAdd -- + * + * Atomic read (returned), add a value, write. + * + * If you have to implement FetchAndAdd() on an architecture other than + * x86 or x86-64, you might want to consider doing something similar to + * Atomic_FetchAndOr(). + * + * Unlike "Unfenced" version, this one may execute the "lfence" after + * interlocked operation. + * + * Results: + * The value of the variable before the operation. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint32 +Atomic_FetchAndAdd(Atomic_uint32 *var, // IN + uint32 val) // IN +#ifdef __GNUC__ +{ + val = Atomic_FetchAndAddUnfenced(var, val); + AtomicEpilogue(); + return val; +} +#else +{ + return Atomic_FetchAndAddUnfenced(var, val); +} +#endif + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_ReadAdd64 -- + * + * Atomic read (returned), add a value, write. + * + * Results: + * The value of the variable before the operation. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint64 +Atomic_ReadAdd64(Atomic_uint64 *var, // IN + uint64 val) // IN +{ +#if defined(__GNUC__) + /* Checked against the AMD manual and GCC --hpreg */ + __asm__ __volatile__( + "lock; xaddq %0, %1" + : "=r" (val), + "+m" (var->value) + : "0" (val) + : "cc" + ); + AtomicEpilogue(); + return val; +#elif defined(_MSC_VER) + return _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)val); +#else +#error No compiler defined for Atomic_ReadAdd64 +#endif +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_FetchAndInc -- + * + * Atomic read (returned), increment, write. + * + * Results: + * The value of the variable before the operation. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint32 +Atomic_FetchAndInc(Atomic_uint32 *var) // IN +{ + return Atomic_FetchAndAdd(var, 1); +} +#define Atomic_ReadInc32 Atomic_FetchAndInc + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_ReadInc64 -- + * + * Atomic read (returned), increment, write. + * + * Results: + * The value of the variable before the operation. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint64 +Atomic_ReadInc64(Atomic_uint64 *var) // IN +{ + return Atomic_ReadAdd64(var, 1); +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_FetchAndDec -- + * + * Atomic read (returned), decrement, write. + * + * Results: + * The value of the variable before the operation. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint32 +Atomic_FetchAndDec(Atomic_uint32 *var) // IN +{ + return Atomic_FetchAndAdd(var, (uint32)-1); +} +#define Atomic_ReadDec32 Atomic_FetchAndDec + + +#if defined(__x86_64__) +/* + *----------------------------------------------------------------------------- + * + * Atomic_ReadDec64 -- + * + * Atomic read (returned), decrement, write. + * + * Results: + * The value of the variable before the operation. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint64 +Atomic_ReadDec64(Atomic_uint64 *var) // IN +{ + return Atomic_ReadAdd64(var, CONST64U(-1)); +} +#endif + + +/* + * Usage of this helper struct is strictly reserved to the following + * function. --hpreg + */ +typedef struct { + uint32 lowValue; + uint32 highValue; +} S_uint64; + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_CMPXCHG64 -- + * + * Compare exchange: Read variable, if equal to oldVal, write newVal + * + * XXX: Ensure that if this function is to be inlined by gcc, it is + * compiled with -fno-strict-aliasing. Otherwise it will break. + * Unfortunately we know that gcc 2.95.3 (used to build the FreeBSD 3.2 + * Tools) does not honor -fno-strict-aliasing. As a workaround, we avoid + * inlining the function entirely for versions of gcc under 3.0. + * + * Results: + * TRUE if equal, FALSE if not equal + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +#if defined(__GNUC__) && __GNUC__ < 3 +static Bool +#else +static INLINE Bool +#endif +Atomic_CMPXCHG64(Atomic_uint64 *var, // IN/OUT + uint64 const *oldVal, // IN + uint64 const *newVal) // IN +#ifdef __GNUC__ +{ + Bool equal; + + /* Checked against the Intel manual and GCC --walken */ +#ifdef VMM64 + uint64 dummy; + __asm__ __volatile__( + "lock; cmpxchgq %3, %0" "\n\t" + "sete %1" + : "+m" (*var), + "=qm" (equal), + "=a" (dummy) + : "r" (*newVal), + "2" (*oldVal) + : "cc" + ); +#else /* 32-bit version */ + int dummy1, dummy2; +# if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. +# if defined __GNUC__ && __GNUC__ < 3 // Part of #188541 - for RHL 6.2 etc. + __asm__ __volatile__( + "xchg %%ebx, %6\n\t" + "mov (%%ebx), %%ecx\n\t" + "mov (%%ebx), %%ebx\n\t" + "lock; cmpxchg8b (%3)\n\t" + "xchg %%ebx, %6\n\t" + "sete %0" + : "=a" (equal), "=d" (dummy2), "=D" (dummy1) + : "S" (var), "0" (((S_uint64 const *)oldVal)->lowValue), + "1" (((S_uint64 const *)oldVal)->highValue), "D" (newVal) + : "ecx", "cc", "memory" + ); +# else + __asm__ __volatile__( + "xchgl %%ebx, %6" "\n\t" + // %3 is a register to make sure it cannot be %ebx-relative. + "lock; cmpxchg8b (%3)" "\n\t" + "xchgl %%ebx, %6" "\n\t" + // Must come after restoring %ebx: %0 could be %ebx-relative. + "sete %0" + : "=qm" (equal), + "=a" (dummy1), + "=d" (dummy2) + : "r" (var), + "1" (((S_uint64 const *)oldVal)->lowValue), + "2" (((S_uint64 const *)oldVal)->highValue), + // Cannot use "m" here: 'newVal' is read-only. + "r" (((S_uint64 const *)newVal)->lowValue), + "c" (((S_uint64 const *)newVal)->highValue) + : "cc", "memory" + ); +# endif +# else + __asm__ __volatile__( + "lock; cmpxchg8b %0" "\n\t" + "sete %1" +# if VM_ASM_PLUS + : "+m" (*var), +# else + : "=m" (*var), +# endif + "=qm" (equal), + "=a" (dummy1), + "=d" (dummy2) + : "2" (((S_uint64 const *)oldVal)->lowValue), + "3" (((S_uint64 const *)oldVal)->highValue), + "b" (((S_uint64 const *)newVal)->lowValue), + "c" (((S_uint64 const *)newVal)->highValue) + : "cc" + ); +# endif +#endif + AtomicEpilogue(); + return equal; +} +#elif defined(_MSC_VER) +#if defined(__x86_64__) +{ + return *oldVal == _InterlockedCompareExchange64((__int64 *)&var->value, + (__int64)*newVal, + (__int64)*oldVal); +} +#else +#pragma warning(push) +#pragma warning(disable : 4035) // disable no-return warning +{ + __asm mov esi, var + __asm mov edx, oldVal + __asm mov ecx, newVal + __asm mov eax, [edx]S_uint64.lowValue + __asm mov edx, [edx]S_uint64.highValue + __asm mov ebx, [ecx]S_uint64.lowValue + __asm mov ecx, [ecx]S_uint64.highValue + __asm lock cmpxchg8b [esi] + __asm sete al + __asm movzx eax, al + // eax is the return value, this is documented to work - edward +} +#pragma warning(pop) +#endif +#else +#error No compiler defined for Atomic_CMPXCHG64 +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_CMPXCHG32 -- + * + * Compare exchange: Read variable, if equal to oldVal, write newVal + * + * Results: + * TRUE if equal, FALSE if not equal + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE Bool +Atomic_CMPXCHG32(Atomic_uint32 *var, // IN/OUT + uint32 oldVal, // IN + uint32 newVal) // IN +{ +#ifdef __GNUC__ + Bool equal; + + uint32 dummy; + __asm__ __volatile__( + "lock; cmpxchgl %3, %0" "\n\t" + "sete %1" +# if VM_ASM_PLUS + : "+m" (*var), + "=qm" (equal), + "=a" (dummy) + : "r" (newVal), + "2" (oldVal) +# else + : "=m" (*var), + "=qm" (equal), + "=a" (dummy) + : /*"0" (*var), */ + "r" (newVal), + "2" (oldVal) +# endif + : "cc" + ); + AtomicEpilogue(); + return equal; +#else + return (Atomic_ReadIfEqualWrite(var, oldVal, newVal) == oldVal); +#endif +} + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Read64 -- + * + * Read and return. + * + * Results: + * The value of the atomic variable. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint64 +Atomic_Read64(Atomic_uint64 const *var) // IN +#if defined(__x86_64__) +{ + return var->value; +} +#elif defined(__GNUC__) && defined(__i386__) /* GCC on x86 */ +{ + uint64 value; + /* + * Since cmpxchg8b will replace the contents of EDX:EAX with the + * value in memory if there is no match, we need only execute the + * instruction once in order to atomically read 64 bits from + * memory. The only constraint is that ECX:EBX must have the same + * value as EDX:EAX so that if the comparison succeeds. We + * intentionally don't tell gcc that we are using ebx and ecx as we + * don't modify them and do not care what value they store. + */ + __asm__ __volatile__( + "mov %%ebx, %%eax" "\n\t" + "mov %%ecx, %%edx" "\n\t" + "lock; cmpxchg8b %1" + : "=&A" (value) + : "m" (*var) + : "cc" + ); + AtomicEpilogue(); + return value; +} +#elif defined(_MSC_VER) /* MSC (assume on x86 for now) */ +# pragma warning(push) +# pragma warning(disable : 4035) // disable no-return warning +{ + __asm mov ecx, var + __asm mov edx, ecx + __asm mov eax, ebx + __asm lock cmpxchg8b [ecx] + // edx:eax is the return value; this is documented to work. --mann +} +# pragma warning(pop) +#else +# error No compiler defined for Atomic_Read64 +#endif + + +/* + *---------------------------------------------------------------------- + * + * Atomic_FetchAndAdd64 -- + * + * Atomically adds a 64-bit integer to another + * + * Results: + * Returns the old value just prior to the addition + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +static INLINE uint64 +Atomic_FetchAndAdd64(Atomic_uint64 *var, // IN/OUT + uint64 addend) // IN +{ + uint64 oldVal; + uint64 newVal; + + do { + oldVal = var->value; + newVal = oldVal + addend; + } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); + + return oldVal; +} + + +/* + *---------------------------------------------------------------------- + * + * Atomic_FetchAndInc64 -- + * + * Atomically increments a 64-bit integer + * + * Results: + * Returns the old value just prior to incrementing + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +static INLINE uint64 +Atomic_FetchAndInc64(Atomic_uint64 *var) // IN/OUT +{ + return Atomic_FetchAndAdd64(var, 1); +} + + +/* + *---------------------------------------------------------------------- + * + * Atomic_FetchAndDec64 -- + * + * Atomically decrements a 64-bit integer + * + * Results: + * Returns the old value just prior to decrementing + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +static INLINE uint64 +Atomic_FetchAndDec64(Atomic_uint64 *var) // IN/OUT +{ + uint64 oldVal; + uint64 newVal; + + do { + oldVal = var->value; + newVal = oldVal - 1; + } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); + + return oldVal; +} + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_ReadWrite64 -- + * + * Read followed by write + * + * Results: + * The value of the atomic variable before the write. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE uint64 +Atomic_ReadWrite64(Atomic_uint64 *var, // IN + uint64 val) // IN +{ +#if defined(__x86_64__) +#if defined(__GNUC__) + /* Checked against the AMD manual and GCC --hpreg */ + __asm__ __volatile__( + "xchgq %0, %1" + : "=r" (val), + "+m" (var->value) + : "0" (val) + ); + AtomicEpilogue(); + return val; +#elif defined(_MSC_VER) + return _InterlockedExchange64((__int64 *)&var->value, (__int64)val); +#else +#error No compiler defined for Atomic_ReadWrite64 +#endif +#else + uint64 oldVal; + + do { + oldVal = var->value; + } while (!Atomic_CMPXCHG64(var, &oldVal, &val)); + + return oldVal; +#endif +} + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_Write64 -- + * + * Write + * + * Results: + * None. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_Write64(Atomic_uint64 *var, // IN + uint64 val) // IN +{ +#if defined(__x86_64__) + var->value = val; +#else + (void)Atomic_ReadWrite64(var, val); +#endif +} + + +/* + * Template code for the Atomic_ type and its operators. + * + * The cast argument is an intermedia type cast to make some + * compilers stop complaining about casting uint32 <-> void *, + * even though we only do it in the 32-bit case so they are always + * the same size. So for val of type uint32, instead of + * (void *)val, we have (void *)(uintptr_t)val. + * The specific problem case is the Windows ddk compiler + * (as used by the SVGA driver). -- edward + */ + +#define MAKE_ATOMIC_TYPE(name, size, in, out, cast) \ + typedef Atomic_uint ## size Atomic_ ## name; \ + \ + \ + static INLINE out \ + Atomic_Read ## name(Atomic_ ## name const *var) \ + { \ + return (out)(cast)Atomic_Read ## size(var); \ + } \ + \ + \ + static INLINE void \ + Atomic_Write ## name(Atomic_ ## name *var, \ + in val) \ + { \ + Atomic_Write ## size(var, (uint ## size)(cast)val); \ + } \ + \ + \ + static INLINE out \ + Atomic_ReadWrite ## name(Atomic_ ## name *var, \ + in val) \ + { \ + return (out)(cast)Atomic_ReadWrite ## size(var, \ + (uint ## size)(cast)val); \ + } \ + \ + \ + static INLINE out \ + Atomic_ReadIfEqualWrite ## name(Atomic_ ## name *var, \ + in oldVal, \ + in newVal) \ + { \ + return (out)(cast)Atomic_ReadIfEqualWrite ## size(var, \ + (uint ## size)(cast)oldVal, (uint ## size)(cast)newVal); \ + } \ + \ + \ + static INLINE void \ + Atomic_And ## name(Atomic_ ## name *var, \ + in val) \ + { \ + Atomic_And ## size(var, (uint ## size)(cast)val); \ + } \ + \ + \ + static INLINE void \ + Atomic_Or ## name(Atomic_ ## name *var, \ + in val) \ + { \ + Atomic_Or ## size(var, (uint ## size)(cast)val); \ + } \ + \ + \ + static INLINE void \ + Atomic_Xor ## name(Atomic_ ## name *var, \ + in val) \ + { \ + Atomic_Xor ## size(var, (uint ## size)(cast)val); \ + } \ + \ + \ + static INLINE void \ + Atomic_Add ## name(Atomic_ ## name *var, \ + in val) \ + { \ + Atomic_Add ## size(var, (uint ## size)(cast)val); \ + } \ + \ + \ + static INLINE void \ + Atomic_Sub ## name(Atomic_ ## name *var, \ + in val) \ + { \ + Atomic_Sub ## size(var, (uint ## size)(cast)val); \ + } \ + \ + \ + static INLINE void \ + Atomic_Inc ## name(Atomic_ ## name *var) \ + { \ + Atomic_Inc ## size(var); \ + } \ + \ + \ + static INLINE void \ + Atomic_Dec ## name(Atomic_ ## name *var) \ + { \ + Atomic_Dec ## size(var); \ + } \ + \ + \ + static INLINE out \ + Atomic_ReadOr ## name(Atomic_ ## name *var, \ + in val) \ + { \ + return (out)(cast)Atomic_ReadOr ## size(var, (uint ## size)(cast)val); \ + } \ + \ + \ + static INLINE out \ + Atomic_ReadAdd ## name(Atomic_ ## name *var, \ + in val) \ + { \ + return (out)(cast)Atomic_ReadAdd ## size(var, (uint ## size)(cast)val); \ + } \ + \ + \ + static INLINE out \ + Atomic_ReadInc ## name(Atomic_ ## name *var) \ + { \ + return (out)(cast)Atomic_ReadInc ## size(var); \ + } \ + \ + \ + static INLINE out \ + Atomic_ReadDec ## name(Atomic_ ## name *var) \ + { \ + return (out)(cast)Atomic_ReadDec ## size(var); \ + } + + +/* + * Since we use a macro to generate these definitions, it is hard to look for + * them. So DO NOT REMOVE THIS COMMENT and keep it up-to-date. --hpreg + * + * Atomic_Ptr + * Atomic_ReadPtr -- + * Atomic_WritePtr -- + * Atomic_ReadWritePtr -- + * Atomic_ReadIfEqualWritePtr -- + * Atomic_AndPtr -- + * Atomic_OrPtr -- + * Atomic_XorPtr -- + * Atomic_AddPtr -- + * Atomic_SubPtr -- + * Atomic_IncPtr -- + * Atomic_DecPtr -- + * Atomic_ReadOrPtr -- + * Atomic_ReadAddPtr -- + * Atomic_ReadIncPtr -- + * Atomic_ReadDecPtr -- + * + * Atomic_Int + * Atomic_ReadInt -- + * Atomic_WriteInt -- + * Atomic_ReadWriteInt -- + * Atomic_ReadIfEqualWriteInt -- + * Atomic_AndInt -- + * Atomic_OrInt -- + * Atomic_XorInt -- + * Atomic_AddInt -- + * Atomic_SubInt -- + * Atomic_IncInt -- + * Atomic_DecInt -- + * Atomic_ReadOrInt -- + * Atomic_ReadAddInt -- + * Atomic_ReadIncInt -- + * Atomic_ReadDecInt -- + */ +#if defined(__x86_64__) +MAKE_ATOMIC_TYPE(Ptr, 64, void const *, void *, uintptr_t) +MAKE_ATOMIC_TYPE(Int, 64, int, int, int) +#else +MAKE_ATOMIC_TYPE(Ptr, 32, void const *, void *, uintptr_t) +MAKE_ATOMIC_TYPE(Int, 32, int, int, int) +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Atomic_MFence -- + * + * Implements mfence in terms of a lock xor. The reason for implementing + * our own mfence is that not all of our supported cpus have an assembly + * mfence (P3, Athlon). We put it here to avoid duplicating code which is + * also why it is prefixed with "Atomic_". + * + * Results: + * None. + * + * Side effects: + * Cause loads and stores prior to this to be globally + * visible. + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Atomic_MFence(void) +{ + Atomic_uint32 fence; + Atomic_Xor(&fence, 0x1); +} + +#endif // ifndef _ATOMIC_H_ diff -Nrup source/vmnet-only/include/vm_basic_asm.h source.edited/vmnet-only/include/vm_basic_asm.h --- source/vmnet-only/include/vm_basic_asm.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vm_basic_asm.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,832 @@ +/********************************************************* + * Copyright (C) 2003 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 + * + *********************************************************/ + +/* + * vm_basic_asm.h + * + * Basic asm macros + */ + +#ifndef _VM_BASIC_ASM_H_ +#define _VM_BASIC_ASM_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMMEXT +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_VMK_MODULE +#define INCLUDE_ALLOW_VMKERNEL +#define INCLUDE_ALLOW_DISTRIBUTE +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMIROM +#include "includeCheck.h" + +#include "vm_basic_types.h" +#include "x86cpuid.h" + +#ifdef VM_X86_64 +#include "vm_basic_asm_x86_64.h" +#else +#include "vm_basic_asm_x86.h" +#endif + + +/* + * x86-64 windows doesn't support inline asm so we have to use these + * intrinsic functions defined in the compiler. Not all of these are well + * documented. There is an array in the compiler dll (c1.dll) which has + * an array of the names of all the intrinsics minus the leading + * underscore. Searching around in the ntddk.h file can also be helpful. + * + * The declarations for the intrinsic functions were taken from the DDK. + * Our declarations must match the ddk's otherwise the 64-bit c++ compiler + * will complain about second linkage of the intrinsic functions. + * We define the intrinsic using the basic types corresponding to the + * Windows typedefs. This avoids having to include windows header files + * to get to the windows types. + */ +#ifdef _MSC_VER +#ifdef __cplusplus +extern "C" { +#endif +/* + * It seems x86 & x86-64 windows still implements these intrinsic + * functions. The documentation for the x86-64 suggest the + * __inbyte/__outbyte intrinsics eventhough the _in/_out work fine and + * __inbyte/__outbyte aren't supported on x86. + */ +int _inp(unsigned short); +unsigned short _inpw(unsigned short); +unsigned long _inpd(unsigned short); + +int _outp(unsigned short, int); +unsigned short _outpw(unsigned short, unsigned short); +unsigned long _outpd(uint16, unsigned long); +#pragma intrinsic(_inp, _inpw, _inpd, _outp, _outpw, _outpw, _outpd) +void _ReadWriteBarrier(void); +#pragma intrinsic(_ReadWriteBarrier) + +#ifdef VM_X86_64 +/* + * intrinsic functions only supported by x86-64 windows as of 2k3sp1 + */ +void __cpuid(unsigned int*, unsigned int); +unsigned __int64 __rdtsc(void); +void __stosw(unsigned short*, unsigned short, size_t); +void __stosd(unsigned long*, unsigned long, size_t); +#pragma intrinsic(__cpuid, __rdtsc, __stosw, __stosd) + +/* + * intrinsic functions supported by x86-64 windows and newer x86 + * compilers (13.01.2035 for _BitScanForward). + */ +unsigned char _BitScanForward(unsigned long*, unsigned long); +void _mm_pause(void); +#pragma intrinsic(_BitScanForward, _mm_pause) +#endif /* VM_X86_64 */ + +#ifdef __cplusplus +} +#endif +#endif /* _MSC_VER */ + + +#ifdef __GNUC__ // { + +/* + * Checked against the Intel manual and GCC --hpreg + * + * volatile because reading from port can modify the state of the underlying + * hardware. + * + * Note: The undocumented %z construct doesn't work (internal compiler error) + * with gcc-2.95.1 + */ + +#define __GCC_IN(s, type, name) \ +static INLINE type \ +name(uint16 port) \ +{ \ + type val; \ + \ + __asm__ __volatile__( \ + "in" #s " %w1, %0" \ + : "=a" (val) \ + : "Nd" (port) \ + ); \ + \ + return val; \ +} + +__GCC_IN(b, uint8, INB) +__GCC_IN(w, uint16, INW) +__GCC_IN(l, uint32, IN32) + + +/* + * Checked against the Intel manual and GCC --hpreg + * + * Note: The undocumented %z construct doesn't work (internal compiler error) + * with gcc-2.95.1 + */ + +#define __GCC_OUT(s, s2, port, val) do { \ + __asm__( \ + "out" #s " %" #s2 "1, %w0" \ + : \ + : "Nd" (port), "a" (val) \ + ); \ +} while (0) + +#define OUTB(port, val) __GCC_OUT(b, b, port, val) +#define OUTW(port, val) __GCC_OUT(w, w, port, val) +#define OUT32(port, val) __GCC_OUT(l, , port, val) + + +#define GET_CURRENT_EIP(_eip) \ + __asm__ __volatile("call 0\n\tpopl %0" : "=r" (_eip): ); + + +/* + * Checked against the Intel manual and GCC --hpreg + * + * Need __volatile__ and "memory" since CPUID has a synchronizing effect. + * The CPUID may also change at runtime (APIC flag, etc). + * + */ + +static INLINE void +__GET_CPUID(int eax, // IN + CPUIDRegs *regs) // OUT +{ + __asm__ __volatile__( +#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. + "movl %%ebx, %1" "\n\t" + "cpuid" "\n\t" + "xchgl %%ebx, %1" + : "=a" (regs->eax), "=&rm" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx) +#else + "cpuid" + : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx) +#endif + : "a" (eax) + : "memory" + ); +} + +static INLINE void +__GET_CPUID2(int eax, // IN + int ecx, // IN + CPUIDRegs *regs) // OUT +{ + __asm__ __volatile__( +#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. + "movl %%ebx, %1" "\n\t" + "cpuid" "\n\t" + "xchgl %%ebx, %1" + : "=a" (regs->eax), "=&rm" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx) +#else + "cpuid" + : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx) +#endif + : "a" (eax), "c" (ecx) + : "memory" + ); +} + +static INLINE uint32 +__GET_EAX_FROM_CPUID(int eax) // IN +{ +#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. + uint32 ebx; + + __asm__ __volatile__( + "movl %%ebx, %1" "\n\t" + "cpuid" "\n\t" + "xchgl %%ebx, %1" + : "=a" (eax), "=&rm" (ebx) + : "a" (eax) + : "memory", "%ecx", "%edx" + ); +#else + __asm__ __volatile__( + "cpuid" + : "=a" (eax) + : "a" (eax) + : "memory", "%ebx", "%ecx", "%edx" + ); +#endif + + return eax; +} + +static INLINE uint32 +__GET_EBX_FROM_CPUID(int eax) // IN +{ + uint32 ebx; + + __asm__ __volatile__( +#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. + "movl %%ebx, %1" "\n\t" + "cpuid" "\n\t" + "xchgl %%ebx, %1" + : "=a" (eax), "=&rm" (ebx) +#else + "cpuid" + : "=a" (eax), "=b" (ebx) +#endif + : "a" (eax) + : "memory", "%ecx", "%edx" + ); + + return ebx; +} + +static INLINE uint32 +__GET_ECX_FROM_CPUID(int eax) // IN +{ + uint32 ecx; +#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. + uint32 ebx; + + __asm__ __volatile__( + "movl %%ebx, %1" "\n\t" + "cpuid" "\n\t" + "xchgl %%ebx, %1" + : "=a" (eax), "=&rm" (ebx), "=c" (ecx) + : "a" (eax) + : "memory", "%edx" + ); +#else + + __asm__ __volatile__( + "cpuid" + : "=a" (eax), "=c" (ecx) + : "a" (eax) + : "memory", "%ebx", "%edx" + ); +#endif + + return ecx; +} + +static INLINE uint32 +__GET_EDX_FROM_CPUID(int eax) // IN +{ + uint32 edx; +#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. + uint32 ebx; + + __asm__ __volatile__( + "movl %%ebx, %1" "\n\t" + "cpuid" "\n\t" + "xchgl %%ebx, %1" + : "=a" (eax), "=&rm" (ebx), "=d" (edx) + : "a" (eax) + : "memory", "%ecx" + ); +#else + + __asm__ __volatile__( + "cpuid" + : "=a" (eax), "=d" (edx) + : "a" (eax) + : "memory", "%ebx", "%ecx" + ); +#endif + + return edx; +} + + +static INLINE uint32 +__GET_EAX_FROM_CPUID4(int ecx) // IN +{ + uint32 eax; +#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. + uint32 ebx; + + __asm__ __volatile__( + "movl %%ebx, %1" "\n\t" + "cpuid" "\n\t" + "xchgl %%ebx, %1" + : "=a" (eax), "=&rm" (ebx), "=c" (ecx) + : "a" (4), "c" (ecx) + : "memory", "%edx" + ); +#else + + __asm__ __volatile__( + "cpuid" + : "=a" (eax), "=c" (ecx) + : "a" (4), "c" (ecx) + : "memory", "%ebx", "%edx" + ); +#endif + + return eax; +} + +#elif defined(_MSC_VER) // } { +static INLINE uint8 +INB(uint16 port) +{ + return (uint8)_inp(port); +} +static INLINE void +OUTB(uint16 port, uint8 value) +{ + _outp(port, value); +} +static INLINE uint16 +INW(uint16 port) +{ + return _inpw(port); +} +static INLINE void +OUTW(uint16 port, uint16 value) +{ + _outpw(port, value); +} +static INLINE uint32 +IN32(uint16 port) +{ + return _inpd(port); +} +static INLINE void +OUT32(uint16 port, uint32 value) +{ + _outpd(port, value); +} + +#ifndef VM_X86_64 +#ifdef NEAR +#undef NEAR +#endif + +#define GET_CURRENT_EIP(_eip) do { \ + __asm call NEAR PTR $+5 \ + __asm pop eax \ + __asm mov _eip, eax \ +} while (0) +#endif + +static INLINE void +__GET_CPUID(int input, CPUIDRegs *regs) +{ +#ifdef VM_X86_64 + __cpuid((unsigned int *)regs, input); +#else + __asm push esi + __asm push ebx + __asm push ecx + __asm push edx + + __asm mov eax, input + __asm mov esi, regs + __asm _emit 0x0f __asm _emit 0xa2 + __asm mov 0x0[esi], eax + __asm mov 0x4[esi], ebx + __asm mov 0x8[esi], ecx + __asm mov 0xC[esi], edx + + __asm pop edx + __asm pop ecx + __asm pop ebx + __asm pop esi +#endif +} + +#ifdef VM_X86_64 + +/* + * No inline assembly in Win64. Implemented in bora/lib/user in + * cpuidMasm64.asm. + */ + +extern void +__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs); + +#else // VM_X86_64 + +static INLINE void +__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs) +{ + __asm push esi + __asm push ebx + __asm push ecx + __asm push edx + + __asm mov eax, inputEax + __asm mov ecx, inputEcx + __asm mov esi, regs + __asm _emit 0x0f __asm _emit 0xa2 + __asm mov 0x0[esi], eax + __asm mov 0x4[esi], ebx + __asm mov 0x8[esi], ecx + __asm mov 0xC[esi], edx + + __asm pop edx + __asm pop ecx + __asm pop ebx + __asm pop esi +} +#endif + +static INLINE uint32 +__GET_EAX_FROM_CPUID(int input) +{ +#ifdef VM_X86_64 + CPUIDRegs regs; + __cpuid((unsigned int *)®s, input); + return regs.eax; +#else + uint32 output; + + //NOT_TESTED(); + __asm push ebx + __asm push ecx + __asm push edx + + __asm mov eax, input + __asm _emit 0x0f __asm _emit 0xa2 + __asm mov output, eax + + __asm pop edx + __asm pop ecx + __asm pop ebx + + return output; +#endif +} + +static INLINE uint32 +__GET_EBX_FROM_CPUID(int input) +{ +#ifdef VM_X86_64 + CPUIDRegs regs; + __cpuid((unsigned int *)®s, input); + return regs.ebx; +#else + uint32 output; + + //NOT_TESTED(); + __asm push ebx + __asm push ecx + __asm push edx + + __asm mov eax, input + __asm _emit 0x0f __asm _emit 0xa2 + __asm mov output, ebx + + __asm pop edx + __asm pop ecx + __asm pop ebx + + return output; +#endif +} + +static INLINE uint32 +__GET_ECX_FROM_CPUID(int input) +{ +#ifdef VM_X86_64 + CPUIDRegs regs; + __cpuid((unsigned int *)®s, input); + return regs.ecx; +#else + uint32 output; + + //NOT_TESTED(); + __asm push ebx + __asm push ecx + __asm push edx + + __asm mov eax, input + __asm _emit 0x0f __asm _emit 0xa2 + __asm mov output, ecx + + __asm pop edx + __asm pop ecx + __asm pop ebx + + return output; +#endif +} + +static INLINE uint32 +__GET_EDX_FROM_CPUID(int input) +{ +#ifdef VM_X86_64 + CPUIDRegs regs; + __cpuid((unsigned int *)®s, input); + return regs.edx; +#else + uint32 output; + + //NOT_TESTED(); + __asm push ebx + __asm push ecx + __asm push edx + + __asm mov eax, input + __asm _emit 0x0f __asm _emit 0xa2 + __asm mov output, edx + + __asm pop edx + __asm pop ecx + __asm pop ebx + + return output; +#endif +} + +#ifdef VM_X86_64 + +/* + * No inline assembly in Win64. Implemented in bora/lib/user in + * cpuidMasm64.asm. + */ + +extern uint32 +__GET_EAX_FROM_CPUID4(int inputEcx); + +#else // VM_X86_64 + +static INLINE uint32 +__GET_EAX_FROM_CPUID4(int inputEcx) +{ + uint32 output; + + //NOT_TESTED(); + __asm push ebx + __asm push ecx + __asm push edx + + __asm mov eax, 4 + __asm mov ecx, inputEcx + __asm _emit 0x0f __asm _emit 0xa2 + __asm mov output, eax + + __asm pop edx + __asm pop ecx + __asm pop ebx + + return output; +} + +#endif // VM_X86_64 + +#else // } +#error +#endif + +#define CPUID_FOR_SIDE_EFFECTS() ((void)__GET_EAX_FROM_CPUID(0)) + +static INLINE void +__GET_CPUID4(int inputEcx, CPUIDRegs *regs) +{ + __GET_CPUID2(4, inputEcx, regs); +} + +/* The first parameter is used as an rvalue and then as an lvalue. */ +#define GET_CPUID(_ax, _bx, _cx, _dx) { \ + CPUIDRegs regs; \ + __GET_CPUID(_ax, ®s); \ + _ax = regs.eax; \ + _bx = regs.ebx; \ + _cx = regs.ecx; \ + _dx = regs.edx; \ +} + + +/* Sequence recommended by Intel for the Pentium 4. */ +#define INTEL_MICROCODE_VERSION() ( \ + __SET_MSR(MSR_BIOS_SIGN_ID, 0), \ + __GET_EAX_FROM_CPUID(1), \ + __GET_MSR(MSR_BIOS_SIGN_ID)) + + +#ifdef _MSC_VER +static INLINE int +ffs(uint32 bitVector) +{ + int idx; + if (!bitVector) { + return 0; + } +#ifdef VM_X86_64 + _BitScanForward((unsigned long*)&idx, (unsigned long)bitVector); +#else + __asm bsf eax, bitVector + __asm mov idx, eax +#endif + return idx+1; +} +#endif + +#ifdef __GNUC__ +static INLINE void * +uint16set(void *dst, uint16 val, size_t count) +{ + int dummy0; + int dummy1; + + __asm__ __volatile__("\t" + "cld" "\n\t" + "rep ; stosw" "\n" + : "=c" (dummy0), "=D" (dummy1) + : "0" (count), "1" (dst), "a" (val) + : "memory", "cc" + ); + + return dst; +} + +static INLINE void * +uint32set(void *dst, uint32 val, size_t count) +{ + int dummy0; + int dummy1; + + __asm__ __volatile__("\t" + "cld" "\n\t" + "rep ; stosl" "\n" + : "=c" (dummy0), "=D" (dummy1) + : "0" (count), "1" (dst), "a" (val) + : "memory", "cc" + ); + + return dst; +} + +#elif defined(_MSC_VER) + +static INLINE void * +uint16set(void *dst, uint16 val, size_t count) +{ +#ifdef VM_X86_64 + __stosw((uint16*)dst, val, count); +#else + __asm { pushf; + mov ax, val; + mov ecx, count; + mov edi, dst; + cld; + rep stosw; + popf; + } +#endif + return dst; +} + +static INLINE void * +uint32set(void *dst, uint32 val, size_t count) +{ +#ifdef VM_X86_64 + __stosd((unsigned long*)dst, (unsigned long)val, count); +#else + __asm { pushf; + mov eax, val; + mov ecx, count; + mov edi, dst; + cld; + rep stosd; + popf; + } +#endif + return dst; +} + +#else +#error "No compiler defined for uint*set" +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Bswap -- + * + * Swap the 4 bytes of "v" as follows: 3210 -> 0123. + * + *----------------------------------------------------------------------------- + */ + +#ifdef __GNUC__ // { +static INLINE uint32 +Bswap(uint32 v) +{ + /* Checked against the Intel manual and GCC --hpreg */ + __asm__( + "bswap %0" + : "=r" (v) + : "0" (v) + ); + return v; +} +#endif // } + +#ifdef __GNUC__ // { +/* + * COMPILER_MEM_BARRIER prevents the compiler from re-ordering memory + * references accross the barrier. NOTE: It does not generate any + * instruction, so the CPU is free to do whatever it wants to... + */ +#define COMPILER_MEM_BARRIER() __asm__ __volatile__ ("": : :"memory") +#elif defined(_MSC_VER) // } { +#define COMPILER_MEM_BARRIER() _ReadWriteBarrier() +#endif // } + + +/* + * PAUSE is a P4 instruction that improves spinlock power+performance; + * on non-P4 IA32 systems, the encoding is interpreted as a REPZ-NOP. + * Use volatile to avoid NOP removal. + */ +static INLINE void +PAUSE(void) +#ifdef __GNUC__ +{ + __asm__ __volatile__( "pause" :); +} +#elif defined(_MSC_VER) +#ifdef VM_X86_64 +{ + _mm_pause(); +} +#else /* VM_X86_64 */ +#pragma warning( disable : 4035) +{ + __asm _emit 0xf3 __asm _emit 0x90 +} +#pragma warning (default: 4035) +#endif /* VM_X86_64 */ +#else /* __GNUC__ */ +#error No compiler defined for PAUSE +#endif + + +/* + * Checked against the Intel manual and GCC --hpreg + * + * volatile because the tsc always changes without the compiler knowing it. + */ +static INLINE uint64 +RDTSC(void) +#ifdef __GNUC__ +{ +#ifdef VM_X86_64 + uint64 tscLow; + uint64 tscHigh; + + __asm__ __volatile__( + "rdtsc" + : "=a" (tscLow), "=d" (tscHigh) + ); + + return tscHigh << 32 | tscLow; +#else + uint64 tim; + + __asm__ __volatile__( + "rdtsc" + : "=A" (tim) + ); + + return tim; +#endif +} +#elif defined(_MSC_VER) +#ifdef VM_X86_64 +{ + return __rdtsc(); +} +#else +#pragma warning( disable : 4035) +{ + __asm _emit 0x0f __asm _emit 0x31 +} +#pragma warning (default: 4035) +#endif /* VM_X86_64 */ +#else /* __GNUC__ */ +#error No compiler defined for RDTSC +#endif /* __GNUC__ */ + +#endif diff -Nrup source/vmnet-only/include/vm_basic_asm_x86_64.h source.edited/vmnet-only/include/vm_basic_asm_x86_64.h --- source/vmnet-only/include/vm_basic_asm_x86_64.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vm_basic_asm_x86_64.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,336 @@ +/********************************************************* + * Copyright (C) 1998-2004 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 + * + *********************************************************/ + +/* + * vm_basic_asm_x86_64.h + * + * Basic x86_64 asm macros. + */ + +#ifndef _VM_BASIC_ASM_X86_64_H_ +#define _VM_BASIC_ASM_X86_64_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMMEXT +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_VMK_MODULE +#define INCLUDE_ALLOW_VMKERNEL +#define INCLUDE_ALLOW_DISTRIBUTE +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMNIXMOD +#include "includeCheck.h" + +#ifndef VM_X86_64 +#error "This file is x86-64 only!" +#endif + +#ifdef _MSC_VER + +#ifdef __cplusplus +extern "C" { +#endif +uint64 _umul128(uint64 multiplier, uint64 multiplicand, + uint64 *highProduct); +int64 _mul128(int64 multiplier, int64 multiplicand, + int64 *highProduct); +uint64 __shiftright128(uint64 lowPart, uint64 highPart, uint8 shift); +#ifdef __cplusplus +} +#endif + +#pragma intrinsic(_umul128, _mul128, __shiftright128) + +#endif // _MSC_VER + +/* + * FXSAVE/FXRSTOR + * save/restore SIMD/MMX fpu state + * + * The pointer passed in must be 16-byte aligned. + * + * Intel and AMD processors behave differently w.r.t. fxsave/fxrstor. Intel + * processors unconditionally save the exception pointer state (instruction + * ptr., data ptr., and error instruction opcode). FXSAVE_ES1 and FXRSTOR_ES1 + * work correctly for Intel processors. + * + * AMD processors only save the exception pointer state if ES=1. This leads to a + * security hole whereby one process/VM can inspect the state of another process + * VM. The AMD recommended workaround involves clobbering the exception pointer + * state unconditionally, and this is implemented in FXRSTOR_AMD_ES0. Note that + * FXSAVE_ES1 will only save the exception pointer state for AMD processors if + * ES=1. + * + * The workaround (FXRSTOR_AMD_ES0) only costs 1 cycle more than just doing an + * fxrstor, on both AMD Opteron and Intel Core CPUs. + */ +#if defined(__GNUC__) + +static INLINE void +FXSAVE_ES1(uint8 *save) +{ + __asm__ __volatile__ ("fxsaveq %0 \n" : "=m" (*save) : : "memory"); +} + +static INLINE void +FXSAVE_COMPAT_ES1(uint8 *save) +{ + __asm__ __volatile__ ("fxsave %0 \n" : "=m" (*save) : : "memory"); +} + +static INLINE void +FXRSTOR_ES1(const uint8 *load) +{ + __asm__ __volatile__ ("fxrstorq %0 \n" : : "m" (*load) : "memory"); +} + +static INLINE void +FXRSTOR_COMPAT_ES1(const uint8 *load) +{ + __asm__ __volatile__ ("fxrstor %0 \n" : : "m" (*load) : "memory"); +} + +static INLINE void +FXRSTOR_AMD_ES0(const uint8 *load) +{ + uint64 dummy = 0; + + __asm__ __volatile__ + ("fnstsw %%ax \n" // Grab x87 ES bit + "bt $7,%%ax \n" // Test ES bit + "jnc 1f \n" // Jump if ES=0 + "fnclex \n" // ES=1. Clear it so fild doesn't trap + "1: \n" + "ffree %%st(7) \n" // Clear tag bit - avoid poss. stack overflow + "fildl %0 \n" // Dummy Load from "safe address" changes all + // x87 exception pointers. + "fxrstorq %1 \n" + : + : "m" (dummy), "m" (*load) + : "ax", "memory"); +} + +#endif /* __GNUC__ */ + + +/* + *----------------------------------------------------------------------------- + * + * Mul64x3264 -- + * + * Unsigned integer by fixed point multiplication: + * result = multiplicand * multiplier >> shift + * + * Unsigned 64-bit integer multiplicand. + * Unsigned 32-bit fixed point multiplier, represented as + * multiplier >> shift, where shift < 64. + * Unsigned 64-bit integer product. + * + * Implementation: + * Multiply 64x64 bits to yield a full 128-bit product. + * Shift result in RDX:RAX right by "shift". + * Return the low-order 64 bits of the above. + * + * Result: + * Product + * + *----------------------------------------------------------------------------- + */ + +#if defined(__GNUC__) + +static INLINE uint64 +Mul64x3264(uint64 multiplicand, + uint32 multiplier, + uint32 shift) +{ + uint64 result, dummy; + const uint64 multiplier64 = multiplier; + + asm("mulq %3 \n\t" + "shrdq %1, %0 \n\t" + : "=a" (result), + "=d" (dummy) + : "0" (multiplier64), + "rm" (multiplicand), + "c" (shift) + : "cc"); + return result; +} + +#elif defined(_MSC_VER) + +static INLINE uint64 +Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) +{ + uint64 tmplo, tmphi; + tmplo = _umul128(multiplicand, multiplier, &tmphi); + return __shiftright128(tmplo, tmphi, (uint8) shift); +} + +#endif + +/* + *----------------------------------------------------------------------------- + * + * Muls64x32s64 -- + * + * Signed integer by fixed point multiplication: + * result = multiplicand * multiplier >> shift + * + * Signed 64-bit integer multiplicand. + * Unsigned 32-bit fixed point multiplier, represented as + * multiplier >> shift, where shift < 64. + * Signed 64-bit integer product. + * + * Implementation: + * Multiply 64x64 bits to yield a full 128-bit product. + * Shift result in RDX:RAX right by "shift". + * Return the low-order 64 bits of the above. + * + * Note: using an unsigned shift instruction is correct because + * shift < 64 and we return only the low 64 bits of the shifted + * result. + * + * Result: + * Product + * + *----------------------------------------------------------------------------- + */ + +#if defined(__GNUC__) + +static inline int64 +Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) +{ + int64 result, dummy; + const int64 multiplier64 = multiplier; + + asm("imulq %3 \n\t" + "shrdq %1, %0 \n\t" + : "=a" (result), + "=d" (dummy) + : "0" (multiplier64), + "rm" (multiplicand), + "c" (shift) + : "cc"); + return result; +} + +#elif defined(_MSC_VER) + +static INLINE int64 +Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) +{ + int64 tmplo, tmphi; + tmplo = _mul128(multiplicand, multiplier, &tmphi); + return __shiftright128(tmplo, tmphi, (uint8) shift); +} + +#endif + + +#if defined(__GNUC__) + +static INLINE void * +uint64set(void *dst, uint64 val, uint64 count) +{ + int dummy0; + int dummy1; + __asm__ __volatile__("\t" + "cld" "\n\t" + "rep ; stosq" "\n" + : "=c" (dummy0), "=D" (dummy1) + : "0" (count), "1" (dst), "a" (val) + : "memory", "cc"); + return dst; +} + +#endif + +/* + *----------------------------------------------------------------------------- + * + * Div643232 -- + * + * Unsigned integer division: + * The dividend is 64-bit wide + * The divisor is 32-bit wide + * The quotient is 32-bit wide + * + * Use this function if you are certain that the quotient will fit in 32 bits, + * If that is not the case, a #DE exception was generated in 32-bit version, + * but not in this 64-bit version. So please be careful. + * + * Results: + * Quotient and remainder + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +#if defined(__GNUC__) || defined(_MSC_VER) + +static INLINE void +Div643232(uint64 dividend, // IN + uint32 divisor, // IN + uint32 *quotient, // OUT + uint32 *remainder) // OUT +{ + *quotient = (uint32)(dividend / divisor); + *remainder = (uint32)(dividend % divisor); +} + +#endif + +/* + *----------------------------------------------------------------------------- + * + * Div643264 -- + * + * Unsigned integer division: + * The dividend is 64-bit wide + * The divisor is 32-bit wide + * The quotient is 64-bit wide + * + * Results: + * Quotient and remainder + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +#if defined(__GNUC__) + +static INLINE void +Div643264(uint64 dividend, // IN + uint32 divisor, // IN + uint64 *quotient, // OUT + uint32 *remainder) // OUT +{ + *quotient = dividend / divisor; + *remainder = dividend % divisor; +} + +#endif + +#endif // _VM_BASIC_ASM_X86_64_H_ diff -Nrup source/vmnet-only/include/vm_basic_asm_x86.h source.edited/vmnet-only/include/vm_basic_asm_x86.h --- source/vmnet-only/include/vm_basic_asm_x86.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vm_basic_asm_x86.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,500 @@ +/********************************************************* + * Copyright (C) 1998-2003 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 + * + *********************************************************/ + +/* + * vm_basic_asm_x86.h + * + * Basic IA32 asm macros + */ + +#ifndef _VM_BASIC_ASM_X86_H_ +#define _VM_BASIC_ASM_X86_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMMEXT +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_VMK_MODULE +#define INCLUDE_ALLOW_VMKERNEL +#define INCLUDE_ALLOW_DISTRIBUTE +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMIROM +#include "includeCheck.h" + +#ifdef VM_X86_64 +/* + * The gcc inline asm uses the "A" constraint which differs in 32 & 64 + * bit mode. 32 bit means eax and edx, 64 means rax or rdx. + */ +#error "x86-64 not supported" +#endif + + + + +/* + * from linux: usr/include/asm/io.h + */ +#ifdef __GNUC__ +#ifndef __SLOW_DOWN_IO +#ifdef SLOW_IO_BY_JUMPING +#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") +#else +#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") +#endif +#endif +#elif defined(_MSC_VER) +#ifdef SLOW_IO_BY_JUMPING +#define __SLOW_DOWN_IO __asm jmp SHORT $+2 __asm jmp SHORT $+2 +#else +#define __SLOW_DOWN_IO __asm out 80h,al +#endif +#else +#error +#endif + +#ifdef REALLY_SLOW_IO +#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; } +#else +#define SLOW_DOWN_IO __SLOW_DOWN_IO +#endif + +/* + * FXSAVE/FXRSTOR + * save/restore SIMD/MMX fpu state + * + * The pointer passed in must be 16-byte aligned. + * + * Intel and AMD processors behave differently w.r.t. fxsave/fxrstor. Intel + * processors unconditionally save the exception pointer state (instruction + * ptr., data ptr., and error instruction opcode). FXSAVE_ES1 and FXRSTOR_ES1 + * work correctly for Intel processors. + * + * AMD processors only save the exception pointer state if ES=1. This leads to a + * security hole whereby one process/VM can inspect the state of another process + * VM. The AMD recommended workaround involves clobbering the exception pointer + * state unconditionally, and this is implemented in FXRSTOR_AMD_ES0. Note that + * FXSAVE_ES1 will only save the exception pointer state for AMD processors if + * ES=1. + * + * The workaround (FXRSTOR_AMD_ES0) only costs 1 cycle more than just doing an + * fxrstor, on both AMD Opteron and Intel Core CPUs. + */ +#if defined(__GNUC__) +static INLINE void +FXSAVE_ES1(uint8 *save) +{ + __asm__ __volatile__ ("fxsave %0\n" : "=m" (*save) : : "memory"); +} + +static INLINE void +FXRSTOR_ES1(const uint8 *load) +{ + __asm__ __volatile__ ("fxrstor %0\n" : : "m" (*load) : "memory"); +} + +static INLINE void +FXRSTOR_AMD_ES0(const uint8 *load) +{ + uint64 dummy = 0; + + __asm__ __volatile__ + ("fnstsw %%ax \n" // Grab x87 ES bit + "bt $7,%%ax \n" // Test ES bit + "jnc 1f \n" // Jump if ES=0 + "fnclex \n" // ES=1. Clear it so fild doesn't trap + "1: \n" + "ffree %%st(7) \n" // Clear tag bit - avoid poss. stack overflow + "fildl %0 \n" // Dummy Load from "safe address" changes all + // x87 exception pointers. + "fxrstor %1 \n" + : + : "m" (dummy), "m" (*load) + : "ax", "memory"); +} +#endif /* __GNUC__ */ + +/* + *----------------------------------------------------------------------------- + * + * Div643232 -- + * + * Unsigned integer division: + * The dividend is 64-bit wide + * The divisor is 32-bit wide + * The quotient is 32-bit wide + * + * Use this function if you are certain that: + * o Either the quotient will fit in 32 bits, + * o Or your code is ready to handle a #DE exception indicating overflow. + * If that is not the case, then use Div643264(). --hpreg + * + * Results: + * Quotient and remainder + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +#if defined(__GNUC__) + +static INLINE void +Div643232(uint64 dividend, // IN + uint32 divisor, // IN + uint32 *quotient, // OUT + uint32 *remainder) // OUT +{ + /* Checked against the Intel manual and GCC --hpreg */ + __asm__( + "divl %4" + : "=a" (*quotient), + "=d" (*remainder) + : "0" ((uint32)dividend), + "1" ((uint32)(dividend >> 32)), + "rm" (divisor) + : "cc" + ); +} + +#elif defined(_MSC_VER) + +static INLINE void +Div643232(uint64 dividend, // IN + uint32 divisor, // IN + uint32 *quotient, // OUT + uint32 *remainder) // OUT +{ + /* Written and tested by mann, checked by dbudko and hpreg */ + __asm { + mov eax, DWORD PTR [dividend] + mov edx, DWORD PTR [dividend+4] + div DWORD PTR [divisor] + mov edi, DWORD PTR [quotient] + mov [edi], eax + mov edi, DWORD PTR [remainder] + mov [edi], edx + } +} + +#else +#error No compiler defined for Div643232 +#endif + + +#if defined(__GNUC__) +/* + *----------------------------------------------------------------------------- + * + * Div643264 -- + * + * Unsigned integer division: + * The dividend is 64-bit wide + * The divisor is 32-bit wide + * The quotient is 64-bit wide --hpreg + * + * Results: + * Quotient and remainder + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +Div643264(uint64 dividend, // IN + uint32 divisor, // IN + uint64 *quotient, // OUT + uint32 *remainder) // OUT +{ + uint32 hQuotient; + uint32 lQuotient; + + /* Checked against the Intel manual and GCC --hpreg */ + __asm__( + "divl %5" "\n\t" + "movl %%eax, %0" "\n\t" + "movl %4, %%eax" "\n\t" + "divl %5" + : "=&rm" (hQuotient), + "=a" (lQuotient), + "=d" (*remainder) + : "1" ((uint32)(dividend >> 32)), + "g" ((uint32)dividend), + "rm" (divisor), + "2" (0) + : "cc" + ); + *quotient = (uint64)hQuotient << 32 | lQuotient; +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Mul64x3264 -- + * + * Unsigned integer by fixed point multiplication: + * Unsigned 64-bit integer multiplicand. + * Unsigned 32-bit fixed point multiplier, represented as + * multiplier >> shift, where shift < 64. + * Unsigned 64-bit integer product. + * + * Implementation: + * Multiply 64x32 bits to yield a full 96-bit product. + * Shift right by shift. + * Return the low-order 64 bits of the result. + * + * Result: + * Product + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +#if defined(__GNUC__) + +static INLINE uint64 +Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) +{ + uint64 result; + uint32 tmp1, tmp2; + // ASSERT(shift >= 0 && shift < 64); + + /* + * Written and tested by mann, improved with suggestions by hpreg. + * + * The main improvement over the previous version is that the test + * of shift against 32 is moved out of the asm and into C code. + * This lets the compiler delete the test and one of the + * alternative code sequences in the case where shift is a + * constant. It also lets us use the best code sequence in each + * alternative, rather than a compromise. The downside is that in + * the non-constant case, this version takes slightly more code + * space. + * + * Note on the constraints: We don't really want multiplicand to + * start in %edx:%eax as the =A constraint dictates; in fact, we'd + * prefer any *other* two registers. But gcc doesn't have + * constraint syntax for any other register pair, and trying to + * constrain ((uint32) multiplicand) to one place and (multiplicand + * >> 32) to another generates *really* bad code -- gcc is just not + * smart enough, at least in the version we are currently using. + */ + if (shift < 32) { + asm("mov %%eax, %2 \n\t" // Save lo(multiplicand) in tmp2 + "mov %%edx, %%eax \n\t" // Get hi(multiplicand) + "mull %4 \n\t" // p2 = hi(multiplicand) * multiplier + "xchg %%eax, %2 \n\t" // Save lo(p2) in tmp2, get lo(multiplicand) + "mov %%edx, %1 \n\t" // Save hi(p2) in tmp1 + "mull %4 \n\t" // p1 = lo(multiplicand) * multiplier + "addl %2, %%edx \n\t" // hi(p1) += lo(p2) + "adcl $0, %1 \n\t" // hi(p2) += carry from previous step + "shrdl %%edx, %%eax \n\t" // result = hi(p2):hi(p1):lo(p1) >> shift + "shrdl %1, %%edx" + : "=A" (result), + "=&r" (tmp1), // use in shrdl requires it to be a register + "=&r" (tmp2) // could be "=&rm" but "m" is slower + : "0" (multiplicand), + "rm" (multiplier), + "c" (shift) + : "cc" + ); + } else { + asm("mov %%edx, %2 \n\t" // Save hi(multiplicand) in tmp2 + "mull %4 \n\t" // p1 = lo(multiplicand) * multiplier + "mov %%edx, %1 \n\t" // Save hi(p1) in tmp1 + "mov %2, %%eax \n\t" // Discard lo(p1), get hi(multiplicand) + "mull %4 \n\t" // p2 = hi(multiplicand) * multiplier + "addl %1, %%eax \n\t" // lo(p2) += hi(p1) + "adcl $0, %%edx \n\t" // hi(p2) += carry from previous step + "shrdl %%edx, %%eax \n\t" // result = p2 >> (shift & 31) + "shrl %%cl, %%edx" + : "=A" (result), + "=&r" (tmp1), // could be "=&rm" but "m" is slower + "=&r" (tmp2) // could be "=&rm" but "m" is slower + : "0" (multiplicand), + "rm" (multiplier), + "c" (shift) + : "cc" + ); + } + return result; +} + +#elif defined(_MSC_VER) +#pragma warning(disable: 4035) + +static INLINE uint64 +Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) +{ + // ASSERT(shift >= 0 && shift < 64); + + /* Written and tested by mann, checked by dbudko and hpreg */ + __asm { + mov eax, DWORD PTR [multiplicand+4] // Get hi(multiplicand) + mul DWORD PTR [multiplier] // p2 = hi(multiplicand) * multiplier + mov ecx, eax // Save lo(p2) + mov ebx, edx // Save hi(p2) + mov eax, DWORD PTR [multiplicand] // Get lo(multiplicand) + mul DWORD PTR [multiplier+0] // p1 = lo(multiplicand) * multiplier + add edx, ecx // hi(p1) += lo(p2) + adc ebx, 0 // hi(p2) += carry from previous step + mov ecx, DWORD PTR [shift] // Get shift + cmp ecx, 32 // shift < 32? + jl SHORT l2 // Go if so + mov eax, edx // result = hi(p2):hi(p1) >> (shift & 31) + mov edx, ebx + shrd eax, edx, cl + shr edx, cl + jmp SHORT l3 + l2: + shrd eax, edx, cl // result = hi(p2):hi(p1):lo(p1) >> shift + shrd edx, ebx, cl + l3: + } + // return with result in edx:eax +} + +#pragma warning(default: 4035) +#else +#error No compiler defined for Mul64x3264 +#endif + +/* + *----------------------------------------------------------------------------- + * + * Muls64x32s64 -- + * + * Signed integer by fixed point multiplication: + * Signed 64-bit integer multiplicand. + * Unsigned 32-bit fixed point multiplier, represented as + * multiplier >> shift, where shift < 64. + * Signed 64-bit integer product. + * + * Implementation: + * Multiply 64x32 bits to yield a full 96-bit product. + * Shift right by the location of the binary point. + * Return the low-order 64 bits of the result. + * + * Result: + * Product + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +#if defined(__GNUC__) + +static INLINE int64 +Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) +{ + int64 result; + uint32 tmp1, tmp2; + // ASSERT(shift >= 0 && shift < 64); + + /* Written and tested by mann, checked by dbudko and hpreg */ + /* XXX hpreg suggested some improvements that we haven't converged on yet */ + asm("mov %%eax, %2\n\t" // Save lo(multiplicand) + "mov %%edx, %%eax\n\t" // Get hi(multiplicand) + "test %%eax, %%eax\n\t" // Check sign of multiplicand + "jl 0f\n\t" // Go if negative + "mull %4\n\t" // p2 = hi(multiplicand) * multiplier + "jmp 1f\n" + "0:\n\t" + "mull %4\n\t" // p2 = hi(multiplicand) * multiplier + "sub %4, %%edx\n" // hi(p2) += -1 * multiplier + "1:\n\t" + "xchg %%eax, %2\n\t" // Save lo(p2), get lo(multiplicand) + "mov %%edx, %1\n\t" // Save hi(p2) + "mull %4\n\t" // p1 = lo(multiplicand) * multiplier + "addl %2, %%edx\n\t" // hi(p1) += lo(p2) + "adcl $0, %1\n\t" // hi(p2) += carry from previous step + "cmpl $32, %%ecx\n\t" // shift < 32? + "jl 2f\n\t" // Go if so + "mov %%edx, %%eax\n\t" // result = hi(p2):hi(p1) >> (shift & 31) + "mov %1, %%edx\n\t" + "shrdl %%edx, %%eax\n\t" + "sarl %%cl, %%edx\n\t" + "jmp 3f\n" + "2:\n\t" + "shrdl %%edx, %%eax\n\t" // result = hi(p2):hi(p1):lo(p1) >> shift + "shrdl %1, %%edx\n" + "3:\n\t" + : "=A" (result), "=&r" (tmp1), "=&r" (tmp2) + : "0" (multiplicand), "rm" (multiplier), "c" (shift) + : "cc"); + return result; +} + +#elif defined(_MSC_VER) +#pragma warning(disable: 4035) + +static INLINE int64 +Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) +{ + //ASSERT(shift >= 0 && shift < 64); + + /* Written and tested by mann, checked by dbudko and hpreg */ + __asm { + mov eax, DWORD PTR [multiplicand+4] // Get hi(multiplicand) + test eax, eax // Check sign of multiplicand + jl SHORT l0 // Go if negative + mul DWORD PTR [multiplier] // p2 = hi(multiplicand) * multiplier + jmp SHORT l1 + l0: + mul DWORD PTR [multiplier] // p2 = hi(multiplicand) * multiplier + sub edx, DWORD PTR [multiplier] // hi(p2) += -1 * multiplier + l1: + mov ecx, eax // Save lo(p2) + mov ebx, edx // Save hi(p2) + mov eax, DWORD PTR [multiplicand] // Get lo(multiplicand) + mul DWORD PTR [multiplier] // p1 = lo(multiplicand) * multiplier + add edx, ecx // hi(p1) += lo(p2) + adc ebx, 0 // hi(p2) += carry from previous step + mov ecx, DWORD PTR [shift] // Get shift + cmp ecx, 32 // shift < 32? + jl SHORT l2 // Go if so + mov eax, edx // result = hi(p2):hi(p1) >> (shift & 31) + mov edx, ebx + shrd eax, edx, cl + sar edx, cl + jmp SHORT l3 + l2: + shrd eax, edx, cl // result = hi(p2):hi(p1):lo(p1) << shift + shrd edx, ebx, cl + l3: + } + // return with result in edx:eax +} + +#pragma warning(default: 4035) +#else +#error No compiler defined for Muls64x32s64 +#endif + + +#endif diff -Nrup source/vmnet-only/include/vm_basic_defs.h source.edited/vmnet-only/include/vm_basic_defs.h --- source/vmnet-only/include/vm_basic_defs.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vm_basic_defs.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,570 @@ +/********************************************************* + * Copyright (C) 2003 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 + * + *********************************************************/ + +/* + * vm_basic_defs.h -- + * + * Standard macros for VMware source code. + */ + +#ifndef _VM_BASIC_DEFS_H_ +#define _VM_BASIC_DEFS_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMMEXT +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_VMKERNEL +#define INCLUDE_ALLOW_VMKDRIVERS +#define INCLUDE_ALLOW_VMK_MODULE +#define INCLUDE_ALLOW_DISTRIBUTE +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMIROM +#include "includeCheck.h" +#include "vm_basic_types.h" // For INLINE. + +#if defined _WIN32 && defined USERLEVEL + #include /* + * We re-define offsetof macro from stddef, make + * sure that its already defined before we do it + */ + #include // for Sleep() and LOWORD() etc. +#endif + + +/* + * Simple macros + */ + +#if defined __APPLE__ && !defined KERNEL +# include +#else +// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning +// XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings +#ifndef offsetof +#ifdef __cplusplus +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#endif +#endif // __APPLE__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof (a) / sizeof *(a)) +#endif + +#ifndef MIN +#define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif + +/* The Solaris 9 cross-compiler complains about these not being used */ +#ifndef sun +static INLINE int +Min(int a, int b) +{ + return a < b ? a : b; +} +#endif + +#ifndef MAX +#define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif + +#ifndef sun +static INLINE int +Max(int a, int b) +{ + return a > b ? a : b; +} +#endif + +#define ROUNDUP(x,y) (((x) + (y) - 1) / (y) * (y)) +#define ROUNDDOWN(x,y) ((x) / (y) * (y)) +#define ROUNDUPBITS(x, bits) (((uintptr_t) (x) + MASK(bits)) & ~MASK(bits)) +#define ROUNDDOWNBITS(x, bits) ((uintptr_t) (x) & ~MASK(bits)) +#define CEILING(x, y) (((x) + (y) - 1) / (y)) +#if defined __APPLE__ +#include +#undef MASK +#endif +#define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */ +#define DWORD_ALIGN(x) ((((x)+3) >> 2) << 2) +#define QWORD_ALIGN(x) ((((x)+4) >> 3) << 3) + +#define IMPLIES(a,b) (!(a) || (b)) + +/* + * Not everybody (e.g., the monitor) has NULL + */ + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + + +/* + * Token concatenation + * + * The C preprocessor doesn't prescan arguments when they are + * concatenated or stringified. So we need extra levels of + * indirection to convince the preprocessor to expand its + * arguments. + */ + +#define CONC(x, y) x##y +#define XCONC(x, y) CONC(x, y) +#define XXCONC(x, y) XCONC(x, y) +#define MAKESTR(x) #x +#define XSTR(x) MAKESTR(x) + + +/* + * Page operations + * + * It has been suggested that these definitions belong elsewhere + * (like x86types.h). However, I deem them common enough + * (since even regular user-level programs may want to do + * page-based memory manipulation) to be here. + * -- edward + */ + +#ifndef PAGE_SHIFT // { +#if defined VM_I386 + #define PAGE_SHIFT 12 +#elif defined __APPLE__ + #define PAGE_SHIFT 12 +#else + #error +#endif +#endif // } + +#ifndef PAGE_SIZE +#define PAGE_SIZE (1<> PAGE_SHIFT) +#endif + +#ifndef BYTES_2_PAGES +#define BYTES_2_PAGES(_nbytes) ((_nbytes) >> PAGE_SHIFT) +#endif + +#ifndef PAGES_2_BYTES +#define PAGES_2_BYTES(_npages) (((uint64)(_npages)) << PAGE_SHIFT) +#endif + +#ifndef MBYTES_2_PAGES +#define MBYTES_2_PAGES(_nbytes) ((_nbytes) << (20 - PAGE_SHIFT)) +#endif + +#ifndef PAGES_2_MBYTES +#define PAGES_2_MBYTES(_npages) ((_npages) >> (20 - PAGE_SHIFT)) +#endif + +#ifndef VM_PAE_LARGE_PAGE_SHIFT +#define VM_PAE_LARGE_PAGE_SHIFT 21 +#endif + +#ifndef VM_PAE_LARGE_PAGE_SIZE +#define VM_PAE_LARGE_PAGE_SIZE (1 << VM_PAE_LARGE_PAGE_SHIFT) +#endif + +#ifndef VM_PAE_LARGE_PAGE_MASK +#define VM_PAE_LARGE_PAGE_MASK (VM_PAE_LARGE_PAGE_SIZE - 1) +#endif + +#ifndef VM_PAE_LARGE_2_SMALL_PAGES +#define VM_PAE_LARGE_2_SMALL_PAGES (BYTES_2_PAGES(VM_PAE_LARGE_PAGE_SIZE)) +#endif + +/* + * Word operations + */ + +#ifndef LOWORD +#define LOWORD(_dw) ((_dw) & 0xffff) +#endif +#ifndef HIWORD +#define HIWORD(_dw) (((_dw) >> 16) & 0xffff) +#endif + +#ifndef LOBYTE +#define LOBYTE(_w) ((_w) & 0xff) +#endif +#ifndef HIBYTE +#define HIBYTE(_w) (((_w) >> 8) & 0xff) +#endif + +#define HIDWORD(_qw) ((uint32)((_qw) >> 32)) +#define LODWORD(_qw) ((uint32)(_qw)) +#define QWORD(_hi, _lo) ((((uint64)(_hi)) << 32) | ((uint32)(_lo))) + + +/* + * Deposit a field _src at _pos bits from the right, + * with a length of _len, into the integer _target. + */ + +#define DEPOSIT_BITS(_src,_pos,_len,_target) { \ + unsigned mask = ((1 << _len) - 1); \ + unsigned shiftedmask = ((1 << _len) - 1) << _pos; \ + _target = (_target & ~shiftedmask) | ((_src & mask) << _pos); \ +} + + +/* + * Get return address. + */ + +#ifdef _MSC_VER +#ifdef __cplusplus +extern "C" +#endif +void *_ReturnAddress(void); +#pragma intrinsic(_ReturnAddress) +#define GetReturnAddress() _ReturnAddress() +#elif __GNUC__ +#define GetReturnAddress() __builtin_return_address(0) +#endif + + +#ifdef __GNUC__ +#ifndef sun + +/* + * Get the frame pointer. We use this assembly hack instead of + * __builtin_frame_address() due to a bug introduced in gcc 4.1.1 + */ +static INLINE_SINGLE_CALLER uintptr_t +GetFrameAddr(void) +{ + uintptr_t bp; +#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0)) + bp = (uintptr_t)__builtin_frame_address(0); +#elif (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 3) +# if defined(VMM64) || defined(VM_X86_64) + __asm__ __volatile__("movq %%rbp, %0\n" : "=g" (bp)); +# else + __asm__ __volatile__("movl %%ebp, %0\n" : "=g" (bp)); +# endif +#else + __asm__ __volatile__( +#ifdef __linux__ + ".print \"This newer version of GCC may or may not have the " + "__builtin_frame_address bug. Need to update this. " + "See bug 147638.\"\n" + ".abort" +#else /* MacOS */ + ".abort \"This newer version of GCC may or may not have the " + "__builtin_frame_address bug. Need to update this. " + "See bug 147638.\"\n" +#endif + : "=g" (bp) + ); +#endif + return bp; +} + + +/* + * Returns the frame pointer of the calling function. + * Equivalent to __builtin_frame_address(1). + */ +static INLINE_SINGLE_CALLER uintptr_t +GetCallerFrameAddr(void) +{ + return *(uintptr_t*)GetFrameAddr(); +} + +#endif // sun +#endif // __GNUC__ + + + + +#ifdef USERLEVEL // { + +/* + * Note this might be a problem on NT b/c while sched_yield guarantees it + * moves you to the end of your priority list, Sleep(0) offers no such + * guarantee. Bummer. --Jeremy. + */ + +#if defined(N_PLAT_NLM) || defined(__FreeBSD__) +/* We do not have YIELD() as we do not need it yet... */ +#elif defined(_WIN32) +# define YIELD() Sleep(0) +#else +# include // For sched_yield. Don't ask. --Jeremy. +# define YIELD() sched_yield() +#endif + + +/* + * Standardize some Posix names on Windows. + */ + +#ifdef _WIN32 // { + +#define snprintf _snprintf +#define vsnprintf _vsnprintf + +static INLINE void +sleep(unsigned int sec) +{ + Sleep(sec * 1000); +} + +static INLINE void +usleep(unsigned long usec) +{ + Sleep(CEILING(usec, 1000)); +} + +typedef int pid_t; +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +#endif // } + +/* + * Macro for username comparison. + */ + +#ifdef _WIN32 // { +#define USERCMP(x,y) Str_Strcasecmp(x,y) +#else +#define USERCMP(x,y) strcmp(x,y) +#endif // } + + +#endif // } + +#ifndef va_copy + +#ifdef _WIN32 + +/* + * Windows needs va_copy. This works for both 32 and 64-bit Windows + * based on inspection of how varags.h from the Visual C CRTL is + * implemented. (Future versions of the RTL may break this). + */ + +#define va_copy(dest, src) ((dest) = (src)) + +#elif defined(__APPLE__) && defined(KERNEL) + +/* + * MacOS kernel-mode needs va_copy. Based on inspection of stdarg.h + * from the MacOSX10.4u.sdk kernel framework, this should work. + * (Future versions of the SDK may break this). + */ + +#define va_copy(dest, src) ((dest) = (src)) + +#elif defined(__GNUC__) && (__GNUC__ < 3) + +/* + * Old versions of gcc recognize __va_copy, but not va_copy. + */ + +#define va_copy(dest, src) __va_copy(dest, src) + +#endif // _WIN32 + +#endif // va_copy + +/* + * This one is outside USERLEVEL because it's used by + * files compiled into the Windows hgfs driver or the display + * driver. + */ + +#ifdef _WIN32 +#define PATH_MAX 256 +#ifndef strcasecmp +#define strcasecmp(_s1,_s2) _stricmp((_s1),(_s2)) +#endif +#ifndef strncasecmp +#define strncasecmp(_s1,_s2,_n) _strnicmp((_s1),(_s2),(_n)) +#endif +#endif + +/* + * Convenience macro for COMMUNITY_SOURCE + */ +#undef EXCLUDE_COMMUNITY_SOURCE +#ifdef COMMUNITY_SOURCE + #define EXCLUDE_COMMUNITY_SOURCE(x) +#else + #define EXCLUDE_COMMUNITY_SOURCE(x) x +#endif + +#undef COMMUNITY_SOURCE_INTEL_SECRET +#if !defined(COMMUNITY_SOURCE) || defined(INTEL_SOURCE) +/* + * It's ok to include INTEL_SECRET source code for non-commsrc, + * or for drops directed at Intel. + */ + #define COMMUNITY_SOURCE_INTEL_SECRET +#endif + +/* + * Convenience macros and definitions. Can often be used instead of #ifdef. + */ + +#undef DEBUG_ONLY +#undef SL_DEBUG_ONLY +#undef VMX86_SL_DEBUG +#ifdef VMX86_DEBUG +#define vmx86_debug 1 +#define DEBUG_ONLY(x) x +/* + * Be very, very, very careful with SL_DEBUG. Pls ask ganesh or min before + * using it. + */ +#define VMX86_SL_DEBUG +#define vmx86_sl_debug 1 +#define SL_DEBUG_ONLY(x) x +#else +#define vmx86_debug 0 +#define DEBUG_ONLY(x) +#define vmx86_sl_debug 0 +#define SL_DEBUG_ONLY(x) +#endif + +#ifdef VMX86_STATS +#define vmx86_stats 1 +#define STATS_ONLY(x) x +#else +#define vmx86_stats 0 +#define STATS_ONLY(x) +#endif + +#ifdef VMX86_DEVEL +#define vmx86_devel 1 +#define DEVEL_ONLY(x) x +#else +#define vmx86_devel 0 +#define DEVEL_ONLY(x) +#endif + +#ifdef VMX86_LOG +#define vmx86_log 1 +#define LOG_ONLY(x) x +#else +#define vmx86_log 0 +#define LOG_ONLY(x) +#endif + +#ifdef VMX86_VMM_SERIAL_LOGGING +#define vmx86_vmm_serial_log 1 +#define VMM_SERIAL_LOG_ONLY(x) x +#else +#define vmx86_vmm_serial_log 0 +#define VMM_SERIAL_LOG_ONLY(x) +#endif + +#ifdef VMX86_SERVER +#define vmx86_server 1 +#define SERVER_ONLY(x) x +#define HOSTED_ONLY(x) +#else +#define vmx86_server 0 +#define SERVER_ONLY(x) +#define HOSTED_ONLY(x) x +#endif + +#ifdef VMX86_WGS +#define vmx86_wgs 1 +#define WGS_ONLY(x) x +#else +#define vmx86_wgs 0 +#define WGS_ONLY(x) +#endif + +#ifdef VMKERNEL +#define vmkernel 1 +#define VMKERNEL_ONLY(x) x +#else +#define vmkernel 0 +#define VMKERNEL_ONLY(x) +#endif + +#ifdef _WIN32 +#define WIN32_ONLY(x) x +#define POSIX_ONLY(x) +#else +#define WIN32_ONLY(x) +#define POSIX_ONLY(x) x +#endif + +#ifdef VMM +#define VMM_ONLY(x) x +#define USER_ONLY(x) +#else +#define VMM_ONLY(x) +#define USER_ONLY(x) x +#endif + +/* VMVISOR ifdef only allowed in the vmkernel */ +#ifdef VMKERNEL +#ifdef VMVISOR +#define vmvisor 1 +#define VMVISOR_ONLY(x) x +#else +#define vmvisor 0 +#define VMVISOR_ONLY(x) +#endif +#endif + +#ifdef _WIN32 +#define VMW_INVALID_HANDLE INVALID_HANDLE_VALUE +#else +#define VMW_INVALID_HANDLE -1 +#endif + +#ifdef _WIN32 +#define fsync(fd) _commit(fd) +#define fileno(f) _fileno(f) +#else +#endif + +#endif // ifndef _VM_BASIC_DEFS_H_ diff -Nrup source/vmnet-only/include/vm_basic_types.h source.edited/vmnet-only/include/vm_basic_types.h --- source/vmnet-only/include/vm_basic_types.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vm_basic_types.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,847 @@ +/********************************************************* + * Copyright (C) 1998-2008 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 + * + *********************************************************/ + +/* + * + * vm_basic_types.h -- + * + * basic data types. + */ + + +#ifndef _VM_BASIC_TYPES_H_ +#define _VM_BASIC_TYPES_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMMEXT +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_VMKERNEL +#define INCLUDE_ALLOW_VMKDRIVERS +#define INCLUDE_ALLOW_VMK_MODULE +#define INCLUDE_ALLOW_DISTRIBUTE +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMIROM +#include "includeCheck.h" + +/* STRICT ANSI means the Xserver build and X defines Bool differently. */ +#if !defined(__STRICT_ANSI__) || defined(__FreeBSD__) +typedef char Bool; +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#define IsBool(x) (((x) & ~1) == 0) +#define IsBool2(x, y) ((((x) | (y)) & ~1) == 0) + +/* + * Macros __i386__ and __ia64 are intrinsically defined by GCC + */ +#ifdef __i386__ +#define VM_I386 +#endif + +#ifdef _WIN64 +#define __x86_64__ +#endif + +#ifdef __x86_64__ +#define VM_X86_64 +#define VM_I386 +#define vm_x86_64 (1) +#else +#define vm_x86_64 (0) +#endif + + + +#ifdef _WIN32 +/* safe assumption for a while */ +#define VM_I386 +#endif + +#ifdef _MSC_VER +typedef unsigned __int64 uint64; +typedef signed __int64 int64; + +#pragma warning (3 :4505) // unreferenced local function +#pragma warning (disable :4018) // signed/unsigned mismatch +#pragma warning (disable :4761) // integral size mismatch in argument; conversion supplied +#pragma warning (disable :4305) // truncation from 'const int' to 'short' +#pragma warning (disable :4244) // conversion from 'unsigned short' to 'unsigned char' +#pragma warning (disable :4267) // truncation of 'size_t' +#pragma warning (disable :4146) // unary minus operator applied to unsigned type, result still unsigned +#pragma warning (disable :4142) // benign redefinition of type + +#elif __GNUC__ +/* The Xserver source compiles with -ansi -pendantic */ +#ifndef __STRICT_ANSI__ +#if defined(VM_X86_64) +typedef unsigned long uint64; +typedef long int64; +#else +typedef unsigned long long uint64; +typedef long long int64; +#endif +#elif defined(__FreeBSD__) +typedef unsigned long long uint64; +typedef long long int64; +#endif +#else +#error - Need compiler define for int64/uint64 +#endif + +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +typedef int int32; +typedef short int16; +typedef char int8; + +/* + * FreeBSD (for the tools build) unconditionally defines these in + * sys/inttypes.h so don't redefine them if this file has already + * been included. [greg] + * + * This applies to Solaris as well. + */ + +/* + * Before trying to do the includes based on OS defines, see if we can use + * feature-based defines to get as much functionality as possible + */ + +#ifdef HAVE_INTTYPES_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_INTTYPES_H +#include +#endif +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#if !defined(USING_AUTOCONF) +# if defined(__FreeBSD__) || defined(sun) +# ifdef KLD_MODULE +# include +# else +# if (BSD_VERSION >= 50) +# include +# include +# else +# include +# endif +# endif +# elif defined __APPLE__ +# if KERNEL +# include +# include /* mostly for size_t */ +# include +# else +# include +# include +# include +# include +# endif +# else +# if !defined(__intptr_t_defined) && !defined(intptr_t) +# define __intptr_t_defined +# define intptr_t intptr_t +# ifdef VM_I386 +# ifdef VM_X86_64 +typedef int64 intptr_t; +# else +typedef int32 intptr_t; +# endif +# endif +# endif + +# ifndef _STDINT_H +# ifdef VM_I386 +# ifdef VM_X86_64 +typedef uint64 uintptr_t; +# else +typedef uint32 uintptr_t; +# endif +# endif +# endif +# endif +#endif + + +/* + * Time + * XXX These should be cleaned up. -- edward + */ + +typedef int64 VmTimeType; /* Time in microseconds */ +typedef int64 VmTimeRealClock; /* Real clock kept in microseconds */ +typedef int64 VmTimeVirtualClock; /* Virtual Clock kept in CPU cycles */ + +/* + * Printf format specifiers for size_t and 64-bit number. + * Use them like this: + * printf("%"FMT64"d\n", big); + * + * FMTH is for handles/fds. + */ + +#ifdef _MSC_VER + #define FMT64 "I64" + #ifdef VM_X86_64 + #define FMTSZ "I64" + #define FMTPD "I64" + #define FMTH "I64" + #else + #define FMTSZ "I" + #define FMTPD "I" + #define FMTH "I" + #endif +#elif __GNUC__ + #define FMTH "" + #if defined(N_PLAT_NLM) || defined(sun) || \ + (defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) < 5)) + /* + * Why (__FreeBSD__ + 0)? See bug 141008. + * Yes, we really need to test both (__FreeBSD__ + 0) and + * ((__FreeBSD__ + 0) < 5). No, we can't remove "+ 0" from + * ((__FreeBSD__ + 0) < 5). + */ + #ifdef VM_X86_64 + #define FMTSZ "l" + #define FMTPD "l" + #else + #define FMTSZ "" + #define FMTPD "" + #endif + #elif defined(__linux__) \ + || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \ + || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \ + || (defined(_POSIX2_VERSION) && _POSIX2_VERSION >= 200112L) + /* BSD/Darwin, Linux */ + #define FMTSZ "z" + #define FMTPD "t" + #else + /* Systems with a pre-C99 libc */ + #define FMTSZ "Z" + #ifdef VM_X86_64 + #define FMTPD "l" + #else + #define FMTPD "" + #endif + #endif + #ifdef VM_X86_64 + #define FMT64 "l" + #elif defined(sun) || defined(__APPLE__) || defined(__FreeBSD__) + #define FMT64 "ll" + #else + #define FMT64 "L" + #endif +#else + #error - Need compiler define for FMT64 and FMTSZ +#endif + +/* + * Suffix for 64-bit constants. Use it like this: + * CONST64(0x7fffffffffffffff) for signed or + * CONST64U(0x7fffffffffffffff) for unsigned. + * + * 2004.08.30(thutt): + * The vmcore/asm64/gen* programs are compiled as 32-bit + * applications, but must handle 64 bit constants. If the + * 64-bit-constant defining macros are already defined, the + * definition will not be overwritten. + */ + +#if !defined(CONST64) || !defined(CONST64U) +#ifdef _MSC_VER +#define CONST64(c) c##I64 +#define CONST64U(c) c##uI64 +#elif __GNUC__ +#ifdef VM_X86_64 +#define CONST64(c) c##L +#define CONST64U(c) c##uL +#else +#define CONST64(c) c##LL +#define CONST64U(c) c##uLL +#endif +#else +#error - Need compiler define for CONST64 +#endif +#endif + +/* + * Use CONST3264/CONST3264U if you want a constant to be + * treated as a 32-bit number on 32-bit compiles and + * a 64-bit number on 64-bit compiles. Useful in the case + * of shifts, like (CONST3264U(1) << x), where x could be + * more than 31 on a 64-bit compile. + */ + +#ifdef VM_X86_64 + #define CONST3264(a) CONST64(a) + #define CONST3264U(a) CONST64U(a) +#else + #define CONST3264(a) (a) + #define CONST3264U(a) (a) +#endif + +#define MIN_INT32 ((int32)0x80000000) +#define MAX_INT32 ((int32)0x7fffffff) + +#define MIN_UINT32 ((uint32)0) +#define MAX_UINT32 ((uint32)0xffffffff) + +#define MIN_INT64 (CONST64(0x8000000000000000)) +#define MAX_INT64 (CONST64(0x7fffffffffffffff)) + +#define MIN_UINT64 (CONST64U(0)) +#define MAX_UINT64 (CONST64U(0xffffffffffffffff)) + +typedef uint8 *TCA; /* Pointer into TC (usually). */ + +/* + * Type big enough to hold an integer between 0..100 + */ +typedef uint8 Percent; +#define AsPercent(v) ((Percent)(v)) +#define CHOOSE_PERCENT AsPercent(101) + + +typedef uintptr_t VA; +typedef uintptr_t VPN; + +typedef uint64 PA; +typedef uint32 PPN; + +typedef uint64 PhysMemOff; +typedef uint64 PhysMemSize; + +/* The Xserver source compiles with -ansi -pendantic */ +#ifndef __STRICT_ANSI__ +typedef uint64 BA; +#endif +typedef uint32 BPN; +typedef uint32 PageNum; +typedef unsigned MemHandle; +typedef int32 World_ID; + +#define INVALID_WORLD_ID ((World_ID)0) + +typedef World_ID User_CartelID; +#define INVALID_CARTEL_ID INVALID_WORLD_ID + +typedef User_CartelID User_SessionID; +#define INVALID_SESSION_ID INVALID_CARTEL_ID + +typedef User_CartelID User_CartelGroupID; +#define INVALID_CARTELGROUP_ID INVALID_CARTEL_ID + +/* world page number */ +typedef uint32 WPN; + +/* The Xserver source compiles with -ansi -pendantic */ +#ifndef __STRICT_ANSI__ +typedef uint64 MA; +typedef uint32 MPN; +#endif + +/* + * This type should be used for variables that contain sector + * position/quantity. + */ +typedef uint64 SectorType; + +/* + * Linear address + */ + +typedef uintptr_t LA; +typedef uintptr_t LPN; +#define LA_2_LPN(_la) ((_la) >> PAGE_SHIFT) +#define LPN_2_LA(_lpn) ((_lpn) << PAGE_SHIFT) + +#define LAST_LPN ((((LA) 1) << (8 * sizeof(LA) - PAGE_SHIFT)) - 1) +#define LAST_LPN32 ((((LA32)1) << (8 * sizeof(LA32) - PAGE_SHIFT)) - 1) +#define LAST_LPN64 ((((LA64)1) << (8 * sizeof(LA64) - PAGE_SHIFT)) - 1) + +/* Valid bits in a LPN. */ +#define LPN_MASK LAST_LPN +#define LPN_MASK32 LAST_LPN32 +#define LPN_MASK64 LAST_LPN64 + +/* + * On 64 bit platform, address and page number types default + * to 64 bit. When we need to represent a 32 bit address, we use + * types defined below. + * + * On 32 bit platform, the following types are the same as the + * default types. + */ +typedef uint32 VA32; +typedef uint32 VPN32; +typedef uint32 LA32; +typedef uint32 LPN32; +typedef uint32 PA32; +typedef uint32 PPN32; +typedef uint32 MA32; +typedef uint32 MPN32; + +/* + * On 64 bit platform, the following types are the same as the + * default types. + */ +typedef uint64 VA64; +typedef uint64 VPN64; +typedef uint64 LA64; +typedef uint64 LPN64; +typedef uint64 PA64; +typedef uint64 PPN64; +typedef uint64 MA64; +typedef uint64 MPN64; + +/* + * VA typedefs for user world apps. + */ +typedef VA32 UserVA32; +typedef VA64 UserVA64; +typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */ +typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */ +#ifdef VMKERNEL +typedef UserVA32 UserVA; +#else +typedef void * UserVA; +#endif + + +/* + * Maximal possible PPN value (errors too) that PhysMem can handle. + * Must be at least as large as MAX_PPN which is the maximum PPN + * for any region other than buserror. + */ +#define PHYSMEM_MAX_PPN ((PPN)0xffffffff) +#define MAX_PPN ((PPN)0x1fffffff) /* Maximal observable PPN value. */ +#define INVALID_PPN ((PPN)0xffffffff) + +#define INVALID_BPN ((BPN) 0x1fffffff) + +#define INVALID_MPN ((MPN)-1) +#define MEMREF_MPN ((MPN)-2) +#define RESERVED_MPN ((MPN) 0) +/* Support 39 bits of address space, minus one page. */ +#define MAX_MPN ((MPN) 0x07ffffff) + +#define INVALID_LPN ((LPN)-1) +#define INVALID_VPN ((VPN)-1) +#define INVALID_LPN64 ((LPN64)-1) +#define INVALID_PAGENUM ((PageNum)-1) +#define INVALID_WPN ((WPN) -1) + + +/* + * Format modifier for printing VA, LA, and VPN. + * Use them like this: Log("%#"FMTLA"x\n", laddr) + */ + +#if defined(VMM64) || defined(FROBOS64) || vm_x86_64 || defined __APPLE__ +# define FMTLA "l" +# define FMTVA "l" +# define FMTVPN "l" +#else +# define FMTLA "" +# define FMTVA "" +# define FMTVPN "" +#endif + + +#define EXTERN extern +#define CONST const + + +#ifndef INLINE +# ifdef _MSC_VER +# define INLINE __inline +# else +# define INLINE inline +# endif +#endif + + +/* + * Annotation for data that may be exported into a DLL and used by other + * apps that load that DLL and import the data. + */ +#if defined(_WIN32) && defined(VMX86_IMPORT_DLLDATA) +# define VMX86_EXTERN_DATA extern __declspec(dllimport) +#else // !_WIN32 +# define VMX86_EXTERN_DATA extern +#endif + +#if defined(_WIN32) && !defined(VMX86_NO_THREADS) +#define THREADSPECIFIC __declspec(thread) +#else +#define THREADSPECIFIC +#endif + +/* + * Due to the wonderful "registry redirection" feature introduced in + * 64-bit Windows, if you access any key under HKLM\Software in 64-bit + * code, you need to open/create/delete that key with + * VMKEY_WOW64_32KEY if you want a consistent view with 32-bit code. + */ + +#ifdef _WIN32 +#ifdef _WIN64 +#define VMW_KEY_WOW64_32KEY KEY_WOW64_32KEY +#else +#define VMW_KEY_WOW64_32KEY 0x0 +#endif +#endif + + +/* + * Consider the following reasons functions are inlined: + * + * 1) inlined for performance reasons + * 2) inlined because it's a single-use function + * + * Functions which meet only condition 2 should be marked with this + * inline macro; It is not critical to be inlined (but there is a + * code-space & runtime savings by doing so), so when other callers + * are added the inline-ness should be removed. + */ + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +/* + * Starting at version 3.3, gcc does not always inline functions marked + * 'inline' (it depends on their size). To force gcc to do so, one must use the + * extra __always_inline__ attribute. + */ +# define INLINE_SINGLE_CALLER INLINE __attribute__((__always_inline__)) +# if defined(VMM) \ + && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1)) +# warning Verify INLINE_SINGLE_CALLER '__always_inline__' attribute (did \ + monitor size change?) +# endif +#else +# define INLINE_SINGLE_CALLER INLINE +#endif + +/* + * Used when a hard guaranteed of no inlining is needed. Very few + * instances need this since the absence of INLINE is a good hint + * that gcc will not do inlining. + */ + +#if defined(__GNUC__) && defined(VMM) +#define ABSOLUTELY_NOINLINE __attribute__((__noinline__)) +#endif + +/* + * Attributes placed on function declarations to tell the compiler + * that the function never returns. + */ + +#ifdef _MSC_VER +#define NORETURN __declspec(noreturn) +#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 9) +#define NORETURN __attribute__((__noreturn__)) +#else +#define NORETURN +#endif + +/* + * GCC 3.2 inline asm needs the + constraint for input/ouput memory operands. + * Older GCCs don't know about it --hpreg + */ + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2) +# define VM_ASM_PLUS 1 +#else +# define VM_ASM_PLUS 0 +#endif + +/* + * Branch prediction hints: + * LIKELY(exp) - Expression exp is likely TRUE. + * UNLIKELY(exp) - Expression exp is likely FALSE. + * Usage example: + * if (LIKELY(excCode == EXC_NONE)) { + * or + * if (UNLIKELY(REAL_MODE(vc))) { + * + * We know how to predict branches on gcc3 and later (hopefully), + * all others we don't so we do nothing. + */ + +#if (__GNUC__ >= 3) +/* + * gcc3 uses __builtin_expect() to inform the compiler of an expected value. + * We use this to inform the static branch predictor. The '!!' in LIKELY + * will convert any !=0 to a 1. + */ +#define LIKELY(_exp) __builtin_expect(!!(_exp), 1) +#define UNLIKELY(_exp) __builtin_expect((_exp), 0) +#else +#define LIKELY(_exp) (_exp) +#define UNLIKELY(_exp) (_exp) +#endif + +/* + * GCC's argument checking for printf-like functions + * This is conditional until we have replaced all `"%x", void *' + * with `"0x%08x", (uint32) void *'. Note that %p prints different things + * on different platforms. Argument checking is enabled for the + * vmkernel, which has already been cleansed. + * + * fmtPos is the position of the format string argument, beginning at 1 + * varPos is the position of the variable argument, beginning at 1 + */ + +#if defined(__GNUC__) +# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos))) +#else +# define PRINTF_DECL(fmtPos, varPos) +#endif + +/* + * UNUSED_PARAM should surround the parameter name and type declaration, + * e.g. "int MyFunction(int var1, UNUSED_PARAM(int var2))" + * + */ + +#ifndef UNUSED_PARAM +# if defined(__GNUC__) +# define UNUSED_PARAM(_parm) _parm __attribute__((__unused__)) +# else +# define UNUSED_PARAM(_parm) _parm +# endif +#endif + +/* + * REGPARM defaults to REGPARM3, i.e., a requent that gcc + * puts the first three arguments in registers. (It is fine + * if the function has fewer than three args.) Gcc only. + * Syntactically, put REGPARM where you'd put INLINE or NORETURN. + */ + +#if defined(__GNUC__) +# define REGPARM0 __attribute__((regparm(0))) +# define REGPARM1 __attribute__((regparm(1))) +# define REGPARM2 __attribute__((regparm(2))) +# define REGPARM3 __attribute__((regparm(3))) +# define REGPARM REGPARM3 +#else +# define REGPARM0 +# define REGPARM1 +# define REGPARM2 +# define REGPARM3 +# define REGPARM +#endif + +/* + * ALIGNED specifies minimum alignment in "n" bytes. + */ + +#ifdef __GNUC__ +#define ALIGNED(n) __attribute__((__aligned__(n))) +#else +#define ALIGNED(n) +#endif + +/* + * __func__ is a stringified function name that is part of the C99 standard. The block + * below defines __func__ on older systems where the compiler does not support that + * macro. + */ +#if defined(__GNUC__) \ + && ((__GNUC__ == 2 && __GNUC_MINOR < 96) \ + || (__GNUC__ < 2)) +# define __func__ __FUNCTION__ +#endif + +/* + * Once upon a time, this was used to silence compiler warnings that + * get generated when the compiler thinks that a function returns + * when it is marked noreturn. Don't do it. Use NOT_REACHED(). + */ + +#define INFINITE_LOOP() do { } while (1) + +/* + * On FreeBSD (for the tools build), size_t is typedef'd if _BSD_SIZE_T_ + * is defined. Use the same logic here so we don't define it twice. [greg] + */ +#ifdef __FreeBSD__ +# ifdef _BSD_SIZE_T_ +# undef _BSD_SIZE_T_ +# ifdef VM_I386 +# ifdef VM_X86_64 + typedef uint64 size_t; +# else + typedef uint32 size_t; +# endif +# endif /* VM_I386 */ +# endif + +# ifdef _BSD_SSIZE_T_ +# undef _BSD_SSIZE_T_ +# define _SSIZE_T +# define __ssize_t_defined +# define _SSIZE_T_DECLARED +# ifdef VM_I386 +# ifdef VM_X86_64 + typedef int64 ssize_t; +# else + typedef int32 ssize_t; +# endif +# endif /* VM_I386 */ +# endif + +#else +# ifndef _SIZE_T +# define _SIZE_T +# ifdef VM_I386 +# ifdef VM_X86_64 + typedef uint64 size_t; +# else + typedef uint32 size_t; +# endif +# endif /* VM_I386 */ +# endif + +# if !defined(FROBOS) && !defined(_SSIZE_T) && !defined(ssize_t) && \ + !defined(__ssize_t_defined) && !defined(_SSIZE_T_DECLARED) +# define _SSIZE_T +# define __ssize_t_defined +# define _SSIZE_T_DECLARED +# ifdef VM_I386 +# ifdef VM_X86_64 + typedef int64 ssize_t; +# else + typedef int32 ssize_t; +# endif +# endif /* VM_I386 */ +# endif + +#endif + +/* + * Format modifier for printing pid_t. On sun the pid_t is a ulong, but on + * Linux it's an int. + * Use this like this: printf("The pid is %"FMTPID".\n", pid); + */ +#ifdef sun +# ifdef VM_X86_64 +# define FMTPID "d" +# else +# define FMTPID "lu" +# endif +#else +# define FMTPID "d" +#endif + +/* + * Format modifier for printing uid_t. On sun the uid_t is a ulong, but on + * Linux it's an int. + * Use this like this: printf("The uid is %"FMTUID".\n", uid); + */ +#ifdef sun +# ifdef VM_X86_64 +# define FMTUID "u" +# else +# define FMTUID "lu" +# endif +#else +# define FMTUID "u" +#endif + +/* + * Format modifier for printing mode_t. On sun the mode_t is a ulong, but on + * Linux it's an int. + * Use this like this: printf("The mode is %"FMTMODE".\n", mode); + */ +#ifdef sun +# ifdef VM_X86_64 +# define FMTMODE "o" +# else +# define FMTMODE "lo" +# endif +#else +# define FMTMODE "o" +#endif + +/* + * Format modifier for printing time_t. Most platforms define a time_t to be + * a long int, but on FreeBSD (as of 5.0, it seems), the time_t is a signed + * size quantity. Refer to the definition of FMTSZ to see why we need silly + * preprocessor arithmetic. + * Use this like this: printf("The mode is %"FMTTIME".\n", time); + */ +#if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5) +# define FMTTIME FMTSZ"d" +#else +# define FMTTIME "ld" +#endif + +/* + * Define MXSemaHandle here so both vmmon and vmx see this definition. + */ + +#ifdef _WIN32 +typedef uintptr_t MXSemaHandle; +#else +typedef int MXSemaHandle; +#endif + +/* + * Define type for poll device handles. + */ + +#ifdef _WIN32 +typedef uintptr_t PollDevHandle; +#else +typedef int PollDevHandle; +#endif + +/* + * Define the utf16_t type. + */ + +#if defined(_WIN32) && defined(_NATIVE_WCHAR_T_DEFINED) +typedef wchar_t utf16_t; +#else +typedef uint16 utf16_t; +#endif + +#endif /* _VM_BASIC_TYPES_H_ */ diff -Nrup source/vmnet-only/include/vm_device_version.h source.edited/vmnet-only/include/vm_device_version.h --- source/vmnet-only/include/vm_device_version.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vm_device_version.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,186 @@ +/********************************************************* + * Copyright (C) 1998 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 + * + *********************************************************/ + +#ifndef VM_DEVICE_VERSION_H +#define VM_DEVICE_VERSION_H + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMMEXT +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMKERNEL +#define INCLUDE_ALLOW_VMCORE +#include "includeCheck.h" + +#ifdef _WIN32 +#include "guiddef.h" +#endif + +/* Our own PCI IDs + * VMware SVGA II (Unified VGA) + * VMware SVGA (PCI Accelerator) + * VMware vmxnet (Idealized NIC) + * VMware vmxscsi (Abortive idealized SCSI controller) + * VMware chipset (Subsystem ID for our motherboards) + * VMware e1000 (Subsystem ID) + * VMware vmxnet3 (Uniform Pass Through NIC) + */ +#define PCI_VENDOR_ID_VMWARE 0x15AD +#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 +#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 +#define PCI_DEVICE_ID_VMWARE_NET 0x0720 +#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 +#define PCI_DEVICE_ID_VMWARE_VMCI 0x0740 +#define PCI_DEVICE_ID_VMWARE_CHIPSET 0x1976 +#define PCI_DEVICE_ID_VMWARE_82545EM 0x0750 /* single port */ +#define PCI_DEVICE_ID_VMWARE_82546EB 0x0760 /* dual port */ +#define PCI_DEVICE_ID_VMWARE_EHCI 0x0770 +#define PCI_DEVICE_ID_VMWARE_1394 0x0780 +#define PCI_DEVICE_ID_VMWARE_BRIDGE 0x0790 +#define PCI_DEVICE_ID_VMWARE_ROOTPORT 0x07A0 +#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0 +#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0 + +/* The hypervisor device might grow. Please leave room + * for 7 more subfunctions. + */ +#define PCI_DEVICE_ID_VMWARE_HYPER 0x0800 +#define PCI_DEVICE_ID_VMWARE_VMI 0x0801 + +#define PCI_DEVICE_VMI_CLASS 0x05 +#define PCI_DEVICE_VMI_SUBCLASS 0x80 +#define PCI_DEVICE_VMI_INTERFACE 0x00 +#define PCI_DEVICE_VMI_REVISION 0x01 + +/* From linux/pci_ids.h: + * AMD Lance Ethernet controller + * BusLogic SCSI controller + * Ensoniq ES1371 sound controller + */ +#define PCI_VENDOR_ID_AMD 0x1022 +#define PCI_DEVICE_ID_AMD_VLANCE 0x2000 +#define PCI_VENDOR_ID_BUSLOGIC 0x104B +#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140 +#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040 +#define PCI_VENDOR_ID_ENSONIQ 0x1274 +#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 + +/* From linux/pci_ids.h: + * Intel 82439TX (430 HX North Bridge) + * Intel 82371AB (PIIX4 South Bridge) + * Intel 82443BX (440 BX North Bridge and AGP Bridge) + * Intel 82545EM (e1000, server adapter, single port) + * Intel 82546EB (e1000, server adapter, dual port) + */ +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_82439TX 0x7100 +#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 +#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 +#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 +#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 +#define PCI_DEVICE_ID_INTEL_82443BX 0x7190 +#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191 +#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 /* Used when no AGP support */ +#define PCI_DEVICE_ID_INTEL_82545EM 0x100f +#define PCI_DEVICE_ID_INTEL_82546EB 0x1010 + + +/************* Strings for IDE Identity Fields **************************/ +#define VIDE_ID_SERIAL_STR "00000000000000000001" /* Must be 20 Bytes */ +#define VIDE_ID_FIRMWARE_STR "00000001" /* Must be 8 Bytes */ + +/* No longer than 40 Bytes */ +#define VIDE_ATA_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE Hard Drive" +#define VIDE_ATAPI_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE CDROM Drive" + +#define ATAPI_VENDOR_ID "NECVMWar" /* Must be 8 Bytes */ +#define ATAPI_PRODUCT_ID PRODUCT_GENERIC_NAME " IDE CDROM" /* Must be 16 Bytes */ +#define ATAPI_REV_LEVEL "1.00" /* Must be 4 Bytes */ + +#define IDE_NUM_INTERFACES 2 /* support for two interfaces */ +#define IDE_DRIVES_PER_IF 2 + +/************* Strings for SCSI Identity Fields **************************/ +#define SCSI_DISK_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI Hard Drive" +#define SCSI_DISK_VENDOR_NAME COMPANY_NAME +#define SCSI_DISK_REV_LEVEL "1.0" +#define SCSI_CDROM_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI CDROM Drive" +#define SCSI_CDROM_VENDOR_NAME COMPANY_NAME +#define SCSI_CDROM_REV_LEVEL "1.0" + +/************* SCSI implementation limits ********************************/ +#define SCSI_MAX_CONTROLLERS 4 // Need more than 1 for MSCS clustering +#define SCSI_MAX_DEVICES 16 // BT-958 emulates only 16 +#define SCSI_IDE_CHANNEL SCSI_MAX_CONTROLLERS +#define SCSI_IDE_HOSTED_CHANNEL (SCSI_MAX_CONTROLLERS + 1) +#define SCSI_MAX_CHANNELS (SCSI_MAX_CONTROLLERS + 2) + +/************* Strings for the VESA BIOS Identity Fields *****************/ +#define VBE_OEM_STRING COMPANY_NAME " SVGA" +#define VBE_VENDOR_NAME COMPANY_NAME +#define VBE_PRODUCT_NAME PRODUCT_GENERIC_NAME + +/************* PCI implementation limits ********************************/ +#define PCI_MAX_BRIDGES 15 + +/************* Ethernet implementation limits ***************************/ +#define MAX_ETHERNET_CARDS 10 + +/************* PCI Passthrough implementation limits ********************/ +#define MAX_PCI_PASSTHRU_DEVICES 2 + +/************* USB implementation limits ********************************/ +#define MAX_USB_DEVICES_PER_HOST_CONTROLLER 127 + +/************* Strings for Host USB Driver *******************************/ + +#ifdef _WIN32 + +/* + * Globally unique ID for the VMware device interface. Define INITGUID before including + * this header file to instantiate the variable. + */ +DEFINE_GUID(GUID_DEVICE_INTERFACE_VMWARE_USB_DEVICES, +0x2da1fe75, 0xaab3, 0x4d2c, 0xac, 0xdf, 0x39, 0x8, 0x8c, 0xad, 0xa6, 0x65); + +/* + * Globally unique ID for the VMware device setup class. + */ +DEFINE_GUID(GUID_CLASS_VMWARE_USB_DEVICES, +0x3b3e62a5, 0x3556, 0x4d7e, 0xad, 0xad, 0xf5, 0xfa, 0x3a, 0x71, 0x2b, 0x56); + +/* + * This string defines the device ID string of a VMware USB device. + * The format is USB\Vid_XXXX&Pid_YYYY, where XXXX and YYYY are the + * hexadecimal representations of the vendor and product ids, respectively. + * + * The official vendor ID for VMware, Inc. is 0x0E0F. + * The product id for USB generic devices is 0x0001. + */ +#define USB_VMWARE_DEVICE_ID_WIDE L"USB\\Vid_0E0F&Pid_0001" +#define USB_DEVICE_ID_LENGTH (sizeof(USB_VMWARE_DEVICE_ID_WIDE) / sizeof(WCHAR)) + +#ifdef UNICODE +#define USB_PNP_SETUP_CLASS_NAME L"VMwareUSBDevices" +#define USB_PNP_DRIVER_NAME L"vmusb" +#else +#define USB_PNP_SETUP_CLASS_NAME "VMwareUSBDevices" +#define USB_PNP_DRIVER_NAME "vmusb" +#endif +#endif + +#endif /* VM_DEVICE_VERSION_H */ diff -Nrup source/vmnet-only/include/vmnetInt.h source.edited/vmnet-only/include/vmnetInt.h --- source/vmnet-only/include/vmnetInt.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vmnetInt.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,169 @@ +/********************************************************* + * Copyright (C) 1998 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 + * + *********************************************************/ + +#ifndef __VMNETINT_H__ +#define __VMNETINT_H__ + + +#define INCLUDE_ALLOW_MODULE +#include "includeCheck.h" +#include "driver-config.h" + + +/* + * Hide all kernel compatibility stuff in those macros. This part of code + * is used only when building prebuilt modules, when autoconf code is disabled. + */ + +/* All kernels above 2.6.23 have net namespaces. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && !defined(VMW_NETDEV_HAS_NET) +# define VMW_NETDEV_HAS_NET +#endif + +/* All kernels above 2.6.23 have skb argument in nf_hookfn. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && !defined(VMW_NFHOOK_USES_SKB) +# define VMW_NFHOOK_USES_SKB +#endif + +/* All kernels above 2.6.25 have dev_net & friends. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) && !defined(VMW_NETDEV_HAS_DEV_NET) +# define VMW_NETDEV_HAS_DEV_NET +#endif + + +#ifdef KERNEL_2_4_0 +# define compat_fop_set_owner(_pFop) do { \ + (_pFop)->owner = THIS_MODULE; \ +} while (0) +# define compat_mod_inc_refcount +# define compat_mod_dec_refcount +#else +# define compat_fop_set_owner(_pFop) +# define compat_mod_inc_refcount do { \ + MOD_INC_USE_COUNT; \ +} while (0) +# define compat_mod_dec_refcount do { \ + MOD_DEC_USE_COUNT; \ +} while (0) +#endif + + +#ifdef skb_shinfo +# define SKB_IS_CLONE_OF(clone, skb) ( \ + skb_shinfo(clone) == skb_shinfo(skb) \ + ) +#else +# define SKB_IS_CLONE_OF(clone, skb) ( \ + skb_datarefp(clone) == skb_datarefp(skb) \ + ) +#endif +#define DEV_QUEUE_XMIT(skb, dev, pri) ( \ + (skb)->dev = (dev), \ + (skb)->priority = (pri), \ + compat_skb_reset_mac_header(skb), \ + compat_skb_set_network_header(skb, sizeof (struct ethhdr)), \ + dev_queue_xmit(skb) \ + ) +#ifdef KERNEL_2_3_15 +# define dev_lock_list() read_lock(&dev_base_lock) +# define dev_unlock_list() read_unlock(&dev_base_lock) +# ifdef VMW_NETDEV_HAS_NET +# define DEV_GET(x) __dev_get_by_name(&init_net, (x)->name) +# ifdef VMW_NETDEV_HAS_DEV_NET +# define compat_dev_net(x) dev_net(x) +# else +# define compat_dev_net(x) (x)->nd_net +# endif +# else +# define DEV_GET(x) __dev_get_by_name((x)->name) +# endif +#else +# define DEV_GET(x) dev_get((x)->name) +#endif + + +/* + * Various fields (including 'dead') of struct sock are replaced with the + * 'flags' bitfield in 2.5.65, with sock_valbool_flag() to set flag's + * value. Since 2.5.71 there is sock_set_flag() to set bit to 1, and + * since 2.6.25-rc1 sock_valbool_flag() is gone. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65) +# define SET_SK_DEAD(_sk) (_sk)->dead = 1 +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 71) +# define SET_SK_DEAD(_sk) sock_valbool_flag(_sk, SOCK_DEAD, 1) +#else +# define SET_SK_DEAD(_sk) sock_set_flag(_sk, SOCK_DEAD) +#endif + + +#ifdef VMW_NETDEV_HAS_NET +extern struct proto vmnet_proto; +# define compat_sk_alloc(_bri, _pri) sk_alloc(&init_net, \ + PF_NETLINK, _pri, &vmnet_proto) +#elif defined(VMW_HAVE_SK_ALLOC_WITH_PROTO) +extern struct proto vmnet_proto; +# define compat_sk_alloc(_bri, _pri) sk_alloc(PF_NETLINK, _pri, &vmnet_proto, 1) +#elif defined(KERNEL_2_5_5) +# define compat_sk_alloc(_bri, _pri) sk_alloc(PF_NETLINK, _pri, 1, NULL) +#else +# define compat_sk_alloc(_bri, _pri) sk_alloc(0, _pri, 1) +#endif + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +# define fileTraversalLock(lock) spin_lock(lock) +# define fileTraversalUnLock(lock) spin_unlock(lock) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +# define fileTraversalLock(lock) read_lock(lock) +# define fileTraversalUnLock(lock) read_unlock(lock) +#else //2.2 kernels +# define fileTraversalLock(lock) lock_kernel() +# define fileTraversalUnLock(lock) unlock_kernel() +#endif + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +# define taskLock(lock) task_lock(lock) +# define taskUnLock(lock) task_unlock(lock) +#else //2.2 kernels +# define taskLock(lock) lock_kernel() +# define taskUnLock(lock) unlock_kernel() +#endif + + +/* + * The "owner" field in nf_hook_ops got added in 2.5.69 + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69) +# define compat_nf_hook_owner .owner = THIS_MODULE, +#else +# define compat_nf_hook_owner +#endif + + +#ifdef NF_IP_LOCAL_IN +#define VMW_NF_INET_LOCAL_IN NF_IP_LOCAL_IN +#define VMW_NF_INET_POST_ROUTING NF_IP_POST_ROUTING +#else +#define VMW_NF_INET_LOCAL_IN NF_INET_LOCAL_IN +#define VMW_NF_INET_POST_ROUTING NF_INET_POST_ROUTING +#endif + + +#endif /* __VMNETINT_H__ */ diff -Nrup source/vmnet-only/include/vm_oui.h source.edited/vmnet-only/include/vm_oui.h --- source/vmnet-only/include/vm_oui.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vm_oui.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,177 @@ +/********************************************************* + * Copyright (C) 1998 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 + * + *********************************************************/ + +#ifndef _VM_OUI_H_ +#define _VM_OUI_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_VMKERNEL +#include "includeCheck.h" + +#include "vm_basic_asm.h" + +/* + * Our own OUIs given by IEEE. + */ + +/* + * This OUI was previously used for generated macs on ESX. + * Don't use it for anything anymore or I'll slab you. --gustav + */ +#define VMX86_LEGACY_OUI 0x000569 + +/* This OUI is used for static MAC addresses. */ +#define VMX86_STATIC_OUI 0x005056 + +/* This OUI is used for generated MAC addresses. */ +#define VMX86_GENERATED_OUI 0x000C29 + +/* Entire OUI is reserved and should not be used for any purpose. */ +#define VMX86_FUTURE_OUI 0x001C14 + +#define VMX86_OUI_SIZE 3 + +#define VMX86_LEGACY_OUI0 ((uint8) (VMX86_LEGACY_OUI >> (VMX86_OUI_SIZE - 1) * 8)) +#define VMX86_LEGACY_OUI1 ((uint8) (VMX86_LEGACY_OUI >> (VMX86_OUI_SIZE - 2) * 8)) +#define VMX86_LEGACY_OUI2 ((uint8) (VMX86_LEGACY_OUI >> (VMX86_OUI_SIZE - 3) * 8)) + +#define VMX86_STATIC_OUI0 ((uint8) (VMX86_STATIC_OUI >> (VMX86_OUI_SIZE - 1) * 8)) +#define VMX86_STATIC_OUI1 ((uint8) (VMX86_STATIC_OUI >> (VMX86_OUI_SIZE - 2) * 8)) +#define VMX86_STATIC_OUI2 ((uint8) (VMX86_STATIC_OUI >> (VMX86_OUI_SIZE - 3) * 8)) + +#define VMX86_GEN_OUI0 ((uint8) (VMX86_GENERATED_OUI >> (VMX86_OUI_SIZE - 1) * 8)) +#define VMX86_GEN_OUI1 ((uint8) (VMX86_GENERATED_OUI >> (VMX86_OUI_SIZE - 2) * 8)) +#define VMX86_GEN_OUI2 ((uint8) (VMX86_GENERATED_OUI >> (VMX86_OUI_SIZE - 3) * 8)) + +#define VMX86_FUTURE_OUI0 ((uint8) (VMX86_FUTURE_OUI >> (VMX86_OUI_SIZE - 1) * 8)) +#define VMX86_FUTURE_OUI1 ((uint8) (VMX86_FUTURE_OUI >> (VMX86_OUI_SIZE - 2) * 8)) +#define VMX86_FUTURE_OUI2 ((uint8) (VMX86_FUTURE_OUI >> (VMX86_OUI_SIZE - 3) * 8)) + +/* This OUI is used for generated WWN addresses. */ +/* What exactly is a WWN address, anyway? */ +#define VMX86_STATIC_WWN_OUI 0x000C29 + +#define VMX86_WWN_OUI_SIZE 3 + +#define VMX86_STATIC_WWN_OUI0 ((uint8) (VMX86_STATIC_WWN_OUI >> (VMX86_WWN_OUI_SIZE - 1) * 8)) +#define VMX86_STATIC_WWN_OUI1 ((uint8) (VMX86_STATIC_WWN_OUI >> (VMX86_WWN_OUI_SIZE - 2) * 8)) +#define VMX86_STATIC_WWN_OUI2 ((uint8) (VMX86_STATIC_WWN_OUI >> (VMX86_WWN_OUI_SIZE - 3) * 8)) + +/* + * Top 2 bits of byte 3 of MAC address + */ + +#define VMX86_MAC_PREFIX 0xc0 +#define VMX86_MAC_RESERVED 0xc0 // reserved private MAC range. +#define VMX86_MAC_VPX 0x80 // VPX MAC range (old IP-based) +#define VMX86_MAC_STATIC 0x00 // reserved static MAC range. +#define VMX86_MAC_ESX 0x40 // standalone ESX VNIC MAC range. + +/* + * Bits left for MAC address assignment + * + * The explicit casts shut the compiler up. -- edward + */ + +#define VMX86_MAC_BITS 22 + +#define VMX86_IS_STATIC_OUI(addr) \ + ((addr)[0] == VMX86_STATIC_OUI0 && \ + (addr)[1] == VMX86_STATIC_OUI1 && \ + (addr)[2] == VMX86_STATIC_OUI2) + +#define VMX86_IS_GENERATED_OUI(addr) \ + ((addr)[0] == VMX86_GEN_OUI0 && \ + (addr)[1] == VMX86_GEN_OUI1 && \ + (addr)[2] == VMX86_GEN_OUI2) + +#define VMX86_IS_FUTURE_OUI(addr) \ + ((addr)[0] == VMX86_FUTURE_OUI0 && \ + (addr)[1] == VMX86_FUTURE_OUI1 && \ + (addr)[2] == VMX86_FUTURE_OUI2) + +#define VMX86_IS_RESERVED_MAC(addr) \ + (VMX86_IS_STATIC_OUI(addr) && \ + ((addr)[3] & VMX86_MAC_PREFIX) == VMX86_MAC_RESERVED) + +#define VMX86_IS_STATIC_MAC(addr) \ + (VMX86_IS_STATIC_OUI(addr) && \ + ((addr)[3] & VMX86_MAC_PREFIX) == VMX86_MAC_STATIC) + +#define VMX86_IS_VPX_MAC(addr) \ + (VMX86_IS_STATIC_OUI(addr) && \ + ((addr)[3] & VMX86_MAC_PREFIX) == VMX86_MAC_VPX) + +/* + * MAC addresses reserved for hostonly adapters. + */ +#define VMX86_IS_VIRT_ADAPTER_MAC(addr) \ + (VMX86_IS_RESERVED_MAC(addr) && \ + ((addr)[3] & ~VMX86_MAC_PREFIX) == 0x00 && \ + (addr)[4] == 0x00) + +#define VMX86_BUILD_MAC(addr, suffix) do { \ + (addr)[0] = VMX86_STATIC_OUI0; \ + (addr)[1] = VMX86_STATIC_OUI1; \ + (addr)[2] = VMX86_STATIC_OUI2; \ + (addr)[3] = (uint8) (VMX86_MAC_RESERVED \ + | (((suffix) >> 16) & ~VMX86_MAC_PREFIX)); \ + (addr)[4] = (uint8) ((suffix) >> 8); \ + (addr)[5] = (uint8) (suffix); \ +} while (0) + + +/* + * Generate a random static MAC usable by devices that are not + * virtual host adapters. + */ + +static INLINE void +VMX86_GENERATE_RANDOM_MAC(uint8 mac[6]) +{ + uint32 offset, r; + + /* + * We use the offset to only generate addresses in the range + * 0xe0:00:00-0xff:ff:ff instead of 0xc0:00:00-0xff:ff:ff. + * We reserve the lower range for other purposes that may come + * later. + * E.g. virtual host adapters use the range c0:00:00-c0:00:ff. + */ + offset = 0x200000; + /* Randomize bits 20-0 and make them unique on this machine. */ + r = (uint32)RDTSC(); + VMX86_BUILD_MAC(mac, r | offset); +} + + +static INLINE void +VMX86_GENERATE_LEGACY_MAC(uint8 mac[6], //OUT: + uint32 suffix) //IN: Only 3 lower bytes are used. +{ + mac[0] = VMX86_LEGACY_OUI0; + mac[1] = VMX86_LEGACY_OUI1; + mac[2] = VMX86_LEGACY_OUI2; + mac[3] = (suffix >> 16) & 0xff; + mac[4] = (suffix >> 8) & 0xff; + mac[5] = (suffix) & 0xff; +} + +#endif diff -Nrup source/vmnet-only/include/vmware_pack_begin.h source.edited/vmnet-only/include/vmware_pack_begin.h --- source/vmnet-only/include/vmware_pack_begin.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vmware_pack_begin.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,43 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +/* + * vmware_pack_begin.h -- + * + * Begin of structure packing. See vmware_pack_init.h for details. + * + * Note that we do not use the following construct in this include file, + * because we want to emit the code every time the file is included --hpreg + * + * #ifndef foo + * # define foo + * ... + * #endif + * + */ + + +#include "vmware_pack_init.h" + + +#ifdef _MSC_VER +# pragma pack(push, 1) +#elif __GNUC__ +#else +# error Compiler packing... +#endif diff -Nrup source/vmnet-only/include/vmware_pack_end.h source.edited/vmnet-only/include/vmware_pack_end.h --- source/vmnet-only/include/vmware_pack_end.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vmware_pack_end.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,44 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +/* + * vmware_pack_end.h -- + * + * End of structure packing. See vmware_pack_init.h for details. + * + * Note that we do not use the following construct in this include file, + * because we want to emit the code every time the file is included --hpreg + * + * #ifndef foo + * # define foo + * ... + * #endif + * + */ + + +#include "vmware_pack_init.h" + + +#ifdef _MSC_VER +# pragma pack(pop) +#elif __GNUC__ +__attribute__((__packed__)) +#else +# error Compiler packing... +#endif diff -Nrup source/vmnet-only/include/vmware_pack_init.h source.edited/vmnet-only/include/vmware_pack_init.h --- source/vmnet-only/include/vmware_pack_init.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vmware_pack_init.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,65 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +#ifndef __VMWARE_PACK_INIT_H__ +# define __VMWARE_PACK_INIT_H__ + + +/* + * vmware_pack_init.h -- + * + * Platform-independent code to make the compiler pack (i.e. have them + * occupy the smallest possible space) structure definitions. The following + * constructs are known to work --hpreg + * + * #include "vmware_pack_begin.h" + * struct foo { + * ... + * } + * #include "vmware_pack_end.h" + * ; + * + * typedef + * #include "vmware_pack_begin.h" + * struct foo { + * ... + * } + * #include "vmware_pack_end.h" + * foo; + */ + + +#ifdef _MSC_VER +/* + * MSVC 6.0 emits warning 4103 when the pack push and pop pragma pairing is + * not balanced within 1 included file. That is annoying because our scheme + * is based on the pairing being balanced between 2 included files. + * + * So we disable this warning, but this is safe because the compiler will also + * emit warning 4161 when there is more pops than pushes within 1 main + * file --hpreg + */ + +# pragma warning(disable:4103) +#elif __GNUC__ +#else +# error Compiler packing... +#endif + + +#endif /* __VMWARE_PACK_INIT_H__ */ diff -Nrup source/vmnet-only/include/vnetEvent.h source.edited/vmnet-only/include/vnetEvent.h --- source/vmnet-only/include/vnetEvent.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vnetEvent.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,50 @@ +/********************************************************* + * Copyright (C) 2007 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 + * + *********************************************************/ + +/* + * vnetEvent.h -- + */ + +#ifndef _VNETEVENT_H_ +#define _VNETEVENT_H_ + +#include "vm_basic_types.h" +#include "vnet.h" + +typedef struct VNetEvent_Mechanism VNetEvent_Mechanism; + +typedef struct VNetEvent_Sender VNetEvent_Sender; + +typedef struct VNetEvent_Listener VNetEvent_Listener; + +typedef void (*VNetEvent_Handler)(void *data, VNet_EventHeader *e); + +int VNetEvent_CreateMechanism(VNetEvent_Mechanism **m); +int VNetEvent_DestroyMechanism(VNetEvent_Mechanism *m); + +int VNetEvent_CreateSender(VNetEvent_Mechanism *m, VNetEvent_Sender **s); +int VNetEvent_DestroySender(VNetEvent_Sender *s); +int VNetEvent_Send(VNetEvent_Sender *s, VNet_EventHeader *e); +int VNetEvent_GetSenderId(const VNetEvent_Sender *s, uint32 *senderId); + +int VNetEvent_CreateListener(VNetEvent_Mechanism *m, VNetEvent_Handler h, + void *data, uint32 classMask, + VNetEvent_Listener **l); +int VNetEvent_DestroyListener(VNetEvent_Listener *l); + +#endif // _VNETEVENT_H_ diff -Nrup source/vmnet-only/include/vnetFilter.h source.edited/vmnet-only/include/vnetFilter.h --- source/vmnet-only/include/vnetFilter.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vnetFilter.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,207 @@ +/********************************************************* + * 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 + * + *********************************************************/ + +/* + * vnetFilter.h -- + * + * This file defines the external interface provided + * by the vmnet driver for host packet filter + * functionality. This functionality is likely to + * be eventually moved to a separate driver. + * + */ + +#ifndef _VNETFILTER_H_ +#define _VNETFILTER_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_MODULE +#include "includeCheck.h" + +#include "vm_basic_types.h" + +/* + * Call: + * Windows vmnet driver using IOCTL_VNET_FILTERHOST2. + * Linux vmnet driver using SIOCSFILTERRULES. + */ + + +/* list of subcommands for the host filter ioctl() call */ +#define VNET_FILTER_CMD_MIN 0x1000 /* equal to smallest sub-command */ +#define VNET_FILTER_CMD_CREATE_RULE_SET 0x1000 +#define VNET_FILTER_CMD_DELETE_RULE_SET 0x1001 +#define VNET_FILTER_CMD_ADD_IPV4_RULE 0x1002 +#define VNET_FILTER_CMD_ADD_IPV6_RULE 0x1003 /* not implemented */ +#define VNET_FILTER_CMD_CHANGE_RULE_SET 0x1004 +#define VNET_FILTER_CMD_SET_LOG_LEVEL 0x1005 +#define VNET_FILTER_CMD_MAX 0x1005 /* equal to largest sub-command */ + +/* action for a rule or rule set */ +/* VNet_CreateRuleSet.defaultAction */ +/* VNet_AddIPv4Rule.action */ +/* VNet_ChangeRuleSet.defaultAction */ +#define VNET_FILTER_RULE_NO_CHANGE 0x2000 +#define VNET_FILTER_RULE_BLOCK 0x2001 +#define VNET_FILTER_RULE_ALLOW 0x2002 + +/* direction that should apply to a rule */ +/* VNet_AddIPv4Rule.direction */ +#define VNET_FILTER_DIRECTION_IN 0x3001 +#define VNET_FILTER_DIRECTION_OUT 0x3002 +#define VNET_FILTER_DIRECTION_BOTH 0x3003 + +/* used to change which rule set is used for host filtering */ +/* VNet_ChangeRuleSet.activate */ +#define VNET_FILTER_STATE_NO_CHANGE 0x4000 +#define VNET_FILTER_STATE_ENABLE 0x4001 +#define VNET_FILTER_STATE_DISABLE 0x4002 + +/* log Levels, cut and paste from bora/lib/public/policy.h */ +#define VNET_FILTER_LOGLEVEL_NONE (0) +#define VNET_FILTER_LOGLEVEL_TERSE (1) +#define VNET_FILTER_LOGLEVEL_NORMAL (2) +#define VNET_FILTER_LOGLEVEL_VERBOSE (3) +#define VNET_FILTER_LOGLEVEL_MAXIMUM (4) + +/* header that's common for all command structs */ +typedef +#include "vmware_pack_begin.h" +struct VNet_RuleHeader { + uint32 type; /* type of struct */ + uint32 ver; /* version of struct */ + uint32 len; /* length of struct */ +} +#include "vmware_pack_end.h" +VNet_RuleHeader; + +typedef +#include "vmware_pack_begin.h" +struct VNet_CreateRuleSet { + VNet_RuleHeader header; /* type = VNET_FILTER_CMD_CREATE_RULE_SET, ver = 1, + len = sizeof(VNet_CreateRuleSet) */ + + uint32 ruleSetId; /* id of rule to delete (must be non-0) */ + uint32 defaultAction; /* VNET_FILTER_RULE_DROP or VNET_FILTER_RULE_PERMIT */ +} +#include "vmware_pack_end.h" +VNet_CreateRuleSet; + +typedef +#include "vmware_pack_begin.h" +struct VNet_DeleteRuleSet { + VNet_RuleHeader header; /* type = VNET_FILTER_CMD_DELETE_RULE_SET, ver = 1, + len = sizeof(VNet_DeleteRuleSet) */ + + uint32 ruleSetId; /* rule set to delete (from VNet_CreateRuleSet.ruleSetId) */ +} +#include "vmware_pack_end.h" +VNet_DeleteRuleSet; + +typedef +#include "vmware_pack_begin.h" +struct VNet_AddIPv4Rule { + VNet_RuleHeader header; /* type = VNET_FILTER_CMD_ADD_IPV4_RULE, ver = 1, + len = sizeof(VNet_AddIPv4Rule) + + addrListLen * sizeof(VNet_IPv4Address) + + protoListLen * sizeof(VNet_IPv4Protocol) */ + + uint32 ruleSetId; /* rule set (from VNet_CreateRuleSet.ruleSetId) */ + uint32 action; /* VNET_FILTER_RULE_DROP or VNET_FILTER_RULE_PERMIT */ + uint32 direction; /* VNET_FILTER_DIRECTION_IN, VNET_FILTER_DIRECTION_OUT, or + VNET_FILTER_DIRECTION_BOTH */ + + uint32 addressListLen; /* Number of VNet_IPv4Address's that follow. + Must be at least one. Must equal 1 if addr==mask==0. + expected but not required: (addr & ~mask) == 0 */ + + uint32 proto; /* ~0 is don't care, otherwise protocol in IP header*/ + + uint32 portListLen; /* Number of VNet_IPv4Port's that follow the + VNet_IPv4Address's. Ports currently only apply for + TCP and UDP. Must be at least one, even if non-TCP or + non-UDP protocol is specified in 'proto' (use 0 or ~0 for + all elements in VNet_IPv4Port). Must equal 1 if all + elements in a VNet_IPv4Port are ~0. */ + /* add flags for tracking in which direction the connection is established? */ +} +#include "vmware_pack_end.h" +VNet_AddIPv4Rule; + +/* + * VNet_AddIPv4Rule is immediately followed by 1 or more VNet_IPv4Address. + * The last VNet_IPv4Address is immediately followed by 1 or more VNet_IPv4Port. + */ + +typedef +#include "vmware_pack_begin.h" +struct VNet_IPv4Address { + /* currently no fields for local address/mask (add them?) */ + + /* can specify don't care on IP address via addr==mask==0, + but only for a list with 1 item */ + uint32 ipv4RemoteAddr; /* remote entity's address (dst on outbound, src on inbound) */ + uint32 ipv4RemoteMask; /* remote entity's mask (dst on outbound, src on inbound) */ +} +#include "vmware_pack_end.h" +VNet_IPv4Address; + +typedef +#include "vmware_pack_begin.h" +struct VNet_IPv4Port { + /* can specify ~0 for all 4 only if one item in the list */ + + uint32 localPortLow; /* ~0 is don't care, otherwise low local range (inclusive) */ + uint32 localPortHigh; /* ~0 is don't care, otherwise high local range (inclusive) */ + uint32 remotePortLow; /* ~0 is don't care, otherwise low remote range (inclusive) */ + uint32 remotePortHigh; /* ~0 is don't care, otherwise high remote range (inclusive) */ +} +#include "vmware_pack_end.h" +VNet_IPv4Port; + +// typedef struct VNet_IPv4Port VNet_IPv6Port; + +typedef +#include "vmware_pack_begin.h" +struct VNet_ChangeRuleSet { + VNet_RuleHeader header; /* type = VNET_FILTER_CMD_CHANGE_RULE_SET, ver = 1, + len = sizeof(VNet_ChangeRuleSet) */ + + uint32 ruleSetId; /* rule set (from VNet_CreateRuleSet.ruleSetId) */ + uint32 defaultAction; /* usually VNET_FILTER_RULE_NO_CHANGE, but can change default + rule via VNET_FILTER_RULE_DROP or VNET_FILTER_RULE_PERMIT */ + uint32 activate; /* specify rule to use for filtering via + VNET_FILTER_STATE_ENABLE or VNET_FILTER_STATE_DISABLE. + Can use VNET_FILTER_STATE_NO_CHANGE to change only the + default rule of the rule set */ +} +#include "vmware_pack_end.h" +VNet_ChangeRuleSet; + +typedef +#include "vmware_pack_begin.h" +struct VNet_SetLogLevel { + VNet_RuleHeader header; /* type = VNET_FILTER_CMD_SET_LOG_LEVEL, */ + /* ver = 1, */ + /* len = sizeof(VNet_SetLogLevel) */ + uint32 logLevel; /* the log level to set */ +} +#include "vmware_pack_end.h" +VNet_SetLogLevel; + +#endif // ifndef _VNETFILTER_H_ diff -Nrup source/vmnet-only/include/vnetFilterInt.h source.edited/vmnet-only/include/vnetFilterInt.h --- source/vmnet-only/include/vnetFilterInt.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vnetFilterInt.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,75 @@ +/********************************************************* + * 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 + * + *********************************************************/ + +/* + * vnetFilterInt.h + * This file defines platform-independent structures and limits that are + * internally used in the vmnet driver for packet filtering. + */ + +#ifndef _VNETFILTERINT_H_ +#define _VNETFILTERINT_H_ + +#define MAX_RULE_SETS 32 /* maximum rule sets to allow */ +#define MAX_RULES_PER_SET 64 /* maximum rules for each rule set */ +#define MAX_ADDR_PER_RULE 64 /* maximum IP addresses for one rule */ +#define MAX_PORT_PER_RULE 64 /* maximum ports for one rule */ + +typedef struct RuleAddr { + uint32 ipv4Addr; /* remote entity's address (dst on outbound, src on inbound) */ + uint32 ipv4Mask; /* remote entity's mask (dst on outbound, src on inbound) */ +} RuleAddr; + +typedef struct RulePort { + uint32 localPortLow; /* ~0 is don't care, otherwise low local range (inclusive) */ + uint32 localPortHigh; /* ~0 is don't care, otherwise high local range (inclusive) */ + uint32 remotePortLow; /* ~0 is don't care, otherwise low remote range (inclusive) */ + uint32 remotePortHigh; /* ~0 is don't care, otherwise low remote range (inclusive) */ +} RulePort; + +typedef struct Rule { + struct Rule *next; /* used for linked list */ + + uint16 action; /* VNET_FILTER_RULE_BLOCK, or VNET_FILTER_RULE_ALLOW */ + uint16 direction; /* VNET_FILTER_DIRECTION_IN, + VNET_FILTER_DIRECTION_OUT, + VNET_FILTER_DIRECTION_BOTH */ + + uint8 addressListLen; /* items in addressList (0 means don't care about address) */ + uint8 portListLen; /* items in portList (0 means don't care about port) */ + + uint16 proto; /* IP protocol that rule applies to (e.g., TCP or UDP) */ + /* ~0 mean don't care, in which case "portList" is ignored */ + + RuleAddr *addressList; /* list of IP addresses for rule */ + + RulePort *portList; /* list of port ranges for rule (if proto is TCP or UDP) */ +} Rule; + +typedef struct RuleSet { + struct RuleSet *next; /* next item in linked list */ + uint32 id; /* id provided to user-mode application */ + uint16 enabled; /* bool: tracks if used enabled to take effect for filtering */ + uint16 action; /* default action to use for rule */ + /* VNET_FILTER_RULE_BLOCK, or VNET_FILTER_RULE_ALLOW */ + struct Rule *list; /* first rule in rule set */ + struct Rule **tail; /* used to quickly add element to end of list */ + uint32 numRules; /* number of rules in 'list' */ +} RuleSet; + +#endif // _VNETFILTERINT_H_ diff -Nrup source/vmnet-only/include/vnet.h source.edited/vmnet-only/include/vnet.h --- source/vmnet-only/include/vnet.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vnet.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,415 @@ +/********************************************************* + * Copyright (C) 1998 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 + * + *********************************************************/ + +#ifndef _VNET_H +#define _VNET_H + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMK_MODULE +#define INCLUDE_ALLOW_VMMEXT +#include "includeCheck.h" +#include "vm_basic_types.h" +#include "vm_atomic.h" + +#define VNET_PVN_ABI_ID_LEN (256 / 8) // bytes used on ioctl() +#define VNET_PVN_ID_LEN (160 / 8) // actual length used + +#define VNET_BIND_VERSION 0x1 +#define VNET_BIND_TO_VNET 0x1 +#define VNET_BIND_TO_PVN 0x2 + +typedef struct VNet_Bind { + uint32 version; // VNET_BIND_VERSION + uint32 bindType; // VNET_BIND_TO_xxx + int32 number; // used for VNET_BIND_TO_VNET + uint8 id[VNET_PVN_ABI_ID_LEN]; // used for VNET_BIND_TO_PVN +} VNet_Bind; + +/* + * We define customized ioctl commands by adding 0x1000 + * to the standard Linux definitions. + * + * See comments in iocontrols.h + */ + +#define VNET_FIRST_CMD 0x99F2 + +// #define SIOCSKEEP 0x99F0 // not used +// #define SIOCGKEEP 0x99F1 // not used +#define SIOCSLADRF 0x99F2 +#define SIOCPORT 0x99F3 +#define SIOCBRIDGE 0x99F4 +#define SIOCNETIF 0x99F5 + +#define SIOCSETMACADDR 0x99F6 +#define SIOCSSWITCHMAP 0x99F7 +#define SIOCSETNOTIFY 0x99F8 +#define SIOCUNSETNOTIFY 0x99F9 +// #define SIOCSETCLUSTERSIZE 0x99FA // obsolete +#define SIOCSETNOTIFY2 0x99FB +#define SIOCGETAPIVERSION 0x99FC + +#define VNET_LAST_CMD 0x99FC + +#if defined __linux__ || defined __APPLE__ +#define SIOCGETAPIVERSION2 _IOWR(0x99, 0xE0, uint32) +#define SIOCGBRSTATUS _IOR(0x99, 0xFD, uint32) +#define SIOCSPEER _IOW(0x99, 0xFE, char[8]) +#define SIOCSPEER2 _IOW(0x99, 0xFE, char[32]) +#define SIOCSBIND _IOW(0x99, 0xFF, VNet_Bind) +#define SIOCSFILTERRULES _IOW(0x99, 0xE1, VNet_RuleHeader) +#define SIOCSUSERLISTENER _IOW(0x99, 0xE2, VNet_SetUserListener) +#endif + +#ifdef __APPLE__ + +#define VMNET_KEXT_NAME_BASE "com.vmware.kext.vmnet" + +#ifdef VMX86_DEVEL +#define VMNET_KEXT_NAME VMNET_KEXT_NAME_BASE ".devel" +#else +#define VMNET_KEXT_NAME VMNET_KEXT_NAME_BASE +#endif + +/* + * We use [gs]etsockopt on Mac OS instead of ioctls for operations on vmnet + */ +enum VMNetSockOpt { + VMNET_SO_APIVERSION = 0, // Must come first, should never change + VMNET_SO_BRSTATUS, + VMNET_SO_PEER, + VMNET_SO_BINDTOHUB, + VMNET_SO_IFADDR, + VMNET_SO_NETIFCREATE, + VMNET_SO_IFFLAGS, + VMNET_SO_LADRF, + VMNET_SO_BRCREATE, + VMNET_SO_SETNOTIFY, + VMNET_SO_READDATA, + VMNET_SO_UNSETNOTIFY, + VMNET_SO_SETUSERLISTENER +}; + +/* + * This magic value is populated in VNet_Notify.actMask and VNet_Notify.pollMask + * to request the driver to clear the Notify pollPtr if the receive queue is empty. + */ +#define VNET_NOTIFY_CLR_MAGIC 0xDECAFBAD + +typedef struct VNet_NetIf { + char name[16]; // The BSD name of the interface + uint8 instance; // The "unit number" of the interface +} VNet_NetIf; + +typedef struct VNet_Read { + VA uAddr; // Buffer to read into + size_t len; // Max number of bytes to read +} VNet_Read; + +#endif + +/* + * VMnet driver version. + * + * Increment major version when you make an incompatible change. + * Compatibility goes both ways (old driver with new executable + * as well as new driver with old executable). + * + * Features under the VNET_API_DEPRECATED define are deprecated (so don't use + * them), but are not important enough to justify an increase of major version. + * However, if for some other reason you need to bump the major version, please + * also remove all code under the VNET_API_DEPRECATED define. --hpreg + */ + +#ifdef linux +#define VNET_API_VERSION (3 << 16 | 0) +#elif defined __APPLE__ +#define VNET_API_VERSION (5 << 16 | 0) +#else +#define VNET_API_VERSION (5 << 16 | 0) +#endif +#define VNET_API_VERSION_MAJOR(v) ((uint32) (v) >> 16) +#define VNET_API_VERSION_MINOR(v) ((uint16) (v)) + +/* + * Make sure the deprecated code will not be compiled anymore starting with the + * next major version. --hpreg + */ +#ifdef linux +# if VNET_API_VERSION < (3 << 16 | 0) +# define VNET_API_DEPRECATED 1 +# endif +#else +# if VNET_API_VERSION < (4 << 16 | 0) +# define VNET_API_DEPRECATED 1 +# endif +#endif + +/* version 1 structure */ + +typedef struct VNet_SetMacAddrIOCTL { + int version; + unsigned char addr[6]; + unsigned flags; +} VNet_SetMacAddrIOCTL; + +typedef struct VNet_Notify { + uint32 version; + uint32 padding; /* Make gcc 64bit abi padding explicit */ + uint64 actPtr; /* (Atomic_uint32 *) */ + uint64 pollPtr; /* (uint32 volatile *) */ + uint64 recvClusterPtr; /* (uint32 volatile *) */ + uint32 actMask; + uint32 pollMask; +} VNet_Notify; + +#define VNET_SETMACADDRF_UNIQUE 0x01 +/* + * The latest 802.3 standard sort of says that the length field ought to + * be less than 1536 (for VLAN tagging support). I am choosing 1532 + * as our max VNET_MTU size, as I'd rather keep it a multiple of 4 and + * VLAN tagging uses only upto 1518 bytes. + */ +#define VNET_MTU 1532 + + +#define VNET_BUF_TOO_SMALL -1 + +/* + * vlan switch stuff + */ + + +#define VNET_MAX_VLANS 255 + +struct VNetSwitchMap { + int trunk; + int vlan; + int connect; + int vnet; +}; + +/* + *---------------------------------------------------------------------------- + * VNetEvent + *---------------------------------------------------------------------------- + */ + +/* the current version */ +#define VNET_EVENT_VERSION 1 + +/* event classes */ +#define VNET_EVENT_CLASS_BRIDGE 1 + +/* event types */ +#define VNET_EVENT_TYPE_LINK_STATE 0 + +/* parameter for SIOCSUSERLISTENER */ +typedef +#include "vmware_pack_begin.h" +struct VNet_SetUserListener { + uint32 version; + uint32 classMask; +} +#include "vmware_pack_end.h" +VNet_SetUserListener; + +/* the event header */ +typedef +#include "vmware_pack_begin.h" +struct VNet_EventHeader { + uint32 size; + uint32 senderId; + uint32 eventId; + uint32 classSet; + uint32 type; +} +#include "vmware_pack_end.h" +VNet_EventHeader; + +/* + * the link state event + * header = { sizeof(VNet_LinkStateEvent), ?, ?, VNET_EVENT_CLASS_BRIDGE, + * VNET_EVENT_TYPE_LINK_STATE } + */ +typedef +#include "vmware_pack_begin.h" +struct VNet_LinkStateEvent { + VNet_EventHeader header; + uint32 adapter; + Bool up; + char _pad[3]; +} +#include "vmware_pack_end.h" +VNet_LinkStateEvent; + +/* + *---------------------------------------------------------------------------- + */ + +#if defined __APPLE__ && !defined KERNEL + +#include +#include +#include "str.h" + +/* + *---------------------------------------------------------------------------- + * + * VMNetOpen -- + * + * Create a socket connected to the vmnet kernel control extension, bind + * it to a vmnet hub. Optionally make the socket non-blocking. Optionally + * set the interface MAC address. Optionally set interface flags. + * + * Results: + * Connected and bound socket on success. + * -1 on failure, returns error message in the "error" parameter. + * + * Side Effects: + * Allocates memory for returning "error" message to caller. Caller should + * remember to free(error). + * + *---------------------------------------------------------------------------- + */ + +static INLINE int +VMNetOpen(int hubNum, // IN: hub number to bind to + Bool nonBlocking, // IN: make socket non-blocking + VNet_SetMacAddrIOCTL *ifAddr, // IN: optional MAC address + uint32 flags, // IN: optional interface flags + char **error) // OUT: error message on failures +{ + int fd; + struct sockaddr_ctl addr; + struct ctl_info info; + socklen_t optlen; + uint32 apiVersion; + + fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + if (fd == -1) { + if (error) { + *error = Str_Asprintf(NULL, "Failed to create control socket: " + "errno %d\n", errno); + } + return -1; + } + + bzero(&addr, sizeof addr); + addr.sc_len = sizeof addr; + addr.sc_family = AF_SYSTEM; + addr.ss_sysaddr = AF_SYS_CONTROL; + + memset(&info, 0, sizeof info); + strncpy(info.ctl_name, VMNET_KEXT_NAME, sizeof info.ctl_name); + if (ioctl(fd, CTLIOCGINFO, &info)) { + if (error) { + *error = Str_Asprintf(NULL, "ioctl(CTLIOCGINFO) failed: errno %d\n", + errno); + } + goto exit_failure; + } + + addr.sc_id = info.ctl_id; + + if (connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0) { + if (error) { + *error = Str_Asprintf(NULL, "Connect to vmnet kext failed: errno %d\n", + errno); + } + goto exit_failure; + } + + /* Optionally make socket non-blocking */ + if (nonBlocking) { + int fFlags; + fFlags = fcntl(fd, F_GETFL); + if (fFlags == -1 || fcntl(fd, F_SETFL, fFlags | O_NONBLOCK) < 0) { + if (error) { + *error = Str_Asprintf(NULL, "Couldn't make socket non-blocking: " + "errno %d\n", errno); + } + goto exit_failure; + } + } + + optlen = sizeof apiVersion; + if (getsockopt(fd, SYSPROTO_CONTROL, VMNET_SO_APIVERSION, &apiVersion, + &optlen) < 0) { + if (error) { + *error = Str_Asprintf(NULL, "getsockopt(VMNET_SO_APIVERSION) failed: " + "errno %d\n", errno); + } + goto exit_failure; + } + + if (VNET_API_VERSION_MAJOR(apiVersion) != + VNET_API_VERSION_MAJOR(VNET_API_VERSION)) { + if (error) { + *error = Str_Asprintf(NULL, "Module version mismatch. Please update " + "host.\n"); + } + goto exit_failure; + } + + if (setsockopt(fd, SYSPROTO_CONTROL, VMNET_SO_BINDTOHUB, &hubNum, + sizeof hubNum) < 0) { + if (error) { + *error = Str_Asprintf(NULL, "Could not bind to hub %d: errno %d\n", + hubNum, errno); + } + goto exit_failure; + } + + /* Optionally set MAC address */ + if (ifAddr) { + if (setsockopt(fd, SYSPROTO_CONTROL, VMNET_SO_IFADDR, ifAddr, + sizeof (*ifAddr)) < 0) { + if (error) { + *error = Str_Asprintf(NULL, "Could not set MAC address: errno %d\n", + errno); + } + goto exit_failure; + } + } + + /* Optionally set interface flags */ + if (flags) { + if (setsockopt(fd, SYSPROTO_CONTROL, VMNET_SO_IFFLAGS, &flags, + sizeof flags) < 0) { + if (error) { + *error = Str_Asprintf(NULL, "Could not set interface flags to 0x%x: " + "errno %d\n", flags, errno); + } + goto exit_failure; + } + } + + /* Return success */ + return fd; + +exit_failure: + /* Return failure */ + close(fd); + return -1; +} + +#endif // __APPLE__ && ! KERNEL + +#endif diff -Nrup source/vmnet-only/include/vnetInt.h source.edited/vmnet-only/include/vnetInt.h --- source/vmnet-only/include/vnetInt.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vnetInt.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,351 @@ +/********************************************************* + * Copyright (C) 1998 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 + * + *********************************************************/ + +#ifndef _VNETINT_H +#define _VNETINT_H + +#define INCLUDE_ALLOW_MODULE +#include "includeCheck.h" +#include "vnet.h" +#include "vm_oui.h" +#include "net.h" +#include "vnetEvent.h" + +#include + +#define INLINE inline + + +/* + * Logging + */ + +#ifdef notdef +#ifdef VMX86_RELEASE +#define LOGLEVEL 0 +#else +#define LOGLEVEL 1 +#endif +#endif + +#define LOGLEVEL 1 + +#if LOGLEVEL >= 0 +#define LOG(level, args) ((void) (LOGLEVEL >= (level) ? (printk args) : 0)) +#else +#define LOG(level, args) +#endif + +#define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) + +/* + * Ethernet + */ + +#define MAC_EQ(_a, _b) !memcmp((_a), (_b), ETH_ALEN) +#define SKB_2_DESTMAC(_skb) (((struct ethhdr *)(_skb)->data)->h_dest) +#define SKB_2_SRCMAC(_skb) (((struct ethhdr *)(_skb)->data)->h_source) +#define UP_AND_RUNNING(_flags) (((_flags) & (IFF_RUNNING|IFF_UP)) == \ + (IFF_RUNNING|IFF_UP)) +#ifdef KERNEL_2_3_47 +#define NETDEV_UP_AND_RUNNING(dev) ((((dev)->flags) & IFF_UP) && netif_running(dev)) +#else +#ifdef KERNEL_2_3_43 +#define NETDEV_UP_AND_RUNNING(dev) ((((dev)->flags) & IFF_UP) && test_bit(LINK_STATE_START, &(dev)->state)) +#else +#define NETDEV_UP_AND_RUNNING(dev) UP_AND_RUNNING((dev)->flags) +#endif +#endif + +/* + * Misc defines + */ + +#define NULL_TERMINATE_STRING(a) (a)[sizeof (a) - 1] = '\0' + +/* + * Fundamental sizes + */ + +#define VNET_NUM_VNETS 256 +#define VNET_MAJOR_NUMBER 119 + +#define NUM_JACKS_PER_HUB 32 +#define VNET_MAX_QLEN 128 + +#define VNET_NUM_IPBASED_MACS 64 +#define VNET_MAX_JACK_NAME_LEN 16 + +#define VNET_LADRF_LEN 8 + +#if ( defined(IFNAMSIZ) && (IFNAMSIZ >= 16) ) +#define VNET_NAME_LEN IFNAMSIZ +#else +#define VNET_NAME_LEN 16 +#endif + +/* + * Data structures + */ + +typedef struct proc_dir_entry VNetProcEntry; + +typedef struct VNetJack VNetJack; +typedef struct VNetPort VNetPort; + +/* + * The jack is the basic mechanism for connecting to objects + * that send packet between them. + */ + +extern struct semaphore vnetStructureSemaphore; + +struct VNetJack { + VNetJack *peer; + int numPorts; + char name[VNET_MAX_JACK_NAME_LEN]; + void *private; // private field for containing object + int index; // private field for containing object + VNetProcEntry *procEntry; // private field for containing object + + void (*free)(VNetJack *this); + void (*rcv)(VNetJack *this, struct sk_buff *skb); + Bool (*cycleDetect)(VNetJack *this, int generation); + void (*portsChanged)(VNetJack *this); + int (*isBridged)(VNetJack *this); +}; + + +/* + * The port is an extension of the jack. It has a user level + * interface and an ethernet address. There are 3 types of ports: + * userif, netif, and bridge. + */ + +struct VNetPort { + VNetJack jack; // must be first + unsigned id; + uint32 flags; + uint8 paddr[ETH_ALEN]; + uint8 ladrf[VNET_LADRF_LEN]; + + VNetPort *next; + + int (*fileOpRead)(VNetPort *this, struct file *filp, + char *buf, size_t count); + int (*fileOpWrite)(VNetPort *this, struct file *filp, + const char *buf, size_t count); + int (*fileOpIoctl)(VNetPort *this, struct file *filp, + unsigned int iocmd, unsigned long ioarg); + int (*fileOpPoll)(VNetPort *this, struct file *filp, + poll_table *wait); +}; + + + +/* + * Functions exported from vnet module + */ + +VNetJack *VNetHub_AllocVnet(int hubNum); +VNetJack *VNetHub_AllocPvn(uint8 id[VNET_PVN_ID_LEN]); +int VNetHub_CreateSender(VNetJack *jack, VNetEvent_Sender **s); +int VNetHub_CreateListener(VNetJack *jack, VNetEvent_Handler h, void* data, + uint32 classMask, VNetEvent_Listener **l); + +int VNetConnect(VNetJack *jack1, VNetJack *jack2); + +VNetJack *VNetDisconnect(VNetJack *jack); + +void VNetSend(const VNetJack *jack, struct sk_buff *skb); + +int VNetProc_MakeEntry(char *name, int mode, + VNetProcEntry **ret); + +void VNetProc_RemoveEntry(VNetProcEntry *node); + +int VNetPrintJack(const VNetJack *jack, char *buf); + +int VNet_MakeMACAddress(VNetPort *port); + +int VNetSetMACUnique(VNetPort *port, const uint8 mac[ETH_ALEN]); + + +/* + * Utility functions + */ + +extern const uint8 allMultiFilter[VNET_LADRF_LEN]; +extern const uint8 broadcast[ETH_ALEN]; + +Bool VNetPacketMatch(const uint8 *destAddr, const uint8 *ifAddr, + const uint8 *ladrf, uint32 flags); + +Bool VNetCycleDetectIf(const char *name, int generation); + +void VNetIncrModCount(int delta); + +int VNetPrintPort(const VNetPort *port, char *buf); + +int VNetSnprintf(char *str, size_t size, const char *format, ...); + +/* + * Procfs file system + */ + +extern int VNetProc_Init(void); + +extern void VNetProc_Cleanup(void); + + +/* + *---------------------------------------------------------------------- + * + * VNetCycleDetect -- + * + * Perform the cycle detect alogorithm for this generation. + * + * Results: + * TRUE if a cycle was detected, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE Bool +VNetCycleDetect(VNetJack *jack, // IN: jack + int generation) // IN: +{ + if (jack && jack->cycleDetect) { + return jack->cycleDetect(jack, generation); + } + + return FALSE; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetPortsChanged -- + * + * Notify a jack that the number of connected ports has changed. + * vnetStructureSemaphore must be held. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE void +VNetPortsChanged(VNetJack *jack) // IN: +{ + if (jack && jack->portsChanged) { + jack->portsChanged(jack); + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetIsBridged -- + * + * Check whether we are bridged. + * vnetPeerLock must be held. + * + * Results: + * 0 - not bridged + * 1 - we are bridged but the interface is down + * 2 - we are bridged and the interface is up + * 3 - some bridges are down + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE int +VNetIsBridged(VNetJack *jack) // IN: jack +{ + if (jack && jack->peer && jack->peer->isBridged) { + return jack->peer->isBridged(jack->peer); + } + + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetFree -- + * + * Free the resources owned by the jack. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE void +VNetFree(VNetJack *jack) // IN: jack +{ + if (jack && jack->free) { + jack->free(jack); + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetGetAttachedPorts -- + * + * Get the number of ports attached to this jack through its peer. + * + * Results: + * The number of attached ports to this jack through its peer. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE int +VNetGetAttachedPorts(VNetJack *jack) // IN: jack +{ + if (jack && jack->peer) { + return jack->peer->numPorts; + } + return 0; +} + +#endif diff -Nrup source/vmnet-only/include/vnetKernel.h source.edited/vmnet-only/include/vnetKernel.h --- source/vmnet-only/include/vnetKernel.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/vnetKernel.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,85 @@ +/********************************************************* + * Copyright (C) 2008 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 + * + *********************************************************/ + +/* + * vnetKernel.h -- + * This file defines platform-independent functions for accessing basic + * kernel functions. This is the Linux implementation. + */ + +#ifndef _VNETKERNEL_H_ +#define _VNETKERNEL_H_ + +#include "driver-config.h" /* must be first */ +#include +#include "compat_sched.h" +#include "compat_slab.h" +#include "compat_semaphore.h" +#include "vm_basic_types.h" + +#define VNetKernel_EBUSY (-EBUSY) +#define VNetKernel_EINVAL (-EINVAL) +#define VNetKernel_ENOMEM (-ENOMEM) + +typedef struct VNetKernel_SpinLock { + spinlock_t lock; +} VNetKernel_SpinLock; + +static INLINE void * +VNetKernel_MemoryAllocate(size_t size) +{ + return kmalloc(size, GFP_ATOMIC); +} + +static INLINE void +VNetKernel_MemoryFree(void *ptr) +{ + kfree(ptr); +} + +static INLINE void +VNetKernel_SpinLockInit(VNetKernel_SpinLock *lock) +{ + spin_lock_init(&lock->lock); +} + +static INLINE void +VNetKernel_SpinLockFree(VNetKernel_SpinLock *lock) +{ + /* nothing to do */ +} + +static INLINE void +VNetKernel_SpinLockAcquire(VNetKernel_SpinLock *lock) +{ + spin_lock(&lock->lock); +} + +static INLINE void +VNetKernel_SpinLockRelease(VNetKernel_SpinLock *lock) +{ + spin_unlock(&lock->lock); +} + +static INLINE void * +VNetKernel_ThreadCurrent(void) +{ + return current; +} + +#endif // _VNETKERNEL_H_ diff -Nrup source/vmnet-only/include/x86cpuid.h source.edited/vmnet-only/include/x86cpuid.h --- source/vmnet-only/include/x86cpuid.h 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/include/x86cpuid.h 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,903 @@ +/********************************************************* + * Copyright (C) 1998 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 + * + *********************************************************/ + +#ifndef _X86CPUID_H_ +#define _X86CPUID_H_ + +/* http://www.sandpile.org/ia32/cpuid.htm */ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMX +#define INCLUDE_ALLOW_VMMEXT +#define INCLUDE_ALLOW_VMKERNEL +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_DISTRIBUTE +#define INCLUDE_ALLOW_VMK_MODULE +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMMON +#include "includeCheck.h" + +#include "vm_basic_types.h" + +/* + * The linux kernel's ptrace.h stupidly defines the bare + * EAX/EBX/ECX/EDX, which wrecks havoc with our preprocessor tricks. + */ +#undef EAX +#undef EBX +#undef ECX +#undef EDX + +typedef struct CPUIDRegs { + uint32 eax, ebx, ecx, edx; +} CPUIDRegs; + +typedef union CPUIDRegsUnion { + uint32 array[4]; + CPUIDRegs regs; +} CPUIDRegsUnion; + +/* + * Results of calling cpuid(eax, ecx) on all host logical CPU. + */ +#ifdef _MSC_VER +#pragma warning (disable :4200) // non-std extension: zero-sized array in struct +#endif + +typedef +#include "vmware_pack_begin.h" +struct CPUIDReply { + /* + * Unique host logical CPU identifier. It does not change across queries, so + * we use it to correlate the replies of multiple queries. + */ + uint64 tag; // OUT + + CPUIDRegs regs; // OUT +} +#include "vmware_pack_end.h" +CPUIDReply; + +typedef +#include "vmware_pack_begin.h" +struct CPUIDQuery { + uint32 eax; // IN + uint32 ecx; // IN + uint32 numLogicalCPUs; // IN/OUT + CPUIDReply logicalCPUs[0]; // OUT +} +#include "vmware_pack_end.h" +CPUIDQuery; + +/* + * CPUID levels the monitor caches and ones that are not cached, but + * have fields defined below (short name and actual value). + * + * The first parameter defines whether the level is masked/tested + * during power-on/migration. Any level which is marked as FALSE here + * *must* have all field masks defined as IGNORE in CPUID_FIELD_DATA. + * A static assert in lib/cpuidcompat/cpuidcompat.c will check this. + * + * IMPORTANT: WHEN ADDING A NEW FIELD TO THE CACHED LEVELS, make sure + * you update vmcore/vmm/cpu/priv.c:Priv_CPUID() and vmcore/vmm64/bt/ + * cpuid_shared.S (and geninfo) to include the new level. + */ + +#define CPUID_CACHED_LEVELS \ + CPUIDLEVEL(TRUE, 0, 0) \ + CPUIDLEVEL(TRUE, 1, 1) \ + CPUIDLEVEL(FALSE,400, 0x40000000) \ + CPUIDLEVEL(FALSE,410, 0x40000010) \ + CPUIDLEVEL(FALSE, 80, 0x80000000) \ + CPUIDLEVEL(TRUE, 81, 0x80000001) \ + CPUIDLEVEL(FALSE, 88, 0x80000008) \ + CPUIDLEVEL(TRUE, 8A, 0x8000000A) + +#define CPUID_UNCACHED_LEVELS \ + CPUIDLEVEL(FALSE, 4, 4) \ + CPUIDLEVEL(FALSE, 5, 5) \ + CPUIDLEVEL(FALSE, 6, 6) \ + CPUIDLEVEL(FALSE, A, 0xA) \ + CPUIDLEVEL(FALSE, 86, 0x80000006) \ + CPUIDLEVEL(FALSE, 87, 0x80000007) \ + +#define CPUID_ALL_LEVELS \ + CPUID_CACHED_LEVELS \ + CPUID_UNCACHED_LEVELS + +/* Define cached CPUID levels in the form: CPUID_LEVEL_ */ +typedef enum { +#define CPUIDLEVEL(t, s, v) CPUID_LEVEL_##s, + CPUID_CACHED_LEVELS +#undef CPUIDLEVEL + CPUID_NUM_LEVELS +} CpuidLevels; + +/* + * CPUID result registers + */ + +#define CPUID_REGS \ + CPUIDREG(EAX, eax) \ + CPUIDREG(EBX, ebx) \ + CPUIDREG(ECX, ecx) \ + CPUIDREG(EDX, edx) + +typedef enum { +#define CPUIDREG(uc, lc) CPUID_REG_##uc, + CPUID_REGS +#undef CPUIDREG + CPUID_NUM_REGS +} CpuidRegs; + +/* + * CPU vendors + */ + +typedef enum { + CPUID_VENDOR_UNKNOWN, + CPUID_VENDOR_COMMON, + CPUID_VENDOR_INTEL, + CPUID_VENDOR_AMD, + CPUID_VENDOR_CYRIX, + CPUID_NUM_VENDORS +} CpuidVendors; + +#define CPUID_INTEL_VENDOR_STRING "GenuntelineI" +#define CPUID_AMD_VENDOR_STRING "AuthcAMDenti" +#define CPUID_CYRIX_VENDOR_STRING "CyriteadxIns" +#define CPUID_INTEL_VENDOR_STRING_FIXED "GenuineIntel" +#define CPUID_AMD_VENDOR_STRING_FIXED "AuthenticAMD" +#define CPUID_CYRIX_VENDOR_STRING_FIXED "CyrixInstead" + +#define CPUID_HYPERV_HYPERVISOR_VENDOR_STRING "Microsoft Hv" + +/* + * FIELDDEF can be defined to process the CPUID information provided + * in the following CPUID_FIELD_DATA macro. The first parameter is + * the CPUID level of the feature (must be defined in CPUID_*_LEVELS. + * The second parameter is the register the field is contained in + * (defined in CPUID_REGS). The third field is the vendor this + * feature applies to. "COMMON" means all vendors apply. UNKNOWN may + * not be used here. The fourth and fifth parameters are the bit + * position of the field and the width, respectively. The sixth is + * the text name of the field. + * + * The seventh and eighth parameters specify the default CPUID + * behavior for power-on, guest view, and migration tests (cpt/rsm & + * vmotion). The eighth parameter is ignored for types other than + * MASK & TEST, and must be zero in this case. + * + * When adding a new field, be sure to consider its purpose. The + * following list of types is provided in order of likely use. + * + * NOTE: this form of representation is separate from the masking + * system specified via the config file. That is because this + * representation must take into account multi-bit fields. + * + * HOST - Passthrough host value and cannot change during migration. + * MASK, 0 - Hide from the guest, because we don't support it or we + * don't want the guest to know that it exists. + * IGNORE - Ignore this field for all tests + * + * (Think twice before using the below mask types/combinations) + * + * MASK, x - Force the guest to always see x, and don't compare for + * migration -- only APIC as of today; it is controlled by + * software and we know how to toggle it + * TEST, x - Require host CPUID field to be x for power-on + * RSVD - Hidden from the guest, but compared during migration + * + * + * Table to explain mask type meanings: + * + * IGNR MASK TEST HOST RSVD + * -------------------------------------------------------- + * Req'd val for power-on - - x - - + * Value guest sees * x * * 0 + * Checked on migration? N N Y Y Y + * + * * - initial host's power-on CPUID value + * + * FIELDDEFA takes a ninth parameter, the name used when creating + * accessor functions in lib/public/cpuidInfoFuncs.h. + * + * FLAGDEF/FLAGDEFA is defined identically to fields, but their + * accessors are more appropriate for 1-bit flags. + */ + +typedef enum { + CPUID_FIELD_MASK_IGNORE, + CPUID_FIELD_MASK_MASK, + CPUID_FIELD_MASK_TEST, + CPUID_FIELD_MASK_HOST, + CPUID_FIELD_MASK_RSVD, + CPUID_NUM_FIELD_MASKS +} CpuidFieldMasks; + +/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ +#define CPUID_FIELD_DATA_LEVEL_0 \ +FIELDDEF( 0, EAX, COMMON, 0, 32, NUMLEVELS, IGNORE, 0, FALSE) \ +FIELDDEF( 0, EBX, COMMON, 0, 32, VENDOR1, HOST, 0, TRUE) \ +FIELDDEF( 0, ECX, COMMON, 0, 32, VENDOR3, HOST, 0, TRUE) \ +FIELDDEF( 0, EDX, COMMON, 0, 32, VENDOR2, HOST, 0, TRUE) + +/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ +#define CPUID_FIELD_DATA_LEVEL_1 \ +FIELDDEFA( 1, EAX, COMMON, 0, 4, STEPPING, IGNORE, 0, FALSE, STEPPING) \ +FIELDDEFA( 1, EAX, COMMON, 4, 4, MODEL, IGNORE, 0, FALSE, MODEL) \ +FIELDDEFA( 1, EAX, COMMON, 8, 4, FAMILY, HOST, 0, FALSE, FAMILY) \ +FIELDDEF( 1, EAX, COMMON, 12, 2, TYPE, IGNORE, 0, FALSE) \ +FIELDDEFA( 1, EAX, COMMON, 16, 4, EXTMODEL, IGNORE, 0, FALSE, EXT_MODEL) \ +FIELDDEFA( 1, EAX, COMMON, 20, 8, EXTFAMILY, HOST, 0, FALSE, EXT_FAMILY) \ +FIELDDEF( 1, EBX, COMMON, 0, 8, BRAND_ID, IGNORE, 0, FALSE) \ +FIELDDEF( 1, EBX, COMMON, 8, 8, CLFL_SIZE, IGNORE, 0, FALSE) \ +FIELDDEFA( 1, EBX, COMMON, 16, 8, LCPU_COUNT, IGNORE, 0, FALSE, LCPU_COUNT) \ +FIELDDEFA( 1, EBX, COMMON, 24, 8, APICID, IGNORE, 0, FALSE, APICID) \ +FLAGDEFA( 1, ECX, COMMON, 0, 1, SSE3, HOST, 0, TRUE, SSE3) \ +FLAGDEF( 1, ECX, INTEL, 2, 1, NDA2, MASK, 0, FALSE) \ +FLAGDEFA( 1, ECX, COMMON, 3, 1, MWAIT, MASK, 0, FALSE, MWAIT) \ +FLAGDEFA( 1, ECX, INTEL, 4, 1, DSCPL, MASK, 0, FALSE, DSCPL) \ +FLAGDEFA( 1, ECX, INTEL, 5, 1, VMX, MASK, 0, FALSE, VMX) \ +FLAGDEF( 1, ECX, INTEL, 6, 1, SMX, MASK, 0, FALSE) \ +FLAGDEF( 1, ECX, INTEL, 7, 1, EST, MASK, 0, FALSE) \ +FLAGDEF( 1, ECX, INTEL, 8, 1, TM2, MASK, 0, FALSE) \ +FLAGDEFA( 1, ECX, COMMON, 9, 1, SSSE3, HOST, 0, TRUE, SSSE3) \ +FLAGDEF( 1, ECX, INTEL, 10, 1, HTCACHE, MASK, 0, FALSE) \ +FLAGDEFA( 1, ECX, COMMON, 13, 1, CMPX16, HOST, 0, TRUE, CMPX16) \ +FLAGDEF( 1, ECX, INTEL, 14, 1, xPPR, MASK, 0, FALSE) \ +FLAGDEF( 1, ECX, INTEL, 15, 1, PERF_MSR, MASK, 0, FALSE) \ +FLAGDEF( 1, ECX, INTEL, 18, 1, DCA, MASK, 0, FALSE) \ +FLAGDEFA( 1, ECX, INTEL, 19, 1, SSE41, HOST, 0, TRUE, SSE41) \ +FLAGDEFA( 1, ECX, INTEL, 20, 1, SSE42, HOST, 0, TRUE, SSE42) \ +FLAGDEF( 1, ECX, INTEL, 21, 1, X2APIC, MASK, 0, FALSE) \ +FLAGDEF( 1, ECX, INTEL, 22, 1, MOVBE, RSVD, 0, TRUE) \ +FLAGDEFA( 1, ECX, COMMON, 23, 1, POPCNT, HOST, 0, TRUE, POPCNT) \ +FLAGDEF( 1, ECX, INTEL, 24, 1, ULE, RSVD, 0, TRUE) \ +FLAGDEF( 1, ECX, INTEL, 26, 1, XSAVE, MASK, 0, FALSE) \ +FLAGDEF( 1, ECX, INTEL, 27, 1, OSXSAVE, RSVD, 0, TRUE) \ +FLAGDEFA( 1, ECX, COMMON, 31, 1, HYPERVISOR, IGNORE, 0, FALSE, HYPERVISOR)\ +FLAGDEFA( 1, EDX, COMMON, 0, 1, FPU, HOST, 0, TRUE, FPU) \ +FLAGDEFA( 1, EDX, COMMON, 1, 1, VME, HOST, 0, FALSE, VME) \ +FLAGDEF( 1, EDX, COMMON, 2, 1, DBGE, HOST, 0, FALSE) \ +FLAGDEF( 1, EDX, COMMON, 3, 1, PGSZE, HOST, 0, FALSE) \ +FLAGDEFA( 1, EDX, COMMON, 4, 1, TSC, HOST, 0, TRUE, TSC) \ +FLAGDEF( 1, EDX, COMMON, 5, 1, MSR, HOST, 0, FALSE) \ +FLAGDEFA( 1, EDX, COMMON, 6, 1, PAE, HOST, 0, FALSE, PAE) \ +FLAGDEF( 1, EDX, COMMON, 7, 1, MCK, HOST, 0, FALSE) \ +FLAGDEF( 1, EDX, COMMON, 8, 1, CPMX, HOST, 0, TRUE) \ +FLAGDEFA( 1, EDX, COMMON, 9, 1, APIC, MASK, 1, FALSE, APIC) \ +FLAGDEFA( 1, EDX, COMMON, 11, 1, SEP, HOST, 0, TRUE, SEP) \ +FLAGDEFA( 1, EDX, COMMON, 12, 1, MTRR, HOST, 0, FALSE, MTRR) \ +FLAGDEFA( 1, EDX, COMMON, 13, 1, PGE, HOST, 0, FALSE, PGE) \ +FLAGDEFA( 1, EDX, COMMON, 14, 1, MCA, HOST, 0, FALSE, MCA) \ +FLAGDEFA( 1, EDX, COMMON, 15, 1, CMOV, HOST, 0, TRUE, CMOV) \ +FLAGDEFA( 1, EDX, COMMON, 16, 1, PAT, HOST, 0, FALSE, PAT) \ +FLAGDEF( 1, EDX, COMMON, 17, 1, 36PG, HOST, 0, FALSE) \ +FLAGDEF( 1, EDX, INTEL, 18, 1, PSN, HOST, 0, FALSE) \ +FLAGDEFA( 1, EDX, COMMON, 19, 1, CLFL, HOST, 0, TRUE, CLFL) \ +FLAGDEF( 1, EDX, INTEL, 21, 1, DTES, HOST, 0, FALSE) \ +FLAGDEF( 1, EDX, INTEL, 22, 1, ACPI, HOST, 0, FALSE) \ +FLAGDEFA( 1, EDX, COMMON, 23, 1, MMX, HOST, 0, TRUE, MMX) \ +FLAGDEFA( 1, EDX, COMMON, 24, 1, FXSAVE, HOST, 0, TRUE, FXSAVE) \ +FLAGDEFA( 1, EDX, COMMON, 25, 1, SSE, HOST, 0, TRUE, SSE) \ +FLAGDEFA( 1, EDX, COMMON, 26, 1, SSE2, HOST, 0, TRUE, SSE2) \ +FLAGDEF( 1, EDX, INTEL, 27, 1, SS, HOST, 0, FALSE) \ +FLAGDEFA( 1, EDX, COMMON, 28, 1, HT, MASK, 0, FALSE, HT) \ +FLAGDEF( 1, EDX, INTEL, 29, 1, TM, MASK, 0, FALSE) \ +FLAGDEF( 1, EDX, INTEL, 30, 1, IA64, MASK, 0, FALSE) \ +FLAGDEF( 1, EDX, INTEL, 31, 1, PBE, MASK, 0, FALSE) + +/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ +#define CPUID_FIELD_DATA_LEVEL_4 \ +FIELDDEF( 4, EAX, INTEL, 0, 5, CACHE_TYPE, IGNORE, 0, FALSE) \ +FIELDDEF( 4, EAX, INTEL, 5, 3, CACHE_LEVEL, IGNORE, 0, FALSE) \ +FIELDDEF( 4, EAX, INTEL, 14, 12, CACHE_NUMHT_SHARING, IGNORE, 0, FALSE) \ +FIELDDEFA( 4, EAX, INTEL, 26, 6, CORE_COUNT, IGNORE, 0, FALSE, INTEL_CORE_COUNT) \ +FIELDDEF( 4, EBX, INTEL, 0, 12, CACHE_LINE, IGNORE, 0, FALSE) \ +FIELDDEF( 4, EBX, INTEL, 12, 10, CACHE_PART, IGNORE, 0, FALSE) \ +FIELDDEF( 4, EBX, INTEL, 22, 10, CACHE_WAYS, IGNORE, 0, FALSE) + +/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ +#define CPUID_FIELD_DATA_LEVEL_5 \ +FIELDDEF( 5, EAX, COMMON, 0, 16, MWAIT_MIN_SIZE, IGNORE, 0, FALSE) \ +FIELDDEF( 5, EBX, COMMON, 0, 16, MWAIT_MAX_SIZE, IGNORE, 0, FALSE) \ +FLAGDEF( 5, ECX, COMMON, 0, 1, MWAIT_EXTENSIONS, IGNORE, 0, FALSE) \ +FLAGDEF( 5, ECX, COMMON, 1, 1, MWAIT_INTR_BREAK, IGNORE, 0, FALSE) \ +FIELDDEF( 5, EDX, INTEL, 0, 4, MWAIT_C0_SUBSTATE, IGNORE, 0, FALSE) \ +FIELDDEF( 5, EDX, INTEL, 4, 4, MWAIT_C1_SUBSTATE, IGNORE, 0, FALSE) \ +FIELDDEF( 5, EDX, INTEL, 8, 4, MWAIT_C2_SUBSTATE, IGNORE, 0, FALSE) \ +FIELDDEF( 5, EDX, INTEL, 12, 4, MWAIT_C3_SUBSTATE, IGNORE, 0, FALSE) \ +FIELDDEF( 5, EDX, INTEL, 16, 4, MWAIT_C4_SUBSTATE, IGNORE, 0, FALSE) + +/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ +#define CPUID_FIELD_DATA_LEVEL_6 \ +FLAGDEF( 6, EAX, INTEL, 0, 1, THERMAL_SENSOR, IGNORE, 0, FALSE) \ +FLAGDEF( 6, EAX, INTEL, 1, 1, TURBO_MODE, IGNORE, 0, FALSE) \ +FIELDDEF( 6, EBX, INTEL, 0, 4, NUM_INTR_THRESHOLDS, IGNORE, 0, FALSE) \ +FLAGDEF( 6, ECX, INTEL, 0, 1, HW_COORD_FEEDBACK, IGNORE, 0, FALSE) + +/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ +#define CPUID_FIELD_DATA_LEVEL_A \ +FIELDDEFA( A, EAX, INTEL, 0, 8, PMC_VERSION, IGNORE, 0, FALSE, PMC_VERSION) \ +FIELDDEFA( A, EAX, INTEL, 8, 8, NUM_PMCS, IGNORE, 0, FALSE, NUM_PMCS) \ +FIELDDEF( A, EAX, INTEL, 16, 8, PMC_BIT_WIDTH, IGNORE, 0, FALSE) \ +FIELDDEFA( A, EAX, INTEL, 24, 8, PMC_EBX_LENGTH, IGNORE, 0, FALSE, PMC_EBX_LENGTH) \ +FLAGDEF( A, EBX, INTEL, 0, 1, PMC_CORE_CYCLE, IGNORE, 0, FALSE) \ +FLAGDEF( A, EBX, INTEL, 1, 1, PMC_INSTR_RETIRED, IGNORE, 0, FALSE) \ +FLAGDEF( A, EBX, INTEL, 2, 1, PMC_REF_CYCLES, IGNORE, 0, FALSE) \ +FLAGDEF( A, EBX, INTEL, 3, 1, PMC_LAST_LVL_CREF, IGNORE, 0, FALSE) \ +FLAGDEF( A, EBX, INTEL, 4, 1, PMC_LAST_LVL_CMISS, IGNORE, 0, FALSE) \ +FLAGDEF( A, EBX, INTEL, 5, 1, PMC_BR_INST_RETIRED, IGNORE, 0, FALSE) \ +FLAGDEF( A, EBX, INTEL, 6, 1, PMC_BR_MISS_RETIRED, IGNORE, 0, FALSE) + +/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ +#define CPUID_FIELD_DATA_LEVEL_80 \ +FIELDDEF( 80, EAX, COMMON, 0, 32, NUM_EXT_LEVELS, IGNORE, 0, FALSE) \ +FIELDDEF( 80, EBX, AMD, 0, 32, AMD_VENDOR1, IGNORE, 0, FALSE) \ +FIELDDEF( 80, ECX, AMD, 0, 32, AMD_VENDOR3, IGNORE, 0, FALSE) \ +FIELDDEF( 80, EDX, AMD, 0, 32, AMD_VENDOR2, IGNORE, 0, FALSE) + +/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ +#define CPUID_FIELD_DATA_LEVEL_81 \ +FIELDDEF( 81, EAX, INTEL, 0, 32, UNKNOWN81EAX, IGNORE, 0, FALSE) \ +FIELDDEF( 81, EAX, AMD, 0, 4, STEPPING, IGNORE, 0, FALSE) \ +FIELDDEF( 81, EAX, AMD, 4, 4, MODEL, IGNORE, 0, FALSE) \ +FIELDDEF( 81, EAX, AMD, 8, 4, FAMILY, IGNORE, 0, FALSE) \ +FIELDDEF( 81, EAX, AMD, 12, 2, TYPE, IGNORE, 0, FALSE) \ +FIELDDEF( 81, EAX, AMD, 16, 4, EXTMODEL, IGNORE, 0, FALSE) \ +FIELDDEF( 81, EAX, AMD, 20, 8, EXTFAMILY, IGNORE, 0, FALSE) \ +FIELDDEF( 81, EBX, INTEL, 0, 32, UNKNOWN81EBX, IGNORE, 0, FALSE) \ +FIELDDEF( 81, EBX, AMD, 0, 16, BRAND_ID, IGNORE, 0, FALSE) \ +FIELDDEF( 81, EBX, AMD, 16, 16, UNDEF, IGNORE, 0, FALSE) \ +FLAGDEFA( 81, ECX, COMMON, 0, 1, LAHF, HOST, 0, TRUE, LAHF64) \ +FLAGDEFA( 81, ECX, AMD, 1, 1, CMPLEGACY, MASK, 0, FALSE, CMPLEGACY) \ +FLAGDEFA( 81, ECX, AMD, 2, 1, SVM, MASK, 0, FALSE, SVM) \ +FLAGDEFA( 81, ECX, AMD, 3, 1, EXTAPICSPC, HOST, 0, FALSE, EXTAPICSPC) \ +FLAGDEFA( 81, ECX, AMD, 4, 1, CR8AVAIL, MASK, 0, FALSE, CR8AVAIL) \ +FLAGDEFA( 81, ECX, AMD, 5, 1, ABM, HOST, 0, TRUE, ABM) \ +FLAGDEFA( 81, ECX, AMD, 6, 1, SSE4A, HOST, 0, TRUE, SSE4A) \ +FLAGDEF( 81, ECX, AMD, 7, 1, MISALIGNED_SSE, HOST, 0, TRUE) \ +FLAGDEFA( 81, ECX, AMD, 8, 1, 3DNPREFETCH, HOST, 0, TRUE, 3DNPREFETCH) \ +FLAGDEF( 81, ECX, AMD, 9, 1, OSVW, MASK, 0, FALSE) \ +FLAGDEF( 81, ECX, AMD, 10, 1, IBS, MASK, 0, FALSE) \ +FLAGDEF( 81, ECX, AMD, 11, 1, SSE5, RSVD, 0, TRUE) \ +FLAGDEF( 81, ECX, AMD, 12, 1, SKINIT, MASK, 0, FALSE) \ +FLAGDEF( 81, ECX, AMD, 13, 1, WATCHDOG, MASK, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 0, 1, FPU, HOST, 0, TRUE) \ +FLAGDEF( 81, EDX, AMD, 1, 1, VME, HOST, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 2, 1, DBGE, HOST, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 3, 1, PGSZE, HOST, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 4, 1, TSC, HOST, 0, TRUE) \ +FLAGDEF( 81, EDX, AMD, 5, 1, MSR, HOST, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 6, 1, PAE, HOST, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 7, 1, MCK, HOST, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 8, 1, CPMX, HOST, 0, TRUE) \ +FLAGDEF( 81, EDX, AMD, 9, 1, APIC, MASK, 1, FALSE) \ +FLAGDEFA( 81, EDX, COMMON, 11, 1, SYSC, IGNORE, 0, TRUE, SYSC) \ +FLAGDEF( 81, EDX, AMD, 12, 1, MTRR, HOST, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 13, 1, PGE, HOST, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 14, 1, MCA, HOST, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 15, 1, CMOV, HOST, 0, TRUE) \ +FLAGDEF( 81, EDX, AMD, 16, 1, PAT, HOST, 0, FALSE) \ +FLAGDEF( 81, EDX, AMD, 17, 1, 36PG, HOST, 0, FALSE) \ +FLAGDEFA( 81, EDX, COMMON, 20, 1, NX, HOST, 0, FALSE, NX) \ +FLAGDEFA( 81, EDX, AMD, 22, 1, MMXEXT, HOST, 0, TRUE, MMXEXT) \ +FLAGDEF( 81, EDX, AMD, 23, 1, MMX, HOST, 0, TRUE) \ +FLAGDEF( 81, EDX, AMD, 24, 1, FXSAVE, HOST, 0, TRUE) \ +FLAGDEFA( 81, EDX, AMD, 25, 1, FFXSR, HOST, 0, FALSE, FFXSR) \ +FLAGDEF( 81, EDX, AMD, 26, 1, PDPE1GB, MASK, 0, FALSE) \ +FLAGDEFA( 81, EDX, COMMON, 27, 1, RDTSCP, HOST, 0, TRUE, RDTSCP) \ +FLAGDEFA( 81, EDX, COMMON, 29, 1, LM, TEST, 1, FALSE, LM) \ +FLAGDEFA( 81, EDX, AMD, 30, 1, 3DNOWPLUS, HOST, 0, TRUE, 3DNOWPLUS) \ +FLAGDEFA( 81, EDX, AMD, 31, 1, 3DNOW, HOST, 0, TRUE, 3DNOW) + +/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ +#define CPUID_FIELD_DATA_LEVEL_8x \ +FIELDDEF( 86, ECX, AMD, 0, 8, CACHE_LINE, IGNORE, 0, FALSE) \ +FIELDDEF( 86, ECX, AMD, 8, 4, CACHE_LINE_PER_TAG, IGNORE, 0, FALSE) \ +FIELDDEF( 86, ECX, AMD, 12, 4, CACHE_WAYS, IGNORE, 0, FALSE) \ +FIELDDEF( 86, ECX, AMD, 16, 16, CACHE_SIZE, IGNORE, 0, FALSE) \ +FLAGDEF( 87, EDX, AMD, 0, 1, TS, IGNORE, 0, FALSE) \ +FLAGDEF( 87, EDX, AMD, 1, 1, FID, IGNORE, 0, FALSE) \ +FLAGDEF( 87, EDX, AMD, 2, 1, VID, IGNORE, 0, FALSE) \ +FLAGDEF( 87, EDX, AMD, 3, 1, TTP, IGNORE, 0, FALSE) \ +FLAGDEF( 87, EDX, AMD, 4, 1, TM, IGNORE, 0, FALSE) \ +FLAGDEF( 87, EDX, AMD, 5, 1, STC, IGNORE, 0, FALSE) \ +FLAGDEF( 87, EDX, AMD, 6, 1, 100MHZSTEPS, IGNORE, 0, FALSE) \ +FLAGDEF( 87, EDX, AMD, 7, 1, HWPSTATE, IGNORE, 0, FALSE) \ +FLAGDEF( 87, EDX, AMD, 8, 1, TSC_INVARIANT, IGNORE, 0, FALSE) \ +FIELDDEFA(88, EAX, COMMON, 0, 8, PHYSBITS, IGNORE, 0, FALSE, PHYS_BITS) \ +FIELDDEFA(88, EAX, COMMON, 8, 8, VIRTBITS, IGNORE, 0, FALSE, VIRT_BITS) \ +FIELDDEFA(88, ECX, AMD, 0, 8, CORE_COUNT, IGNORE, 0, FALSE, AMD_CORE_COUNT) \ +FIELDDEF( 88, ECX, AMD, 12, 4, APICID_COREID_SIZE, IGNORE, 0, FALSE) \ +FIELDDEFA(8A, EAX, AMD, 0, 8, SVM_REVISION, MASK, 0, FALSE, SVM_REVISION) \ +FLAGDEF( 8A, EAX, AMD, 8, 1, SVM_HYPERVISOR, MASK, 0, FALSE) \ +FIELDDEF( 8A, EAX, AMD, 9, 23, SVMEAX_RSVD, MASK, 0, FALSE) \ +FIELDDEF( 8A, EBX, AMD, 0, 32, SVM_N_ASIDS, MASK, 0, FALSE) \ +FIELDDEF( 8A, ECX, AMD, 0, 32, SVMECX_RSVD, MASK, 0, FALSE) \ +FLAGDEFA( 8A, EDX, AMD, 0, 1, SVM_NP, MASK, 0, FALSE, NPT) \ +FLAGDEF( 8A, EDX, AMD, 1, 1, SVM_LBR, MASK, 0, FALSE) \ +FLAGDEF( 8A, EDX, AMD, 2, 1, SVM_LOCK, MASK, 0, FALSE) \ +FLAGDEF( 8A, EDX, AMD, 3, 1, SVM_NRIP, MASK, 0, FALSE) \ +FIELDDEF( 8A, EDX, AMD, 4, 28, SVMEDX_RSVD, MASK, 0, FALSE) + +#define CPUID_FIELD_DATA \ + CPUID_FIELD_DATA_LEVEL_0 \ + CPUID_FIELD_DATA_LEVEL_1 \ + CPUID_FIELD_DATA_LEVEL_4 \ + CPUID_FIELD_DATA_LEVEL_5 \ + CPUID_FIELD_DATA_LEVEL_6 \ + CPUID_FIELD_DATA_LEVEL_A \ + CPUID_FIELD_DATA_LEVEL_80 \ + CPUID_FIELD_DATA_LEVEL_81 \ + CPUID_FIELD_DATA_LEVEL_8x + +/* + * Define all field and flag values as an enum. The result is a full + * set of values taken from the table above in the form: + * + * CPUID_FEATURE__ID_ == mask for feature + * CPUID__ID__MASK == mask for field + * CPUID__ID__SHIFT == offset of field + * + * e.g. - CPUID_FEATURE_COMMON_ID1EDX_FPU = 0x1 + * - CPUID_COMMON_ID88EAX_VIRTBITS_MASK = 0xff00 + * - CPUID_COMMON_ID88EAX_VIRTBITS_SHIFT = 8 + * + * Note: The FEATURE/MASK definitions must use some gymnastics to get + * around a warning when shifting left by 32. + */ +#define VMW_BIT_MASK(shift) (((1 << (shift - 1)) << 1) - 1) + +#define FIELDDEF(lvl, reg, vend, bitpos, size, name, m, v, c3) \ + CPUID_##vend##_ID##lvl##reg##_##name##_SHIFT = bitpos, \ + CPUID_##vend##_ID##lvl##reg##_##name##_MASK = \ + VMW_BIT_MASK(size) << bitpos, \ + CPUID_FEATURE_##vend##_ID##lvl##reg##_##name = \ + CPUID_##vend##_ID##lvl##reg##_##name##_MASK, + +#define FIELDDEFA(lvl, reg, vend, bitpos, size, name, m, v, c3, f) \ + CPUID_##vend##_ID##lvl##reg##_##name##_SHIFT = bitpos, \ + CPUID_##vend##_ID##lvl##reg##_##name##_MASK = \ + VMW_BIT_MASK(size) << bitpos, \ + CPUID_FEATURE_##vend##_ID##lvl##reg##_##name = \ + CPUID_##vend##_ID##lvl##reg##_##name##_MASK, + +#define FLAGDEFA FIELDDEFA +#define FLAGDEF FIELDDEF + +enum { + /* Define data for every CPUID field we have */ + CPUID_FIELD_DATA +}; +#undef VMW_BIT_MASK +#undef FIELDDEF +#undef FLAGDEF +#undef FIELDDEFA +#undef FLAGDEFA + +/* + * Legal CPUID config file mask characters. For a description of the + * cpuid masking system, please see: + * + * http://vmweb.vmware.com/~mts/cgi-bin/view.cgi/Apps/CpuMigrationChecks + */ + +#define CPUID_MASK_HIDE_CHR '0' +#define CPUID_MASK_HIDE_STR "0" +#define CPUID_MASK_FORCE_CHR '1' +#define CPUID_MASK_FORCE_STR "1" +#define CPUID_MASK_PASS_CHR '-' +#define CPUID_MASK_PASS_STR "-" +#define CPUID_MASK_TRUE_CHR 'T' +#define CPUID_MASK_TRUE_STR "T" +#define CPUID_MASK_FALSE_CHR 'F' +#define CPUID_MASK_FALSE_STR "F" +#define CPUID_MASK_IGNORE_CHR 'X' +#define CPUID_MASK_IGNORE_STR "X" +#define CPUID_MASK_HOST_CHR 'H' +#define CPUID_MASK_HOST_STR "H" +#define CPUID_MASK_RSVD_CHR 'R' +#define CPUID_MASK_RSVD_STR "R" +#define CPUID_MASK_INSTALL_CHR 'I' +#define CPUID_MASK_INSTALL_STR "I" + +/* + * If a level is listed as not masked/tested in CPUID_LEVELS above, + * use all "don't care" values for its mask. + */ + +#define CPT_DFLT_UNDEFINED_MASK "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX" + +/* + * When LM is disabled, we overlay the following masks onto the + * guest's default masks. Any level that is not defined below should + * be treated as all "-"s + */ + +#define CPT_ID1ECX_LM_DISABLED "----:----:----:----:--0-:----:----:----" +#define CPT_ID81EDX_LM_DISABLED "--0-:----:----:----:----:----:----:----" +#define CPT_ID81ECX_LM_DISABLED "----:----:----:----:----:----:----:---0" + +#define CPT_GET_LM_DISABLED_MASK(lvl, reg) \ + ((lvl == 1 && reg == CPUID_REG_ECX) ? CPT_ID1ECX_LM_DISABLED : \ + (lvl == 0x80000001 && reg == CPUID_REG_ECX) ? CPT_ID81ECX_LM_DISABLED : \ + (lvl == 0x80000001 && reg == CPUID_REG_EDX) ? CPT_ID81EDX_LM_DISABLED : \ + NULL) + +/* + * Macro to define GET and SET functions for various common CPUID + * fields. To create function for a new field, simply name it (CPUID_ + * and CPUID_SET_ are automatically prepended), and list the field + * name that it needs to use. + */ + +#define FIELD_FUNC(name, field) \ + static INLINE uint32 CPUID_##name(uint32 reg) \ + { \ + return (reg & field##_MASK) >> field##_SHIFT; \ + } \ + static INLINE void CPUID_SET_##name(uint32 *reg, uint32 val) \ + { \ + *reg = (*reg & ~field##_MASK) | (val << field##_SHIFT); \ + } + +FIELD_FUNC(STEPPING, CPUID_COMMON_ID1EAX_STEPPING) +FIELD_FUNC(MODEL, CPUID_COMMON_ID1EAX_MODEL) +FIELD_FUNC(FAMILY, CPUID_COMMON_ID1EAX_FAMILY) +FIELD_FUNC(TYPE, CPUID_COMMON_ID1EAX_TYPE) +FIELD_FUNC(EXTENDED_MODEL, CPUID_COMMON_ID1EAX_EXTMODEL) +FIELD_FUNC(EXTENDED_FAMILY, CPUID_COMMON_ID1EAX_EXTFAMILY) +FIELD_FUNC(LCPU_COUNT, CPUID_COMMON_ID1EBX_LCPU_COUNT) +FIELD_FUNC(APICID, CPUID_COMMON_ID1EBX_APICID) +FIELD_FUNC(PA_BITS, CPUID_COMMON_ID88EAX_PHYSBITS) +FIELD_FUNC(VIRT_BITS, CPUID_COMMON_ID88EAX_VIRTBITS) +FIELD_FUNC(SVM_REVISION, CPUID_AMD_ID8AEAX_SVM_REVISION) +FIELD_FUNC(SVM_N_ASIDS, CPUID_AMD_ID8AEBX_SVM_N_ASIDS) +FIELD_FUNC(INTEL_CORE_COUNT, CPUID_INTEL_ID4EAX_CORE_COUNT) +FIELD_FUNC(AMD_CORE_COUNT, CPUID_AMD_ID88ECX_CORE_COUNT) +FIELD_FUNC(AMD_APICID_COREID_SIZE, CPUID_AMD_ID88ECX_APICID_COREID_SIZE) +FIELD_FUNC(AMD_EXTAPICSPC, CPUID_AMD_ID81ECX_EXTAPICSPC) +FIELD_FUNC(NUM_PMCS, CPUID_INTEL_IDAEAX_NUM_PMCS) +FIELD_FUNC(MWAIT_MIN_SIZE, CPUID_COMMON_ID5EAX_MWAIT_MIN_SIZE) +FIELD_FUNC(MWAIT_MAX_SIZE, CPUID_COMMON_ID5EBX_MWAIT_MAX_SIZE) +FIELD_FUNC(MWAIT_C0_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C0_SUBSTATE) +FIELD_FUNC(MWAIT_C1_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C1_SUBSTATE) +FIELD_FUNC(MWAIT_C2_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C2_SUBSTATE) +FIELD_FUNC(MWAIT_C3_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C3_SUBSTATE) +FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE) +#undef FIELD_FUNC + + +/* + * Definitions of various fields' values and more complicated + * macros/functions for reading cpuid fields. + */ + +/* Effective Intel CPU Families */ +#define CPUID_FAMILY_486 4 +#define CPUID_FAMILY_P5 5 +#define CPUID_FAMILY_P6 6 +#define CPUID_FAMILY_P4 15 + +/* Effective AMD CPU Families */ +#define CPUID_FAMILY_5x86 4 +#define CPUID_FAMILY_K5 5 +#define CPUID_FAMILY_K6 5 +#define CPUID_FAMILY_K7 6 +#define CPUID_FAMILY_K8 15 +#define CPUID_FAMILY_K8L 16 +#define CPUID_FAMILY_K8MOBILE 17 +#define CPUID_FAMILY_EXTENDED 15 + +/* Intel model information */ +#define CPUID_MODEL_PPRO 1 +#define CPUID_MODEL_PII_03 3 +#define CPUID_MODEL_PII_05 5 +#define CPUID_MODEL_CELERON_06 6 +#define CPUID_MODEL_PM_09 9 +#define CPUID_MODEL_PM_0E 14 // Yonah / Sossaman +#define CPUID_MODEL_CORE_0F 15 // Conroe / Merom +#define CPUID_MODEL_CORE_17 0x17 // Penryn +#define CPUID_MODEL_NEHALEM_1A 0x1a // Nehalem / Gainestown +#define CPUID_MODEL_CORE_1D 0x1d // Dunnington + +#define CPUID_MODEL_PIII_07 7 +#define CPUID_MODEL_PIII_08 8 +#define CPUID_MODEL_PIII_0A 10 + +static INLINE uint32 +CPUID_EFFECTIVE_FAMILY(uint32 v) /* %eax from CPUID with %eax=1. */ +{ + return CPUID_FAMILY(v) + + (CPUID_FAMILY(v) == CPUID_FAMILY_EXTENDED ? CPUID_EXTENDED_FAMILY(v) : 0); +} + +/* Normally only used when FAMILY==CPUID_FAMILY_EXTENDED, but Intel is + * now using the extended model field for FAMILY==CPUID_FAMILY_P6 to + * refer to the newer Core2 CPUs + */ +static INLINE uint32 +CPUID_EFFECTIVE_MODEL(uint32 v) /* %eax from CPUID with %eax=1. */ +{ + return CPUID_MODEL(v) + (CPUID_EXTENDED_MODEL(v) << 4); +} + +/* + * Notice that CPUID families for Intel and AMD overlap. The following macros + * should only be used AFTER the manufacturer has been established (through + * the use of CPUID standard function 0). + */ +static INLINE Bool +CPUID_FAMILY_IS_486(uint32 _eax) +{ + return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_486; +} + +static INLINE Bool +CPUID_FAMILY_IS_P5(uint32 _eax) +{ + return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_P5; +} + +static INLINE Bool +CPUID_FAMILY_IS_P6(uint32 _eax) +{ + return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_P6; +} + +static INLINE Bool +CPUID_FAMILY_IS_PENTIUM4(uint32 _eax) +{ + return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_P4; +} + +/* + * Intel Pentium M processors are Yonah/Sossaman or an older P-M + */ +static INLINE Bool +CPUID_UARCH_IS_PENTIUM_M(uint32 v) // IN: %eax from CPUID with %eax=1. +{ + /* Assumes the CPU manufacturer is Intel. */ + return CPUID_FAMILY_IS_P6(v) && + (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_09 || + CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_0E); +} + +/* + * Intel Core processors are Merom, Conroe, Woodcrest, Clovertown, + * Penryn, Dunnington, Kentsfield, Yorktown, Harpertown, ........ + */ +static INLINE Bool +CPUID_UARCH_IS_CORE(uint32 v) // IN: %eax from CPUID with %eax=1. +{ + uint32 model = CPUID_EFFECTIVE_MODEL(v); + /* Assumes the CPU manufacturer is Intel. */ + return CPUID_FAMILY_IS_P6(v) && + model >= CPUID_MODEL_CORE_0F && + (model < CPUID_MODEL_NEHALEM_1A || + model == CPUID_MODEL_CORE_1D); +} + + +/* + * Intel Nehalem processors are: Nehalem, Gainestown. + */ +static INLINE Bool +CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1. +{ + /* Assumes the CPU manufacturer is Intel. */ + return CPUID_FAMILY_IS_P6(v) && + CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A; +} + + +static INLINE Bool +CPUID_FAMILY_IS_K7(uint32 _eax) +{ + return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K7; +} + +static INLINE Bool +CPUID_FAMILY_IS_K8(uint32 _eax) +{ + return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K8; +} + +static INLINE Bool +CPUID_FAMILY_IS_K8EXT(uint32 _eax) +{ + /* + * We check for this pattern often enough that it's + * worth a separate function, for syntactic sugar. + */ + return CPUID_FAMILY_IS_K8(_eax) && + CPUID_EXTENDED_MODEL(_eax) != 0; +} + +static INLINE Bool +CPUID_FAMILY_IS_K8L(uint32 _eax) +{ + return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K8L; +} + +static INLINE Bool +CPUID_FAMILY_IS_K8MOBILE(uint32 _eax) +{ + /* Essentially a K8 (not K8L) part, but with mobile features. */ + return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K8MOBILE; +} + +static INLINE Bool +CPUID_FAMILY_IS_K8STAR(uint32 _eax) +{ + /* + * Read function name as "K8*", as in wildcard. + * Matches K8 or K8L or K8MOBILE + */ + return CPUID_FAMILY_IS_K8(_eax) || CPUID_FAMILY_IS_K8L(_eax) || + CPUID_FAMILY_IS_K8MOBILE(_eax); +} + + +#define CPUID_TYPE_PRIMARY 0 +#define CPUID_TYPE_OVERDRIVE 1 +#define CPUID_TYPE_SECONDARY 2 + +#define CPUID_INTEL_ID4EAX_CACHE_TYPE_NULL 0 +#define CPUID_INTEL_ID4EAX_CACHE_TYPE_DATA 1 +#define CPUID_INTEL_ID4EAX_CACHE_TYPE_INST 2 +#define CPUID_INTEL_ID4EAX_CACHE_TYPE_UNIF 3 + +#define CPUID_INTEL_ID4EAX_CACHE_SELF_INIT 0x00000100 +#define CPUID_INTEL_ID4EAX_CACHE_FULLY_ASSOC 0x00000200 + + +/* + * On AMD chips before Opteron and Intel chips before P4 model 3, + * WRMSR(TSC) clears the upper half of the TSC instead of using %edx. + */ +static INLINE Bool +CPUID_FullyWritableTSC(Bool isIntel, // IN + uint32 v) // IN: %eax from CPUID with %eax=1. +{ + /* + * Returns FALSE if: + * - Intel && P6 (pre-core) or + * - Intel && P4 (model < 3) or + * - !Intel && pre-K8 Opteron + * Otherwise, returns TRUE. + */ + return !((isIntel && + ((CPUID_FAMILY_IS_P6(v) && + CPUID_EFFECTIVE_MODEL(v) < CPUID_MODEL_PM_0E) || + (CPUID_FAMILY_IS_PENTIUM4(v) && + CPUID_EFFECTIVE_MODEL(v) < 3))) || + (!isIntel && + CPUID_FAMILY(v) < CPUID_FAMILY_K8)); +} + + +/* + * For certain AMD processors, an lfence instruction is necessary at various + * places to ensure ordering. + */ + +static INLINE Bool +CPUID_VendorRequiresFence(CpuidVendors vendor) +{ + return vendor == CPUID_VENDOR_AMD; +} + +static INLINE Bool +CPUID_VersionRequiresFence(uint32 version) +{ + return CPUID_EFFECTIVE_FAMILY(version) == CPUID_FAMILY_K8 && + CPUID_EFFECTIVE_MODEL(version) < 0x40; +} + +static INLINE Bool +CPUID_ID0RequiresFence(CPUIDRegs *id0) +{ + if (id0->eax == 0) { + return FALSE; + } + // hard to get strcmp() in some environments, so do it in the raw + return (id0->ebx == *(uint32 *) (CPUID_AMD_VENDOR_STRING + 0) && + id0->ecx == *(uint32 *) (CPUID_AMD_VENDOR_STRING + 4) && + id0->edx == *(uint32 *) (CPUID_AMD_VENDOR_STRING + 8)); +} + +static INLINE Bool +CPUID_ID1RequiresFence(CPUIDRegs *id1) +{ + return CPUID_VersionRequiresFence(id1->eax); +} + +static INLINE Bool +CPUID_RequiresFence(CpuidVendors vendor, // IN + uint32 version) // IN: %eax from CPUID with %eax=1. +{ + return CPUID_VendorRequiresFence(vendor) && + CPUID_VersionRequiresFence(version); +} + + +/* + *---------------------------------------------------------------------- + * + * CPUID_CountsCPUIDAsBranch -- + * + * Returns TRUE iff the cpuid given counts CPUID as a branch + * (i.e. is a pre-Merom E CPU). + * + *---------------------------------------------------------------------- + */ + +static INLINE Bool +CPUID_CountsCPUIDAsBranch(uint32 v) /* %eax from CPUID with %eax=1 */ +{ + /* + * CPUID no longer a branch starting with Merom E. Bug 148411. + * Penryn (Extended Model: 1) also has this fixed. + * + * Merom E is: CPUID.1.eax & 0xfff = 0x6f9 + */ + return !(CPUID_FAMILY_IS_P6(v) && + (CPUID_EFFECTIVE_MODEL(v) > CPUID_MODEL_CORE_0F || + (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_CORE_0F && + CPUID_STEPPING(v) >= 9))); +} + + +/* + * The following low-level functions compute the number of + * cores per cpu. They should be used cautiously because + * they do not necessarily work on all types of CPUs. + * High-level functions that are correct for all CPUs are + * available elsewhere: see lib/cpuidInfo/cpuidInfo.c. + */ + +static INLINE uint32 +CPUID_IntelCoresPerPackage(uint32 v) /* %eax from CPUID with %eax=4 and %ecx=0. */ +{ + // Note: This is not guaranteed to work on older Intel CPUs. + return 1 + CPUID_INTEL_CORE_COUNT(v); +} + +static INLINE uint32 +CPUID_AMDCoresPerPackage(uint32 v) /* %ecx from CPUID with %eax=0x80000008. */ +{ + // Note: This is not guaranteed to work on older AMD CPUs. + return 1 + CPUID_AMD_CORE_COUNT(v); +} + +/* + * Hypervisor CPUID space is 0x400000XX. + */ +static INLINE Bool +CPUID_IsHypervisorLevel(uint32 level, uint32 *offset) +{ + *offset = level & 0xff; + return (level & 0xffffff00) == 0x40000000; +} + + +#endif diff -Nrup source/vmnet-only/includeCheck.h source.edited/vmnet-only/includeCheck.h --- source/vmnet-only/includeCheck.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/includeCheck.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,17 +0,0 @@ -/********************************************************* - * Copyright (C) 2008 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 - * - *********************************************************/ diff -Nrup source/vmnet-only/linux/bridge.c source.edited/vmnet-only/linux/bridge.c --- source/vmnet-only/linux/bridge.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/bridge.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,1651 @@ +/********************************************************* + * Copyright (C) 1998 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" + +#define EXPORT_SYMTAB + +#include +#include +#include +#ifdef KERNEL_2_2 +# include +#else +# include +#endif +#include + +#include +#include +#include +#include "compat_skbuff.h" +#include +#include "compat_sock.h" + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_NET_RADIO +# include +#endif +#include "vmnetInt.h" +#include "compat_spinlock.h" +#include "compat_netdevice.h" +#include "vnetInt.h" +#include "smac.h" + +#define VNET_BRIDGE_HISTORY 48 + +/* + * Bytes reserved before start of packet. As Ethernet header has 14 bytes, + * to get aligned IP header we must skip 2 bytes before packet. Not that it + * matters a lot for us, but using 2 is compatible with what newer 2.6.x + * kernels do. + */ +#ifndef NET_IP_ALIGN +#define NET_IP_ALIGN 2 +#endif + +#if LOGLEVEL >= 4 +static struct timeval vnetTime; +#endif + +typedef struct VNetBridge VNetBridge; + +struct VNetBridge { + struct notifier_block notifier; // for device state changes + char name[VNET_NAME_LEN]; // name of net device (e.g., "eth0") + struct net_device *dev; // device structure for 'name' + struct sock *sk; // socket associated with skb's + struct packet_type pt; // used to add packet handler + Bool enabledPromisc; // track if promisc enabled + Bool warnPromisc; // tracks if warning has been logged + struct sk_buff *history[VNET_BRIDGE_HISTORY]; // avoid duplicate packets + spinlock_t historyLock; // protects 'history' + VNetPort port; // connection to virtual hub + Bool wirelessAdapter; // connected to wireless adapter? + struct SMACState *smac; // device structure for wireless + VNetEvent_Sender *eventSender; // event sender +}; + +typedef PacketStatus (* SMACINT SMACFunc)(struct SMACState *, SMACPackets *); + +static int VNetBridgeUp(VNetBridge *bridge, Bool rtnlLock); +static void VNetBridgeDown(VNetBridge *bridge, Bool rtnlLock); + +static int VNetBridgeNotify(struct notifier_block *this, u_long msg, + void *data); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) && \ + !defined(VMW_TL10S64_WORKAROUND) +static int VNetBridgeReceiveFromDev(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *pt); +#else +static int VNetBridgeReceiveFromDev(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *pt, + struct net_device *real_dev); +#endif + +static void VNetBridgeFree(VNetJack *this); +static void VNetBridgeReceiveFromVNet(VNetJack *this, struct sk_buff *skb); +static Bool VNetBridgeCycleDetect(VNetJack *this, int generation); +static Bool VNetBridgeIsDeviceWireless(struct net_device *dev); +static void VNetBridgePortsChanged(VNetJack *this); +static int VNetBridgeIsBridged(VNetJack *this); +static int VNetBridgeProcRead(char *page, char **start, off_t off, + int count, int *eof, void *data); + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeStartPromisc -- + * + * Set IFF_PROMISC on the peer interface. + * + * Results: + * None. + * + * Side effects: + * The peer interface IFF_PROMISC flag may be changed. + * + *---------------------------------------------------------------------- + */ + +static void +VNetBridgeStartPromisc(VNetBridge *bridge, // IN: + Bool rtnlLock) // IN: Acquire RTNL lock +{ + struct net_device *dev = bridge->dev; + + /* + * Disable wireless cards from going into promiscous mode because those + * cards which do support RF monitoring would not be able to function + * correctly i.e. they would not be able to send data packets. + */ + if (rtnlLock) { + rtnl_lock(); + } + if (!bridge->enabledPromisc && !bridge->wirelessAdapter) { + dev_set_promiscuity(dev, 1); + bridge->enabledPromisc = TRUE; + bridge->warnPromisc = FALSE; + LOG(0, (KERN_NOTICE "bridge-%s: enabled promiscuous mode\n", + bridge->name)); + } + if (rtnlLock) { + rtnl_unlock(); + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeStopPromisc -- + * + * Restore saved IFF_PROMISC on the peer interface. + * + * Results: + * None. + * + * Side effects: + * The peer interface IFF_PROMISC flag may be changed. + * + *---------------------------------------------------------------------- + */ + +static void +VNetBridgeStopPromisc(VNetBridge *bridge, // IN: + Bool rtnlLock) // IN: Acquire RTNL lock +{ + struct net_device *dev = bridge->dev; + + if (rtnlLock) { + rtnl_lock(); + } + if (bridge->enabledPromisc && !bridge->wirelessAdapter) { + dev_set_promiscuity(dev, -1); + bridge->enabledPromisc = FALSE; + LOG(0, (KERN_NOTICE "bridge-%s: disabled promiscuous mode\n", + bridge->name)); + } + if (rtnlLock) { + rtnl_unlock(); + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeCheckPromisc -- + * + * Make sure IFF_PROMISC on the peer interface is set. + * + * This can be called periodically. + * + * Results: + * None. + * + * Side effects: + * Hopefully enables promiscuous mode again if it should have been enabled. + * + *---------------------------------------------------------------------- + */ + +static INLINE_SINGLE_CALLER void +VNetBridgeCheckPromisc(VNetBridge *bridge) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + if (bridge->enabledPromisc && !bridge->wirelessAdapter) { + struct net_device *dev = bridge->dev; + Bool devPromisc = (dev->flags & IFF_PROMISC) != 0; + + if (!devPromisc) { + if (!bridge->warnPromisc) { + bridge->warnPromisc = TRUE; + LOG(0, (KERN_NOTICE "bridge-%s: someone disabled promiscuous mode\n" + "Your Ethernet driver is not compatible with VMware's bridged networking.\n", + bridge->name)); + } + rtnl_lock(); + dev_set_promiscuity(dev, 0); + rtnl_unlock(); + } + } +#endif +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeDevCompatible -- + * + * Check whether bridge and network device are compatible. + * + * Results: + * Non-zero if device is good enough for bridge. Zero otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE_SINGLE_CALLER int +VNetBridgeDevCompatible(VNetBridge *bridge, // IN: Bridge + struct net_device *net) // IN: Network device +{ +#ifdef VMW_NETDEV_HAS_NET + if (compat_dev_net(net) != &init_net) { + return 0; + } +#endif + return strcmp(net->name, bridge->name) == 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridge_Create -- + * + * Creates a bridge. Allocates struct, allocates internal device, + * initializes port/jack, and creates a proc entry. Finally, creates an + * event sender and register itself with the kernel for device state + * change notifications. + * + * At this time the bridge is not yet plugged into the hub, because this + * will be done by the caller, i.e. the driver. But we need to know the + * hub in order to create an event sender. This allows for enabling + * the notification mechanism, which will instantly start firing, which in + * turn will bring up the bridge (if present), which eventually will + * inject bridge events. Moreover, the bridge will start injecting + * packets, which will be dropped on the floor. All in all, this is not + * that elegant. Alternatively, we could (i) plug into the hub inside of + * this function, which would require adding a few parameters, (ii) split + * the function into a create part and a registration part. Both ways are + * not consistent with how driver.c plugs the ports into the hub. + * + * Results: + * Errno. Also returns an allocated jack to connect to, + * NULL on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetBridge_Create(const char *devName, // IN: name of device (e.g., "eth0") + VNetJack *hubJack, // IN: the future hub + VNetPort **ret) // OUT: port to virtual hub +{ + VNetBridge *bridge = NULL; + static unsigned id = 0; + int retval = 0; + + *ret = NULL; + + /* + * Its an error if device name is empty. + */ + + if (devName[0] == '\0') { + retval = -EINVAL; + goto out; + } + + /* + * Allocate bridge structure + */ + + bridge = kmalloc(sizeof *bridge, GFP_USER); + if (bridge == NULL) { + retval = -ENOMEM; + goto out; + } + memset(bridge, 0, sizeof *bridge); + spin_lock_init(&bridge->historyLock); + memcpy(bridge->name, devName, sizeof bridge->name); + NULL_TERMINATE_STRING(bridge->name); + + /* + * Initialize jack. + */ + + bridge->port.id = id++; + bridge->port.next = NULL; + + bridge->port.jack.peer = NULL; + bridge->port.jack.numPorts = 1; + VNetSnprintf(bridge->port.jack.name, sizeof bridge->port.jack.name, + "bridge%u", bridge->port.id); + bridge->port.jack.private = bridge; + bridge->port.jack.index = 0; + bridge->port.jack.procEntry = NULL; + bridge->port.jack.free = VNetBridgeFree; + bridge->port.jack.rcv = VNetBridgeReceiveFromVNet; + bridge->port.jack.cycleDetect = VNetBridgeCycleDetect; + bridge->port.jack.portsChanged = VNetBridgePortsChanged; + bridge->port.jack.isBridged = VNetBridgeIsBridged; + + /* + * Make proc entry for this jack. + */ + + retval = VNetProc_MakeEntry(bridge->port.jack.name, S_IFREG, + &bridge->port.jack.procEntry); + if (retval) { + if (retval == -ENXIO) { + bridge->port.jack.procEntry = NULL; + } else { + goto out; + } + } else { + bridge->port.jack.procEntry->read_proc = VNetBridgeProcRead; + bridge->port.jack.procEntry->data = bridge; + } + + /* + * Rest of fields. + */ + + bridge->port.flags = IFF_RUNNING; + + memset(bridge->port.paddr, 0, sizeof bridge->port.paddr); + memset(bridge->port.ladrf, 0, sizeof bridge->port.ladrf); + + bridge->port.paddr[0] = VMX86_STATIC_OUI0; + bridge->port.paddr[1] = VMX86_STATIC_OUI1; + bridge->port.paddr[2] = VMX86_STATIC_OUI2; + + bridge->port.fileOpRead = NULL; + bridge->port.fileOpWrite = NULL; + bridge->port.fileOpIoctl = NULL; + bridge->port.fileOpPoll = NULL; + + /* create event sender */ + retval = VNetHub_CreateSender(hubJack, &bridge->eventSender); + if (retval != 0) { + goto out; + } + + /* + * on RHEL3 Linux 2.4.21-47 (others maybe too) the notifier does not fire + * and bring up the bridge as expected, thus we bring it up manually + * *before* registering the notifier (PR306435) + */ + VNetBridgeUp(bridge, TRUE); + + /* + * register notifier for network device state change notifications, the + * notifier will fire right away, and the notifier handler will bring up + * the bridge (see exception above) + */ + bridge->notifier.notifier_call = VNetBridgeNotify; + bridge->notifier.priority = 0; + register_netdevice_notifier(&bridge->notifier); + + /* return bridge */ + *ret = &bridge->port; + LOG(1, (KERN_DEBUG "bridge-%s: attached\n", bridge->name)); + return 0; + +out: + if (bridge != NULL) { + kfree(bridge); + } + return retval; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeFree -- + * + * Unregister from device state notifications, disable the bridge, + * destroy sender, remove proc entry, cleanup smac, and deallocate + * struct. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +VNetBridgeFree(VNetJack *this) // IN: jack to free +{ + VNetBridge *bridge = (VNetBridge*)this->private; + + /* unregister notifier */ + if (bridge->notifier.notifier_call != NULL) { + int err; + + err = compat_unregister_netdevice_notifier(&bridge->notifier); + if (err != 0) { + LOG(0, (KERN_NOTICE "Can't unregister netdevice notifier (%d)\n", + err)); + } + bridge->notifier.notifier_call = NULL; + } + + /* disable bridge */ + if (bridge->dev != NULL) { + LOG(1, (KERN_DEBUG "bridge-%s: disabling the bridge\n", bridge->name)); + VNetBridgeDown(bridge, TRUE); + } + + /* destroy event sender */ + VNetEvent_DestroySender(bridge->eventSender); + bridge->eventSender = NULL; + + /* remove /proc entry */ + if (this->procEntry) { + VNetProc_RemoveEntry(this->procEntry); + } + + if (bridge->smac){ + SMAC_CleanupState(&(bridge->smac)); + } + + /* free bridge */ + LOG(1, (KERN_DEBUG "bridge-%s: detached\n", bridge->name)); + kfree(bridge); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetCallSMACFunc -- + * + * Wrapper for SMAC functions. + * + * Results: + * Packet Status. + * + * Side effects: + * The skb buffer is freed if not successful otherwise it points to + * the clone. + * + *---------------------------------------------------------------------- + */ + +PacketStatus +VNetCallSMACFunc(struct SMACState *state, // IN: pointer to state + struct sk_buff **skb, // IN/OUT: packet to process + void *startOfData, // IN: points to start of data + SMACFunc func) // IN: function to be called +{ + SMACPackets packets = { {0} }; + PacketStatus status; + + packets.orig.skb = *skb; + packets.orig.startOfData = startOfData; + + status = func(state, &packets); + if (status != PacketStatusForwardPacket) { + dev_kfree_skb(*skb); + return status; + } + + if (packets.clone.skb) { + dev_kfree_skb(*skb); + *skb = packets.clone.skb; + } + return status; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeReceiveFromVNet -- + * + * This jack is receiving a packet from a vnet. This function + * sends down (i.e., out on the host net device) if the packet + * isn't destined for the host, and it sends up (i.e., + * simulates a receive for the host) if the packet + * satisfies the host's packet filter. + * + * When the function sends up it keeps a reference to the + * packet in a history list so that we can avoid handing + * a VM a copy of its own packet. + * + * Results: + * None. + * + * Side effects: + * Frees skb. Checks if host device is still using + * promiscuous mode. + * + *---------------------------------------------------------------------- + */ + +void +VNetBridgeReceiveFromVNet(VNetJack *this, // IN: jack + struct sk_buff *skb) // IN: pkt to receive +{ + VNetBridge *bridge = (VNetBridge*)this->private; + struct net_device *dev = bridge->dev; + uint8 dest[ETH_ALEN]; + struct sk_buff *clone; + + LOG(3, (KERN_DEBUG "bridge-%s: transmit %d\n", + bridge->name, (int) skb->len)); + + if (!dev) { + dev_kfree_skb(skb); + return; + } + + /* + * skb might be freed by wireless code, so need to keep + * a local copy of the MAC rather than a pointer to it. + */ + + memcpy(dest, SKB_2_DESTMAC(skb), ETH_ALEN); + + /* + * Check promiscuous bit periodically + */ + + VNetBridgeCheckPromisc(bridge); + +#ifdef notdef + // xxx; + /* + * We need to send the packet both up to the host and down + * to the interface. + * However, we ignore packets destined only for this hub. + */ + + for (i = 0; i < VNET_PORTS_PER_HUB; i++) { + VNetPort *p = &port->hub->port[i]; + if (UP_AND_RUNNING(p->flags) && MAC_EQ(dest, p->paddr)) { + return; + } + } +#endif + + /* + * Wireless processing + */ + + if (bridge->smac) { + if (VNetCallSMACFunc(bridge->smac, &skb, skb->data, + SMAC_CheckPacketToHost) != + PacketStatusForwardPacket) { + LOG(4, (KERN_NOTICE "bridge-%s: packet dropped .\n", + bridge->name)); + return; + } + } + + /* + * Send down (imitate packet_sendmsg) + * + * Do this only if the packet is not addressed to the peer, + * and the packet size is not too big. + */ + + dev_lock_list(); + if (MAC_EQ(dest, dev->dev_addr) || + skb->len > dev->mtu + dev->hard_header_len) { + dev_unlock_list(); + } else { +# if 0 // XXX we should do header translation + if ((dev->flags & IFF_SOFTHEADERS) != 0) { + if (skb->len > dev->mtu) { + clone = NULL; + } else { + clone = dev_alloc_skb(skb->len + dev->hard_header_len, GFP_ATOMIC); + } + if (clone != NULL) { + skb_reserve(clone, dev->hard_header_len); + if (dev->hard_header != NULL) { + dev->hard_header(clone, dev, ETH_P_IP, NULL, NULL, skb->len); + } + memcpy(skb_put(clone, skb->len), skb->data, skb->len); + } + } +# endif + clone = skb_clone(skb, GFP_ATOMIC); + if (clone == NULL) { + dev_unlock_list(); + } else { + struct sock *sk = bridge->sk; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) + atomic_add(skb->truesize, &sk->sk_wmem_alloc); +#else +#warning EHUD gotta figure out what this does and how to fix it: atomic_add(skb->truesize, &sk->sk_wmem_alloc); +#endif /* 2.6.29 */ + clone->sk = sk; + clone->protocol = ((struct ethhdr *)skb->data)->h_proto; // XXX + if ((dev->flags & IFF_UP) != 0) { + dev_unlock_list(); + DEV_QUEUE_XMIT(clone, dev, 0); + } else { + dev_unlock_list(); + dev_kfree_skb(clone); + } + } + } + + /* + * Send up (imitate Ethernet receive) + * + * Do this if the packet is addressed to the peer (or is broadcast, etc.). + * + * This packet will get back to us, via VNetBridgeReceive. + * We save it so we can recognize it (and its clones) again. + */ + + if (VNetPacketMatch(dest, dev->dev_addr, allMultiFilter, dev->flags)) { + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) { + unsigned long flags; + int i; + + atomic_inc(&clone->users); + + clone->dev = dev; + clone->protocol = eth_type_trans(clone, dev); + spin_lock_irqsave(&bridge->historyLock, flags); + for (i = 0; i < VNET_BRIDGE_HISTORY; i++) { + if (bridge->history[i] == NULL) { + bridge->history[i] = clone; +# if LOGLEVEL >= 3 + { + int j; + int count = 0; + for (j = 0; j < VNET_BRIDGE_HISTORY; j++) { + if (bridge->history[j] != NULL) { + count++; + } + } + LOG(3, (KERN_DEBUG "bridge-%s: host slot %d history %d\n", + bridge->name, i, count)); + } +# endif + break; + } + } + if (i >= VNET_BRIDGE_HISTORY) { + LOG(1, (KERN_NOTICE "bridge-%s: history full\n", + bridge->name)); + + for (i = 0; i < VNET_BRIDGE_HISTORY; i++) { + struct sk_buff *s = bridge->history[i]; + + /* + * We special case 0 to avoid races with another thread on + * another cpu wanting to use the 0 entry. This could happen + * when we release the lock to free the former entry. + * See bug 11231 for details. + */ + if (i == 0) { + bridge->history[0] = clone; + } else { + bridge->history[i] = NULL; + } + if (s) { + spin_unlock_irqrestore(&bridge->historyLock, flags); + dev_kfree_skb(s); + spin_lock_irqsave(&bridge->historyLock, flags); + } + } + } + spin_unlock_irqrestore(&bridge->historyLock, flags); + + /* + * We used to cli() before calling netif_rx() here. It was probably + * unneeded (as we never did it in netif.c, and the code worked). In + * any case, now that we are using netif_rx_ni(), we should certainly + * not do it, or netif_rx_ni() will deadlock on the cli() lock --hpreg + */ + + netif_rx_ni(clone); +# if LOGLEVEL >= 4 + do_gettimeofday(&vnetTime); +# endif + } + } + + // xxx; + dev_kfree_skb(skb); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeCycleDetect -- + * + * Cycle detection algorithm. + * + * Results: + * TRUE if a cycle was detected, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Bool +VNetBridgeCycleDetect(VNetJack *this, // IN: jack + int generation) // IN: generation +{ + VNetBridge *bridge = (VNetBridge*)this->private; + return VNetCycleDetectIf(bridge->name, generation); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgePortsChanged -- + * + * The number of ports connected to this jack has change, react + * accordingly by starting/stopping promiscuous mode based on + * whether any peers exist. + * + * Results: + * None. + * + * Side effects: + * Promiscuous mode may be started or stopped. + * + *---------------------------------------------------------------------- + */ + +void +VNetBridgePortsChanged(VNetJack *this) // IN: jack +{ + VNetBridge *bridge = (VNetBridge*)this->private; + if (bridge->dev) { + if (VNetGetAttachedPorts(this)) { + VNetBridgeStartPromisc(bridge, TRUE); + } else { + VNetBridgeStopPromisc(bridge, TRUE); + } + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeIsBridged -- + * + * Reports if the bridged interface is up or down. + * + * Results: + * 1 - we are bridged but the interface is not up + * 2 - we are bridged and the interface is up + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetBridgeIsBridged(VNetJack *this) // IN: jack +{ + VNetBridge *bridge = (VNetBridge*)this->private; + if (bridge->dev) { + return 2; + } else { + return 1; + } +} + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeIsDeviceWireless -- + * + * Check if the device is a wireless adapter, depending on the version + * of the wireless extension present in the kernel. + * + * Results: + * TRUE if the device is wireless, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Bool +VNetBridgeIsDeviceWireless(struct net_device *dev) //IN: sock +{ +#ifdef CONFIG_WIRELESS_EXT + return dev->wireless_handlers != NULL; +#elif !defined(CONFIG_NET_RADIO) + return FALSE; +#elif defined(WIRELESS_EXT) && WIRELESS_EXT > 19 + return dev->wireless_handlers != NULL; +#elif defined(WIRELESS_EXT) && WIRELESS_EXT > 12 + return dev->wireless_handlers != NULL || dev->get_wireless_stats != NULL; +#else + return dev->get_wireless_stats != NULL; +#endif +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeSendLinkStateEvent -- + * + * Sends a link state event. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static int +VNetBridgeSendLinkStateEvent(VNetBridge *bridge, // IN: the bridge + uint32 adapter, // IN: the adapter + Bool up) // IN: the link state +{ + VNet_LinkStateEvent event; + int res; + + event.header.size = sizeof event; + res = VNetEvent_GetSenderId(bridge->eventSender, &event.header.senderId); + if (res != 0) { + LOG(1, (KERN_NOTICE "bridge-%s: can't send link state event, " + "getSenderId failed (%d)\n", bridge->name, res)); + return res; + } + event.header.eventId = 0; + event.header.classSet = VNET_EVENT_CLASS_BRIDGE; + event.header.type = VNET_EVENT_TYPE_LINK_STATE; + event.adapter = adapter; + event.up = up; + res = VNetEvent_Send(bridge->eventSender, &event.header); + if (res != 0) { + LOG(1, (KERN_NOTICE "bridge-%s: can't send link state event, send " + "failed (%d)\n", bridge->name, res)); + } + return res; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeUp -- + * + * Bring a bridge up. Gets peer's device structure, verifies + * that interface is up, checks the header length, + * allocates a socket, adds a packet handler to the network + * stack, and then places the peer's device in promiscuous + * mode. + * + * Results: + * errno. + * + * Side effects: + * Bridging may be brought up with a peer interface. + * + *---------------------------------------------------------------------- + */ + +static int +VNetBridgeUp(VNetBridge *bridge, // IN: bridge struct + Bool rtnlLock) // IN: acquire RTNL lock +{ + int retval = 0; + + if (bridge->dev != NULL) { + LOG(0, (KERN_NOTICE "bridge-%s: already up\n", bridge->name)); + goto out; + } + + /* + * Get peer device structure + */ + + dev_lock_list(); + bridge->dev = DEV_GET(bridge); + LOG(2, (KERN_DEBUG "bridge-%s: got dev %p\n", + bridge->name, bridge->dev)); + if (bridge->dev == NULL) { + dev_unlock_list(); + retval = -ENODEV; + goto out; + } + if (!(bridge->dev->flags & IFF_UP)) { + LOG(2, (KERN_DEBUG "bridge-%s: interface %s is not up\n", + bridge->name, bridge->dev->name)); + dev_unlock_list(); + retval = -ENODEV; + goto out; + } + + /* + * At a minimum, the header size should be the same as ours. + * + * XXX we should either do header translation or ensure this + * is an Ethernet. + */ + + if (bridge->dev->hard_header_len != ETH_HLEN) { + LOG(1, (KERN_DEBUG "bridge-%s: can't bridge with %s, bad header length %d\n", + bridge->name, bridge->dev->name, bridge->dev->hard_header_len)); + dev_unlock_list(); + retval = -EINVAL; + goto out; + } + + /* + * Get a socket to play with + * + * We set the dead field so we don't get a call back from dev_kfree_skb(). + * (The alternative is to support the callback.) + */ + + bridge->sk = compat_sk_alloc(bridge, GFP_ATOMIC); + if (bridge->sk == NULL) { + dev_unlock_list(); + retval = -ENOMEM; + goto out; + } + SET_SK_DEAD(bridge->sk); + + bridge->wirelessAdapter = VNetBridgeIsDeviceWireless(bridge->dev); + + /* + * If it is a wireless adapter initialize smac struct. + */ + + if (bridge->wirelessAdapter) { + + LOG(1, (KERN_NOTICE "bridge-%s: is a Wireless Adapter\n", bridge->name)); + SMAC_InitState(&(bridge->smac)); + if (bridge->smac) { + /* + * Store the MAC address of the adapter + */ + + SMAC_SetMac(bridge->smac, bridge->dev->dev_addr); + } + } + + /* + * Link up with the peer device by adding a + * packet handler to the networking stack. + */ + + bridge->pt.func = VNetBridgeReceiveFromDev; + bridge->pt.type = htons(ETH_P_ALL); + bridge->pt.dev = bridge->dev; + + /* + * TurboLinux10 uses 2.6.0-test5, which we do not support, so special case it, + * 2.6.0 with tl_kernel_version_h is 2.6.0-pre5... + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) || \ + (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 0) && defined(__tl_kernel_version_h__)) + bridge->pt.data = bridge->sk; +#else + bridge->pt.af_packet_priv = bridge->sk; +#endif + bridge->enabledPromisc = FALSE; + bridge->warnPromisc = FALSE; + dev_add_pack(&bridge->pt); + dev_unlock_list(); + + /* + * Put in promiscuous mode if need be. + */ + + down(&vnetStructureSemaphore); + if (VNetGetAttachedPorts(&bridge->port.jack)) { + VNetBridgeStartPromisc(bridge, rtnlLock); + } + up(&vnetStructureSemaphore); + + /* send link state up event */ + retval = VNetBridgeSendLinkStateEvent(bridge, bridge->dev->ifindex, TRUE); + if (retval != 0) { + LOG(1, (KERN_NOTICE "bridge-%s: can't send link state event (%d)\n", + bridge->name, retval)); + goto out; + } + + LOG(1, (KERN_DEBUG "bridge-%s: up\n", bridge->name)); + + /* + * Return + */ + +out: + if (retval != 0) { + if (bridge->sk != NULL) { + sk_free(bridge->sk); + bridge->sk = NULL; + } + bridge->dev = NULL; + } + return retval; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeDown -- + * + * Bring a bridge down. Stops promiscuous mode, removes the + * packet handler from the network stack, and frees the + * socket. + * + * Results: + * None. + * + * Side effects: + * Bridging is brought down. + * + *---------------------------------------------------------------------- + */ + +static void +VNetBridgeDown(VNetBridge *bridge, // IN: bridge + Bool rtnlLock) // IN: acquire RTNL lock +{ + int retval; + + if (bridge->dev == NULL) { + LOG(0, (KERN_NOTICE "bridge-%s: already down\n", bridge->name)); + return; + } + + /* send link state down event */ + retval = VNetBridgeSendLinkStateEvent(bridge, bridge->dev->ifindex, FALSE); + if (retval != 0) { + LOG(1, (KERN_NOTICE "bridge-%s: can't send link state event (%d)\n", + bridge->name, retval)); + } + + VNetBridgeStopPromisc(bridge, rtnlLock); + if (bridge->smac){ + SMAC_SetMac(bridge->smac, NULL); + } + bridge->dev = NULL; + dev_remove_pack(&bridge->pt); + sk_free(bridge->sk); + bridge->sk = NULL; + + LOG(1, (KERN_DEBUG "bridge-%s: down\n", bridge->name)); +} + + +/* + *----------------------------------------------------------------------------- + * + * VNetBridgeNotifyLogBridgeUpError -- + * + * Logs a bridge up error for the notify function following this function. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static void +VNetBridgeNotifyLogBridgeUpError(int errno, // IN: the error number + char *bridgeName, // IN: the bridge name + char *devName) // IN: the device name +{ + switch (errno) { + case -ENODEV: + LOG(0, (KERN_WARNING "bridge-%s: interface %s not found or not " + "up\n", bridgeName, devName)); + break; + case -EINVAL: + LOG(0, (KERN_WARNING "bridge-%s: interface %s is not a valid " + "Ethernet interface\n", bridgeName, devName)); + break; + case -ENOMEM: + LOG(0, (KERN_WARNING "bridge-%s: failed to allocate memory\n", + bridgeName)); + break; + default: + /* This should never happen --hpreg */ + LOG(0, (KERN_WARNING "bridge-%s: failed to enable the bridge to " + "interface %s (error %d)\n", bridgeName, devName, + -errno)); + break; + } +} + + +/* + *----------------------------------------------------------------------------- + * + * VNetBridgeNotify -- + * + * Callback on peer device state change. The function brings + * the bridge up/down in response to changes in the peer device. + * + * Results: + * NOTIFY_DONE + * + * Side effects: + * Promiscuous mode is changed when bridge brought up/down. + * + *----------------------------------------------------------------------------- + */ + +static int +VNetBridgeNotify(struct notifier_block *this, // IN: callback data (bridge) + u_long msg, // IN: type of event + void *data) // IN: device pertaining to event +{ + VNetBridge *bridge = list_entry(this, VNetBridge, notifier); + struct net_device *dev = (struct net_device *) data; + + switch (msg) { + case NETDEV_UNREGISTER: + LOG(2, (KERN_DEBUG "bridge-%s: interface %s is unregistering\n", + bridge->name, dev->name)); + if (dev == bridge->dev) { + /* This should never happen --hpreg */ + LOG(0, (KERN_WARNING "bridge-%s: interface %s unregistered without " + "going down! Disabling the bridge\n", bridge->name, + dev->name)); + VNetBridgeDown(bridge, FALSE); + } + break; + + case NETDEV_DOWN: + LOG(2, (KERN_DEBUG "bridge-%s: interface %s is going down\n", + bridge->name, dev->name)); + if (dev == bridge->dev) { + LOG(1, (KERN_DEBUG "bridge-%s: disabling the bridge\n", + bridge->name)); + VNetBridgeDown(bridge, FALSE); + } + break; + + case NETDEV_CHANGE: + LOG(2, (KERN_DEBUG "bridge-%s: interface %s is changing\n", + bridge->name, dev->name)); + if (dev == bridge->dev) { + LOG(1, (KERN_DEBUG "bridge-%s: disabling the bridge\n", + bridge->name)); + VNetBridgeDown(bridge, FALSE); + } else if (bridge->dev == NULL && VNetBridgeDevCompatible(bridge, dev)) { + int errno; + + LOG(1, (KERN_DEBUG "bridge-%s: enabling the bridge\n", bridge->name)); + errno = VNetBridgeUp(bridge, FALSE); + if (errno != 0) { + VNetBridgeNotifyLogBridgeUpError(errno, bridge->name, dev->name); + } + } + break; + + + case NETDEV_UP: + LOG(2, (KERN_DEBUG "bridge-%s: interface %s is going up\n", + bridge->name, dev->name)); + if (bridge->dev == NULL && VNetBridgeDevCompatible(bridge, dev)) { + int errno; + + LOG(1, (KERN_DEBUG "bridge-%s: enabling the bridge\n", bridge->name)); + errno = VNetBridgeUp(bridge, FALSE); + if (errno != 0) { + VNetBridgeNotifyLogBridgeUpError(errno, bridge->name, dev->name); + } + } + break; + + default: + LOG(2, (KERN_DEBUG "bridge-%s: interface %s is sending notification " + "0x%lx\n", bridge->name, dev->name, msg)); + break; + } + + return NOTIFY_DONE; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeComputeHeaderPos -- + * + * Compute correct position for UDP/TCP header. + * + * Results: + * None. + * + * Side effects: + * transport header pointer updated to point to the tcp/udp header. + * + *---------------------------------------------------------------------- + */ + +static INLINE_SINGLE_CALLER void +VNetBridgeComputeHeaderPos(struct sk_buff *skb) // IN: buffer to examine +{ + /* Maybe some kernel gets it right... */ + if (compat_skb_network_header_len(skb)) { + return; + } + switch (be16_to_cpu(skb->protocol)) { + case ETH_P_IP: { + struct iphdr *ipHdr = compat_skb_ip_header(skb); + + compat_skb_set_transport_header(skb, compat_skb_network_offset(skb) + + ipHdr->ihl * 4); + } + return; + default: + LOG(3, (KERN_DEBUG "Unknown EII protocol %04X: csum at %d\n", + be16_to_cpu(skb->protocol), compat_skb_csum_offset(skb))); + break; + } + return; +} + + +/* + * We deal with three types of kernels: + * New kernels: skb_shinfo() has gso_size member, and there is + * skb_gso_segment() helper to split GSO skb into flat ones. + * Older kernels: skb_shinfo() has tso_size member, and there is + * no helper. + * Oldest kernels: without any segmentation offload support. + */ +#if defined(NETIF_F_GSO) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) +#define VNetBridgeIsGSO(skb) skb_shinfo(skb)->gso_size +#define VNetBridgeGSOSegment(skb) skb_gso_segment(skb, 0) +#elif defined(NETIF_F_TSO) +#define VNetBridgeIsGSO(skb) skb_shinfo(skb)->tso_size + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeGSOSegment -- + * + * Split a large TCP/IPv4 sk_buff into multiple sk_buffs of + * size skb_shinfo(skb)->tso_size + * Called from VNetBridgeSendLargePacket(). + * + * Results: + * List of skbs created. + * + * Side effects: + * The incoming packet is split into multiple packets. + * + *---------------------------------------------------------------------- + */ + +static struct sk_buff * +VNetBridgeGSOSegment(struct sk_buff *skb) // IN: packet to split +{ + struct sk_buff *segs = NULL; + struct sk_buff **next = &segs; + int bytesPerPacket, bytesLeft; + int macHdrLen, ipHdrLen, tcpHdrLen, allHdrLen; + int curByteOffset; + uint16 ipID; + uint32 seqNo; + + if (((struct ethhdr *)compat_skb_mac_header(skb))->h_proto != htons(ETH_P_IP)) { + return ERR_PTR(-EPFNOSUPPORT); + } + + if (compat_skb_ip_header(skb)->protocol != IPPROTO_TCP) { + return ERR_PTR(-EPROTONOSUPPORT); + } + + macHdrLen = compat_skb_network_header(skb) - compat_skb_mac_header(skb); + ipHdrLen = compat_skb_ip_header(skb)->ihl << 2; + tcpHdrLen = compat_skb_tcp_header(skb)->doff << 2; + allHdrLen = macHdrLen + ipHdrLen + tcpHdrLen; + + ipID = ntohs(compat_skb_ip_header(skb)->id); + seqNo = ntohl(compat_skb_tcp_header(skb)->seq); + + /* Host TCP stack populated this (MSS) for the host NIC driver */ + bytesPerPacket = skb_shinfo(skb)->tso_size; + + bytesLeft = skb->len - allHdrLen; + curByteOffset = allHdrLen; + + while (bytesLeft) { + struct sk_buff *newSkb; + int payloadSize = (bytesLeft < bytesPerPacket) ? bytesLeft : bytesPerPacket; + + newSkb = dev_alloc_skb(payloadSize + allHdrLen + NET_IP_ALIGN); + if (!newSkb) { + while (segs) { + newSkb = segs; + segs = segs->next; + newSkb->next = NULL; + dev_kfree_skb(newSkb); + } + return ERR_PTR(-ENOMEM); + } + skb_reserve(newSkb, NET_IP_ALIGN); + newSkb->dev = skb->dev; + newSkb->protocol = skb->protocol; + newSkb->pkt_type = skb->pkt_type; + newSkb->ip_summed = VM_TX_CHECKSUM_PARTIAL; + + /* + * MAC+IP+TCP copy + * This implies that ALL fields in the IP and TCP headers are copied from + * the original skb. This is convenient: we'll only fix up fields that + * need to be changed below + */ + memcpy(skb_put(newSkb, allHdrLen), skb->data, allHdrLen); + + /* Fix up pointers to different layers */ + compat_skb_reset_mac_header(newSkb); + compat_skb_set_network_header(newSkb, macHdrLen); + compat_skb_set_transport_header(newSkb, macHdrLen + ipHdrLen); + + /* Payload copy */ + skb_copy_bits(skb, curByteOffset, compat_skb_tail_pointer(newSkb), payloadSize); + skb_put(newSkb, payloadSize); + + curByteOffset+=payloadSize; + bytesLeft -= payloadSize; + + /* Fix up IP hdr */ + compat_skb_ip_header(newSkb)->tot_len = htons(payloadSize + tcpHdrLen + ipHdrLen); + compat_skb_ip_header(newSkb)->id = htons(ipID); + compat_skb_ip_header(newSkb)->check = 0; + /* Recompute new IP checksum */ + compat_skb_ip_header(newSkb)->check = + ip_fast_csum(compat_skb_network_header(newSkb), + compat_skb_ip_header(newSkb)->ihl); + + /* Fix up TCP hdr */ + compat_skb_tcp_header(newSkb)->seq = htonl(seqNo); + /* Clear FIN/PSH if not last packet */ + if (bytesLeft > 0) { + compat_skb_tcp_header(newSkb)->fin = 0; + compat_skb_tcp_header(newSkb)->psh = 0; + } + /* Recompute partial TCP checksum */ + compat_skb_tcp_header(newSkb)->check = + ~csum_tcpudp_magic(compat_skb_ip_header(newSkb)->saddr, + compat_skb_ip_header(newSkb)->daddr, + payloadSize+tcpHdrLen, IPPROTO_TCP, 0); + + /* Offset of field */ + newSkb->csum = offsetof(struct tcphdr, check); + + /* Join packet to the list of segments */ + *next = newSkb; + next = &newSkb->next; + + /* Bump up our counters */ + ipID++; + seqNo += payloadSize; + + } + return segs; +} +#else +#define VNetBridgeIsGSO(skb) (0) +#define VNetBridgeGSOSegment(skb) ERR_PTR(-ENOSYS) +#endif + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeSendLargePacket -- + * + * Split and send a large TCP/IPv4 sk_buff into multiple sk_buffs which + * fits on wire. Called from VNetBridgeReceiveFromDev(), which is a + * protocol handler called from the bottom half, so steady as she + * goes... + * + * skb passed in is deallocated by function. + * + * Results: + * None. + * + * Side effects: + * The incoming packet is split into multiple packets and sent to the + * vnet. + * + *---------------------------------------------------------------------- + */ + +void +VNetBridgeSendLargePacket(struct sk_buff *skb, // IN: packet to split + VNetBridge *bridge) // IN: bridge +{ + struct sk_buff *segs; + + segs = VNetBridgeGSOSegment(skb); + dev_kfree_skb(skb); + if (IS_ERR(segs)) { + LOG(1, (KERN_DEBUG "bridge-%s: cannot segment packet: error %ld\n", + bridge->name, PTR_ERR(segs))); + return; + } + + while (segs) { + struct sk_buff *newSkb; + + newSkb = segs; + segs = newSkb->next; + newSkb->next = NULL; + /* Send it along */ + skb = newSkb; + VNetSend(&bridge->port.jack, newSkb); + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeReceiveFromDev -- + * + * Receive a packet from a bridged peer device + * + * This is called from the bottom half. Must be careful. + * + * Results: + * errno. + * + * Side effects: + * A packet may be sent to the vnet. + * + *---------------------------------------------------------------------- + */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) && \ + !defined(VMW_TL10S64_WORKAROUND) +int +VNetBridgeReceiveFromDev(struct sk_buff *skb, // IN: packet to receive + struct net_device *dev, // IN: unused + struct packet_type *pt) // IN: pt (pointer to bridge) +#else +int +VNetBridgeReceiveFromDev(struct sk_buff *skb, // IN: packet to receive + struct net_device *dev, // IN: unused + struct packet_type *pt, // IN: pt (pointer to bridge) + struct net_device *real_dev) // IN: real device, unused +#endif +{ + VNetBridge *bridge = list_entry(pt, VNetBridge, pt); + int i; + unsigned long flags; + + if (bridge->dev == NULL) { + LOG(3, (KERN_DEBUG "bridge-%s: received %d closed\n", + bridge->name, (int) skb->len)); + dev_kfree_skb(skb); + return -EIO; // value is ignored anyway + } + + /* + * Check is this is a packet that we sent up to the host, and if + * so then don't bother to receive the packet. + */ + + spin_lock_irqsave(&bridge->historyLock, flags); + for (i = 0; i < VNET_BRIDGE_HISTORY; i++) { + struct sk_buff *s = bridge->history[i]; + if (s != NULL && + (s == skb || SKB_IS_CLONE_OF(skb, s))) { + bridge->history[i] = NULL; + spin_unlock_irqrestore(&bridge->historyLock, flags); + dev_kfree_skb(s); + LOG(3, (KERN_DEBUG "bridge-%s: receive %d self %d\n", + bridge->name, (int) skb->len, i)); + dev_kfree_skb(skb); + return 0; + } + } + spin_unlock_irqrestore(&bridge->historyLock, flags); + +# if LOGLEVEL >= 4 + { + struct timeval now; + do_gettimeofday(&now); + LOG(3, (KERN_DEBUG "bridge-%s: time %d\n", + bridge->name, + (int)((now.tv_sec * 1000000 + now.tv_usec) + - (vnetTime.tv_sec * 1000000 + vnetTime.tv_usec)))); + } +# endif + + if (bridge->smac) { + if (VNetCallSMACFunc(bridge->smac, &skb, compat_skb_mac_header(skb), + SMAC_CheckPacketFromHost) != + PacketStatusForwardPacket) { + LOG(4, (KERN_NOTICE "bridge-%s: packet dropped .\n", + bridge->name)); + return 0; + } + } + +#ifdef KERNEL_2_3_15 + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) { + return 0; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) + /* + * Unbelievable... Caller sets h.raw = nh.raw before invoking us... + */ + VNetBridgeComputeHeaderPos(skb); +#endif +#endif + + skb_push(skb, skb->data - compat_skb_mac_header(skb)); + LOG(3, (KERN_DEBUG "bridge-%s: receive %d\n", + bridge->name, (int) skb->len)); + + /* + * If this is a large packet, chop chop chop (if supported)... + */ + if (VNetBridgeIsGSO(skb)) { + VNetBridgeSendLargePacket(skb, bridge); + } else { + VNetSend(&bridge->port.jack, skb); + } + + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetBridgeProcRead -- + * + * Callback for read operation on this bridge entry in vnets proc fs. + * + * Results: + * Length of read operation. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetBridgeProcRead(char *page, // IN/OUT: buffer to write into + char **start, // OUT: 0 if file < 4k, else offset into page + off_t off, // IN: (unused) offset of read into the file + int count, // IN: (unused) maximum number of bytes to read + int *eof, // OUT: TRUE if there is nothing more to read + void *data) // IN: client data - pointer to bridge +{ + VNetBridge *bridge = (VNetBridge*)data; + int len = 0; + + if (!bridge) { + return len; + } + + len += VNetPrintPort(&bridge->port, page+len); + + len += sprintf(page+len, "dev %s ", bridge->name); + + len += sprintf(page+len, "\n"); + + *start = 0; + *eof = 1; + return len; +} diff -Nrup source/vmnet-only/linux/driver.c source.edited/vmnet-only/linux/driver.c --- source/vmnet-only/linux/driver.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/driver.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,1853 @@ +/********************************************************* + * Copyright (C) 1998 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" + +#define EXPORT_SYMTAB + +#include +#include "compat_module.h" +#include +#include +#ifdef KERNEL_2_2 +# include +#else +# include +#endif +#include + +#include +#include + +#include +#include +#include +#include "compat_skbuff.h" +#include +#include +#include "compat_sock.h" + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include +#if defined(__x86_64__) && !defined(HAVE_COMPAT_IOCTL) +#include +#endif + +#include "vnetInt.h" +#include "vnetFilter.h" + +#include "compat_uaccess.h" +#include "compat_kdev_t.h" +#include "compat_sched.h" +#include "compat_semaphore.h" +#include "vmnetInt.h" + +/* + * Initialization and creation routines from other files. + * Putting them here reduces the need for so many header files. + */ + +extern int VNetUserIf_Create(VNetPort **ret); +extern int VNetNetIf_Create(char *devName, VNetPort **ret, int hubNum); +extern int VNetBridge_Create(char *devName, VNetJack *hubJack, VNetPort **ret); +extern int VNetUserListener_Create(uint32 classMask, VNetJack *hubJack, VNetPort **ret); + +#ifdef CONFIG_NETFILTER +/* + * Filter routine from filter.c + */ +extern int VNetFilter_HandleUserCall(VNet_RuleHeader *ruleHeader, unsigned long ioarg); +extern void VNetFilter_Shutdown(void); +#endif + +/* + * Structure for cycle detection of host interfaces. This + * struct is only used by VNetCycleDetectIf(). + */ + +typedef struct VNetInterface { + char name[VNET_NAME_LEN]; + int myGeneration; + struct VNetInterface *next; +} VNetInterface; + +static VNetInterface *vnetInterfaces = NULL; + +/* this will let all multicast packets go through. */ +const uint8 allMultiFilter[VNET_LADRF_LEN] = { 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff }; + +/* broadcast MAC */ +const uint8 broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +/* + * All jack->peer accesses are guarded by this lock. + * + * This lock is acquired for read from interrupt context: + * use write_lock_irqsave() to gain write access. + * + * If you are acquiring this lock for write, and you do + * not have vnetStructureSemaphore already acquired, + * it is most certainly a bug. + */ +static rwlock_t vnetPeerLock = RW_LOCK_UNLOCKED; + +/* + * All concurrent changes to the network structure are + * guarded by this semaphore. + * + * For change to peer field you must own both + * vnetStructureSemaphore and vnetPeerLock for write. + */ +DECLARE_MUTEX(vnetStructureSemaphore); + +#if defined(VM_X86_64) && !defined(HAVE_COMPAT_IOCTL) +/* + * List of ioctl commands we translate 1:1 between 32bit + * userspace and 64bit kernel. + * + * Whole range is translated + * 1:1 in addition to the commands listed below. + */ +static const unsigned int ioctl32_cmds[] = { + SIOCGBRSTATUS, SIOCSPEER, SIOCSPEER2, SIOCSBIND, SIOCGETAPIVERSION2, + SIOCSFILTERRULES, 0, +}; +#endif + +/* + * List of known ports. Use vnetStructureSemaphore for locking. + */ + +static VNetPort *vnetAllPorts = NULL; + + +#ifdef VMW_HAVE_SK_ALLOC_WITH_PROTO +struct proto vmnet_proto = { + .name = "VMNET", + .owner = THIS_MODULE, + .obj_size = sizeof(struct sock), +}; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +struct proto vmnet_proto = { + .name = "VMNET", + .owner = THIS_MODULE, + .obj_size = sizeof(struct sock), +}; + +#endif + +/* + * Device driver interface. + */ + +int VNetRegister(int value); +static int VNetFileOpOpen(struct inode *inode, struct file *filp); +static int VNetFileOpClose(struct inode *inode, struct file *filp); +static unsigned int VNetFileOpPoll(struct file *filp, poll_table *wait); +static ssize_t VNetFileOpRead(struct file *filp, char *buf, size_t count, + loff_t *ppos); +static ssize_t VNetFileOpWrite(struct file *filp, const char *buf, size_t count, + loff_t *ppos); +static int VNetFileOpIoctl(struct inode *inode, struct file *filp, + unsigned int iocmd, unsigned long ioarg); +#if defined(HAVE_UNLOCKED_IOCTL) || defined(HAVE_COPAT_IOCTL) +static long VNetFileOpUnlockedIoctl(struct file * filp, + unsigned int iocmd, unsigned long ioarg); +#endif + +static struct file_operations vnetFileOps; + +/* + * Utility functions + */ + +static void VNetFreeInterfaceList(void); +static int VNetSwitchToDifferentPeer(VNetJack *jack, VNetJack *newPeer, + Bool connectNewToPeer, + struct file *filp, VNetPort *jackPort, + VNetPort *newPeerPort); + +/* + *---------------------------------------------------------------------- + * + * VNetRegister -- + * + * (debugging support) Should be the first function of this file + * + * Results: + * + * Registers the module. + * /sbin/ksyms -a | grep VNetRegister will return the base + * address of that function as loaded in the kernel. + * + * Since this is the first function of the kernel module, + * every other symbol can be computing by adding the base + * to the output of nm. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetRegister(int value) // IN: unused +{ + LOG(0, (KERN_WARNING "/dev/vmnet: VNetRegister called\n")); + return 0; +} + +#ifdef VMW_HAVE_SK_ALLOC_WITH_PROTO + +/* + *---------------------------------------------------------------------- + * + * VNetProtoRegister -- + * VNetProtoUnregister -- + * + * Register or unregister the struct proto that we use for sk_alloc. + * + * Results: + * int. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +#define VNetProtoRegister() proto_register(&vmnet_proto, 0) +#define VNetProtoUnregister() \ + do { \ + proto_unregister(&vmnet_proto); \ + } while (0) + +#else + +#define VNetProtoRegister() 0 +#define VNetProtoUnregister() + +#endif + +#if defined(VM_X86_64) && !defined(HAVE_COMPAT_IOCTL) +/* + *---------------------------------------------------------------------- + * + * LinuxDriver_Ioctl32_Handler -- + * + * Wrapper for allowing 64-bit driver to handle ioctls() + * from 32-bit applications. + * + * Results: + * + * -ENOTTY, or result of call to VNetFileOpIoctl(). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +LinuxDriver_Ioctl32_Handler(unsigned int fd, // IN: (unused) + unsigned int iocmd, // IN: + unsigned long ioarg, // IN: + struct file * filp) // IN: +{ + int ret = -ENOTTY; + lock_kernel(); + if (filp && filp->f_op && filp->f_op->ioctl == VNetFileOpIoctl) { + ret = VNetFileOpIoctl(filp->f_dentry->d_inode, filp, iocmd, ioarg); + } + unlock_kernel(); + return ret; +} + + +/* + *---------------------------------------------------------------------- + * + * register_ioctl32_handlers -- + * + * Registers LinuxDriver_Ioctl32_Handler as the wrapper for + * allowing 64-bit driver to handle ioctls() + * from 32-bit applications. + * + * Does nothing on non-64bit systems. + * + * Results: + * + * errno (0 on success) + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +register_ioctl32_handlers(void) +{ + int i; + int retval; + + for (i = VNET_FIRST_CMD; i <= VNET_LAST_CMD; i++) { + retval = register_ioctl32_conversion(i, LinuxDriver_Ioctl32_Handler); + if (retval) { + int j; + LOG(0, (KERN_WARNING "Fail to register ioctl32 conversion for cmd %d\n", i)); + for (j = VNET_FIRST_CMD; j < i; ++j) { + unregister_ioctl32_conversion(j); + } + return retval; + } + } + for (i = 0; ioctl32_cmds[i]; i++) { + retval = register_ioctl32_conversion(ioctl32_cmds[i], LinuxDriver_Ioctl32_Handler); + if (retval) { + int j; + LOG(0, (KERN_WARNING "Fail to register ioctl32 conversion for cmd %08X\n", + ioctl32_cmds[i])); + for (j = VNET_FIRST_CMD; j < VNET_LAST_CMD; ++j) { + unregister_ioctl32_conversion(j); + } + for (j = 0; j < i; ++j) { + unregister_ioctl32_conversion(ioctl32_cmds[j]); + } + return retval; + } + } + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * unregister_ioctl32_handlers -- + * + * Unregisters the wrappers we specified for + * allowing a 64-bit driver to handle ioctls() + * from 32-bit applications. + * + * Does nothing on non-64bit systems. + * + * Results: + * + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +unregister_ioctl32_handlers(void) +{ + int i; + int retval; + + for (i = VNET_FIRST_CMD; i <= VNET_LAST_CMD; i++) { + retval = unregister_ioctl32_conversion(i); + if (retval) { + LOG(0, (KERN_WARNING "Fail to unregister ioctl32 conversion for cmd %d\n", i)); + } + } + for (i = 0; ioctl32_cmds[i]; i++) { + retval = unregister_ioctl32_conversion(ioctl32_cmds[i]); + if (retval) { + LOG(0, (KERN_WARNING "Fail to unregister ioctl32 conversion for cmd %08X\n", + ioctl32_cmds[i])); + } + } +} +#else +#define register_ioctl32_handlers() (0) +#define unregister_ioctl32_handlers() do { } while (0) +#endif + + +/* + *---------------------------------------------------------------------- + * + * VNetAddPortToList -- + * + * Add port to list of known ports. + * Caller must own vnetStructureSemaphore. + * + * Results: + * + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE void +VNetAddPortToList(VNetPort *port) // IN: port to add to list +{ + port->next = vnetAllPorts; + vnetAllPorts = port; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetRemovePortFromList -- + * + * Remove port from list of known ports. + * Caller must own vnetStructureSemaphore. + * + * Results: + * + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE void +VNetRemovePortFromList(const VNetPort *port) // IN: port to remove from list +{ + VNetPort **p; + + for (p = &vnetAllPorts; *p; p = &(*p)->next) { + if (*p == port) { + *p = port->next; + break; + } + } +} + + +/* + *---------------------------------------------------------------------- + * + * init_module -- + * + * linux module entry point. Called by /sbin/insmod command. + * Initializes module and Registers this driver for a + * vnet major #. The 64-bit version of this driver also + * registers handlers for 32-bit applications. + * + * Results: + * errno (0 on success). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +init_module(void) +{ + int retval; + + /* + * First initialize everything, and as a last step register + * vmnet device: immediately after registration anybody can + * ask driver for anything. + */ + + retval = VNetProc_Init(); + if (retval) { + LOG(0, (KERN_NOTICE "/dev/vmnet: could not register proc fs\n")); + return -ENOENT; + } + + retval = VNetProtoRegister(); + if (retval) { + goto err_proto; + } + + /* + * Initialize the file_operations structure. Because this code is always + * compiled as a module, this is fine to do it here and not in a static + * initializer. + */ + + memset(&vnetFileOps, 0, sizeof vnetFileOps); + compat_fop_set_owner(&vnetFileOps); + vnetFileOps.read = VNetFileOpRead; + vnetFileOps.write = VNetFileOpWrite; + vnetFileOps.poll = VNetFileOpPoll; +#ifdef HAVE_UNLOCKED_IOCTL + vnetFileOps.unlocked_ioctl = VNetFileOpUnlockedIoctl; +#else + vnetFileOps.ioctl = VNetFileOpIoctl; +#endif +#ifdef HAVE_COMPAT_IOCTL + vnetFileOps.compat_ioctl = VNetFileOpUnlockedIoctl; +#endif + vnetFileOps.open = VNetFileOpOpen; + vnetFileOps.release = VNetFileOpClose; + + retval = register_chrdev(VNET_MAJOR_NUMBER, "vmnet", &vnetFileOps); + if (retval) { + LOG(0, (KERN_NOTICE "/dev/vmnet: could not register major device %d\n", + VNET_MAJOR_NUMBER)); + goto err_chrdev; + } + + retval = register_ioctl32_handlers(); + if (retval) { + goto err_ioctl; + } + + return 0; + +err_ioctl: + unregister_chrdev(VNET_MAJOR_NUMBER, "vmnet"); +err_chrdev: + VNetProtoUnregister(); +err_proto: + VNetProc_Cleanup(); + return retval; +} + + +/* + *---------------------------------------------------------------------- + * + * cleanup_module -- + * + * Called by /sbin/rmmod. Unregisters this driver for a + * vnet major #, and deinitializes the modules. The 64-bit + * version of this driver also unregisters the handlers + * for 32-bit applications. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +cleanup_module(void) +{ + unregister_ioctl32_handlers(); + unregister_chrdev(VNET_MAJOR_NUMBER, "vmnet"); + VNetProtoUnregister(); + VNetProc_Cleanup(); +#ifdef CONFIG_NETFILTER + VNetFilter_Shutdown(); +#endif +} + + +/* + *---------------------------------------------------------------------- + * + * VNetIncrModCount -- + * + * Increment or decrement the module use count. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +VNetIncrModCount(int delta) // IN: delta (typically 1 or -1) +{ + if (delta > 0) { + compat_mod_inc_refcount; + } else if (delta < 0) { + compat_mod_dec_refcount; + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetFileOpOpen -- + * + * The virtual network's open file operation. Connects to (and + * potentially allocates) a hub, then opens a connection to + * this virtual network (i.e., plugs a cable into the virtual + * hub). + * + * Results: + * Errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetFileOpOpen(struct inode *inode, // IN: used to get hub number + struct file *filp) // IN: filp +{ + VNetPort *port; + VNetJack *hubJack; + int hubNum; + int retval; + + LOG(1, (KERN_DEBUG "/dev/vmnet: open called by PID %d (%s)\n", + current->pid, current->comm)); + + /* + * Sanity check the hub number. + */ + + hubNum = minor(inode->i_rdev); + if (hubNum < 0 || hubNum >= VNET_NUM_VNETS) { + return -ENODEV; + } + + /* + * Allocate port + */ + + retval = VNetUserIf_Create(&port); + if (retval) { + return -retval; + } + + /* + * Allocate and connect to hub. + */ + + hubJack = VNetHub_AllocVnet(hubNum); + if (!hubJack) { + VNetFree(&port->jack); + return -EBUSY; + } + + down(&vnetStructureSemaphore); + retval = VNetConnect(&port->jack, hubJack); + if (retval) { + up(&vnetStructureSemaphore); + VNetFree(&port->jack); + VNetFree(hubJack); + return retval; + } + + VNetAddPortToList(port); + up(&vnetStructureSemaphore); + + /* + * Store away jack in file pointer private field for later use. + */ + + filp->private_data = port; + + LOG(1, (KERN_DEBUG "/dev/vmnet: port on hub %d successfully opened\n", hubNum)); + + compat_mod_inc_refcount; + + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetFileOpClose -- + * + * The virtual network's close file operation. Disconnects + * from the virtual hub (i.e., unplugs the cable). + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +VNetFileOpClose(struct inode *inode, // IN: (unused) + struct file *filp) // IN: filp +{ + VNetPort *port = (VNetPort*)filp->private_data; + VNetJack *peer; + + if (!port) { + LOG(1, (KERN_DEBUG "/dev/vmnet: bad file pointer on close\n")); + return -EBADF; + } + + down(&vnetStructureSemaphore); + peer = VNetDisconnect(&port->jack); + VNetRemovePortFromList(port); + up(&vnetStructureSemaphore); + + VNetFree(&port->jack); + VNetFree(peer); + + compat_mod_dec_refcount; + + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetFileOpRead -- + * + * The virtual network's read file operation. + * + * Results: + * On success the len of the packet received, + * else if no packet waiting and nonblocking 0, + * else -errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +ssize_t +VNetFileOpRead(struct file *filp, // IN: + char *buf, // OUT: + size_t count, // IN: + loff_t *ppos) // IN: (unused) +{ + VNetPort *port = (VNetPort*)filp->private_data; + + if (!port) { + LOG(1, (KERN_DEBUG "/dev/vmnet: bad file pointer on read\n")); + return -EBADF; + } + + if (!port->fileOpRead) { + return -EPERM; + } + + return port->fileOpRead(port, filp, buf, count); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetFileOpWrite -- + * + * The virtual network's write file operation. + * + * Results: + * On success the count of bytes written else errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +ssize_t +VNetFileOpWrite(struct file *filp, // IN: + const char *buf, // IN: + size_t count, // IN: + loff_t *ppos) // IN: (unused) +{ + VNetPort *port = (VNetPort*)filp->private_data; + + if (!port) { + LOG(1, (KERN_DEBUG "/dev/vmnet: bad file pointer on write\n")); + return -EBADF; + } + + if (!port->fileOpWrite) { + return -EPERM; + } + + return port->fileOpWrite(port, filp, buf, count); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetFileOpPoll -- + * + * The virtual network's file select operation. + * + * Results: + * Return 1 if success, else sleep and return 0. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static unsigned int +VNetFileOpPoll(struct file *filp, // IN: + poll_table *wait) // IN: +{ + VNetPort *port = (VNetPort*)filp->private_data; + + if (!port) { + LOG(1, (KERN_DEBUG "/dev/vmnet: bad file pointer on poll\n")); + return -EBADF; + } + + if (!port->fileOpPoll) { + return -EPERM; + } + + return port->fileOpPoll(port, filp, wait); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetFileOpIoctl -- + * + * The virtual network's ioctl file operation. This is used for + * setup of the connection. Currently supported commands are + * (taken from sockios.h): + * + * SIOCGIFADDR - get ethernet address - ioarg OUT: 6 bytes + * SIOCSIFADDR - set ethernet address - ioarg IN: 6 bytes +#ifdef VNET_API_DEPRECATED + * SIOCGIFFLAGS - get flags - ioarg OUT 4 bytes +#endif + * SIOCSIFFLAGS - set flags - ioarg IN: 4 bytes + * + * Private ioctl calls, taken from device-private ioctl space + * in sockios.h, and defined in includes/vm_oui.h: + * + * SIOCSLADRF (0x89F2) - set logical address filter (for + * filtering multicast packets) - ioarg IN: 8 bytes + * + * SIOCGBRSTATUS - get bridging status - ioarg OUT: 4 bytes + * SIOCSPEER - set bridge peer interface - ioarg IN: 8 bytes + * SIOCSPEER2 - set bridge peer interface - ioarg IN: 32 bytes + * SIOCSBIND - bind to a particular vnet/PVN - ioarg IN: VNet_Bind + * SIOCSFILTERRULES - set host filter rules - ioarg IN: VNet_Filter + * SIOCBRIDGE - (legacy see SIOCSPEER) + * SIOCSUSERLISTENER - set user listener - ioarg IN: VNet_SetUserListener + * + * Supported flags are (taken from if.h): + * + * IFF_UP - ready to receive packets - OFF by default + * IFF_BROADCAST - receive broadcast packets - OFF by default + * IFF_DEBUG - turn on debugging - OFF by default + * IFF_PROMISC - promiscuous mode - OFF by default + * IFF_MULTICAST - receive multicast packets - OFF by default + * IFF_ALLMULTI - receive all multicast packets + * (like IFF_PROMISC but with multicast) - OFF by default + * + * Results: + * On success 0 else errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetFileOpIoctl(struct inode *inode, // IN: + struct file *filp, // IN: + unsigned int iocmd, // IN: + unsigned long ioarg) // IN: +{ + VNetPort *port = (VNetPort*)filp->private_data; + VNetJack *hubJack; + VNetPort *new; + char name[32]; + int retval; + VNet_SetMacAddrIOCTL macAddr; + VNet_Bind newNetwork; +#ifdef CONFIG_NETFILTER + VNet_RuleHeader ruleHeader; +#endif + + if (!port) { + LOG(1, (KERN_DEBUG "/dev/vmnet: bad file pointer on ioctl\n")); + return -EBADF; + } + + // sprintf(vnetHub[hubNum]->devName, "vmnet%d", hubNum); + + switch (iocmd) { +#ifdef VNET_API_DEPRECATED + case SIOCSIFBR: +#endif + case SIOCSPEER: + case SIOCBRIDGE: + if (copy_from_user(name, (void *)ioarg, 8)) { + return -EFAULT; + } + name[8] = '\0'; /* allow 8-char unterminated string */ + + if (!capable(CAP_NET_RAW)) { + return -EACCES; + } + retval = VNetBridge_Create(name, port->jack.peer, &new); + + return retval ? retval : VNetSwitchToDifferentPeer(&port->jack, + &new->jack, TRUE, + filp, port, new); + break; + case SIOCSPEER2: + if (copy_from_user(name, (void *)ioarg, sizeof name)) { + return -EFAULT; + } + NULL_TERMINATE_STRING(name); + + if (!capable(CAP_NET_RAW)) { + return -EACCES; + } + retval = VNetBridge_Create(name, port->jack.peer, &new); + + return retval ? retval : VNetSwitchToDifferentPeer(&port->jack, + &new->jack, TRUE, + filp, port, new); + break; + case SIOCSUSERLISTENER: + { + VNet_SetUserListener param; + + /* copy parameters */ + if (copy_from_user(¶m, (void *)ioarg, sizeof param)) { + return -EFAULT; + } + + /* check version */ + if (param.version != VNET_EVENT_VERSION) { + return -EINVAL; + } + + /* create user listener */ + retval = VNetUserListener_Create(param.classMask, port->jack.peer, &new); + if (retval != 0) { + return retval; + } + + /* replace current port with user listener */ + retval = VNetSwitchToDifferentPeer(&port->jack, &new->jack, TRUE, + filp, port, new); + } + break; + case SIOCPORT: + retval = VNetUserIf_Create(&new); + + return retval ? retval : VNetSwitchToDifferentPeer(&port->jack, &new->jack, + TRUE, filp, port, new); + break; + case SIOCNETIF: + if (copy_from_user(name, (void *)ioarg, 8)) { + return -EFAULT; + } + name[8] = '\0'; /* allow 8-char unterminated string */ + + retval = VNetNetIf_Create(name, &new, minor(inode->i_rdev)); + + return retval ? retval : VNetSwitchToDifferentPeer(&port->jack, &new->jack, + TRUE, filp, port, new); + break; + + case SIOCSBIND: + if (copy_from_user(&newNetwork, (void *)ioarg, sizeof newNetwork)) { + return -EFAULT; + } + if (newNetwork.version != VNET_BIND_VERSION) { + LOG(1, (KERN_NOTICE "/dev/vmnet: bad bind version: %u %u\n", + newNetwork.version, VNET_BIND_VERSION)); + return -EINVAL; + } + switch (newNetwork.bindType) { + case VNET_BIND_TO_VNET: + if (newNetwork.number < 0 || newNetwork.number >= VNET_NUM_VNETS) { + LOG(1, (KERN_NOTICE "/dev/vmnet: invalid bind to vnet %d\n", + newNetwork.number)); + return -EINVAL; + } + hubJack = VNetHub_AllocVnet(newNetwork.number); + break; + case VNET_BIND_TO_PVN: + { + uint8 id[VNET_PVN_ID_LEN] = {0}; + + if (memcmp(id, newNetwork.id, sizeof id < sizeof newNetwork.id ? + sizeof id : sizeof newNetwork.id) == 0) { + LOG(0, (KERN_NOTICE "/dev/vmnet: invalid bind to pvn\n")); + return -EINVAL; + } + memcpy(id, newNetwork.id, sizeof id < sizeof newNetwork.id ? + sizeof id : sizeof newNetwork.id); + hubJack = VNetHub_AllocPvn(id); + } + break; + default: + LOG(1, (KERN_NOTICE "/dev/vmnet: bad bind type: %u\n", + newNetwork.bindType)); + return -EINVAL; + } + + return VNetSwitchToDifferentPeer(&port->jack, hubJack, FALSE, NULL, NULL, NULL); + break; + + case SIOCSFILTERRULES: +#ifdef CONFIG_NETFILTER + if (copy_from_user(&ruleHeader, (void *)ioarg, sizeof ruleHeader)) { + return -EFAULT; + } + + /* Verify the call is for a known type */ + if (ruleHeader.type < VNET_FILTER_CMD_MIN || + ruleHeader.type > VNET_FILTER_CMD_MAX) { + LOG(1, (KERN_NOTICE "/dev/vmnet: invalid filter command\n")); + return -EINVAL; + } + + /* + * Version check should be done on a per-sub-command basis, but every + * sub-command is currently using 1, so for now we globally check for + * all sub-commands here in one place. + */ + if (ruleHeader.ver != 1) { + LOG(1, (KERN_NOTICE "/dev/vmnet: invalid version for " + "filter command\n")); + return -EINVAL; + } + + /* + * Dispatch the sub-command. + */ + return VNetFilter_HandleUserCall(&ruleHeader, ioarg); +#else + LOG(0, (KERN_NOTICE "/dev/vmnet: kernel doesn't support netfilter\n")); + return -EINVAL; + break; +#endif + +#ifdef VNET_API_DEPRECATED + case SIOCGIFBR: +#endif + case SIOCGBRSTATUS: + { + uint32 flags; + + read_lock(&vnetPeerLock); + flags = VNetIsBridged(&port->jack); + read_unlock(&vnetPeerLock); + + if (copy_to_user((void *)ioarg, &flags, sizeof flags)) { + return -EFAULT; + } + } + break; + + case SIOCGIFADDR: + if (copy_to_user((void *)ioarg, port->paddr, ETH_ALEN)) { + return -EFAULT; + } + break; + + case SIOCSIFADDR: + return -EFAULT; + + case SIOCSLADRF: + if (copy_from_user(port->ladrf, (void *)ioarg, sizeof port->ladrf)) { + return -EFAULT; + } + break; + +#ifdef VNET_API_DEPRECATED + /* We can't think of a good reason to use this ioctl. --gustav,hpreg */ + case SIOCGIFFLAGS: + if (copy_to_user((void *)ioarg, &port->flags, sizeof port->flags)) { + return -EFAULT; + } + break; + +#endif + case SIOCSIFFLAGS: + if (copy_from_user(&port->flags, (void *)ioarg, sizeof port->flags)) { + return -EFAULT; + } + port->flags = ((port->flags + & (IFF_UP|IFF_BROADCAST|IFF_DEBUG + |IFF_PROMISC|IFF_MULTICAST|IFF_ALLMULTI)) + | IFF_RUNNING); + if (port->fileOpIoctl) { + + /* + * Userif ports have some postprocessing when the IFF_UP flags is + * changed. + */ + port->fileOpIoctl(port, filp, iocmd, ioarg); + } + break; + + case SIOCSETMACADDR: + if (copy_from_user(&macAddr, (void *)ioarg, sizeof macAddr)) { + return -EFAULT; + } + + switch (macAddr.version) { + case 1: + if (macAddr.flags & VNET_SETMACADDRF_UNIQUE) { + if (VMX86_IS_VIRT_ADAPTER_MAC(macAddr.addr)) { + return -EBUSY; + } + return VNetSetMACUnique(port, macAddr.addr); + } + memcpy(port->paddr, macAddr.addr, ETH_ALEN); + break; + default: + return -EINVAL; + break; + } + break; + case SIOCGETAPIVERSION2: + { + uint32 verFromUser; + if (copy_from_user(&verFromUser, (void *)ioarg, sizeof verFromUser)) { + return -EFAULT; + } + /* Should we require verFromUser == VNET_API_VERSION? */ + } + /* fall thru */ + case SIOCGETAPIVERSION: + { + uint32 verToUser = VNET_API_VERSION; + if (copy_to_user((void*)ioarg, &verToUser, sizeof verToUser)) { + return -EFAULT; + } + } + break; + default: + if (!port->fileOpIoctl) { + return -ENOIOCTLCMD; + } + return port->fileOpIoctl(port, filp, iocmd, ioarg); + break; + } + + return 0; +} + + +#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL) +/* + *---------------------------------------------------------------------- + * + * VNetFileOpUnlockedIoctl -- + * + * Wrapper around VNetFileOpIoctl. See VNetFileOpIoctl for + * supported arguments. Called without big kernel lock held. + * + * Results: + * On success 0 else errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static long +VNetFileOpUnlockedIoctl(struct file *filp, // IN: + unsigned int iocmd, // IN: + unsigned long ioarg) // IN: +{ + struct inode *inode = NULL; + long err; + + if (filp && filp->f_dentry) { + inode = filp->f_dentry->d_inode; + } + lock_kernel(); + err = VNetFileOpIoctl(inode, filp, iocmd, ioarg); + unlock_kernel(); + return err; +} +#endif + + +/* + *---------------------------------------------------------------------- + * + * VNetSwitchToDifferentPeer -- + * + * This function is used to disconnect from a one peer and + * connect to another peer. If the connect to the new peer + * fails (e.g., if the connect would create a cycle), then + * the function will reconnect back to the original peer. + * The function will deallocate the old or the new peer, + * whichever is the one that has been disconnected. + * + * optional behavior: + * + * For the case where the function was successful in switching + * to the new peer, the caller can optionally provide a 'filp' + * (private_data is set to the new port), and the caller + * can also provide one each of a port to be added to + * and/or removed from the port list. If the caller provides + * ports to add/remove from the list, then + * connectNewToPeerOfJack should be set to TRUE (otherwise + * inconsistencies in the port list are likely to occur). + * + * Results: + * errno (0 on success). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +VNetSwitchToDifferentPeer(VNetJack *jack, // IN: jack whose peer is to be changed + VNetJack *newPeer, // IN: the new peer to try to switch to + Bool connectNewToPeerOfJack, // IN: connect new to peer of 'jack' or to 'jack' itself? + struct file *filp, // IN: (optional) set filp to 'newpeerPort' on success + VNetPort *jackPort, // IN: (optional) port to remove from list on success + VNetPort *newPeerPort) // IN: (optional) port to add to list on success +{ + VNetJack *oldPeer; + int retval; + + if (newPeer == NULL) { + LOG(0, (KERN_NOTICE "/dev/vmnet: failed to alloc new peer\n")); + return -EINVAL; + } + + /* + * OK this is tricky. Try and connect the new peer while saving + * enough information so that we can reconnect back to the + * old peer if a cycle is detected. + */ + + down(&vnetStructureSemaphore); + + /* Disconnect from the old peer */ + oldPeer = VNetDisconnect(jack); + + /* Try to connect to the new peer */ + if (connectNewToPeerOfJack) { + retval = VNetConnect(oldPeer, newPeer); + } else { + retval = VNetConnect(jack, newPeer); + } + if (retval) { + + /* Connect failed, so reconnect back to old peer */ + int retval2 = VNetConnect(jack, oldPeer); + up(&vnetStructureSemaphore); + + /* Free the new peer */ + VNetFree(newPeer); + if (retval2) { + // assert xxx redo this + LOG(1, (KERN_NOTICE "/dev/vmnet: cycle on connect failure\n")); + return -EBADF; + } + return retval; + } + + if (newPeerPort != NULL) { + VNetAddPortToList(newPeerPort); + } + if (filp != NULL) { + filp->private_data = newPeerPort; + } + if (jackPort != NULL) { + VNetRemovePortFromList(jackPort); + } + + up(&vnetStructureSemaphore); + + /* Connected to new peer, so dealloc the old peer */ + if (connectNewToPeerOfJack) { + VNetFree(jack); + } else { + VNetFree(oldPeer); + } + + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetMulticastFilter -- + * + * Utility function that filters multicast packets according + * to a 64-bit logical address filter (like the one on the + * lance chipset). AllMultiFilter lets all packets through. + * + * We generate a hash value from the destination MAC address + * and see if it's in our filter. Broadcast packets have + * already OK'd by PacketMatch, so we don't have to worry + * about that. + * + * (This is in the green AMD "Ethernet Controllers" book, + * page 1-53.) + * + * Results: + * TRUE if packet is in filter, FALSE if not. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ + +static INLINE_SINGLE_CALLER Bool +VNetMulticastFilter(const uint8 *destAddr, // IN: multicast MAC + const uint8 *ladrf) // IN: multicast filter +{ + uint16 hashcode; + int32 crc; + int32 poly = CRC_POLYNOMIAL_BE; + int j; + int bit; + int byte; + + crc = 0xffffffff; /* init CRC for each address */ + for (byte = 0; byte < ETH_ALEN; byte++) { /* for each address byte */ + /* process each address bit */ + for (bit = *destAddr++, j = 0; + j < VNET_LADRF_LEN; + j++, bit >>= 1) { + crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0); + } + } + hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */ + for (j = 0; j < 5; j++) { /* ... in reverse order. */ + hashcode = (hashcode << 1) | ((crc>>=1) & 1); + } + + byte = hashcode >> 3; /* bit[3-5] -> byte in filter */ + bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ + if (ladrf[byte] & bit) { + return TRUE; + } else { + return FALSE; + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetPacketMatch -- + * + * Determines whether the packet should be given to the interface. + * + * Results: + * TRUE if the pasket is OK for this interface, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Bool +VNetPacketMatch(const uint8 *destAddr, // IN: destination MAC + const uint8 *ifAddr, // IN: MAC of interface + const uint8 *ladrf, // IN: multicast filter + uint32 flags) // IN: filter flags +{ + /* + * Return TRUE if promiscuous requested, or unicast destined + * for interface, or broadcast (and broadcast requested), or + * if multicast (and all multicast, or this specific + * multicast MAC, was requested). + */ + + return ((flags & IFF_PROMISC) || MAC_EQ(destAddr, ifAddr) || + ((flags & IFF_BROADCAST) && MAC_EQ(destAddr, broadcast)) || + ((destAddr[0] & 0x1) && (flags & IFF_ALLMULTI || + (flags & IFF_MULTICAST && + VNetMulticastFilter(destAddr, ladrf))))); +} + + +/* + *---------------------------------------------------------------------- + * + * VNet_MakeMACAddress -- + * + * Generate a unique MAC address and assign it to the given port. + * The address will be in the range: + * + * VMX86_STATIC_OUI:e0:00:00 - VMX86_STATIC_OUI:ff:ff:ff + * + * Results: + * errno. + * + * Side effects: + * The address is changed. + * + *---------------------------------------------------------------------- + */ + +int +VNet_MakeMACAddress(VNetPort *port) // IN: port +{ + uint8 paddr[ETH_ALEN] = {0}; + int conflict; + int maxTries = 1000; + + do { + VMX86_GENERATE_RANDOM_MAC(paddr); + + conflict = VNetSetMACUnique(port, paddr); + + /* + * We don't have to check for conflicts with the virtual + * host adapters since they are in the range + * c0:00:00-c0:00:FF. + */ + + } while (maxTries-- > 0 && conflict); + + return conflict; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetConnect -- + * + * Connect 2 jacks. + * vnetStructureSemaphore must be held. + * + * Results: + * errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetConnect(VNetJack *jack1, // IN: jack + VNetJack *jack2) // IN: jack +{ + static int vnetGeneration = 0; + Bool foundCycle; + unsigned long flags; + + vnetGeneration++; + + foundCycle = VNetCycleDetect(jack1, vnetGeneration); + if (foundCycle) { + VNetFreeInterfaceList(); + return -EDEADLK; + } + + foundCycle = VNetCycleDetect(jack2, vnetGeneration); + if (foundCycle) { + VNetFreeInterfaceList(); + return -EDEADLK; + } + VNetFreeInterfaceList(); + + /* + * Synchronize with peer readers + */ + + write_lock_irqsave(&vnetPeerLock, flags); + jack1->peer = jack2; + jack2->peer = jack1; + write_unlock_irqrestore(&vnetPeerLock, flags); + + if (jack2->numPorts) { + VNetPortsChanged(jack1); + } + + if (jack1->numPorts) { + VNetPortsChanged(jack2); + } + + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetDisconnect -- + * + * Disconnect 2 jacks. + * vnetStructureSemaphore must be held. + * + * Results: + * Return the peer jack (returns NULL on error, or if no peer) + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +VNetJack * +VNetDisconnect(VNetJack *jack) // IN: jack +{ + VNetJack *peer; + unsigned long flags; + + write_lock_irqsave(&vnetPeerLock, flags); + peer = jack->peer; + if (!peer) { + write_unlock_irqrestore(&vnetPeerLock, flags); + return NULL; + } + jack->peer = NULL; + peer->peer = NULL; + write_unlock_irqrestore(&vnetPeerLock, flags); + + if (peer->numPorts) { + VNetPortsChanged(jack); + } + + if (jack->numPorts) { + VNetPortsChanged(peer); + } + + return peer; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetCycleDetectIf -- + * + * Perform the cycle detect alogorithm for this generation on a + * specific interface. This could be a bridged interface, host + * interface or both. + * vnetStructureSemaphore must be held. + * + * Results: + * TRUE if a cycle was detected, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Bool +VNetCycleDetectIf(const char *name, // IN: + int generation) // IN: +{ + VNetInterface *p; + + for (p = vnetInterfaces; p != NULL; p = p->next) { + if (!strcmp(name, p->name)) { + if (p->myGeneration == generation) { + return TRUE; + } else { + p->myGeneration = generation; + return FALSE; + } + } + } + + p = kmalloc(sizeof *p, GFP_USER); + if (!p) { + // assert + return TRUE; + } + + memcpy(p->name, name, sizeof p->name); + NULL_TERMINATE_STRING(p->name); + p->myGeneration = generation; + p->next = vnetInterfaces; + vnetInterfaces = p; + + return FALSE; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetFreeInterfaceList -- + * + * Free's the linked list that may have been constructed + * during a recent run on the cycle detect alogorithm. + * vnetStructureSemaphore must be held. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +VNetFreeInterfaceList() +{ + while (vnetInterfaces != NULL) { + VNetInterface *next = vnetInterfaces->next; + kfree(vnetInterfaces); + vnetInterfaces = next; + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetSend -- + * + * Send a packet through this jack. Note, the packet goes to the + * jacks peer. + * + * Results: + * None. + * + * Side effects: + * The skb is no longer owned by us. + * + *---------------------------------------------------------------------- + */ + +void +VNetSend(const VNetJack *jack, // IN: jack + struct sk_buff *skb) // IN: packet +{ + read_lock(&vnetPeerLock); + if (jack && jack->peer && jack->peer->rcv) { + jack->peer->rcv(jack->peer, skb); + } else { + dev_kfree_skb(skb); + } + read_unlock(&vnetPeerLock); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetSetMACUnique -- + * + * Verify that MAC address is not used by other ports. + * Function grabs semaphore, so caller shouldn't hold any + * locks. + * + * Results: + * + * 0 if address is unique. Port's paddr is updated. + * -EBUSY if address is already in use. Port's paddr is unchanged. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetSetMACUnique(VNetPort *port, // IN: + const uint8 mac[ETH_ALEN]) // IN: +{ + VNetPort *p; + + down(&vnetStructureSemaphore); + for (p = vnetAllPorts; p != NULL; p = p->next) { + if (p != port && MAC_EQ(p->paddr, mac)) { + up(&vnetStructureSemaphore); + return -EBUSY; + } + } + memcpy(port->paddr, mac, ETH_ALEN); + up(&vnetStructureSemaphore); + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetPrintJack -- + * + * Print info about the jack to a buffer. + * + * Results: + * Length of the write. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetPrintJack(const VNetJack *jack, // IN: jack + char *buf) // OUT: info about jack +{ + int len = 0; + + read_lock(&vnetPeerLock); + if (!jack->peer) { + len += sprintf(buf+len, "connected not "); + } else { + len += sprintf(buf+len, "connected %s ", jack->peer->name); + } + read_unlock(&vnetPeerLock); + + return len; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetPrintPort -- + * + * Print info about the port to a buffer. + * + * Results: + * Length of the write. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetPrintPort(const VNetPort *port, // IN: port + char *buf) // OUT: info about port +{ + int len = 0; + + len += VNetPrintJack(&port->jack, buf+len); + + len += sprintf(buf+len, "mac %02x:%02x:%02x:%02x:%02x:%02x ", + port->paddr[0], port->paddr[1], port->paddr[2], + port->paddr[3], port->paddr[4], port->paddr[5]); + + len += sprintf(buf+len, "ladrf %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ", + port->ladrf[0], port->ladrf[1], port->ladrf[2], + port->ladrf[3], port->ladrf[4], port->ladrf[5], + port->ladrf[6], port->ladrf[7]); + + len += sprintf(buf+len, "flags IFF_RUNNING"); + + if (port->flags & IFF_UP) { + len += sprintf(buf+len, ",IFF_UP"); + } + + if (port->flags & IFF_BROADCAST) { + len += sprintf(buf+len, ",IFF_BROADCAST"); + } + + if (port->flags & IFF_DEBUG) { + len += sprintf(buf+len, ",IFF_DEBUG"); + } + + if (port->flags & IFF_PROMISC) { + len += sprintf(buf+len, ",IFF_PROMISC"); + } + + if (port->flags & IFF_MULTICAST) { + len += sprintf(buf+len, ",IFF_MULTICAST"); + } + + if (port->flags & IFF_ALLMULTI) { + len += sprintf(buf+len, ",IFF_ALLMULTI"); + } + + len += sprintf(buf+len, " "); + + return len; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetSnprintf -- + * + * Wrapper to account for lack of snprintf() in older kernels, + * where 'old' appears to be older than 2.4.8. + * + * Results: + * Refer to docs for snprintf() and / or sprintf(). This + * version unconditionally adds NULL termination to the end + * of the string. + * + * Side effects: + * Might overrun buffer on older kernels. + * + *---------------------------------------------------------------------- + */ + +int +VNetSnprintf(char *str, // OUT: resulting string + size_t size, // IN: length of 'result' in bytes + const char *format, // IN: format string + ...) // IN: (optional) +{ + int length; + va_list args; + + va_start(args, format); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) + length = vsnprintf(str, size, format, args); +#else + length = vsprintf(str, format, args); +#endif + + va_end(args); + + str[size - 1] = '\0'; + + return length; +} + + +MODULE_AUTHOR("VMware, Inc."); +MODULE_DESCRIPTION("VMware Virtual Networking Driver."); +MODULE_LICENSE("GPL v2"); diff -Nrup source/vmnet-only/linux/epoll.c source.edited/vmnet-only/linux/epoll.c --- source/vmnet-only/linux/epoll.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/epoll.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,36 @@ +/********************************************************* + * Copyright (C) 2004 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 + * + *********************************************************/ + +/* + * Detect whether we have 'struct poll_wqueues' + * 2.6.x kernels always had this struct. Stock 2.4.x kernels + * never had it, but some distros backported epoll patch. + */ + +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +#include + +void poll_test(void) { + struct poll_wqueues test; + + return poll_initwait(&test); +} +#endif diff -Nrup source/vmnet-only/linux/filter.c source.edited/vmnet-only/linux/filter.c --- source/vmnet-only/linux/filter.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/filter.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,1540 @@ +/********************************************************* + * 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 +#include +#include +#include +#include +#include +#include "compat_skbuff.h" +#include +/* + * All this makes sense only if NETFILTER support is configured in our kernel. + */ +#ifdef CONFIG_NETFILTER + +#include +#include +#include + +#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, + compat_nf_hook_owner + .pf = PF_INET, + .hooknum = VMW_NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_FILTER - 1, }, + { .hook = VNetFilterHookFn, + compat_nf_hook_owner + .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 DECLARE_MUTEX(filterIoctlSem); /* 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. + */ +spinlock_t activeRuleLock = SPIN_LOCK_UNLOCKED; + +/* + * 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 +VNetFilterHookFn(unsigned int hooknum, // IN: +#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. */ + transmit = (hooknum == VMW_NF_INET_POST_ROUTING); + + 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 = down_interruptible(&filterIoctlSem); + 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: + up(&filterIoctlSem); + 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 diff -Nrup source/vmnet-only/linux/geninclude.c source.edited/vmnet-only/linux/geninclude.c --- source/vmnet-only/linux/geninclude.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/geninclude.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,40 @@ +/********************************************************* + * Copyright (C) 2003 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 + +#ifdef CONFIG_X86_VOYAGER +APATH/mach-voyager +#endif +#ifdef CONFIG_X86_VISWS +APATH/mach-visws +#endif +#ifdef CONFIG_X86_NUMAQ +APATH/mach-numaq +#endif +#ifdef CONFIG_X86_BIGSMP +APATH/mach-bigsmp +#endif +#ifdef CONFIG_X86_SUMMIT +APATH/mach-summit +#endif +#ifdef CONFIG_X86_GENERICARCH +APATH/mach-generic +#endif +APATH/mach-default + diff -Nrup source/vmnet-only/linux/hub.c source.edited/vmnet-only/linux/hub.c --- source/vmnet-only/linux/hub.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/hub.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,741 @@ +/********************************************************* + * Copyright (C) 1998 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" + +#define EXPORT_SYMTAB + +#include +#include +#include +#ifdef KERNEL_2_2 +# include +#else +# include +#endif +#include + +#include +#include +#include +#include "compat_skbuff.h" +#include +#include +#include "compat_sock.h" + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include + +#include "vnetInt.h" + +#define HUB_TYPE_VNET 0x1 +#define HUB_TYPE_PVN 0x2 + +typedef struct VNetHubStats { + unsigned tx; +} VNetHubStats; + +typedef struct VNetHub { + uint32 hubType; // HUB_TYPE_xxx + union { + int vnetNum; // vnet number (HUB_TYPE_VNET) + uint8 pvnID[VNET_PVN_ID_LEN]; // PVN ID (HUB_TYPE_PVN) + } id; + Bool used[NUM_JACKS_PER_HUB]; // tracks which jacks in use + VNetJack jack[NUM_JACKS_PER_HUB]; // jacks for the hub + VNetHubStats stats[NUM_JACKS_PER_HUB]; // stats for the jacks + int totalPorts; // num devices reachable from hub + int myGeneration; // used for cycle detection + struct VNetHub *next; // next hub in linked list + VNetEvent_Mechanism *eventMechanism; // event notification mechanism +} VNetHub; + +static VNetJack *VNetHubAlloc(Bool allocPvn, int hubNum, + uint8 id[VNET_PVN_ID_LEN]); +static void VNetHubFree(VNetJack *this); +static void VNetHubReceive(VNetJack *this, struct sk_buff *skb); +static Bool VNetHubCycleDetect(VNetJack *this, int generation); +static void VNetHubPortsChanged(VNetJack *this); +static int VNetHubIsBridged(VNetJack *this); +static int VNetHubProcRead(char *page, char **start, off_t off, + int count, int *eof, void *data); + +static VNetHub *vnetHub = NULL; + +/* + * UP spin_lock_irqsave() doesn't actually use the lock variable, + * so we use __attribute__((unused)) to quiet the compiler. + */ + +static spinlock_t vnetHubLock __attribute__((unused)) = SPIN_LOCK_UNLOCKED; + + +/* + *---------------------------------------------------------------------- + * + * VNetHubFindHubByNum -- + * + * Find a hub for a specified vnet number. + * Caller must be holding vnetHubLock. + * + * Results: + * Pointer to hub, or NULL if not found. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static VNetHub * +VNetHubFindHubByNum(int hubNum) // IN: vnet number to find +{ + VNetHub *currHub = vnetHub; + while (currHub && (currHub->hubType != HUB_TYPE_VNET || + currHub->id.vnetNum != hubNum)) { + currHub = currHub->next; + } + return currHub; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetHubFindHubByID -- + * + * Find a hub for a specified PVN id. + * Caller must be holding vnetHubLock. + * + * Results: + * Pointer to hub, or NULL if not found. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static VNetHub * +VNetHubFindHubByID(uint8 idNum[VNET_PVN_ID_LEN]) // IN: PVN id to find +{ + VNetHub *currHub = vnetHub; + while (currHub && (currHub->hubType != HUB_TYPE_PVN || + memcmp(idNum, currHub->id.pvnID, sizeof idNum))) { + currHub = currHub->next; + } + return currHub; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetHubAddHubToList -- + * + * Add hub to list of known hubs. + * Caller must be holding vnetHubLock. + * + * Results: + * + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE void +VNetHubAddHubToList(VNetHub *hub) // IN: hub to add to list +{ + hub->next = vnetHub; + vnetHub = hub; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetHubRemoveHubFromList -- + * + * Remove hub from list of known hubs. + * Caller must be holding vnetHubLock. + * + * Results: + * + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE void +VNetHubRemoveHubFromList(VNetHub *hub) // IN: hub to remove from list +{ + VNetHub **h; + + for (h = &vnetHub; *h; h = &(*h)->next) { + if (*h == hub) { + *h = hub->next; + break; + } + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetHub_AllocVnet -- + * + * Allocate a jack on a hub for a vnet. + * + * Results: + * The jack to connect to, NULL on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +VNetJack * +VNetHub_AllocVnet(int hubNum) // IN: the vnet number to alloc on +{ + return VNetHubAlloc(FALSE, hubNum, NULL); +} + +/* + *---------------------------------------------------------------------- + * + * VNetHub_AllocPvn -- + * + * Allocate a jack on a hub for a PVN. + * + * Results: + * The jack to connect to, NULL on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +VNetJack * +VNetHub_AllocPvn(uint8 id[]) // IN: the PVN ID to alloc on +{ + return VNetHubAlloc(TRUE, -1, id); +} + +/* + *---------------------------------------------------------------------- + * + * VNetHubAlloc -- + * + * Allocate a jack on this hub. + * + * Results: + * The jack to connect to, NULL on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +VNetJack * +VNetHubAlloc(Bool allocPvn, // IN: TRUE for PVN, FALSE for vnet + int hubNum, // IN: vnet # to use (-1 if allocPvn == TRUE) + uint8 id[]) // IN: PVN ID to use (NULL if allocPvn == FALSE) +{ + VNetHub *hub; + VNetJack *jack; + int i; + int retval; + unsigned long flags; + static uint32 pvnInstance = 0; + + spin_lock_irqsave(&vnetHubLock, flags); + + hub = allocPvn ? VNetHubFindHubByID(id) : VNetHubFindHubByNum(hubNum); + if (!hub) { + spin_unlock_irqrestore(&vnetHubLock, flags); + LOG(1, (KERN_DEBUG "/dev/vmnet: hub %d does not exist, allocating memory.\n", + hubNum)); + + hub = kmalloc(sizeof *hub, GFP_KERNEL); + if (hub == NULL) { + LOG(1, (KERN_DEBUG "/dev/vmnet: no memory to allocate hub %d\n", hubNum)); + return NULL; + } + for (i = 0; i < NUM_JACKS_PER_HUB; i++) { + jack = &hub->jack[i]; + + /* + * The private field indicates if this jack is allocated. + * NULL means free, otherwise the jack is allocated and it + * should point back to the hub. + */ + + jack->peer = NULL; + jack->numPorts = 0; + if (allocPvn) { + VNetSnprintf(jack->name, sizeof jack->name, "pvn%d.%d", + pvnInstance, i); + } else { + VNetSnprintf(jack->name, sizeof jack->name, "hub%d.%d", hubNum, i); + } + jack->private = NULL; + jack->index = i; + jack->procEntry = NULL; + jack->free = VNetHubFree; + jack->rcv = VNetHubReceive; + jack->cycleDetect = VNetHubCycleDetect; + jack->portsChanged = VNetHubPortsChanged; + jack->isBridged = VNetHubIsBridged; + + memset(&hub->stats[i], 0, sizeof hub->stats[i]); + + hub->used[i] = FALSE; + } + + if (allocPvn) { + hub->hubType = HUB_TYPE_PVN; + memcpy(hub->id.pvnID, id, sizeof id); + ++pvnInstance; + } else { + hub->hubType = HUB_TYPE_VNET; + hub->id.vnetNum = hubNum; + } + hub->next = NULL; + hub->totalPorts = 0; + hub->myGeneration = 0; + + /* create event mechanism */ + retval = VNetEvent_CreateMechanism(&hub->eventMechanism); + if (retval != 0) { + LOG(1, (KERN_DEBUG "can't create event mechanism (%d)\n", retval)); + kfree(hub); + return NULL; + } + + spin_lock_irqsave(&vnetHubLock, flags); + if (allocPvn ? VNetHubFindHubByID(id) : VNetHubFindHubByNum(hubNum)) { + /* + * Someone else just allocated this hub. Free our structure + * and use already present hub. + */ + + kfree(hub); + hub = allocPvn ? VNetHubFindHubByID(id) : VNetHubFindHubByNum(hubNum); + } else { + VNetHubAddHubToList(hub); + } + } + + for (i = 0; i < NUM_JACKS_PER_HUB; i++) { + jack = &hub->jack[i]; + if (!hub->used[i]) { + hub->used[i] = TRUE; + spin_unlock_irqrestore(&vnetHubLock, flags); + + /* + * Make proc entry for this jack. + */ + + retval = VNetProc_MakeEntry(jack->name, S_IFREG, &jack->procEntry); + if (retval) { + if (retval == -ENXIO) { + jack->procEntry = NULL; + } else { + hub->used[i] = FALSE; + return NULL; + } + } else { + jack->procEntry->read_proc = VNetHubProcRead; + jack->procEntry->data = jack; + } + + /* + * OK, now allocate this jack. + */ + + jack->numPorts = hub->totalPorts; + jack->peer = NULL; + jack->private = hub; + + return jack; + } + } + spin_unlock_irqrestore(&vnetHubLock, flags); + + return NULL; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetHubFree -- + * + * Free the jack on this hub. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +VNetHubFree(VNetJack *this) +{ + VNetHub *hub = (VNetHub*)this->private; + int i = 0; + int retval; + unsigned long flags; + + if (this != &hub->jack[this->index]) { + LOG(1, (KERN_DEBUG "/dev/vmnet: bad free of hub jack\n")); + return; + } + + if (this->procEntry) { + VNetProc_RemoveEntry(this->procEntry); + this->procEntry = NULL; + } + + this->private = NULL; + + spin_lock_irqsave(&vnetHubLock, flags); + + hub->used[this->index] = FALSE; + + for (i = 0; i < NUM_JACKS_PER_HUB; i++) { + if (hub->used[i]) { + spin_unlock_irqrestore(&vnetHubLock, flags); + return; + } + } + VNetHubRemoveHubFromList(hub); + + spin_unlock_irqrestore(&vnetHubLock, flags); + + /* destroy event mechanism */ + retval = VNetEvent_DestroyMechanism(hub->eventMechanism); + if (retval != 0) { + LOG(1, (KERN_DEBUG "can't destroy event mechanism (%d)\n", retval)); + } + hub->eventMechanism = NULL; + + kfree(hub); +} + + +/* + *----------------------------------------------------------------------------- + * + * VNetHub_CreateSender -- + * + * Creates an event sender for the mechanism of this hub. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VNetHub_CreateSender(VNetJack *jack, // IN: a jack to a hub + VNetEvent_Sender **s) // OUT: the new sender +{ + if (jack != NULL && jack->private != NULL) { + VNetHub *hub = (VNetHub*)jack->private; + return VNetEvent_CreateSender(hub->eventMechanism, s); + } else { + return -EINVAL; + } +} + + +/* + *----------------------------------------------------------------------------- + * + * VNetHub_CreateListener -- + * + * Creates an event listener for the mechanism of this hub. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VNetHub_CreateListener(VNetJack *jack, // IN: a jack to a hub + VNetEvent_Handler h, // IN: a handler + void *data, // IN: the handler's data + uint32 classMask, // IN: a class mask + VNetEvent_Listener **l) // OUT: the new listener +{ + if (jack != NULL && jack->private != NULL) { + VNetHub *hub = (VNetHub*)jack->private; + return VNetEvent_CreateListener(hub->eventMechanism, h, data, classMask, + l); + } else { + return -EINVAL; + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetHubReceive -- + * + * This jack is receiving a packet. Take appropriate action. + * + * Results: + * None. + * + * Side effects: + * Frees skb. + * + *---------------------------------------------------------------------- + */ + +void +VNetHubReceive(VNetJack *this, // IN: + struct sk_buff *skb) // IN: +{ + VNetHub *hub = (VNetHub*)this->private; + VNetJack *jack; + struct sk_buff *clone; + int i; + + hub->stats[this->index].tx++; + + for (i = 0; i < NUM_JACKS_PER_HUB; i++) { + jack = &hub->jack[i]; + if (jack->private && /* allocated */ + jack->peer && /* and connected */ + jack->peer->rcv && /* and has a receiver */ + (jack != this)) { /* and not a loop */ + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) { + VNetSend(jack, clone); + } + } + } + + dev_kfree_skb(skb); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetHubCycleDetect -- + * + * Cycle detection algorithm. + * + * Results: + * TRUE if a cycle was detected, FALSE otherwise. + * + * Side effects: + * Will generate other cycleDetect events to other jacks on hub. + * + *---------------------------------------------------------------------- + */ + +Bool +VNetHubCycleDetect(VNetJack *this, + int generation) +{ + VNetHub *hub = (VNetHub *)this->private; + Bool foundCycle; + int i; + + if (hub->myGeneration == generation) { + return TRUE; + } + + hub->myGeneration = generation; + + for (i = 0; i < NUM_JACKS_PER_HUB; i++) { + if (hub->jack[i].private && (i != this->index)) { + foundCycle = VNetCycleDetect(hub->jack[i].peer, generation); + if (foundCycle) { + return TRUE; + } + } + } + + return FALSE; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetHubPortsChanged -- + * + * The number of ports connected to this jack has change, react + * accordingly. + * This function presumes that the caller has the semaphore. + * + * Results: + * None. + * + * Side effects: + * May generate other portsChanged events to other jacks on hub. + * + *---------------------------------------------------------------------- + */ + +void +VNetHubPortsChanged(VNetJack *this) +{ + VNetHub *hub = (VNetHub *)this->private; + int num, new; + int i; + + hub->totalPorts = 0; + + for (i=0; ijack[i].private) { + hub->totalPorts += VNetGetAttachedPorts(&hub->jack[i]); + } + } + + for (i=0; ijack[i].private) { + num = VNetGetAttachedPorts(&hub->jack[i]); + new = hub->totalPorts - num; + if (i == this->index) { + if (new != hub->jack[i].numPorts) { + /* basically an assert failure */ + LOG(0, (KERN_DEBUG "/dev/vmnet: numPorts mismatch.\n")); + } + } else { + hub->jack[i].numPorts = new; + VNetPortsChanged(hub->jack[i].peer); + } + } + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetHubIsBridged -- + * + * Check whether we are bridged. + * + * Results: + * 0 - not bridged + * 1 - we are bridged but the interface is not up + * 2 - we are bridged and the interface is up + * 3 - some bridges are down + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetHubIsBridged(VNetJack *this) +{ + VNetHub *hub = (VNetHub*)this->private; + int ret = 0; + int num; + int i; + + for (i=0; ijack[i].private) && (i != this->index)) { + num = VNetIsBridged(&hub->jack[i]); + ret = MAX(ret, num); + if ((num == 1) && (ret == 2)) { + ret = 3; + } + } + } + + return ret; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetHubProcRead -- + * + * Callback for read operation on hub entry in vnets proc fs. + * + * Results: + * Length of read operation. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetHubProcRead(char *page, // IN/OUT: buffer to write into + char **start, // OUT: 0 if file < 4k, else offset into page + off_t off, // IN: offset of read into the file + int count, // IN: maximum number of bytes to read + int *eof, // OUT: TRUE if there is nothing more to read + void *data) // IN: client data - not used +{ + VNetJack *jack = (VNetJack*)data; + VNetHub *hub; + int len = 0; + + if (!jack || !jack->private) { + return len; + } + hub = (VNetHub*)jack->private; + + len += VNetPrintJack(jack, page+len); + + len += sprintf(page+len, "tx %u ", hub->stats[jack->index].tx); + + len += sprintf(page+len, "\n"); + + *start = 0; + *eof = 1; + return len; +} diff -Nrup source/vmnet-only/linux/netdev_has_dev_net.c source.edited/vmnet-only/linux/netdev_has_dev_net.c --- source/vmnet-only/linux/netdev_has_dev_net.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/netdev_has_dev_net.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,37 @@ +/********************************************************* + * Copyright (C) 2008 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 + * + *********************************************************/ + +/* + * Detect whether there is dev_net accessor for dev->nd_net. + * It appeared between 2.6.25 and 2.6.26-rc1. + */ + +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) +# error This compile test intentionally fails. +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) +# include + +struct net * +vmware_dev_net(struct net_device *dev) +{ + return dev_net(dev); +} +#endif diff -Nrup source/vmnet-only/linux/netdev_has_net.c source.edited/vmnet-only/linux/netdev_has_net.c --- source/vmnet-only/linux/netdev_has_net.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/netdev_has_net.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,43 @@ +/********************************************************* + * Copyright (C) 2007 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 + * + *********************************************************/ + +/* + * Detect whether there is separate net namespace. It got introduced after + * 2.6.23. If this builds, there are two arguments to __dev_get_by_name... + * For lower boundary use 2.6.23 - hopefully nobody crossports patch to + * older kernels. Note that this also affects sk_alloc interface - + * for that there are two versions: sk_alloc(net, family, gfp, proto, 1) for + * kernels 2.6.23 < x <= 2.6.24-rc1, and 4 argument version + * sk_alloc(net, family, gfp, proto) for 2.6.24-rc1 < x. We do ignore 2.6.24-rc1 + * as hopefully in few weeks all 2.6.24-rc1 users will be gone. + */ + +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) +# error This compile test intentionally fails. +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) +# include + +struct net_device * +vmware_get_by_name(void) +{ + return __dev_get_by_name(0, "dummy"); +} +#endif diff -Nrup source/vmnet-only/linux/netif.c source.edited/vmnet-only/linux/netif.c --- source/vmnet-only/linux/netif.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/netif.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,755 @@ +/********************************************************* + * Copyright (C) 1998 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" + +#define EXPORT_SYMTAB + +#include +#include +#include +#ifdef KERNEL_2_2 +# include +#else +# include +#endif +#include + +#include +#include +#include +#include "compat_skbuff.h" +#include +#include "compat_sock.h" + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include + +#include "vnetInt.h" +#include "compat_netdevice.h" +#include "vmnetInt.h" + + +typedef struct VNetNetIF { + VNetPort port; + struct net_device *dev; + char devName[VNET_NAME_LEN]; + struct net_device_stats stats; +} VNetNetIF; + + +static void VNetNetIfFree(VNetJack *this); +static void VNetNetIfReceive(VNetJack *this, struct sk_buff *skb); +static Bool VNetNetIfCycleDetect(VNetJack *this, int generation); + +static int VNetNetifOpen(struct net_device *dev); +static int VNetNetifProbe(struct net_device *dev); +static int VNetNetifClose(struct net_device *dev); +static int VNetNetifStartXmit(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *VNetNetifGetStats(struct net_device *dev); +static int VNetNetifSetMAC(struct net_device *dev, void *addr); +static void VNetNetifSetMulticast(struct net_device *dev); +#if 0 +#ifdef KERNEL_2_3_43 +static void VNetNetifTxTimeout(struct net_device *dev); +#endif +#endif + +static int VNetNetIfProcRead(char *page, char **start, off_t off, + int count, int *eof, void *data); + +#ifndef KERNEL_2_3_43 +/* softnet API emulation */ + + +/* + *---------------------------------------------------------------------- + * + * netif_stop_queue -- + * + * Stops queue processing. + * + * Results: + * None. + * + *---------------------------------------------------------------------- + */ + +static inline void +netif_stop_queue(struct net_device *dev) // IN: +{ + dev->tbusy = 1; +} + + +/* + *---------------------------------------------------------------------- + * + * netif_start_queue -- + * + * Enables queue processing. It does not try to start received + * frames processing. + * + * Results: + * None. + * + *---------------------------------------------------------------------- + */ + +static inline void +netif_start_queue(struct net_device *dev) // IN: +{ + dev->tbusy = 0; +} + + +/* + *---------------------------------------------------------------------- + * + * netif_wake_queue -- + * + * Enables queue processing. It schedules receive queue processing. + * + * Results: + * None. + * + *---------------------------------------------------------------------- + */ + +static inline void +netif_wake_queue(struct net_device *dev) // IN: +{ + dev->tbusy = 0; + mark_bh(NET_BH); +} +#endif + + +#if 0 +#ifdef KERNEL_2_3_43 +/* + *---------------------------------------------------------------------- + * + * VNetNetIfTxTimeout -- + * + * Enables processing of Tx queue after it was stopped for so long. + * It should not happen with vmnet system. + * + * Results: + * None. + * + * Side effects: + * Tx queue enabled, message in log. + * + *---------------------------------------------------------------------- + */ + +static void +VNetNetifTxTimeout(struct net_device *dev) // IN: +{ + static int netRateLimit = 0; + + if (netRateLimit < 10) { + LOG(0, (KERN_NOTICE "%s: Transmit timeout\n", dev->name)); + netRateLimit++; + } + /* We cannot stuck due to hardware, so always wake up processing */ + netif_wake_queue(dev); +} +#endif +#endif + + +/* + *---------------------------------------------------------------------- + * + * VNetNetIfSetup -- + * + * Sets initial netdevice state. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) + +static const struct net_device_ops vnet_netdev_ops = { + + .ndo_init = VNetNetifProbe, + .ndo_open = VNetNetifOpen, + .ndo_start_xmit = VNetNetifStartXmit, + .ndo_stop = VNetNetifClose, + .ndo_get_stats = VNetNetifGetStats, + .ndo_set_mac_address = VNetNetifSetMAC, + .ndo_set_multicast_list = VNetNetifSetMulticast, +}; +#endif + +static void +VNetNetIfSetup(struct net_device *dev) // IN: +{ + ether_setup(dev); // turns on IFF_BROADCAST, IFF_MULTICAST +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) + dev->netdev_ops = &vnet_netdev_ops; +#else + dev->init = VNetNetifProbe; + dev->open = VNetNetifOpen; + dev->hard_start_xmit = VNetNetifStartXmit; + dev->stop = VNetNetifClose; + dev->get_stats = VNetNetifGetStats; + dev->set_mac_address = VNetNetifSetMAC; + dev->set_multicast_list = VNetNetifSetMulticast; +#endif + /* + * We cannot stuck... If someone will report problems under + * low memory conditions or some such, we should enable it. + */ +#if 0 + dev->tx_timeout = VNetNetifTxTimeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetIf_Create -- + * + * Create a net level port to the wonderful world of virtual + * networking. + * + * Results: + * Errno. Also returns an allocated port to connect to, + * NULL on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetNetIf_Create(char *devName, // IN: + VNetPort **ret, // OUT: + int hubNum) // IN: +{ + VNetNetIF *netIf; + struct net_device *dev; + int retval = 0; + static unsigned id = 0; + + netIf = kmalloc(sizeof *netIf, GFP_KERNEL); + if (!netIf) { + retval = -ENOMEM; + goto out; + } + + /* + * Initialize fields. + */ + + netIf->port.id = id++; + netIf->port.next = NULL; + + netIf->port.jack.peer = NULL; + netIf->port.jack.numPorts = 1; + VNetSnprintf(netIf->port.jack.name, sizeof netIf->port.jack.name, + "netif%u", netIf->port.id); + netIf->port.jack.private = netIf; + netIf->port.jack.index = 0; + netIf->port.jack.procEntry = NULL; + netIf->port.jack.free = VNetNetIfFree; + netIf->port.jack.rcv = VNetNetIfReceive; + netIf->port.jack.cycleDetect = VNetNetIfCycleDetect; + netIf->port.jack.portsChanged = NULL; + netIf->port.jack.isBridged = NULL; + + /* + * Make proc entry for this jack. + */ + + retval = VNetProc_MakeEntry(netIf->port.jack.name, S_IFREG, + &netIf->port.jack.procEntry); + if (retval) { + if (retval == -ENXIO) { + netIf->port.jack.procEntry = NULL; + } else { + netIf->port.jack.procEntry = NULL; + goto out; + } + } else { + netIf->port.jack.procEntry->read_proc = VNetNetIfProcRead; + netIf->port.jack.procEntry->data = netIf; + } + + /* + * Rest of fields. + */ + + netIf->port.flags = IFF_RUNNING; + + memset(netIf->port.paddr, 0, sizeof netIf->port.paddr); + memset(netIf->port.ladrf, 0, sizeof netIf->port.ladrf); + + /* This will generate the reserved MAC address c0:00:?? where ?? == hubNum. */ + VMX86_BUILD_MAC(netIf->port.paddr, hubNum); + + /* Make sure the MAC is unique. */ + retval = VNetSetMACUnique(&netIf->port, netIf->port.paddr); + if (retval) { + goto out; + } + + netIf->port.fileOpRead = NULL; + netIf->port.fileOpWrite = NULL; + netIf->port.fileOpIoctl = NULL; + netIf->port.fileOpPoll = NULL; + + memset(&netIf->stats, 0, sizeof netIf->stats); + + memcpy(netIf->devName, devName, sizeof netIf->devName); + NULL_TERMINATE_STRING(netIf->devName); + + dev = compat_alloc_netdev(0, netIf->devName, VNetNetIfSetup); + if (!dev) { + retval = -ENOMEM; + goto out; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) + dev->priv = netIf; +#endif /* 2.6.29 */ + + netIf->dev = dev; + + memcpy(dev->dev_addr, netIf->port.paddr, sizeof netIf->port.paddr); + + if (register_netdev(dev) != 0) { + LOG(0, (KERN_NOTICE "%s: could not register network device\n", devName)); + retval = -ENODEV; + goto outFreeDev; + } + + *ret = (VNetPort*)netIf; + return 0; + +outFreeDev: + compat_free_netdev(dev); +out: + if (netIf) { + if (netIf->port.jack.procEntry) { + VNetProc_RemoveEntry(netIf->port.jack.procEntry); + } + kfree(netIf); + } + return retval; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetIfFree -- + * + * Free the net interface port. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +VNetNetIfFree(VNetJack *this) // IN: jack +{ + VNetNetIF *netIf = (VNetNetIF*)this; + + unregister_netdev(netIf->dev); + compat_free_netdev(netIf->dev); + if (this->procEntry) { + VNetProc_RemoveEntry(this->procEntry); + } + kfree(netIf); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetIfReceive -- + * + * This jack is receiving a packet. Take appropriate action. + * + * Results: + * None. + * + * Side effects: + * Frees skb. + * + *---------------------------------------------------------------------- + */ + +void +VNetNetIfReceive(VNetJack *this, // IN: jack + struct sk_buff *skb) // IN: packet +{ + VNetNetIF *netIf = (VNetNetIF*)this->private; + uint8 *dest = SKB_2_DESTMAC(skb); + + if (!NETDEV_UP_AND_RUNNING(netIf->dev)) { + goto drop_packet; + } + + if (!VNetPacketMatch(dest, + netIf->dev->dev_addr, + allMultiFilter, + netIf->dev->flags)) { + goto drop_packet; + } + + /* send to the host interface */ + skb->dev = netIf->dev; + skb->protocol = eth_type_trans(skb, netIf->dev); + netif_rx_ni(skb); + netIf->stats.rx_packets++; + + return; + + drop_packet: + dev_kfree_skb(skb); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetIfCycleDetect -- + * + * Cycle detection algorithm. + * + * Results: + * TRUE if a cycle was detected, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Bool +VNetNetIfCycleDetect(VNetJack *this, // IN: jack + int generation) // IN: +{ + VNetNetIF *netIf = (VNetNetIF*)this->private; + return VNetCycleDetectIf(netIf->devName, generation); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetifOpen -- + * + * The virtual network's open dev operation. + * + * Results: + * errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetNetifOpen(struct net_device *dev) // IN: +{ + /* + * The host interface is not available if the hub is bridged. + * + * It's actually okay to support both. We just need + * to tag packets when VNetXmitPacket gives them to the interface + * so they can be dropped by VNetBridgeReceive(). + * + * if so return -EBUSY; + */ + + netif_start_queue(dev); +#ifndef KERNEL_2_3_43 + /* Softnet does not have interrupt hack ... */ + dev->interrupt = 0; + /* ... and sets start for us */ + dev->start = 1; +#endif + // xxx need to change flags + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetifProbe -- + * + * ??? + * + * Results: + * 0. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetNetifProbe(struct net_device *dev) // IN: unused +{ + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetifClose -- + * + * The virtual network's close dev operation. + * + * Results: + * errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetNetifClose(struct net_device *dev) // IN: +{ +#ifndef KERNEL_2_3_43 + /* Softnet generic layer clears it for us */ + dev->start = 0; +#endif + netif_stop_queue(dev); + // xxx need to change flags + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetifStartXmit -- + * + * The virtual network's start xmit dev operation. + * + * Results: + * ???, 0. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetNetifStartXmit(struct sk_buff *skb, // IN: + struct net_device *dev) // IN: +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) + VNetNetIF *netIf = (VNetNetIF*)dev->priv; +#else + VNetNetIF *netIf = netdev_priv(dev); +#endif /* 2.6.29 */ + + if(skb == NULL) { + return 0; + } + + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + * If this ever occurs the queue layer is doing something evil! + */ + +#ifndef KERNEL_2_3_43 + /* Softnet does not play with tbusy... */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) + { + LOG(0, (KERN_NOTICE "%s: transmitter access conflict.\n", dev->name)); + return 1; + } +#endif + VNetSend(&netIf->port.jack, skb); + + netIf->stats.tx_packets++; +#ifndef KERNEL_2_3_43 + dev->tbusy = 0; +#endif + dev->trans_start = jiffies; + + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetifSetMAC -- + * + * Sets MAC address (i.e. via ifconfig) of netif device. + * + * Results: + * Errno. + * + * Side effects: + * The MAC address may be changed. + * + *---------------------------------------------------------------------- + */ + +int +VNetNetifSetMAC(struct net_device *dev, // IN: + void *p) // IN: +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) + VNetNetIF *netIf = (VNetNetIF*)dev->priv; +#else + VNetNetIF *netIf = netdev_priv(dev); +#endif /* 2.6.29 */ + + struct sockaddr const *addr = p; + if (!VMX86_IS_STATIC_MAC(addr->sa_data)) { + return -EINVAL; + } + memcpy(netIf->port.paddr, addr->sa_data, dev->addr_len); + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetifSetMulticast -- + * + * Sets or clears the multicast address list. This information + * comes from an array in dev->mc_list, and with a counter in + * dev->mc_count. + * + * Since host-only network ifaces can't be bridged, it's debatable + * whether this is at all useful, but at least now you can turn it + * on from ifconfig without getting an ioctl error. + * Results: + * Void. + * + * Side effects: + * Multicast address list might get changed. + * + *---------------------------------------------------------------------- + */ + +void +VNetNetifSetMulticast(struct net_device *dev) // IN: unused +{ +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetifGetStats -- + * + * The virtual network's get stats dev operation. + * + * Results: + * A struct full of stats. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +struct net_device_stats * +VNetNetifGetStats(struct net_device *dev) // IN: +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) + VNetNetIF *netIf = (VNetNetIF*)dev->priv; +#else + VNetNetIF *netIf = netdev_priv(dev); +#endif /* 2.6.29 */ + return &(netIf->stats); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetNetIfProcRead -- + * + * Callback for read operation on this netif entry in vnets proc fs. + * + * Results: + * Length of read operation. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetNetIfProcRead(char *page, // IN/OUT: buffer to write into + char **start, // OUT: 0 if file < 4k, else offset into page + off_t off, // IN: (unused) offset of read into the file + int count, // IN: (unused) maximum number of bytes to read + int *eof, // OUT: TRUE if there is nothing more to read + void *data) // IN: client data +{ + VNetNetIF *netIf = (VNetNetIF*)data; + int len = 0; + + if (!netIf) { + return len; + } + + len += VNetPrintPort(&netIf->port, page+len); + + len += sprintf(page+len, "dev %s ", netIf->devName); + + len += sprintf(page+len, "\n"); + + *start = 0; + *eof = 1; + return len; +} diff -Nrup source/vmnet-only/linux/nfhook_uses_skb.c source.edited/vmnet-only/linux/nfhook_uses_skb.c --- source/vmnet-only/linux/nfhook_uses_skb.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/nfhook_uses_skb.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,45 @@ +/********************************************************* + * Copyright (C) 2007 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 + * + *********************************************************/ + +/* + * Detect whether nf_hookfn takes struct sk_buff* skb, or struct sk_buff** pskb. + * Kernels before 2.6.23 take pskb, kernels since 2.6.24 take skb, and we + * are not sure about 2.6.23 itself, as change occured between 2.6.23 and + * 2.6.24-rc1. + */ + +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) +# error This compile test intentionally fails. +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) +# include + +nf_hookfn test_function; + +unsigned int +test_function(unsigned int hooknum, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*defn)(struct sk_buff*)) +{ + return 1234; +} +#endif diff -Nrup source/vmnet-only/linux/procfs.c source.edited/vmnet-only/linux/procfs.c --- source/vmnet-only/linux/procfs.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/procfs.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,402 @@ +/********************************************************* + * Copyright (C) 1998 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" + +#define EXPORT_SYMTAB + +#include +#include +#include +#ifdef KERNEL_2_2 +# include +#else +# include +#endif +#include + +#include +#include +#include +#include "compat_skbuff.h" +#include +#include +#include "compat_sock.h" + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include + +#include "vnetInt.h" + + +#if defined(CONFIG_PROC_FS) + +static int VNetProcMakeEntryInt(VNetProcEntry *parent, char *name, int mode, + VNetProcEntry **ret); +static void VNetProcRemoveEntryInt(VNetProcEntry *node, VNetProcEntry *parent); +#ifndef KERNEL_2_3_25 +static void VNetProcModCount(struct inode *inode, int fill); +#endif + +static VNetProcEntry *base = NULL; + + +/* + *---------------------------------------------------------------------- + * + * VNetProc_Init -- + * + * Initialize the vnets procfs entries. + * + * Results: + * errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetProc_Init(void) +{ + int retval; + + retval = VNetProcMakeEntryInt(NULL, "vmnet", S_IFDIR, &base); + if (retval) { + return retval; + } + +#ifndef KERNEL_2_3_25 + base->fill_inode = VNetProcModCount; +#endif + + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetProc_Cleanup -- + * + * Cleanup the vnets proc filesystem entries. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +VNetProc_Cleanup(void) +{ + VNetProcRemoveEntryInt(base, NULL); + base = NULL; +} + +#ifndef KERNEL_2_3_25 +/* + *---------------------------------------------------------------------- + * + * VNetProcModCount -- + * + * Callback for the vnets proc filesystem. This gets called when + * the inode goes into or out of service. For example when someone + * cd's to the vmnet directory. We must put a use count on the module + * so that its doesn't go away. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void +VNetProcModCount(struct inode *inode, // IN: + int fill) // IN: +{ + VNetIncrModCount((fill) ? 1 : -1); +} +#endif + +/* + *---------------------------------------------------------------------- + * + * VNetProcMakeEntryInt -- + * + * Make an entry in the vnets proc file system. + * + * Results: + * errno. If errno is 0 and ret is non NULL then ret is filled + * in with the resulting proc entry. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetProcMakeEntryInt(VNetProcEntry *parent, // IN: + char *name, // IN: + int mode, // IN: + VNetProcEntry **ret) // OUT: +{ + VNetProcEntry *ent; +#ifndef KERNEL_2_3_29 + int retval; + + if (ret) { + *ret = NULL; + } + + ent = kmalloc(sizeof *ent, GFP_KERNEL); + if (!ent) { + return -ENOMEM; + } + + memset(ent, 0, sizeof *ent); + + if (mode == S_IFDIR) { + mode |= S_IRUGO | S_IXUGO; + } else if (mode == S_IFREG) { + mode |= S_IRUGO; + } + + ent->low_ino = 0; + ent->name = name; + ent->namelen = strlen(name); + ent->mode = mode; + + if (S_ISDIR(mode)) { + ent->nlink = 2; + } else { + ent->nlink = 1; + } + + if (!parent) { + parent = &proc_root; + } + + retval = proc_register(parent, ent); + if (retval) { + kfree(ent); + return retval; + } + + if (ret) { + *ret = ent; + } +#else /* KERNEL_2_3_29 */ + ent = create_proc_entry(name, mode, parent); + *ret = ent; + if (!ent) + return -ENOMEM; +#endif /* KERNEL_2_3_29 */ + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetProcRemoveEntryInt -- + * + * Remove a previously installed proc entry. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +VNetProcRemoveEntryInt(VNetProcEntry *node, + VNetProcEntry *parent) +{ + if (node) { +#ifndef KERNEL_2_3_29 + if (!parent) { + parent = &proc_root; + } + proc_unregister(parent, node->low_ino); + kfree(node); +#else /* KERNEL_2_3_29 */ + remove_proc_entry(node->name, parent); +#endif /* KERNEL_2_3_29 */ + } +} + + +/* + *---------------------------------------------------------------------- + * + * VNetProc_MakeEntry -- + * + * Make an entry in the vnets proc file system. + * + * Results: + * errno. If errno is 0 and ret is non NULL then ret is filled + * in with the resulting proc entry. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetProc_MakeEntry(char *name, // IN: + int mode, // IN: + VNetProcEntry **ret) // OUT: +{ + return VNetProcMakeEntryInt(base, name, mode, ret); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetProc_RemoveEntry -- + * + * Remove a previously installed proc entry. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +VNetProc_RemoveEntry(VNetProcEntry *node) +{ + VNetProcRemoveEntryInt(node, base); +} + + +#else /* CONFIG_PROC_FS */ + + +/* + *---------------------------------------------------------------------- + * + * VNetProc_Init -- + * + * Initialize the vnets procfs entries. + * + * Results: + * errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetProc_Init(void) +{ + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetProc_Cleanup -- + * + * Cleanup the vnets proc filesystem entries. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +VNetProc_Cleanup(void) +{ +} + + +/* + *---------------------------------------------------------------------- + * + * VNetProc_MakeEntry -- + * + * Make an entry in the vnets proc file system. + * + * Results: + * errno. If errno is 0 and ret is non NULL then ret is filled + * in with the resulting proc entry. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetProc_MakeEntry(char *name, + int mode, + VNetProcEntry **ret) +{ + return -ENXIO; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetProc_RemoveEntry -- + * + * Remove a previously installed proc entry. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +VNetProc_RemoveEntry(VNetProcEntry *parent) +{ +} + +#endif /* CONFIG_PROC_FS */ diff -Nrup source/vmnet-only/linux/setnice.c source.edited/vmnet-only/linux/setnice.c --- source/vmnet-only/linux/setnice.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/setnice.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,32 @@ +/********************************************************* + * Copyright (C) 2005 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 + * + *********************************************************/ + +/* + * set_user_nice appeared in 2.4.21. But some distros + * backported it to older kernels. + */ +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 21) +#include + +void test(void) { + set_user_nice(current, -20); +} +#endif diff -Nrup source/vmnet-only/linux/sk_alloc.c source.edited/vmnet-only/linux/sk_alloc.c --- source/vmnet-only/linux/sk_alloc.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/sk_alloc.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,39 @@ +/********************************************************* + * Copyright (C) 2005 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 + * + *********************************************************/ + +/* + * Detect whether sk_alloc takes a struct proto * as third parameter. + * This API change was introduced between 2.6.12-rc1 and 2.6.12-rc2. + */ + +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13) +#include + +static struct proto test_proto = { + .name = "TEST", +}; + +struct sock * +vmware_sk_alloc(void) +{ + return sk_alloc(PF_NETLINK, 0, &test_proto, 1); +} +#endif diff -Nrup source/vmnet-only/linux/skblin.c source.edited/vmnet-only/linux/skblin.c --- source/vmnet-only/linux/skblin.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/skblin.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,41 @@ +/********************************************************* + * 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 + * + *********************************************************/ + +/* + * Detect whether skb_linearize takes one or two arguments. + */ + +#include +#include + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17) +/* + * Since 2.6.18 all kernels have single-argument skb_linearize. For + * older kernels use autodetection. Not using autodetection on newer + * kernels saves us from compile failure on some post 2.6.18 kernels + * which do not have selfcontained skbuff.h. + */ + +#include + +int test_skb_linearize(struct sk_buff *skb) +{ + return skb_linearize(skb); +} + +#endif diff -Nrup source/vmnet-only/linux/smac.c source.edited/vmnet-only/linux/smac.c --- source/vmnet-only/linux/smac.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/smac.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,3792 @@ +/********************************************************* + * Copyright (C) 2002 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 + * + *********************************************************/ + +/* + * smac.c -- + * + * This file defines functionality that allows the + * bridge to be used across links that do + * not support promiscuous mode, or to not provide the + * ability to transmit ethernet frames whose MAC source + * address does not match the hardware's MAC address. + * + * This code extension basically forces the bridge to + * use a single MAC, thus the name SMAC. + */ + +/* platform-dependent includes */ + +#ifdef _WIN32 + +#define BINARY_COMPATIBLE 0 // NT-only driver (optimizes some NDIS calls) +#include + +#include "vnetInt.h" + +#else /* _WIN32 */ + +#undef __KERNEL__ //To prevent including any kernel specific stuff + +#ifdef VMX86_DEVEL +#define DBG 1 +#else +#undef DBG +#endif /* VMX86_DEVEL */ + +#ifdef __APPLE__ +#include +#include +#endif + +#include "smac_compat.h" + +#endif /* _WIN32 */ + +/* platform-independent includes */ +#include "smac.h" +#include "vm_basic_defs.h" + +#define SMAC_MODULE "SMAC: " +#define MODULE_NAME SMAC_MODULE + +/* platform-dependent defines */ +#ifdef _WIN32 +#define ALLOCATEMEMORY(a,b) VNet_AllocateMemoryWithTag((a),(b)) +#define FREEMEMORY(a) VNet_FreeMemory((a)) +#define MEMCPY(a,b,c) NdisMoveMemory((a),(b),(c)) +#define MEMSET(a,b,c) NdisFillMemory((a),(c),(b)) + +#define SPINLOCKINIT() do { } while (0) +#define INITSPINLOCK(a) do { NdisAllocateSpinLock( (a) ); } while(0) +#define RAISEIRQL() do { irql = KeRaiseIrqlToDpcLevel(); } while(0) +#define ACQUIRESPINLOCK(a) do { ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \ + NdisDprAcquireSpinLock( (a) ); } while(0) +#define RELEASESPINLOCK(a) do { NdisDprReleaseSpinLock( (a) ); } while(0) +#define LOWERIRQL() do { KeLowerIrql(irql); } while(0) +#define FREESPINLOCK(a) do { NdisFreeSpinLock( (a) ); } while(0) +#define ASSERTLOCKHELD() ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL) +#define SNPRINTF(a) (_snprintf a) + +#elif defined __linux__ || defined __APPLE__ + +#define ALLOCATEMEMORY(a,b) SMACL_Alloc((a)) +#define MEMCPY(a,b,c) SMACL_Memcpy((a),(b),(c)) +#define MEMSET(a,b,c) SMACL_Memset((a),(b),(c)) + +#define INITSPINLOCK(a) SMACL_InitSpinlock( (a) ) +#define RAISEIRQL() do { } while (0) +#define LOWERIRQL() do { } while (0) +#define ASSERTLOCKHELD() do { } while (0) + +#define UNREFERENCED_PARAMETER(a) { (a) = (a); } + +/* + * The following are defined to create OS dependent versions of + * functionality available on Windows. + */ + +#undef ASSERT + +#ifdef DBG +#define VNETKdPrint(a) (SMACL_Print a) +#define ASSERT(a) do {if (!(a)) {VNETKdPrint(("ASSERT FAILED: "#a));}} while(0) +#else +#define VNETKdPrint(a) do { } while (0) +#define ASSERT(a) do { } while (0) +#endif + +#define VNETKdPrintCall(a) VNETKdPrint((MODULE_NAME "Calling : %s\n", a)) +#define VNETKdPrintReturn(a) VNETKdPrint((MODULE_NAME "Returned : %s\n", a)) + +#ifndef MAC_EQ +#define MAC_EQ(a,b) (SMACL_Memcmp((a),(b),ETH_ALEN)==0) +#endif /* MAC_EQ */ + +#define IS_MULTICAST(_hdr) ((_hdr)[0] & 0x1) +#define IS_BROADCAST(_a) \ + ((_a)[0] == 0xff && (_a)[1] == 0xff && (_a)[2] == 0xff && \ + (_a)[3] == 0xff && (_a)[4] == 0xff && (_a)[5] == 0xff) + +#ifdef __linux__ +#define FREEMEMORY(a) SMACL_Free((a)) +#define SPINLOCKINIT() unsigned long flags +#define FREESPINLOCK(a) SMACL_Free(*a) +#define ACQUIRESPINLOCK(a) SMACL_AcquireSpinlock( (a), &flags) +#define RELEASESPINLOCK(a) SMACL_ReleaseSpinlock( (a), &flags) +#define SNPRINTF(a) (SMACL_Snprintf a) +#else /* __APPLE__ */ +#define FREEMEMORY(a) SMACL_Free((a), sizeof *(a)) +#define SPINLOCKINIT() do { } while (0) +#define FREESPINLOCK(a) SMACL_FreeSpinlock( (a) ) +#define ACQUIRESPINLOCK(a) SMACL_AcquireSpinlock( *(a) ) +#define RELEASESPINLOCK(a) SMACL_ReleaseSpinlock( *(a) ) +#define SNPRINTF(a) (snprintf a) +#endif + +#else +#error "unknown platform" +#endif /* _WIN32 */ + +/* Offsets/lengths for IP, UDP, and ARP headers */ +#define IP_HEADER_LEN 20 +#define IP_HEADER_DEST_ADDR_OFFSET 16 +#define IP_HEADER_SRC_ADDR_OFFSET 12 +#define IP_HEADER_FLAGS_OFFSET 6 +#define IP_HEADER_PROTO_OFFSET 9 +#define UDP_HEADER_LEN 8 +#define ARP_HEADER_LEN 28 +#define ARP_SENDER_MAC_OFFSET 8 +#define ARP_SENDER_IP_OFFSET 14 +#define ARP_TARGET_MAC_OFFSET 18 +#define ARP_TARGET_IP_OFFSET 24 + +#define IP_ADDR_BROADCAST 0xFFFFFFFF + +/* + * To limit the amount of kernel log information, define + * WIRELESS_BE_QUIET or WIRELESS_BE_VERY_QUIET. The former + * reduces the logging to a point where the host system isn't + * bogged down with logging all the details of broadcast traffic + * coming in from the company network. The latter define will + * completely turn off wireless logging. + */ + +#define WIRELESS_BE_VERY_QUIET +//#define WIRELESS_BE_QUIET + +#ifdef WIRELESS_BE_VERY_QUIET +#define WW_VNETKdPrint(a) +#define W_VNETKdPrint(a) +#else // WIRELESS_BE_VERY_QUIET + +#ifdef WIRELESS_BE_QUIET +#define WW_VNETKdPrint(a) +#define W_VNETKdPrint(a) VNETKdPrint(a) +#else // WIRELESS_BE_QUIET +#define WW_VNETKdPrint(a) VNETKdPrint(a) +#define W_VNETKdPrint(a) VNETKdPrint(a) +#endif // WIRELESS_BE_QUIET + +#endif // WIRELESS_BE_VERY_QUIET + +/* + * Host-to-Network / Network-to-Host byte-order routines + * + * Macro and function versions provided; offers tradeoff between + * speed, compile-time versus run-time, and type checking + */ + +#ifdef __APPLE__ +#undef HTONL +#undef NTOHL +#undef HTONS +#undef NTOHS +#endif /* __APPLE__ */ + +#define HTONL(i) (((uint32)i)>>24 | (i)<<24 | ((i)&0x00ff0000)>>8 | \ + ((i)&0x0000ff00)<<8) +#define NTOHL(i) HTONL(i) +#define HTONS(i) (((uint16)i)>>8 | (i)<<8) +#define NTOHS(i) HTONS(i) + +#ifndef __APPLE__ +static INLINE_SINGLE_CALLER uint32 +htonl(uint32 i) { + return HTONL(i); +} +static INLINE_SINGLE_CALLER uint32 +ntohl(uint32 i) { + return NTOHL(i); +} +static INLINE_SINGLE_CALLER uint16 +htons(uint16 i) { + return HTONS(i); +} +static INLINE_SINGLE_CALLER uint16 +ntohs(uint16 i) { + return NTOHS(i); +} +#endif /* __APPLE__ */ + +/* + * Create 8-bit IP hash, currently by adding up each of the 4 octets + */ + +#define IP_HASH(i) ( (((i>>24)&0xff)+((i>>16)&0xff)+((i>>8)&0xff)+\ + ((i>>0)&0xff)) & SMAC_HASH_MASK ) + +/* + * IPmacLookupEntry: defines entry in IP/MAC hash tables for finding which + * IP corresonds to which MAC + */ + +#ifdef _WIN32 +typedef uint64 SmacLastAccess; +#define LAST_ACCESS_FORMAT "%"FMT64"u" // format of lastAccess for printf() +#else +typedef unsigned long SmacLastAccess; +#define LAST_ACCESS_FORMAT "%lu" // format of lastAccess for printf() +#endif /* _WIN32 */ + +typedef struct IPmacLookupEntry { + struct IPmacLookupEntry *ipNext; // pointer to next item in bucket in IP hash table + uint32 IPv4address; // IPv4 address + // uint8 IPv6address[16]; // IPv6 address (for future support) + uint8 mac[ETH_ALEN]; // ethernet MAC address + SmacLastAccess lastAccess; // estimated time of entry's last use +} IPmacLookupEntry; + +/* + * EthernetHeader: struct that corresponds with common ethernet header + * (an ethernet frame that contians a VLAN header has different + * format: 2 additional bytes after srcAddr) + */ + +typedef struct EthernetHeader { + uint8 destAddr[ETH_ALEN]; // destination MAC + uint8 srcAddr[ETH_ALEN]; // source MAC + uint16 lengthType; // length/type field +} EthernetHeader; + +/* + * EthClass: used to classify the various ethernet media types + * into a small group of classes. + */ + +typedef enum { + EthClassIllegal = 0x345, // media type in an unrefined/reserved range + EthClassCommon, // means known but no special handling needed + EthClassUncommon, // like common, but should trigger more debug printouts + EthClassUnknown, // not specifically known/handled), but a legal type + EthClassIP, // IPv4 type + EthClassARP, // one of the various ARP protocols + EthClassVLAN // VLAN type +} EthClass; + +/* + * SMACState: encapsulates all wireless state for a specific host adapter + */ + +#define SMAC_HASH_TABLE_SIZE 256 // length of table, must be power of 2 +#define SMAC_HASH_MASK (SMAC_HASH_TABLE_SIZE - 1) // hash bits + +typedef struct SMACState { +#ifdef _WIN32 + NDIS_SPIN_LOCK smacSpinLock; // spinlock that protects wireless state +#else /* _WIN32 */ + void *smacSpinLock; // spinlock that protects wireless state +#endif /* _WIN32 */ + SmacLastAccess lastUptimeRead; // used to track uptime counter overflow + struct IPmacLookupEntry * IPlookupTable[SMAC_HASH_TABLE_SIZE]; // IP hash table IP->MAC + uint32 numberOfIPandMACEntries; // # of hash table entries + uint32 lastIPadded; // last IP added to hash + uint8 lastMACadded[ETH_ALEN]; // last MAC added to hash + struct IPmacLookupEntry * lastEntryAdded; // ptr to cache entry (to update timestamp) + Bool smacFowardUnknownPackets; // forward "all" packets? (typically doesn't) + uint8 macAddress[ETH_ALEN]; // pointer to host MAC address +} SMACState; + +/* + * Function prototypes + */ + +static INLINE uint32 SUM32(uint32 in); +static uint32 CalcChecksumDiff(uint32 sumBefore, uint32 sumAfter); +static uint16 UpdateSum(uint16 oricheck, uint32 sumDiff); + +static INLINE IPmacLookupEntry *LookupByIPNoAcquireLock(SMACState *state, + uint32 addr); +static Bool LookupByIP(SMACState *state, uint32 addr, uint8 *macAddress); + +static INLINE Bool RemoveIPfromHashTableNoAcquireLock(SMACState *state, + IPmacLookupEntry *entryToRemove); + +static void TrimLookupTableIfNecessary(SMACState *state); + +static INLINE void SetCacheEntry(SMACState *state, IPmacLookupEntry *entry); + +static Bool AddIPv4andMACcombo(SMACState *state, uint32 addr, uint8 *mac); + +static void ProcessOutgoingIPv4Packet(SMACPacket *packet, uint32 ethHeaderLen); +#ifdef DBG +static void ProcessIncomingIPv4Packet(SMACPacket *packet, + Bool knownMacForIp); +#endif +static SmacLastAccess GetSystemUptime(SMACState *state); + +/* get information from packet */ +static INLINE uint32 GetPacketLength(SMACPacket *packet); +static Bool GetPacketData(SMACPacket *packet, uint32 offset, + uint32 length, void *data); + +/* set information in packet */ +static Bool SetPacketByte(SMACPacket *packet, uint32 offset, + uint8 data); + +/* clone source / write data to clone */ +static Bool ClonePacket(SMACPackets *packets); +static Bool CopyDataToClonedPacket(SMACPackets *packets, const void *source, + uint32 offset, uint32 length); + +/* write data to source (on Windows) / write data to clone (on Linux) */ +static Bool CopyDataForPacketFromHost(SMACPackets *packets, uint32 changeNum, + uint32 offset, const uint8 *macAddress); + +static EthClass LookupTypeClass(uint16 typeValue); +#ifdef DBG +static EthClass LookupTypeName(uint16 typeValue, char *type); +#endif + +/* + * IP hash table routines: the following routines pertain to operations + * on the IP hash table. SMACState->smacSpinLock should be held when reading or + * writing data in the hash table. A read/write lock might be better + * but the locks are usually held for a brief period of time. + * + * 'lastIPadded' and 'lastMACadded' are used to cache the last entry that + * was added to the hash table. For most packets we attempt to add IP/MAC + * information from that packet to the hash table. In most cases (especially + * during file transfers) the entry will already be added to the table so we + * cache the last addition to minimize overhead. The cache information is + * not used for lookups, only to make adds more efficient. + */ + + +/* + *---------------------------------------------------------------------- + * + * LookupByIP -- + * LookupByIPNoAcquireLock -- + * + * Lookup entry or MAC address that corresponds to the + * specified IP address. Locking and non-locking versions + * are provided. The non-locking version returns the actual + * table entry, while the locking version only returns the + * actual MAC address (to avoid reference counting). + * + * Results: + * Nonlocking: pointer to entry (if found), otherwise NULL + * Locking: TRUE if MAC found, otherwise FALSE + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE IPmacLookupEntry * +LookupByIPNoAcquireLock(SMACState *state, // IN: state + uint32 addr) // IN: IP to lookup +{ + uint8 hash = IP_HASH(addr); + IPmacLookupEntry *curr = state->IPlookupTable[hash]; // get bucket + + ASSERT(SMAC_HASH_TABLE_SIZE == 256); + + /* + * Search thru bucket for match + */ + + while (curr && curr->IPv4address != addr) { + curr = curr->ipNext; + } + return curr; +} + + +static Bool +LookupByIP(SMACState *state, // IN: adapter + uint32 addr, // IN: IP to lookup + uint8 *macAddress) // OUT: (optional) MAC of IP (uint8[ETH_ALEN]) +{ + IPmacLookupEntry *entry; + SPINLOCKINIT(); + + WW_VNETKdPrint((MODULE_NAME "LookupByIP: told to find %d.%d.%d.%d\n", + addr&0xff, (addr>>8)&0xff, (addr>>16)&0xff, (addr>>24)&0xff)); + + ACQUIRESPINLOCK(&state->smacSpinLock); + entry = LookupByIPNoAcquireLock(state, addr); + if (entry != NULL && macAddress != NULL) { + MEMCPY(macAddress, entry->mac, ETH_ALEN); + } + RELEASESPINLOCK(&state->smacSpinLock); + return entry != NULL; +} + + +/* + *---------------------------------------------------------------------- + * + * RemoveIPfromHashTable -- + * RemoveIPfromHashTableNoAcquireLock -- + * + * Removed specified entry from the IP hash table. Function + * presumes that specified table entry still contains the IP + * address that was used to add the entry to the hash table. + * Locking and no-locking version of function are provided + * + * This function doesn't check whether the cached entry is + * being removed (and thus won't reset the cached entry). This + * code is primarily used to remove the oldest entry, and by + * definition the cached entry is the newest (i.e., it's never + * the oldest and thus won't be removed). + * + * Results: + * TRUE if entry removed, FALSE otherwise. + * + * Side effects: + * May remove entry from IP hash table. Actual entry is not + * modified nor deallocated by this function. + * + *---------------------------------------------------------------------- + */ + +static INLINE Bool +RemoveIPfromHashTableNoAcquireLock(SMACState *state, // IN: state + IPmacLookupEntry * entryToRemove) // IN: packet +{ + uint8 ipHashToRemove; + IPmacLookupEntry * prev = NULL, *entry; + + ASSERT(entryToRemove); + ASSERT(SMAC_HASH_TABLE_SIZE == 256); + + ipHashToRemove = IP_HASH(entryToRemove->IPv4address); + entry = state->IPlookupTable[ipHashToRemove]; // get bucket + + /* + * locate and remove old IP entry from bucket + */ + + while (entry) { + if (entry == entryToRemove) { + if (prev) { + W_VNETKdPrint((MODULE_NAME "RemoveIPfromHashTable: removed IP " + "entry from middle of bucket\n")); + prev->ipNext = entry->ipNext; + } else { + W_VNETKdPrint((MODULE_NAME "RemoveIPfromHashTable: removed IP " + "entry from front of bucket\n")); + state->IPlookupTable[ipHashToRemove] = entry->ipNext; + } + return TRUE; + } else { + prev = entry; + entry = entry->ipNext; + } + } + return FALSE; +} + + +/* + *---------------------------------------------------------------------- + * + * TrimLookupTableIfNecessary -- + * + * If the number of entries in the IP and MAC tables exceeds a + * specified value (currently 20), then we remove and deallocate + * an entry--ideally the entry which has been used least recently + * is removed. The code presumes that this function will be called + * anytime a new entry is added, thus we should never need to + * remove more than one entry per function call. + * + * Function presumes that state lock is held while this function + * is called. + * + * Results: + * None. + * + * Side effects: + * May remove and deallocates an entry from the IP and MAC hash + * tables. + * + *---------------------------------------------------------------------- + */ + +static void +TrimLookupTableIfNecessary(SMACState *state) // IN: smac state +{ + IPmacLookupEntry * oldestEntry = NULL; // oldest entry found + SmacLastAccess oldestUpdate = ~0; // age of oldest entry + SmacLastAccess currentUptime = 0; // time since the system was booted + int i; + + VNETKdPrintCall(("TrimLookupTableIfNecessary")); + ASSERT(state); + ASSERT(SMAC_HASH_TABLE_SIZE == 256); + ASSERTLOCKHELD(); + + if (state->numberOfIPandMACEntries <= 20) { // if not too many entries + VNETKdPrint((MODULE_NAME "TrimLookupTableIfNeccessary: number of " + "entries is small: %d\n", state->numberOfIPandMACEntries)); + return; + } + + VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: " + "reducing # of entries\n")); + + currentUptime = GetSystemUptime(state); /* must be called with lock held */ + + VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: current uptime is " + LAST_ACCESS_FORMAT "\n", currentUptime)); + + /* + * NOTE: this code presumes that no system will ever be up long enough + * for the uptime to wrap. To get around this assumption we could try to + * determine "oldest" by computing which entry has the largest difference + * from the current updtime. However, there are no guarantees that this + * metric is any more accurate. Given that we never expect more than 20 + * entries to ever exist, I won't implement a more sophisiticated + * mechanism at this time. + */ + + /* + * Search thru entire table to find oldest uptime, and remove it + */ + + for (i = 0; i < SMAC_HASH_TABLE_SIZE; ++i) { + IPmacLookupEntry *currentEntry = state->IPlookupTable[i]; + while (currentEntry) { + if (currentEntry->lastAccess < oldestUpdate) { // if older than candidate + + /* + * Skip cached entry since the entry was used most recently, but its + * timestamp might be old since the timestamp is only updated after + * the entry is no longer cached (i.e., something else is now the newest) + * + * This code will only be executed if at least 20 entries exist, so there + * must be some much better candidates elsewhere in the table. + */ + + if (currentEntry == state->lastEntryAdded) { + VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: oldest " + "candidate is the cached entry, so skipping\n")); + } else { + VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: current " + "oldest candidate: %d.%d.%d.%d time " LAST_ACCESS_FORMAT "\n", + (currentEntry->IPv4address)&0xff, + (currentEntry->IPv4address>>8)&0xff, + (currentEntry->IPv4address>>16)&0xff, + (currentEntry->IPv4address>>24)&0xff, + currentEntry->lastAccess)); + oldestEntry = currentEntry; + oldestUpdate = currentEntry->lastAccess; + } + } + if (currentEntry->lastAccess > currentUptime) { + VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: " + "ERROR: last access " LAST_ACCESS_FORMAT + " > current uptime " LAST_ACCESS_FORMAT "\n", + currentEntry->lastAccess, currentUptime)); + } + + currentEntry = currentEntry->ipNext; + } + } + + if (oldestEntry) { + VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: found oldest " + "candidate: %d.%d.%d.%d time " LAST_ACCESS_FORMAT "\n", + (oldestEntry->IPv4address) & 0xff, + ((oldestEntry->IPv4address)>>8) & 0xff, + ((oldestEntry->IPv4address)>>16) & 0xff, + ((oldestEntry->IPv4address)>>24) & 0xff, + oldestEntry->lastAccess)); + if (!RemoveIPfromHashTableNoAcquireLock(state, oldestEntry)) { + VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: could not " + "find entry in IP table\n")); + ASSERT(0); // should never occur + } else { + FREEMEMORY(oldestEntry); + --state->numberOfIPandMACEntries; + } + } + else { + VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: " + "found no entry to remove!!\n")); + } + + VNETKdPrintReturn(("TrimLookupTableIfNecessary")); + return; +} + + +/* + *---------------------------------------------------------------------- + * + * SetCacheEntry -- + * + * Sets the cached MAC/IP entry for an adapter, and updates the + * access time for the previous cache entry (if any). The cache + * is used to avoid the overhead of checking for the existance of, + * for the purposes of adding, a MAC/IP entry that has already + * been added recently. + * + * Function is called with state->smacSpinLock held. + * + * Results: + * None. + * + * Side effects: + * Modified the cached entry for the adapter, and updates the + * access time for the previous cache entry (if any) + * + *---------------------------------------------------------------------- + */ + +static INLINE void +SetCacheEntry(SMACState *state, // IN: smac state + IPmacLookupEntry *entry) // IN: entry to cache +{ + ASSERT(state); + ASSERT(entry); + + /* + * Set new cached entry, but first set the current cache entry's + * access time to the current time + */ + + if (state->lastEntryAdded) { + state->lastEntryAdded->lastAccess = GetSystemUptime(state); + } + + state->lastIPadded = entry->IPv4address; + MEMCPY(state->lastMACadded, entry->mac, ETH_ALEN); + state->lastEntryAdded = entry; + entry->lastAccess = GetSystemUptime(state); +} + + +/* + *---------------------------------------------------------------------- + * + * AddIPv4andMACcombo -- + * + * Adds an entry for a paired MAC/IPv4 into the IP and MAC + * hash tables. + * + * Results: + * TRUE if added, updated, or already present, FALSE on error. + * + * Side effects: + * Allocates a new table entry and adds it to the IP and MAC + * hash tables. + * + *---------------------------------------------------------------------- + */ + +static Bool +AddIPv4andMACcombo(SMACState *state, // IN: smac state + uint32 addr, // IN: IPv4 address to add + uint8 *mac) // IN: ethernet MAC to add +{ + Bool result = TRUE; + IPmacLookupEntry *entryIP = NULL; + SPINLOCKINIT(); + + /* + * If the current IP/MAC is the same as the immediately prior add, then + * return and don't bother to process this request. + */ + + VNETKdPrint((MODULE_NAME "AddIPMAC: told to add %d.%d.%d.%d " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + addr&0xff, (addr>>8)&0xff, + (addr>>16)&0xff, (addr>>24)&0xff, + mac[0]&0xff, mac[1]&0xff, mac[2]&0xff, + mac[3]&0xff, mac[4]&0xff, mac[5]&0xff)); + ASSERTLOCKHELD(); + ASSERT(SMAC_HASH_TABLE_SIZE == 256); + + if (addr == state->lastIPadded && MAC_EQ(mac, state->lastMACadded)) { + VNETKdPrint((MODULE_NAME "AddIPMAC: cache says already present\n")); + return TRUE; + } + + /* + * Don't allow an IP of 0.0.0.0 or 255.255.255.255 to be added. In fact, + * consider deleting any existing MAC entry that was provided, since the + * IP is apparently no longer in use. + */ + + if (!addr || addr == IP_ADDR_BROADCAST) { + VNETKdPrint((MODULE_NAME "AddIPMAC: trying to add IP 0.0.0.0 or " + "255.255.255.255, disallowing add & removing MAC entry\n")); + return TRUE; + } + + ACQUIRESPINLOCK(&state->smacSpinLock); + + /* + * Lookup table entry for specified IP addr and ethernet MAC. + */ + + entryIP = LookupByIPNoAcquireLock(state, addr); + + /* + * If an entry for the specified IP addr was found, and the MACs match, + * then we don't need to add a new entry nor modify any existing entries + * and can return immediately. + */ + + if (entryIP && MAC_EQ(entryIP->mac, mac)) { + VNETKdPrint((MODULE_NAME "AddIPMAC: entry already exists, " + "and matches current IP/MAC\n")); + + /* + * Update the cached entry to this new request. + */ + + SetCacheEntry(state, entryIP); + goto exit; + } + + /* + * If no table entry was found for the IP, then this is a completely new add + * (also, no changes need to made to pre-existing table entries). + */ + + if (!entryIP) { + uint8 ipHash = IP_HASH(addr); + + IPmacLookupEntry *entry = (IPmacLookupEntry*) + ALLOCATEMEMORY(sizeof *entry, REORDER_TAG('SMle')); + VNETKdPrint((MODULE_NAME "AddIPMACnew: neither MAC or IP is in table," + " so adding new entry for " + "%d.%d.%d.%d %02x:%02x:%02x:%02x:%02x:%02x\n", + addr&0xff,(addr>>8)&0xff, (addr>>16)&0xff, (addr>>24)&0xff, + mac[0]&0xff, mac[1]&0xff, mac[2]&0xff, mac[3]&0xff, + mac[4]&0xff, mac[5]&0xff)); + + if (!entry) { + // entry allocation error + VNETKdPrint((MODULE_NAME "AddIPMACnew: Failed to allocate " + " MAC/IP entry\n")); + result = FALSE; + goto exit; + } + + ++state->numberOfIPandMACEntries; + + // initialize the contents of the table entry + entry->IPv4address = addr; + entry->lastAccess = 0; /* initialize to 0 for sanity, although it's not vital */ + + MEMCPY(entry->mac, mac, ETH_ALEN); + + // add entry to IP hash table + entry->ipNext = state->IPlookupTable[ipHash]; + state->IPlookupTable[ipHash] = entry; + + VNETKdPrint((MODULE_NAME "AddIPMACnew: entry allocated, and added\n")); + SetCacheEntry(state, entry); + TrimLookupTableIfNecessary(state); + + } else { + + /* + * If table entry was found for IP, but the MACs don't match, then this means + * that a new/different ethernet device/MAC is using the IP address. We need + * to update the contents of the table entry to specify the new MAC + */ + + VNETKdPrint((MODULE_NAME "AddIPMACmacmod: IP has changed from known " + "MAC %02x:%02x:%02x:%02x:%02x:%02x to new unknown " + "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + entryIP->mac[0]&0xff, entryIP->mac[1]&0xff, + entryIP->mac[2]&0xff, entryIP->mac[3]&0xff, + entryIP->mac[4]&0xff, entryIP->mac[5]&0xff, + mac[0]&0xff, mac[1]&0xff, mac[2]&0xff, mac[3]&0xff, + mac[4]&0xff, mac[5]&0xff)); + + // update MAC in the table entry + MEMCPY(entryIP->mac, mac, ETH_ALEN); + + // update which was the last IP/MAC combo to be added + SetCacheEntry(state, entryIP); + // no new entry added, so no need to call TrimLookupTableIfNecessary() + } + +exit: + + RELEASESPINLOCK(&state->smacSpinLock); + return result; +} + + +/* + * Overview of functions: + * + * "LookupTypeClass" and "LookupTypeName" are used to identify an + * ethernet frame's type, esentially IP, ARP, or neither. + * "LookupTypeName" is used for debugging purposes, since it also + * returns a string representing the name of the type. + * + * When the bridge wishes to send a packet to the host/network, it + * calls "SMAC_CheckPacketToHost", which essentially handles the + * link layer and ARP. If the packet is IPv4 then it calls + * ProcessOutgoingIPv4Packet to analyze (and potentially modify) + * the packet. Currently ProcessOutgoingIPv4Packet only turns on + * the broadcast flag for DHCP client packets. + * + * When the bridge receives a packet from the host/network, it + * calls "SMAC_CheckPacketFromHost", which essentially handles the + * link layer and ARP. If the packet is IPv4 then it calls + * ProcessIncomingIPv4Packet to analyze (and potentially modify) + * the packet. + * + * On Linux, the packet modifications are made to a private clone + * of the network packet. We don't want to modify a packet from + * the host, nor do we want to make modifications in a way that's + * visible to VMs on the same subnet. + * + * On Windows, we only clone packets that are headed towards the host. + * Packets from the host can be modified since they're already a private + * copy. However, we might not have the whole packet and thus need to + * store the changes in a separate table until the whole packet is + * received (at which time the modifications can then be made). + * + * On Mac OS, the packet modifications are made to the original network packet, + * since the packet passed to us is already pre-cloned and private and can be + * modified here. So cloning is faked by simply setting the clone to be a + * pointer to the original packet. + */ + + +/* + *---------------------------------------------------------------------- + * + * SMAC_CheckPacketFromHost -- + * + * Examines the contents of a packet that has been received from + * the network. On Windows the function will provide suggestions + * (via table) for where MAC substitution should occur. + * Function supports IP, ARP, RARP, IARP, and DHCP. On Linux the + * function will clone the packet and make modifications to the + * clone (the caller is responsible for freeing the original and + * the cloned packets). + * + * NOTE: On Windows this function presumes it is called at DISPATCH_LEVEL + * + * Results: + * Returns 'PacketStatusForwardPacket' if packet should/can be + * received, 'PacketStatusDropPacket' if packet should be filtered + * and not received, PacketStatusTooShort if insufficient data + * provided to process packet (suggested action it to receive + * packet in its entirety, and call this function + * again on the whole packet) + * + * Side effects: + * May add/modify the adapter's MAC/IP hash tables. May clone a + * packet if function returns PacketStatusForwardPacket. + * + *---------------------------------------------------------------------- + */ + +PacketStatus SMACINT +SMAC_CheckPacketFromHost(SMACState *state, // IN: pointer to state + SMACPackets *packets) // IN/OUT: packet to process +{ + EthernetHeader eh; + EthClass typeClass; + SMACPacket *packet = NULL; // original packet from host + + ASSERT(state); + ASSERT(packets); + + WW_VNETKdPrint((MODULE_NAME "FromHost: Called\n")); + + ASSERTLOCKHELD(); + +#ifdef _WIN32 + { + MacReplacementTable *macTable = packets->table; + ASSERT(macTable); + macTable->numOfOffsets = 0; + } +#endif /* _WIN32 */ + + packet = &(packets->orig); + +#ifdef __linux__ + if (SMACL_LinearizeSkb(packet->skb)) { + VNETKdPrint((MODULE_NAME "FromHost: Failed to Linearize packet, dropping\n")); + return PacketStatusDropPacket; + } +#endif /* __linux__ */ + + + /* + * Read in the Ethernet header, and return failure if this + * is a runt packet that doesn't have a whole header + */ + + ASSERT(sizeof eh == ETH_HLEN); + if (!GetPacketData(packet, 0, sizeof eh, &eh)) { + VNETKdPrint((MODULE_NAME "FromHost: Packet missing eth header\n")); + return PacketStatusDropPacket; // instruct bridge to drop this runt packet + } + +#ifdef __linux__ + /* + * Reject the duplicate packet (occurs only in Infrastructure mode) + * + * When the vm is communicating with the host, the host arp table + * would have the vm's mac address same as the physical hw address. + * so when SMAC_PacketFromHost is called it will create a duplicate of + * the packet and let the original pass as is, this original packet + * would then be transmitted on the network, where the AP would return + * it back to us because it matches the hardware address , this is the + * duplicate packet we are talking about. + */ + if (SMACL_IsSkbHostBound(packet->skb) && + MAC_EQ(state->macAddress, eh.srcAddr)) { + W_VNETKdPrint((MODULE_NAME "FromHostIP: incoming request has " + "same mac as destination, so blackholing\n")); + return PacketStatusDropPacket; + } +#endif + + /* + * Lookup the ethernet media type of the packet + */ + + typeClass = LookupTypeClass(ntohs(eh.lengthType)); + + /* + * For reference, the VLAN support was removed since it was determined that + * for Windows, such information would be present only in the OOB area of a + * NDIS packet, and thus no specific support/handling for VLAN is required + * for that OS. + * + * For any other OS, we need to add support to the vmnet driver for that OS + * to allow VLAN tagged frames. + */ + +#if 0 + + /* + * If broadcast, then allow packet with no further checks. We might be + * able to actually enable this code, depending on how we want to handle + * DHCP replies. Currently DHCP replies don't need to be processed, so + * it's probably okay to enable this. Currently it's disabled so that + * the debug statements can continue to give us information about each + * packet. + */ + + if (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr)) { + return PacketStatusForwardPacket; + } + +#endif /* 0 */ + + /* + * DEBUG: if not IP & not ARP + */ + + if (typeClass != EthClassIP && typeClass != EthClassARP) { + + /* + * If not a common/known media type, then print a status + * message and return + */ + +#ifdef DBG + if (typeClass != EthClassCommon) { // print only if not a common type + char type[50] = ""; // holds textual name of type + LookupTypeName(ntohs(eh.lengthType), type); // lookup ethernet type + VNETKdPrint((MODULE_NAME "FromHost: non-IP & non-ARP %s " + "%02x:%02x:%02x:%02x:%02x:%02x -> " + "%02x:%02x:%02x:%02x:%02x:%02x %s\n", + (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr))? + "(b|m)cast":"ucast", + eh.srcAddr[0], eh.srcAddr[1], eh.srcAddr[2], + eh.srcAddr[3], eh.srcAddr[4], eh.srcAddr[5], + eh.destAddr[0], eh.destAddr[1], eh.destAddr[2], + eh.destAddr[3], eh.destAddr[4], eh.destAddr[5], type)); + } +#endif /* DBG */ + + /* + * Let these unrecognized packets through only if they are broadcast or + * multicast. Drop unicast packets because it's easier to debug a lack + * of traffic than damaged traffic. + */ + + if (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr)) { + VNETKdPrint((MODULE_NAME "FromHost: Forward unrecognized " + "non-arp/ip b/mcast\n")); + return PacketStatusForwardPacket; + } else { +#ifdef DBG + char type[50] = ""; // holds textual name of type + LookupTypeName(ntohs(eh.lengthType), type); + VNETKdPrint((MODULE_NAME "FromHost: Dropping unrecognized " + "unicast non-IP & non-ARP unicast packet: %s\n", type)); + VNETKdPrint((MODULE_NAME "FromHost: the non-IP & non-ARP is " + "%02x:%02x:%02x:%02x:%02x:%02x -> " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + eh.srcAddr[0], eh.srcAddr[1], eh.srcAddr[2], + eh.srcAddr[3], eh.srcAddr[4], eh.srcAddr[5], + eh.destAddr[0], eh.destAddr[1], eh.destAddr[2], + eh.destAddr[3], eh.destAddr[4], eh.destAddr[5])); +#endif + /* + * Drop non-IP/non-ARP unicast packets, unless we've been + * requested to forward unknown/unrecognized packets. + */ + + if (state->smacFowardUnknownPackets) { + return PacketStatusForwardPacket; + } else { + return PacketStatusDropPacket; + } + } + } + + /* + * If IP packet, then lookup ethernet MAC based on dest IP and replace + * dest ethernet MAC with that of the lookup table entry + */ + + if (typeClass == EthClassIP) { // if IP packet + uint8 ipHeader[IP_HEADER_LEN]; // IP header + uint32 ipVer; // IP header ver + uint32 ipHeaderLen; // IP header length + + /* Verify that we have at least a whole, minimal IP header */ + if (!GetPacketData(packet, ETH_HLEN, sizeof ipHeader, ipHeader)) { + VNETKdPrint((MODULE_NAME "FromHostIP: Got type IP, " + "but only have partial IP header\n")); + return PacketStatusTooShort; + } + + ipVer = ipHeader[0] >> 4; // IP header ver + ipHeaderLen = 4 * (ipHeader[0] & 0xf); // IP header length + + /* + * Verify basic fields in IP header + */ + + if (ipVer != 4 || ipHeaderLen < 20 || + (GetPacketLength(packet) - ETH_HLEN) < ipHeaderLen) { + VNETKdPrint((MODULE_NAME "FromHostIP: got an IP version %d, " + "or len %d < reported len %d\n", ipVer, + GetPacketLength(packet) - ETH_HLEN, ipHeaderLen)); + if ((GetPacketLength(packet) - ETH_HLEN) < ipHeaderLen) { + + /* + * insufficient data -- process anyway since we have the necessary + * amount of information (first 20 bytes) to process this packet? + */ + + VNETKdPrint((MODULE_NAME "FromHostIP: got an IP " + "that's too short\n")); + return PacketStatusTooShort; + } else { + VNETKdPrint((MODULE_NAME "FromHostIP: got an IP " + "that's unrecognised\n")); + return PacketStatusDropPacket; // invalid/unrecognized data + } + } + + /* + * broadcast/multicast processing: don't modify dest MAC but check if the + * payload should be modified + * + * unicast processing: modify MAC (if packet destined for VM) and check if + * the payload should be modified + */ + + if (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr)) { + + /* + * Check if payload should be modified. + */ + + /* + * NOTE: ProcessIncomingIPv4Packet doesn't currently modify packets, + * so in an actual product release we can remove this call. + */ + +#ifdef DBG + ProcessIncomingIPv4Packet(packet, FALSE); +#endif + W_VNETKdPrint((MODULE_NAME "FromHostIP: forward b/mcast IP\n")); + return PacketStatusForwardPacket; + + } else { // unicast ethernet + + uint32 destIP; + Bool foundMac; + uint8 vmMacAddress[ETH_ALEN]; + + destIP = *((uint32*)(ipHeader + IP_HEADER_DEST_ADDR_OFFSET)); + + /* + * For unicast IP processing: lookup MAC based on IP addr + */ + + foundMac = LookupByIP(state, destIP, vmMacAddress); + + if (!foundMac && destIP == IP_ADDR_BROADCAST) { + /* + * If IP destination address is the IP limited broadcast address + * '255.255.255.255', then SMAC the unicast ethernet MAC address into + * the ethernet broadcast MAC address 'ff:ff:ff:ff:ff:ff' and forward + * the packet. + * + * Certain DHCP Servers/Relay Agents choose to ignore the + * recommendations of RFC 1542 "Clarifications and Extensions for the + * Bootstrap Protocol" section 4.1.2, and send DHCP Offers/ACKs to a + * unicast ethernet address in response to DHCP Discovers/Requests + * with the "Broadcast" flag set. See PRs 224129, 172947. + * + * Other than such packets, there shouldn't be any other IPv4 packets + * sent to the IP limited broadcast address but not to the ethernet + * broadcast address, but even if there are, we'll forward such + * packets onto the VNet and let the guests decide what to do about + * them. + */ + MEMSET(vmMacAddress, 0xFF, ETH_ALEN); + foundMac = TRUE; + } + + if (foundMac) { // if IP is known on VNet, then substitute MAC + W_VNETKdPrint((MODULE_NAME "FromHostIP: would assign MAC" + " of %d.%d.%d.%d to packet\n", + (destIP>> 0)&0xff, (destIP>> 8)&0xff, + (destIP>>16)&0xff, (destIP>>24)&0xff)); + + /* + * Eth dest MAC needs to be corrected + */ + + if (!CopyDataForPacketFromHost(packets, 0, 0, vmMacAddress)) { + VNETKdPrint((MODULE_NAME "FromHostIP: couldn't clone packet\n")); + return PacketStatusDropPacket; + } + + /* + * NOTE: ProcessIncomingIPv4Packet doesn't currently modify packets, + * so in an actual product release we can remove this call. + */ + +#ifdef DBG + ProcessIncomingIPv4Packet(packet, foundMac); +#endif /* DBG */ + W_VNETKdPrint((MODULE_NAME "FromHostIP: forward IP\n")); + return PacketStatusForwardPacket; + } else { // IP is unknown on VNet + VNETKdPrint((MODULE_NAME "FromHostIP: could not find IP " + "%d.%d.%d.%d in lookup, so drop\n", + (destIP>>0)&0xff, (destIP>>8)&0xff, + (destIP>>16)&0xff, (destIP>>24)&0xff)); + if (state->smacFowardUnknownPackets) { + return PacketStatusForwardPacket; + } else { + return PacketStatusDropPacket; // drop packet + } + } // end IP addr lookup + } // end unicast + } // end IP + + /* + * If ARP packet, then lookup ethernet MAC based on dest IP and replace + * dest ethernet MAC (and potentially ARP MAC) with that of the lookup table entry + */ + + else { // if ARP packet: typeClass == EthClassARP + uint32 arpHeaderWord1; // first word in ARP header + uint32 arpHeaderWord2; // second word in ARP header + + if (GetPacketLength(packet) < ETH_HLEN + ARP_HEADER_LEN) { + VNETKdPrint((MODULE_NAME "FromHostARP: ARP packet is insufficient " + "length of IPv4 and Ethernet, expected %d got %d\n", + ETH_HLEN + ARP_HEADER_LEN, GetPacketLength(packet))); + return PacketStatusTooShort; + } + + /* + * Verify the first word of ARP header (hardcoded for ethernet and IPv4) + * + * I recently added IEEE802 support. These types of ARP requests were + * observed on the company network, so someone uses them. As long as + * the address lengths are the same then I imagine that the processing + * is identical and we can handle them (lengths are checked as part + * of processing the second word of ARP header). + */ + + if (!GetPacketData(packet, ETH_HLEN, sizeof arpHeaderWord1, + &arpHeaderWord1)) { + VNETKdPrint((MODULE_NAME "FromHostARP: couldn't read " + "ARP header #1\n")); + return PacketStatusTooShort; + } + + if (arpHeaderWord1 != HTONL(0x00010800) /* ethernet */ && + arpHeaderWord1 != HTONL(0x00060800) /* ieee802 */ ) { + VNETKdPrint((MODULE_NAME "FromHostARP: ARP header1 appears " + "wrong, got %08x\n", arpHeaderWord1)); + return PacketStatusDropPacket; + } + + /* + * Perform action based on opcode in second word of ARP header. + */ + + if (!GetPacketData(packet, ETH_HLEN + sizeof arpHeaderWord1, + sizeof arpHeaderWord2, &arpHeaderWord2)) { + VNETKdPrint((MODULE_NAME "FromHostARP: couldn't read " + "ARP header #2\n")); + return PacketStatusTooShort; + } + +#ifdef DBG + + /* + * DEBUG: print general information about the packet + */ + + switch (arpHeaderWord2) { + case NTOHL(0x06040001): + WW_VNETKdPrint((MODULE_NAME "FromHostARP: " + "ARP header2 indicates ARP request\n")); + break; + case NTOHL(0x06040002): + W_VNETKdPrint((MODULE_NAME "FromHostARP: " + "ARP header2 indicates ARP reply\n")); + break; + case NTOHL(0x06040003): + VNETKdPrint((MODULE_NAME "FromHostARP: " + "ARP header2 indicates RARP request\n")); + break; + case NTOHL(0x06040004): + VNETKdPrint((MODULE_NAME "FromHostARP: " + "ARP header2 indicates RARP reply\n")); + break; + case NTOHL(0x06040008): + VNETKdPrint((MODULE_NAME "FromHostARP: " + "ARP header2 indicates IARP request\n")); + break; + case NTOHL(0x06040009): + VNETKdPrint((MODULE_NAME "FromHostARP: " + "ARP header2 indicates IARP reply\n")); + break; + default: + VNETKdPrint((MODULE_NAME "FromHostARP: " + "ARP header2 indicates unknown opcode\n")); + break; + } + + { + uint8 data[ETH_ALEN + 4] = {0}; // MAC and IP in one contiguous buffer + if (GetPacketData(packet, ETH_HLEN + ARP_SENDER_MAC_OFFSET, + sizeof data, data)) { + WW_VNETKdPrint((MODULE_NAME "FromHostARP: sender MAC is " + "%02x:%02x:%02x:%02x:%02x:%02x IP is %d.%d.%d.%d\n", + ((unsigned char*)data)[0]&0xff, ((unsigned char*)data)[1]&0xff, + ((unsigned char*)data)[2]&0xff, ((unsigned char*)data)[3]&0xff, + ((unsigned char*)data)[4]&0xff, ((unsigned char*)data)[5]&0xff, + ((unsigned char*)data)[6]&0xff, ((unsigned char*)data)[7]&0xff, + ((unsigned char*)data)[8]&0xff, ((unsigned char*)data)[9]&0xff)); + } else { + VNETKdPrint((MODULE_NAME "FromHostARP: couldn't read " + "sender MAC/IP\n")); + } + + if (GetPacketData(packet, ETH_HLEN + ARP_TARGET_MAC_OFFSET, + sizeof data, data)) { + WW_VNETKdPrint((MODULE_NAME "FromHostARP: target MAC is " + "%02x:%02x:%02x:%02x:%02x:%02x IP is %d.%d.%d.%d\n", + ((unsigned char*)data)[0]&0xff, ((unsigned char*)data)[1]&0xff, + ((unsigned char*)data)[2]&0xff, ((unsigned char*)data)[3]&0xff, + ((unsigned char*)data)[4]&0xff, ((unsigned char*)data)[5]&0xff, + ((unsigned char*)data)[6]&0xff, ((unsigned char*)data)[7]&0xff, + ((unsigned char*)data)[8]&0xff, ((unsigned char*)data)[9]&0xff)); + } else { + VNETKdPrint((MODULE_NAME "FromHostARP: couldn't read " + "target MAC/IP\n")); + } + } + +#endif + + /* + * ARP handling for *incoming traffic* + * + * ARP: host wants to know the MAC that corresponds to a particular IP + * 1 ARP request: + * ALLOW CONDITIONALLY: if dest eth mac broadcast then nothing to modify, + * otherwise need to patch ucast dest eth mac. + * 2 ARP reply: + * ALLOW IF BROADCAST: broadcast so nothing to modify (except ARP dest MAC?) + * ALLOW IF LOOKUP: lookup dstIP and mofify dstMAC (ðDestMAC) to match VM + * + * RARP: host knows its MAC and wants to find out which IP it is assigned + * 3 RARP request: can't store , + * ALLOW CONDITIONALLY: if dest eth mac broadcast then nothing to modify, + * otherwise need to patch ucast dest eth mac. + * 4 RARP reply: + * ALLOW IF BROADCAST: broadcast so nothing to modify (except ARP dest MAC?) + * ALLOW IF LOOKUP: lookup dstIP and modify dstMAC (ðDestMAC) to match VM + * + * IARP: host knows a peer's MAC and wants to determine its IP address + * 8 IARP request: + * ALLOW CONDITIONALLY: if dest eth mac broadcast then nothing to modify, + * otherwise need to patch ucast dest eth mac. + * 9 IARP reply: + * ALLOW IF BROADCAST: broadcast so nothing to modify (except ARP dest MAC?) + * ALLOW IF LOOKUP: lookup dstIP and modify dstMAC (ðDestMAC) to match VM + */ + + if (arpHeaderWord2 == HTONL(0x06040001) || // If ARP request + arpHeaderWord2 == HTONL(0x06040003) || // If RARP request + arpHeaderWord2 == HTONL(0x06040008)) { // If IARP request + + uint32 targetAddr; + uint32 sourceAddr; + Bool foundIP; + + if (!GetPacketData(packet, ETH_HLEN + ARP_TARGET_IP_OFFSET, + sizeof targetAddr, &targetAddr) || + !GetPacketData(packet, ETH_HLEN + ARP_SENDER_IP_OFFSET, + sizeof sourceAddr, &sourceAddr)) { + VNETKdPrint((MODULE_NAME "FromHostARP: " + "couldn't read target and/or sourceAddr\n")); + return PacketStatusTooShort; + } + + /* + * Some host configurations will require allowing packet loopback, meaning + * that we'll see the packets that we're transmitting. Since we're performing + * MAC tricks, the guest could see its own ARP request--this echoed ARP request + * will contain the host's wireless MAC, and thus the guest OS might think that + * there is a address conflict. Thus, if we receive an ARP request whose source + * IP address is a known VM, and the MAC is the wireless hardware, then the + * ARP request is dropped. This will allow address conflicts to be detected + * when a conflict exists with another device, but it prevents conflict + * detection when the conflict is present on/within the host. + */ + + foundIP = LookupByIP(state, sourceAddr, NULL); + if (foundIP) { // if known IP is contained within request + uint8 packetMac[ETH_ALEN]; + VNETKdPrint((MODULE_NAME "FromHostARP: observed a " + "incoming request from an IP we know about\n")); + + if (!GetPacketData(packet, ETH_HLEN + ARP_SENDER_MAC_OFFSET, + sizeof packetMac, packetMac)) { + VNETKdPrint((MODULE_NAME "FromHostARP: " + "couldn't read MAC\n")); + return PacketStatusTooShort; + } + + /* + * Check if the sender MAC is using the wireless MAC + */ + + if (MAC_EQ(state->macAddress, packetMac)) { + + /* + * Sender is using wireless MAC, so drop packet + * -- the reasons for this are stated above in the large comment block. + */ + + VNETKdPrint((MODULE_NAME "FromHostARP: incoming request using " + "wireless hardware addr, so blackholing\n")); + return PacketStatusDropPacket; + } + /* + * Requester IP matches a VM IP, but the source MAC is different. + * This is apparently a true conflict with another network peer, so + * we'll forward the packet + */ + VNETKdPrint((MODULE_NAME "FromHostARP: incoming request using " + "non-wireless-hardware-addr, may conflict--allowing\n")); + } else { + /* + * We don't have information about the source (typical case), + * so forward the packet. + */ + WW_VNETKdPrint((MODULE_NAME "FromHostARP: got ARP, no record of " + "source so forward\n")); + } + + if (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr)) { + /* dest mac is broacast, so can just forward */ + return PacketStatusForwardPacket; + } else if (!MAC_EQ(state->macAddress, eh.destAddr)) { + VNETKdPrint((MODULE_NAME "FromHostARP: incoming request using " + "non-wireless-hardware-addr eth dest MAC, dropping\n")); + return PacketStatusDropPacket; + } else { + Bool foundMac; + uint8 vmMacAddress[ETH_ALEN]; + + /* + * Someone sent request to VM with the host's destination MAC, + * so need to patch this with the VM's MAC so the VM can reply. + */ + + /* + * Unicast destination--lookup MAC in table. If entry exists then + * do MAC replacement and return. Otherwise, drop the packet + */ + + foundMac = LookupByIP(state, targetAddr, vmMacAddress); + if (!foundMac) { + W_VNETKdPrint((MODULE_NAME "FromHostARP: target IP in request ARP was" + " NOT found in table, presuming for another peer\n")); + return PacketStatusDropPacket; + } + + VNETKdPrint((MODULE_NAME "FromHostARP: target IP in " + "request ARP was found in table\n")); + +#ifdef DBG + { + uint8 packetMac[ETH_ALEN]; + if (!GetPacketData(packet, ETH_HLEN + ARP_TARGET_MAC_OFFSET, + sizeof packetMac, packetMac)) { + VNETKdPrint((MODULE_NAME "FromHostARP: " + "couldn't read MAC\n")); + return PacketStatusTooShort; + } + W_VNETKdPrint((MODULE_NAME "FromHostARP: will modify request " + "ARP ETH MAC %02x.%02x.%02x.%02x.%02x.%02x " + "dest address and ARP target address " + "%02x.%02x.%02x.%02x.%02x.%02x to " + "match VM %02x.%02x.%02x.%02x.%02x.%02x\n", + eh.destAddr[0], eh.destAddr[1], eh.destAddr[2], + eh.destAddr[3], eh.destAddr[4], eh.destAddr[5], + packetMac[0], packetMac[1], packetMac[2], + packetMac[3], packetMac[4], packetMac[5], + vmMacAddress[0], vmMacAddress[1], vmMacAddress[2], + vmMacAddress[3], vmMacAddress[4], vmMacAddress[5])); + } +#endif + /* + * Copy in the MAC that will be written to eth dest MAC. + */ + + if (!CopyDataForPacketFromHost(packets, 0, 0, vmMacAddress)) { + W_VNETKdPrint((MODULE_NAME "FromHostIP: couldn't clone request packet\n")); + return PacketStatusDropPacket; + } + return PacketStatusForwardPacket; + } + } + + if (arpHeaderWord2 == HTONL(0x06040002) || // If ARP reply + arpHeaderWord2 == HTONL(0x06040004) || // If RARP reply + arpHeaderWord2 == HTONL(0x06040009)) { // If IARP reply + uint32 targetAddr; + Bool foundMac; + uint8 vmMacAddress[ETH_ALEN]; + + if (!GetPacketData(packet, ETH_HLEN + ARP_TARGET_IP_OFFSET, + sizeof targetAddr, &targetAddr)) { + VNETKdPrint((MODULE_NAME "FromHostARP: couldn't target IP\n")); + return PacketStatusTooShort; + } + + /* + * If broadcast then return because we don't need to modify anything + */ + + if (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr)) { + VNETKdPrint((MODULE_NAME "FromHostARP: observed a " + "broadcast ARP, RARP, or IARP reply packet\n")); + + /* + * Don't need to make changes since target MAC is the broadcast addr + */ + + /* + * Ethernet MAC is broadcast, but the dest ARP address might + * be unicast (in fact, it likely is), so we should patch the + * destination ARP MAC address?? + */ + + foundMac = LookupByIP(state, targetAddr, vmMacAddress); + if (foundMac) { + uint8 packetMac[ETH_ALEN]; + + VNETKdPrint((MODULE_NAME "FromHostARP: target IP in " + "broadcast reply ARP was found in table\n")); + + if (!GetPacketData(packet, ETH_HLEN + ARP_TARGET_MAC_OFFSET, + sizeof packetMac, packetMac)) { + VNETKdPrint((MODULE_NAME "FromHostARP: " + "couldn't read MAC\n")); + return PacketStatusTooShort; + } + + W_VNETKdPrint((MODULE_NAME "FromHostARP: will modify reply " + "ARP target address %02x.%02x.%02x.%02x.%02x.%02x to " + "match VM %02x.%02x.%02x.%02x.%02x.%02x\n", + packetMac[0], packetMac[1], packetMac[2], + packetMac[3], packetMac[4], packetMac[5], + vmMacAddress[0], vmMacAddress[1], vmMacAddress[2], + vmMacAddress[3], vmMacAddress[4], vmMacAddress[5])); + + /* + * Copy in the MAC that will be written to ARP dest MAC + */ + + if (!CopyDataForPacketFromHost(packets, 0, + ETH_HLEN + ARP_TARGET_MAC_OFFSET, + vmMacAddress)) { + VNETKdPrint((MODULE_NAME "FromHostIP: couldn't " + "clone packet\n")); + return PacketStatusDropPacket; + } + return PacketStatusForwardPacket; + } else { + W_VNETKdPrint((MODULE_NAME "FromHostARP: target IP in broadcast " + "reply ARP was NOT found in table\n")); + return PacketStatusForwardPacket; + } + } + + W_VNETKdPrint((MODULE_NAME "FromHostARP: target IP is %d.%d.%d.%d\n", + (targetAddr)&0xff, (targetAddr>>8)&0xff, + (targetAddr>>16)&0xff, (targetAddr>>24)&0xff)); +#ifdef DBG + { + uint32 senderAddr; + if (!GetPacketData(packet, ETH_HLEN + ARP_SENDER_IP_OFFSET, + sizeof senderAddr, &senderAddr)) { + VNETKdPrint((MODULE_NAME "FromHostARP: couldn't " + "read IP addr\n")); + return PacketStatusTooShort; + } + W_VNETKdPrint((MODULE_NAME "FromHostARP: sender IP %d.%d.%d.%d\n", + (senderAddr&0xff), (senderAddr>>8)&0xff, + (senderAddr>>16)&0xff, (senderAddr>>24)&0xff)); + } +#endif + + /* + * Unicast destination--lookup MAC in table. If entry exists then + * do MAC replacement and return. Otherwise, drop the packet + */ + + // see if the reply is for a host that we're aware of, and modify as necessary + foundMac = LookupByIP(state, targetAddr, vmMacAddress); + if (foundMac) { + VNETKdPrint((MODULE_NAME "FromHostARP: target IP in " + "reply ARP was found in table\n")); + +#ifdef DBG + { + uint8 packetMac[ETH_ALEN]; + if (!GetPacketData(packet, ETH_HLEN + ARP_TARGET_MAC_OFFSET, + sizeof packetMac, packetMac)) { + VNETKdPrint((MODULE_NAME "FromHostARP: " + "couldn't read MAC\n")); + return PacketStatusTooShort; + } + W_VNETKdPrint((MODULE_NAME "FromHostARP: will modify reply " + "ARP ETH MAC %02x.%02x.%02x.%02x.%02x.%02x " + "dest address and ARP target address " + "%02x.%02x.%02x.%02x.%02x.%02x to " + "match VM %02x.%02x.%02x.%02x.%02x.%02x\n", + eh.destAddr[0], eh.destAddr[1], eh.destAddr[2], + eh.destAddr[3], eh.destAddr[4], eh.destAddr[5], + packetMac[0], packetMac[1], packetMac[2], + packetMac[3], packetMac[4], packetMac[5], + vmMacAddress[0], vmMacAddress[1], vmMacAddress[2], + vmMacAddress[3], vmMacAddress[4], vmMacAddress[5])); + } +#endif + /* + * Copy in the MAC that will be written to eth + * dest MAC and ARP dest MAC + */ + + if (!CopyDataForPacketFromHost(packets, 0, 0, vmMacAddress)) { + W_VNETKdPrint((MODULE_NAME "FromHostIP: couldn't " + "clone packet\n")); + return PacketStatusDropPacket; + } + if (!CopyDataForPacketFromHost(packets, 1, + ETH_HLEN + ARP_TARGET_MAC_OFFSET, + vmMacAddress)) { + W_VNETKdPrint((MODULE_NAME "FromHostIP: " + "couldn't clone packet #2\n")); + return PacketStatusDropPacket; + } + + return PacketStatusForwardPacket; + } else { + W_VNETKdPrint((MODULE_NAME "FromHostARP: target IP in reply ARP was" + " NOT found in table, presuming for another peer\n")); + return PacketStatusDropPacket; + } + } + VNETKdPrint((MODULE_NAME "FromHostARP: unrecognized ARP type %08x\n", + arpHeaderWord2)); + return PacketStatusDropPacket; + } +} + + +/* + *---------------------------------------------------------------------- + * + * SMAC_CheckPacketToHost -- + * + * Modifies packet contents to be suitable for transmission over + * a wireless network. Function supports IP, ARP, RARP, IARP. + * Function will support DHCP in the future. This function clones + * the source packet, modifies the clone packet in situations + * where the packet should be forwarded to the host. + * + * NOTE: On Windows this function presumes it is called at DISPATCH_LEVEL + * + * Results: + * Returns 'PacketStatusTooShort' if insufficient data to process + * packet (suggest packet drop), 'PacketStatusDropPacket' if the + * packet should be dropped, or 'PacketStatusForwardPacket' if + * the packet should be forwarded. + * + * Side effects: + * Modifies contents of network packet, if nessary. + * + *---------------------------------------------------------------------- + */ + +PacketStatus SMACINT +SMAC_CheckPacketToHost(SMACState *state, // IN: pointer to state + SMACPackets *packets) // IN/OUT: packet to process; cloned/modified packet +{ + uint8 buf[sizeof(EthernetHeader) + 4]; /* allocate extra 4 for VLAN headers */ + EthernetHeader *eh = (EthernetHeader*)buf; + uint32 ethHeaderLen = ETH_HLEN; // tracks length of ethernet header + SMACPacket *packet = NULL; + EthClass typeClass; // classification of ethernet frame's type + + ASSERT(state); + + W_VNETKdPrint((MODULE_NAME "ToHost: Called\n")); + ASSERTLOCKHELD(); + ASSERT(sizeof(EthernetHeader) == ETH_HLEN); + + packet = &(packets->orig); + ASSERT(packet); + +#ifdef __linux__ + if (SMACL_LinearizeSkb(packet->skb)) { + VNETKdPrint((MODULE_NAME "ToHost: Failed to Linearize packet, dropping\n")); + return PacketStatusDropPacket; + } +#endif /* __linux__ */ + + /* + * Verify that we have at least a minimal packet + */ + + if (!GetPacketData(packet, 0, ethHeaderLen, eh)) { + VNETKdPrint((MODULE_NAME "ToHost: Packet missing eth header\n")); + return PacketStatusTooShort; + } + + /* + * Lookup the ethernet media type of the packet + */ + + typeClass = LookupTypeClass(ntohs(eh->lengthType)); + + /* + * If packet type is a VLAN header, then adjust pointers and + * decode the "real" media type which follows the VLAN header + */ + + if (typeClass == EthClassVLAN) { + uint16 actualType = 0; + + ethHeaderLen +=4; + if (!GetPacketData(packet, 0, ethHeaderLen, eh)) { + VNETKdPrint((MODULE_NAME " ToHost: Packet is using VLAN header, " + "but supplied header is too small\n")); + return PacketStatusTooShort; + } + + actualType = *(uint16*)(((uint8*)&(eh->lengthType)) + 4); + + VNETKdPrint((MODULE_NAME " ToHost: Taking special measures for VLAN\n")); + typeClass = LookupTypeClass(ntohs(actualType)); + } + + /* + * If the packet is not type IP or ARP, then drop the packet + * unless it is a broadcast packet (broadcast packets don't + * require much manipulating, so they should be safe to let thru). + */ + + if (typeClass != EthClassIP && typeClass != EthClassARP) { + + /* + * DEBUG: if not a common/known media type, then print a status message + */ + +#ifdef DBG + if (typeClass != EthClassCommon) { + char type[50] = ""; // holds textual name of type + if (ethHeaderLen == ETH_HLEN) { // if not a vlan packet + LookupTypeName(ntohs(eh->lengthType), type); + } else { // if a vlan packet + uint16 actualType = *(uint16*)(((uint8*)&(eh->lengthType)) + 4); + LookupTypeName(ntohs(actualType), type); + } + VNETKdPrint((MODULE_NAME " ToHost: non-IP & non-ARP " + "%02x:%02x:%02x:%02x:%02x:%02x -> " + "%02x:%02x:%02x:%02x:%02x:%02x %s\n", + eh->srcAddr[0]&0xff, eh->srcAddr[1]&0xff, + eh->srcAddr[2]&0xff, eh->srcAddr[3]&0xff, + eh->srcAddr[4]&0xff, eh->srcAddr[5]&0xff, + eh->destAddr[0]&0xff, eh->destAddr[1]&0xff, + eh->destAddr[2]&0xff, eh->destAddr[3]&0xff, + eh->destAddr[4]&0xff, eh->destAddr[5]&0xff, type)); + } +#endif + + /* + * Let these unrecognized packets through only if they are broadcast or + * multicast, and drop unicast packets (it's easier/debug loss of traffic + * versus corrupted/invalid traffic). + */ + + if (IS_MULTICAST(eh->destAddr) || IS_BROADCAST(eh->destAddr)) { + + /* + * Modify the source address to be that of the wireless hardware, so + * that this packet can be transmitted. First we need to duplicate + * the packet so that other VMs don't get confused about MACs that + * arbitrarily change between the VM's MAC and the host's MAC. + */ + + if (!ClonePacket(packets)) { + VNETKdPrint((MODULE_NAME " ToHost: couldn't clone packet\n")); + return PacketStatusDropPacket; + } + + CopyDataToClonedPacket(packets, state->macAddress, + ETH_ALEN /* offset for source MAC */, + ETH_ALEN /* length */); + return PacketStatusForwardPacket; + } else { + + /* + * Drop the packet, but first display a status message indicating + * that we're dropping this packet (largely so we know what kind/type + * of traffic that we are dropping + */ + +#ifdef DBG + char type[50] = ""; // holds textual name of type + if (ethHeaderLen == ETH_HLEN) { // if not a vlan packet + LookupTypeName(ntohs(eh->lengthType), type); + } else { // if a vlan packet + uint16 actualType = *(uint16*)(((uint8*) & (eh->lengthType)) + 4); + LookupTypeName(ntohs(actualType), type); + } + VNETKdPrint((MODULE_NAME " ToHost: Dropping unrecognized " + "unicast non-IP & non-ARP unicast packet: %s\n", type)); + VNETKdPrint((MODULE_NAME " ToHost: the non-IP & non-ARP is " + "%02x:%02x:%02x:%02x:%02x:%02x -> " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + eh->srcAddr[0]&0xff, eh->srcAddr[1]&0xff, + eh->srcAddr[2]&0xff, eh->srcAddr[3]&0xff, + eh->srcAddr[4]&0xff, eh->srcAddr[5]&0xff, + eh->destAddr[0]&0xff, eh->destAddr[1]&0xff, + eh->destAddr[2]&0xff, eh->destAddr[3]&0xff, + eh->destAddr[4]&0xff, eh->destAddr[5]&0xff)); +#endif + return PacketStatusDropPacket; + } + } + + /* + * If IPv4 packet, then store in lookup + * table and replace source ethernet MAC with that of the wireless hardware + */ + + if (typeClass == EthClassIP) { + uint8 ipHeader[IP_HEADER_LEN]; + + uint32 ipVer; // version of IP header + uint32 ipHeaderLen; // reported length of IP header + + uint16 ipLen; // reported length of IP packet + uint32 ipSrcAddr; // source address + + /* + * If have contents of at least a minimal IP packet header + */ + + if (!GetPacketData(packet, ethHeaderLen, sizeof ipHeader, ipHeader)) { + VNETKdPrint((MODULE_NAME " ToHostIP: got an IP type, " + "but incomplete header\n")); + return PacketStatusTooShort; + } + + ipVer = ipHeader[0]>>4; // version of IP header + ipHeaderLen = 4 * (ipHeader[0]&0xf); // reported length of IP header + + ipLen = ntohs(*(uint16*)(ipHeader + 2)); // packet len + ipSrcAddr = *((uint32*)(ipHeader + IP_HEADER_SRC_ADDR_OFFSET)); + /* + * Verify basic fields in IP header + */ + + if (ipVer != 4 || ipHeaderLen < IP_HEADER_LEN || + GetPacketLength(packet) < ethHeaderLen + ipHeaderLen) { + VNETKdPrint((MODULE_NAME " ToHostIP: got an IP version %d, " + "or len %d < reported len %d\n", ipVer, + GetPacketLength(packet), ethHeaderLen + ipHeaderLen)); + return PacketStatusDropPacket; + } + + W_VNETKdPrint((MODULE_NAME " ToHostIP: processing IP packet\n")); + + /* + * Store IP/MAC combo in lookup table, that way we can replace + * the MAC when any replies to this IP are received + */ + + if (!AddIPv4andMACcombo(state, ipSrcAddr, eh->srcAddr)) { + return PacketStatusDropPacket; + } + + /* + * Replace source MAC with wireless hardware MAC + */ + + W_VNETKdPrint((MODULE_NAME " ToHostIP: modifying ETH MAC " + "%02x.%02x.%02x.%02x.%02x.%02x source address to match " + "wireless hardware %02x.%02x.%02x.%02x.%02x.%02x \n", + eh->srcAddr[0]&0xff, eh->srcAddr[1]&0xff, + eh->srcAddr[2]&0xff, eh->srcAddr[3]&0xff, + eh->srcAddr[4]&0xff, eh->srcAddr[5]&0xff, + state->macAddress[0]&0xff, state->macAddress[1]&0xff, + state->macAddress[2]&0xff, state->macAddress[3]&0xff, + state->macAddress[4]&0xff, state->macAddress[5]&0xff)); + + { + /* + * Duplicate the packet so that other VMs don't get confused about + * MACs that arbitrarily change between the VM's MAC and the host's + * MAC. + */ + + if (!ClonePacket(packets)) { + VNETKdPrint((MODULE_NAME " ToHostIP: couldn't clone packet\n")); + return PacketStatusDropPacket; + } + + CopyDataToClonedPacket(packets, state->macAddress, + ETH_ALEN /* offset for source MAC */, + ETH_ALEN /* length */); + + /* + * Make any necessary modifications to packet payload + */ + + ProcessOutgoingIPv4Packet(&(packets->clone), ethHeaderLen); + + return PacketStatusForwardPacket; + } + } + + /* + * If ARP packet, then store in + * lookup table (if possible) and replace source ethernet MAC (and source + * ARP MAC, if appropriate) with that of the wireless hardware + */ + + else { // typeClass == EthClassARP + uint32 arpHeaderWord1; // first word of ARP header + uint32 arpHeaderWord2; // second word of ARP header + + /* + * Verify that packet meets minimum length expectations, the ARP header + * is 7 words for ethernet and IPv4, but the length may actually be 60 + * due to ethernet's minimum length requirements. + */ + + if (GetPacketLength(packet) < ethHeaderLen + ARP_HEADER_LEN) { + VNETKdPrint((MODULE_NAME " ToHostARP: ARP packet is insufficient " + "length of IPv4 and Ethernet, expected %d got %d\n", + ethHeaderLen + ARP_HEADER_LEN, GetPacketLength(packet))); + return PacketStatusDropPacket; + } + + /* + * Verify the first word of the ARP header (hardcoded for ethernet and IPv4) + * + * I recently added IEEE802 support. These types of ARP requests were + * observed on the company network, so someone uses them. As long as + * the address lengths are the same then I imagine that the processing + * is identical and we can handle them (lengths are checked as part + * of processing the second word of ARP header). + */ + + if (!GetPacketData(packet, ethHeaderLen, sizeof arpHeaderWord1, + &arpHeaderWord1) || + !GetPacketData(packet, ethHeaderLen + sizeof arpHeaderWord1, + sizeof arpHeaderWord2, &arpHeaderWord2)) { + VNETKdPrint((MODULE_NAME "ToHostARP: ARP header couldnt be loaded\n")); + return PacketStatusDropPacket; + } + + if (arpHeaderWord1 != HTONL(0x00010800) /* ethernet */ && + arpHeaderWord1 != HTONL(0x00060800) /* ieee802 */ ) { + VNETKdPrint((MODULE_NAME " ToHostARP: ARP header appears wrong, " + "got %08x\n", arpHeaderWord1)); + return PacketStatusDropPacket; + } + + /* + * Perform action based on opcode in second word of ARP header. + * DEBUG: print general information about the packet + */ + +#ifdef DBG + switch (arpHeaderWord2) { + case NTOHL(0x06040001): + W_VNETKdPrint((MODULE_NAME " ToHostARP: " + "ARP header2 indicates ARP request\n")); + break; + case NTOHL(0x06040002): + W_VNETKdPrint((MODULE_NAME " ToHostARP: " + "ARP header2 indicates ARP reply\n")); + break; + case NTOHL(0x06040003): + VNETKdPrint((MODULE_NAME " ToHostARP: " + "ARP header2 indicates RARP request\n")); + break; + case NTOHL(0x06040004): + VNETKdPrint((MODULE_NAME " ToHostARP: " + "ARP header2 indicates RARP reply\n")); + break; + case NTOHL(0x06040008): + VNETKdPrint((MODULE_NAME " ToHostARP: " + "ARP header2 indicates IARP request\n")); + break; + case NTOHL(0x06040009): + VNETKdPrint((MODULE_NAME " ToHostARP: " + "ARP header2 indicates IARP reply\n")); + break; + default: + VNETKdPrint((MODULE_NAME " ToHostARP: " + "ARP header2 indicates unknown opcode\n")); + break; + } + + { + uint8 packetMac[ETH_ALEN]; + uint8 packetIP[4]; + + if (!GetPacketData(packet, ethHeaderLen + ARP_SENDER_MAC_OFFSET, + sizeof packetMac, packetMac)) { + VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read MAC\n")); + return PacketStatusTooShort; + } + if (!GetPacketData(packet, ethHeaderLen + ARP_SENDER_IP_OFFSET, + sizeof packetIP, packetIP)) { + VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read IP\n")); + return PacketStatusTooShort; + } + + W_VNETKdPrint((MODULE_NAME " ToHostARP: sender MAC is " + "%02x:%02x:%02x:%02x:%02x:%02x IP is %d.%d.%d.%d\n", + packetMac[0], packetMac[1], packetMac[2], + packetMac[3], packetMac[4], packetMac[5], + packetIP[0], packetIP[1], packetIP[2], packetIP[3])); + + if (!GetPacketData(packet, ethHeaderLen + ARP_TARGET_MAC_OFFSET, + sizeof packetMac, packetMac)) { + VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read MAC\n")); + return PacketStatusTooShort; + } + if (!GetPacketData(packet, ethHeaderLen + ARP_TARGET_IP_OFFSET, + sizeof packetIP, packetIP)) { + VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read IP\n")); + return PacketStatusTooShort; + } + + W_VNETKdPrint((MODULE_NAME " ToHostARP: target MAC is " + "%02x:%02x:%02x:%02x:%02x:%02x IP is %d.%d.%d.%d\n", + packetMac[0], packetMac[1], packetMac[2], + packetMac[3], packetMac[4], packetMac[5], + packetIP[0], packetIP[1], packetIP[2], packetIP[3])); + } +#endif + + /* + * ARP handling for *outgoing traffic* + * + * ARP: host wants to know the MAC that corresponds to a particular IP + * 1 ARP request: store source , + * modify source MAC in eth & ARP + * 2 ARP reply: store source , + * modify source MAC in eth & ARP + * + * RARP: host knows its MAC and wants to find out which IP it is + * assigned (simple form of DHCP) + * 3 RARP request: can't store , + * should modify srcMAC but response would be MAC/IP of host + * I'm tempted to blackhole this packet, but for now I will just modify + * the eth MAC and allow it to be sent + * -- for now, presuming that lookup done on second srcMAC, but packet + * sent to first srcMAC (in other words, like IARP). This may + * be more correct / interoperable, but we still won't be able to + * handle RARP replies properly unless they are broadcasted. + * 4 RARP reply: store source , + * modify source MAC in eth & ARP + * + * IARP: host knows a peer's MAC and wants to determine its IP address + * 8 IARP request: store source , + * modify source MAC in eth & ARP + * 9 IARP reply: store source , + * modify source MAC in eth & ARP + */ + + if (arpHeaderWord2 == HTONL(0x06040001) || + arpHeaderWord2 == HTONL(0x06040002) || + arpHeaderWord2 == HTONL(0x06040003) || + arpHeaderWord2 == HTONL(0x06040004) || + arpHeaderWord2 == HTONL(0x06040008) || + arpHeaderWord2 == HTONL(0x06040009)) { + + if (arpHeaderWord2 != HTONL(0x06040003)) { // don't store MAC/IP for RARP req. + uint32 IPaddr; + uint8 packetMac[ETH_ALEN]; + + W_VNETKdPrint((MODULE_NAME " ToHostARP: adding MAC/IP " + "combo to lookup table\n")); + + /* read IP */ + if (!GetPacketData(packet, ethHeaderLen + ARP_SENDER_IP_OFFSET, + sizeof IPaddr, &IPaddr)) { + VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read IP\n")); + return PacketStatusTooShort; + } + + /* read MAC */ + if (!GetPacketData(packet, ethHeaderLen + ARP_SENDER_MAC_OFFSET, + sizeof packetMac, packetMac)) { + VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read MAC\n")); + return PacketStatusTooShort; + } + + /* + * Store combo in table. For MAC we could also use + * (char*)(packet)+ETH_ALEN, but it's more consistent with the ARP + * protocol to use the MAC located within the packet + */ + + if (!AddIPv4andMACcombo(state, IPaddr, packetMac)) { + return PacketStatusDropPacket; + } + } + + /* + * First we need to duplicate the packet so that other VMs don't + * get confused about MACs that arbitrarily change between the + * VM's MAC and the host's MAC. + */ + + { + if (!ClonePacket(packets)) { + VNETKdPrint((MODULE_NAME " ToHostARP: couldn't " + "clone packet\n")); + return PacketStatusDropPacket; + } + + /* + * Substitute sender ethernet MAC with the wireless hardware's MAC + */ + + W_VNETKdPrint((MODULE_NAME " ToHostARP: modifying ETH MAC " + "%02x.%02x.%02x.%02x.%02x.%02x source address to match" + " wireless hardware %02x.%02x.%02x.%02x.%02x.%02x \n", + eh->srcAddr[0]&0xff, eh->srcAddr[1]&0xff, + eh->srcAddr[2]&0xff, eh->srcAddr[3]&0xff, + eh->srcAddr[4]&0xff, eh->srcAddr[5]&0xff, + state->macAddress[0]&0xff, state->macAddress[1]&0xff, + state->macAddress[2]&0xff, state->macAddress[3]&0xff, + state->macAddress[4]&0xff, state->macAddress[5]&0xff)); + + CopyDataToClonedPacket(packets, state->macAddress, ETH_ALEN /* offset */, + ETH_ALEN /* length */); + + /* + * Modify ARP source MAC + */ + + // substitute sender MAC with the wireless hardware's MAC +#ifdef DBG + { + uint8 packetMac[ETH_ALEN]; + if (!GetPacketData(packet, ethHeaderLen + ARP_SENDER_MAC_OFFSET, + sizeof packetMac, packetMac)) { + VNETKdPrint((MODULE_NAME " ToHostARP: " + "couldn't read MAC\n")); + return PacketStatusTooShort; + } + + W_VNETKdPrint((MODULE_NAME " ToHostARP: modifying ETH ARP " + "%02x.%02x.%02x.%02x.%02x.%02x source address to match " + "wireless hardware %02x.%02x.%02x.%02x.%02x.%02x \n", + packetMac[0], packetMac[1], packetMac[2], + packetMac[3], packetMac[4], packetMac[5], + state->macAddress[0], state->macAddress[1], + state->macAddress[2], state->macAddress[3], + state->macAddress[4], state->macAddress[5])); + } +#endif + + CopyDataToClonedPacket(packets, state->macAddress, + ethHeaderLen + ARP_SENDER_MAC_OFFSET /* offset */, + ETH_ALEN /* length */); + return PacketStatusForwardPacket; + } + } + + VNETKdPrint((MODULE_NAME " ToHostARP: unrecognized ARP type %08x\n", + arpHeaderWord2)); + return PacketStatusDropPacket; + } +} + + +/* + *---------------------------------------------------------------------- + * + * ProcessOutgoingIPv4Packet -- + * + * This function is used to examine IPv4 packets, and make any + * adjustments (if necessary) to the IP header and/or payload. + * The caller should have determined that the packet is IPv4 + * before calling this function. + * + * Currently this function just makes sure that the broadcast + * bit is set on outgoing client DHCP packets that are being + * sent to a server. + * + * Results: + * None. + * + * Side effects: + * May modify the contents of the packet. Length should be + * unchanged. + * + *---------------------------------------------------------------------- + */ + +static void +ProcessOutgoingIPv4Packet(SMACPacket *packet, // IN: cloned packet to process + uint32 ethHeaderLen) // IN: length of ethernet header +{ + uint8 proto; // protocol within ip + uint16 ipFlags; // flags and offset + + /* + * Should certain checks, e.g., IP version field, be checked here, + * or assume that caller has already performed this check? + */ + + // check should have been performed by caller + ASSERT(GetPacketLength(packet) >= IP_HEADER_LEN + ethHeaderLen); + + if (!GetPacketData(packet, ethHeaderLen + IP_HEADER_PROTO_OFFSET, + sizeof proto, &proto)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get protocol\n")); + ASSERT(0); // should never occur + return; + } + + if (!GetPacketData(packet, ethHeaderLen + IP_HEADER_FLAGS_OFFSET, + sizeof ipFlags, &ipFlags)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get flags\n")); + ASSERT(0); // should never occur + return; + } + + /* + * Verify offset=0 and M=0: mask off "fragment" flag, + * all others should be zero. This is to ensure that we're processing + * only the front of the actual packet (i.e., validate that what we + * think if offset 0 is really offset 0). + */ + + if (ipFlags & HTONS((uint16)(0xbfff))) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got a fragmented IP " + "(ipFlags %04x), so not performing higher-level processing\n", + ipFlags)); + return; + } + + /* + * NOTE: the following switch statement can be replaced with a single + * check for proto==17, since UDP is the only non-debug case + */ + + switch (proto) { + case 1: { // ICMP +#ifdef DBG + uint8 ipHeader[IP_HEADER_LEN]; + uint32 ipHeaderLen = 0; + uint32 ipVer = 0; + uint16 ipLen = 0; + uint8 typeField = 0; + uint8 codeField = 0; + + /* Verify that we have at least a whole, minimal IP header */ + if (!GetPacketData(packet, ethHeaderLen, sizeof ipHeader, ipHeader)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get IP\n")); + return; + } + + ipHeaderLen = 4 * (ipHeader[0] & 0xf); // version of IP header + ipVer = ipHeader[0] >> 4; // length of IP header + ipLen = ntohs(*(uint16*)(ipHeader + 2)); // total datagram len + + if (ipVer == 4 && GetPacketLength(packet) >= + ipHeaderLen + ethHeaderLen + 2 * 4 && + GetPacketData(packet, ethHeaderLen + ipHeaderLen, + sizeof typeField, &typeField) && + GetPacketData(packet, ethHeaderLen + ipHeaderLen + 1, + sizeof codeField, &codeField)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got ICMP, " + "type = %d, code = %d,\n", typeField, codeField)); + } else { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got ICMP, " + "but couldn't process\n")); + } +#endif /* DBG */ + return; + } + case 2: // IGMP + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got IGMP\n")); + return; + case 4: // IP in IP + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got IP in IP\n")); + return; + case 6: // TCP + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got TCP\n")); + return; + case 17: { // UDP + uint8 ipHeaderFirstByte; + uint32 ipHeaderLen; // length of IP header + uint16 srcPort; // UDP source port + uint16 destPort; // UDP dest port + + if (!GetPacketData(packet, ethHeaderLen, + sizeof ipHeaderFirstByte, &ipHeaderFirstByte)) { + VNETKdPrint((MODULE_NAME "FromHostIP: Failed to get IP length\n")); + return; + } + + ipHeaderLen = 4 * (ipHeaderFirstByte & 0xf); // version of IP header + + W_VNETKdPrint((MODULE_NAME "ProcessOutgoing: got UDP\n")); + + /* + * Verify that sufficient data for UDP packet header is present + */ + + if (GetPacketLength(packet) < ethHeaderLen + ipHeaderLen + UDP_HEADER_LEN) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: UDP header not present\n")); + return; + } + + /* + * decode the source and destination ports in UDP header + */ + + if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen, + sizeof srcPort, &srcPort) || + !GetPacketData(packet, ethHeaderLen + ipHeaderLen + 2, + sizeof destPort, &destPort)) { + VNETKdPrint((MODULE_NAME "FromHostIP: Failed to get UDP ports\n")); + return; + } + + srcPort = ntohs(srcPort); + destPort = ntohs(destPort); + +#ifdef DBG + { + uint8 srcAddr[4]; + uint8 destAddr[4]; + + if (!GetPacketData(packet, ethHeaderLen + IP_HEADER_SRC_ADDR_OFFSET, + sizeof srcAddr, srcAddr) || + !GetPacketData(packet, ethHeaderLen + IP_HEADER_DEST_ADDR_OFFSET, + sizeof destAddr, destAddr)) { + VNETKdPrint((MODULE_NAME "FromHostIP: Failed to get IP addrs\n")); + ASSERT(0); // should never happen + } else { + W_VNETKdPrint((MODULE_NAME "ProcessOutgoing: got UDP, " + "src %d.%d.%d.%d %d dest %d.%d.%d.%d %d\n", + srcAddr[0], srcAddr[1], srcAddr[2], srcAddr[3], srcPort, + destAddr[0], destAddr[1], destAddr[2], destAddr[3], + destPort)); + } + } +#endif + + if (destPort == 67) { // if destined for DHCP server port + uint32 firstDHCPword; + uint16 dhcpFlags; + + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got client " + "DHCP packet destined for a server\n")); + + /* + * Should this really be 300, or something smaller (like the maximum + * length that we'll actually index into the DHCP data)? + */ + + if (GetPacketLength(packet) < ethHeaderLen + ipHeaderLen + + UDP_HEADER_LEN + 300) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: packet " + "too small for DHCP\n")); + return; + } + + /* + * Verify that the first word in the DHCP header matches + * out expectations + */ + + if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen + + UDP_HEADER_LEN, sizeof firstDHCPword, &firstDHCPword)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get first " + "DHCP word\n")); + return; + } + + firstDHCPword = NTOHL(firstDHCPword); + if ((firstDHCPword & 0xffffff00) != 0x01010600) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: DHCP " + "first word appears incorrect\n")); + return; + } + + /* + * Turn on the broadcast flag, just in case. This + * instructs/requests that the server broadcast the reply + * back, which is a nice way to avoid the issue about + * whether to set chaddr to the VM MAC or the wireless MAC. + * + * If chaddr is set to wireless MAC then we'd receive the reply, + * but the DHCP server might confuse us with the host and send + * us a copy of the host's current IP address assignment. This + * confusion should be occur if all OSes used the client identifier + * extension, but we can't rely on this. + * + * If chaddr is set to VM MAC then no alias confusion should occur, + * but the reply might be unicast to the VM's MAC (in which case + * we might not , or will not, receive the reply). To avoid the + * receive issue, it's easiest to just set the broadcast packet + * if it's not already set. + * + * One potential downside is that the VM might be expecting a unicast + * reply, and it's unclear whether it can or will handling a + * broadcast reply properly. We can special case this support, if + * necessary. + */ + + if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen + + UDP_HEADER_LEN + 10, sizeof dhcpFlags, &dhcpFlags)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " + "DHCP flags\n")); + return; + } + + dhcpFlags = ntohs(dhcpFlags); + if (dhcpFlags & 0x8000) { // if flag already set, then no work to do + VNETKdPrint((MODULE_NAME "ProcessOutgoing: DHCP broadcast " + "bit is already set\n")); + } else { + + /* + * Get the original checksum + */ + + uint16 oriChecksum; + + if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen + 6, + sizeof oriChecksum, &oriChecksum)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " + "UDP checksum\n")); + return; + } + oriChecksum = ntohs(oriChecksum); + + VNETKdPrint((MODULE_NAME "ProcessOutgoing: DHCP broadcast bit " + "NOT set, need to do so\n")); + + if (oriChecksum) { // if checksum specified + + /* + * Compute the checksum over the word that we're about to change + */ + + uint32 sumBefore; // checksum before + uint32 sumAfter; // checksum after changes + uint32 sumDiff; // difference in checksum + uint16 newChecksum; // new checksum + + /* checksum bytes 8-11 */ + + if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen + + UDP_HEADER_LEN + 8, + sizeof sumBefore, &sumBefore)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " + "UDP checksum before\n")); + return; + } + + sumBefore = SUM32(sumBefore); // checksum before + + VNETKdPrint((MODULE_NAME "ProcessOutgoing: DHCP UDP checksum " + "is present, changing flags and checksum\n")); + + /* + * Set the actual flag in bytes 10 and 11 + */ + + dhcpFlags |= 0x8000; + + if (!SetPacketByte(packet, ethHeaderLen + ipHeaderLen + + UDP_HEADER_LEN + 11, dhcpFlags & 0xff) || + !SetPacketByte(packet, ethHeaderLen + ipHeaderLen + + UDP_HEADER_LEN + 10, dhcpFlags >> 8)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't set " + "new UDP flags\n")); + return; + } + + /* + * Compute the checksum over the word that we have just changed + */ + + /* checksum (again) bytes 8-11 */ + + if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen + + UDP_HEADER_LEN + 8, + sizeof sumAfter, &sumAfter)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " + "UDP checksum after\n")); + ASSERT(0); // should never occur + return; + } + + sumAfter = SUM32(sumAfter); + + /* + * Compute difference/delta between old and new checksums + */ + + sumDiff = CalcChecksumDiff(sumBefore, sumAfter); + + /* + * Compute new checksum, based on delta from existing checksum + */ + + newChecksum = UpdateSum(oriChecksum, sumDiff); + + /* + * Verify that the new checksum isn't 0 (in which case make it ~0) + */ + + if (!newChecksum) { + newChecksum = 0xffff; + } + + /* + * Write back the new checksum + */ + + if (!SetPacketByte(packet, ethHeaderLen + ipHeaderLen + 6, + newChecksum >> 8) || + !SetPacketByte(packet, ethHeaderLen + ipHeaderLen + 7, + newChecksum & 0xff)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't set " + "new UDP checksum\n")); + return; + } + } else { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: DHCP UDP " + "checksum is NOT present, changing only flags\n")); + /* + * Set the actual flag without modifying checksum + */ + + dhcpFlags |= 0x8000; + if (!SetPacketByte(packet, ethHeaderLen + ipHeaderLen + + UDP_HEADER_LEN + 11, dhcpFlags & 0xff) || + !SetPacketByte(packet, ethHeaderLen + ipHeaderLen + + UDP_HEADER_LEN + 10, dhcpFlags >> 8)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't set " + "new UDP flags, non-checksum case\n")); + return; + } + } + } + +#ifdef DBG + { + uint32 IPDestAddr; + if (!GetPacketData(packet, ethHeaderLen + IP_HEADER_DEST_ADDR_OFFSET, + sizeof IPDestAddr, &IPDestAddr)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " + "IP dest addr\n")); + return; + } + + if (IPDestAddr == IP_ADDR_BROADCAST) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: server-bound DHCP " + "packet is broadcast\n")); + } else { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: server-bound DHCP " + "packet is unicast\n")); + } + } +#endif + return; + } else if (destPort == 68) { // if packet for destined DHCP client port +#ifdef DBG + uint32 IPDestAddr = 0; + if (!GetPacketData(packet, ethHeaderLen + IP_HEADER_DEST_ADDR_OFFSET, + sizeof IPDestAddr, &IPDestAddr)) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " + "IP dest addr\n")); + return; + } + + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got server " + "DHCP packet destined for a client\n")); + + if (IPDestAddr == IP_ADDR_BROADCAST) { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: client-bound " + "DHCP packet is broadcast\n")); + } else { + VNETKdPrint((MODULE_NAME "ProcessOutgoing: client-bound " + "DHCP packet is unicast\n")); + } +#endif /* DBG */ + return; + } else { + W_VNETKdPrint((MODULE_NAME "ProcessOutgoing: got UDP srcPort " + "%d destPort %d\n", srcPort, destPort)); + return; + } + } + case 27: // RDP + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got RDP\n")); + return; + case 41: // IPv6 + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got IPv6\n")); + return; + case 51: // Authentication Header + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got Authentication Header\n")); + return; + case 55: // Mobile IP + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got Mobile IP\n")); + return; + case 103: // PIM + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got PIM\n")); + return; + case 111: // IPX in IP + VNETKdPrint((MODULE_NAME "ProcessOutgoing: got IPX in IP\n")); + return; + default: + VNETKdPrint((MODULE_NAME "ProcessOutgoing: Unknown/unhandled " + "service reported by IP packet\n")); + return; + } +} + + +/* + *---------------------------------------------------------------------- + * + * ProcessIncomingIPv4Packet -- + * + * This function is used to examine IPv4 packets, and make any + * adjustments (if necessary) to the IP header and/or payload. + * The third paramter is optional (specify NULL if not provided). + * + * Currently **this function does nothing** but print out debug + * information about the contents of the IP packet + * + * Results: + * None. + * + * Side effects: + * May modify the contents of the packet. Length should be + * unchanged. + * + *---------------------------------------------------------------------- + */ + +/* + * NOTE: this abstraction doesn't match reality because we may only have + * a partial packet received so far. But, since we're not modifying the + * packet (and only trying to ID/classify it) then this shouldn't matter. + */ + +#ifdef DBG + +static void +ProcessIncomingIPv4Packet(SMACPacket *packet, // IN/OUT: incoming packet + Bool knownMacForIp) // IN: IP is present in table? +{ + uint8 proto; // protocol within ip + uint16 ipFlags; // offset and flags + + /* + * Should certain checks, e.g., IP version field, be checked here, + * or assume that caller has already performed this check? + */ + + /* + * Presuming that caller has performed checks, and that IP header + * comes exactly ETH_HLEN bytes into the packet + */ + + if (GetPacketLength(packet) < ETH_HLEN + IP_HEADER_LEN) { + return; + } + + if (!GetPacketData(packet, ETH_HLEN + IP_HEADER_PROTO_OFFSET, sizeof proto, + &proto)) { + VNETKdPrint((MODULE_NAME "ProcessIncoming: couldn't get protocol\n")); + return; + } + + if (!GetPacketData(packet, ETH_HLEN + IP_HEADER_FLAGS_OFFSET, sizeof ipFlags, + &ipFlags)) { + VNETKdPrint((MODULE_NAME "ProcessIncoming: couldn't get ip flags\n")); + return; + } + + /* + * Verify offset=0 and M=0: mask off "fragment" flag, + * all others should be zero + */ + + if (ipFlags & HTONS(~(uint16)(0x4000))) { + VNETKdPrint((MODULE_NAME "ProcessIncoming: got a fragmented IP " + "(ipFlags %04x), so not performing higher-level processing\n", + ipFlags)); + return; + } + + switch (proto) { + case 1: { // ICMP + uint32 ipHeaderLen = 0; // length of IP header + uint32 ipVer = 0; // version of IP header + uint16 ipLen = 0; // total length of datagram + uint8 firstByte = '\0'; // used to safely read from packet + + if (!GetPacketData(packet, ETH_HLEN, sizeof firstByte, &firstByte)) { + VNETKdPrint((MODULE_NAME "ProcessIncoming: ICMP read ver error\n")); + return; + } + ipHeaderLen = 4 * (firstByte & 0xf); // length of IP header + ipVer = firstByte>>4; // version of IP header + + if (!GetPacketData(packet, ETH_HLEN + 2, sizeof ipLen, &ipLen)) { + VNETKdPrint((MODULE_NAME "ProcessIncoming: ICMP read len error\n")); + return; + } + ipLen = ntohs(ipLen); + + if (ipVer == 4 && GetPacketLength(packet) >= + ipHeaderLen + 2 * 4 + ETH_HLEN) { + uint8 typeField = 0; + uint8 codeField = 0; + if (!GetPacketData(packet, ETH_HLEN + ipHeaderLen, + sizeof typeField, &typeField) || + !GetPacketData(packet, ETH_HLEN + ipHeaderLen + 1, + sizeof codeField, &codeField)) { + VNETKdPrint((MODULE_NAME "ProcessIncoming: ICMP " + "read ICMP error\n")); + return; + } + + W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got ICMP, " + "type = %d, code = %d,\n", typeField, codeField)); + } else { + VNETKdPrint((MODULE_NAME "ProcessIncoming: got ICMP, " + "but couldn't process\n")); + } + return; + } + case 2: // IGMP + W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got IGMP\n")); + return; + case 4: // IP in IP + VNETKdPrint((MODULE_NAME "ProcessIncoming: got IP in IP\n")); + return; + case 6: // TCP + W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got TCP\n")); + return; + case 17: { // UDP + uint32 ipHeaderLen = 0; // length of IP header + uint32 ipVer = 0; // version of IP header + uint16 ipLen = 0; // total length of datagram + uint8 firstByte; // used to safely read from packet + + if (!GetPacketData(packet, ETH_HLEN, sizeof firstByte, &firstByte)) { + VNETKdPrint((MODULE_NAME "ProcessIncoming: ICMP read ver error\n")); + ASSERT(0); + return; + } + ipHeaderLen = 4 * (firstByte&0xf); // length of IP header + ipVer = firstByte >> 4; // version of IP header + + /* + * verifify that IP fragment offset is 0 + */ + + if (!GetPacketData(packet, ETH_HLEN + 2, sizeof ipLen, &ipLen)) { + VNETKdPrint((MODULE_NAME "ProcessIncoming: ICMP read len error\n")); + ASSERT(0); + return; + } + ipLen = ntohs(ipLen); + + W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got UDP, " + "IP ver %d, header len %d," + "overall len %d\n", ipVer, ipHeaderLen, ipLen)); + + if (ipVer == 4 && GetPacketLength(packet) >= + ipHeaderLen + 2 * 4 + ETH_HLEN) { + uint16 srcPort = 0; + uint16 destPort = 0; + uint8 srcAddr[4]; + uint8 destAddr[4]; + + if (!GetPacketData(packet, ipHeaderLen + ETH_HLEN, + sizeof srcPort, &srcPort) || + !GetPacketData(packet, ipHeaderLen + ETH_HLEN + 2, + sizeof destPort, &destPort)) { + VNETKdPrint((MODULE_NAME "ProcessIncoming: read " + "UDP header error\n")); + ASSERT(0); + return; + } + + srcPort = ntohs(srcPort); + destPort = ntohs(destPort); + + if (!GetPacketData(packet, ETH_HLEN + IP_HEADER_SRC_ADDR_OFFSET, + sizeof srcAddr, srcAddr) || + !GetPacketData(packet, ETH_HLEN + IP_HEADER_DEST_ADDR_OFFSET, + sizeof destAddr, destAddr)) { + VNETKdPrint((MODULE_NAME "ProcessIncoming: couldn't read " + "source and/or dest IP addr\n")); + return; + } + + W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got UDP, src " + "%d.%d.%d.%d %d dest %d.%d.%d.%d %d\n", + srcAddr[0], srcAddr[1], srcAddr[2], srcAddr[3], + srcPort, destAddr[0], destAddr[1], destAddr[2], + destAddr[3], destPort)); + + if (destPort == 67) { + + if (knownMacForIp) { + W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got client DHCP " + "packet destined for THIS server\n")); + } else { + W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got client DHCP " + "packet destined for a server\n")); + } + + } else if (destPort == 68) { + + if (knownMacForIp) { + W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got server DHCP " + "packet destined for THIS client\n")); + } else { + W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got server DHCP " + "packet destined for a client\n")); + } + + } + } + return; + } + case 27: // RDP + VNETKdPrint((MODULE_NAME "ProcessIncoming: got RDP\n")); + return; + case 41: // IPv6 + VNETKdPrint((MODULE_NAME "ProcessIncoming: got IPv6\n")); + return; + case 51: // Authentication Header + VNETKdPrint((MODULE_NAME "ProcessIncoming: got Authentication Header\n")); + return; + case 55: // Mobile IP + VNETKdPrint((MODULE_NAME "ProcessIncoming: got Mobile IP\n")); + return; + case 103: // PIM + VNETKdPrint((MODULE_NAME "ProcessIncoming: got PIM\n")); + return; + case 111: // IPX in IP + VNETKdPrint((MODULE_NAME "ProcessIncoming: got IPX in IP\n")); + return; + default: + VNETKdPrint((MODULE_NAME "ProcessIncoming: Unknown/unhandled service " + "reported by IP packet\n")); + return; + } +} + +#endif /* DBG */ + +/* + *---------------------------------------------------------------------- + * + * SMAC_InitState -- + * + * Initialize adapter SMAC state. Presumes that the + * supplied adapter object has already been initialized to zero. + * + * Results: + * None. + * + * Side effects: + * Initializes adapter SMAC state. + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMAC_InitState(SMACState **ptr) // OUT: pointer to alloced/inited state +{ + SMACState * state; + VNETKdPrintCall(("SMAC_InitState")); + ASSERT(ptr); + + state = ALLOCATEMEMORY(sizeof *state, REORDER_TAG('SMAC')); + if (state == NULL) { + *ptr = NULL; + return; + } + + MEMSET(state, 0, sizeof *state); + + VNETKdPrint((MODULE_NAME "SMAC_InitState: state %p\n", state)); + + INITSPINLOCK(&(state->smacSpinLock)); +#ifndef _WIN32 + if (state->smacSpinLock == NULL) { + VNETKdPrint((MODULE_NAME "SMAC_InitState: coudln't initialize spinlock." + "Freeing state.\n")); + FREEMEMORY(state); + state = NULL; + } +#endif + VNETKdPrintReturn(("SMAC_InitState")); + *ptr = state; +} + + +/* + *---------------------------------------------------------------------- + * + * SMAC_SetMac -- + * + * Set MAC stored in SMAC state. Presumes that the + * supplied SMAC state has already been initialized. + * + * Results: + * None. + * + * Side effects: + * Sets MAC in SMAC state. + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMAC_SetMac(SMACState *state, // IN: state to update + uint8 *mac) // IN: pointer to host adapter's MAC +{ + VNETKdPrintCall(("SMAC_SetMac")); + ASSERT(state); + + VNETKdPrint((MODULE_NAME "SMAC_SetMac: state %p mac %p\n", + state, mac)); +#ifdef DBG + if (mac) { + VNETKdPrint((MODULE_NAME + "mac 0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + } +#endif + + /* + * There's likely some atomicity issues here, but grabbing a lock + * here won't help since the readers won't be grabbing a lock. + * The only time an update can occur with traffic being processed + * is on Linux, which I don't see as a big deal given the lack + * of demand for this feature on that OS. + */ + + if (mac) { + MEMCPY(state->macAddress, mac, ETH_ALEN); + } else { + MEMSET(state->macAddress, 0, ETH_ALEN); + } + VNETKdPrintReturn(("SMAC_SetMac")); +} + + +/* + *---------------------------------------------------------------------- + * + * SMAC_SetForwardUnknownPackets -- + * + * Initialize adapter SMAC state. Presumes that the + * supplied adapter object has already been initialized to zero. + * + * Results: + * None. + * + * Side effects: + * Initializes adapter SMAC state. + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMAC_SetForwardUnknownPackets(SMACState *state, // IN: pointer to smac state + Bool forwardUnknown) // IN: T/F to forward +{ + VNETKdPrintCall(("SMAC_SetForwardUnknownPackets")); + ASSERT(state); + state->smacFowardUnknownPackets = forwardUnknown; + VNETKdPrintReturn(("SMAC_SetForwardUnknownPackets")); +} + + +/* + *---------------------------------------------------------------------- + * + * SMAC_CleanupState -- + * + * Deallocates adapter SMAC state. + * + * Results: + * None + * + * Side effects: + * Deallocates adapter SMAC state. + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMAC_CleanupState(SMACState **ptr) // IN: state to dealloc +{ + uint32 i = 0; + SMACState *state; +#ifdef _WIN32 + KIRQL irql; +#endif + SPINLOCKINIT(); + + VNETKdPrintCall(("SMAC_CleanupState")); + ASSERT(ptr); + + state = *ptr; + if (state == NULL) { + return; + } + *ptr = NULL; + + RAISEIRQL(); + ACQUIRESPINLOCK(&state->smacSpinLock); + + for (i = 0; i < SMAC_HASH_TABLE_SIZE; ++i) { + IPmacLookupEntry * entry = state->IPlookupTable[i]; + while (entry) { + IPmacLookupEntry * next = entry->ipNext; + VNETKdPrintCall(("--deleted entry\n")); + FREEMEMORY(entry); + --state->numberOfIPandMACEntries; + entry = next; + } + } + if (state->numberOfIPandMACEntries != 0) { + VNETKdPrint((MODULE_NAME "SMAC_CleanupState: " + "entry count is non-zero: %d\n", + state->numberOfIPandMACEntries)); + ASSERT(state->numberOfIPandMACEntries == 0); + } + + RELEASESPINLOCK(&state->smacSpinLock); + FREESPINLOCK(&state->smacSpinLock); + LOWERIRQL(); + FREEMEMORY(state); + + VNETKdPrintReturn(("SMAC_CleanupState")); +} + + +/* + *---------------------------------------------------------------------- + * + * LookupTypeClass -- + * + * Examines and classifies the protocol type of an ethernet frame + * + * Results: + * Returns the appropriate EthClass classification for the + * specified ethernet media type. + * + * + * Side effects: + * May modify the contents of the packet. Length should be + * unchanged. + * + *---------------------------------------------------------------------- + */ + +EthClass +LookupTypeClass(unsigned short typeValue) // IN: ethernet type +{ + if (typeValue <=1500) { + return EthClassCommon; + } + if (typeValue >= 0x600) { + switch (typeValue) { + case 0x0800: // IPv4 + return EthClassIP; + case 0x0806: // ARP + return EthClassARP; + case 0x0BAD: // Banyan Vines + return EthClassUncommon; + case 0x2000: // Cisco CDP + return EthClassCommon; + case 0x6002: // DEC MOP Remote Console + case 0x6558: // Trans Ether Bridging [RFC1701] + case 0x6559: // Raw Frame Relay [RFC1701] + return EthClassUncommon; + case 0x8035: // Reverse ARP + return EthClassARP; + case 0x809B: // AppleTalk + case 0x80F3: // AppleTalk AARP + return EthClassUncommon; + case 0x8100: // VLAN special type + return EthClassVLAN; + case 0x8137: // Novell 8137 + case 0x8138: // Novell 8138 + case 0x86DD: // IPv6 + case 0x876B: // TCP/IP Compression [RFC1144] + return EthClassUncommon; + case 0x886f: // Microsoft 886f + return EthClassCommon; + default: + return EthClassUnknown; + } + } else { + return EthClassUnknown; + } +} + + +#ifdef DBG + +/* + *---------------------------------------------------------------------- + * + * LookupTypeName -- + * + * Examines and classifies the protocol type of an ethernet frame + * + * Results: + * Provides textual name of type in 'type' pointer. + * Returns the appropriate EthClass classification for the + * specified ethernet media type. + * + * + * Side effects: + * May modify the contents of the packet. Length should be + * unchanged. + * + *---------------------------------------------------------------------- + */ + +EthClass +LookupTypeName(unsigned short typeValue, // IN: ethernet type + char * type) // IN/OUT: string to store type name +{ + if (typeValue <=1500) { + SNPRINTF((type, 15, "length %d", typeValue)); + return EthClassCommon; + } +#ifdef _WIN32 +#define STRCPY(a,b) strcpy(a,b) +#else +#define STRCPY(a,b) MEMCPY(a, b, sizeof b) +#endif + if (typeValue >= 0x600) { + switch (typeValue) { + case 0x0800: + if (type) { + STRCPY(type, "IPv4"); + } + return EthClassIP; + case 0x0806: + if (type) { + STRCPY(type, "ARP"); + } + return EthClassARP; + case 0x0BAD: + if (type) { + STRCPY(type, "Banyan VINES"); + } + return EthClassUncommon; + case 0x2000: + if (type) { + STRCPY(type, "Cisco CDP"); + } + return EthClassCommon; + case 0x6002: + if (type) { + STRCPY(type, "DEC MOP Remote Console"); + } + return EthClassUncommon; + case 0x6558: + if (type) { + STRCPY(type, "Trans Ether Bridging [RFC1701]"); + } + return EthClassUncommon; + case 0x6559: + if (type) { + STRCPY(type, "Raw Frame Relay [RFC1701]"); + } + return EthClassUncommon; + case 0x8035: + if (type) { + STRCPY(type, "Reverse ARP"); + } + return EthClassARP; + case 0x809B: + if (type) { + STRCPY(type, "AppleTalk"); + } + return EthClassUncommon; + case 0x80F3: + if (type) { + STRCPY(type, "AppleTalk AARP"); + } + return EthClassUncommon; + case 0x8100: + if (type) { + STRCPY(type, "VLAN special type"); + } + return EthClassVLAN; + case 0x8137: + if (type) { + STRCPY(type, "Novell 8137"); + } + return EthClassUncommon; + case 0x8138: + if (type) { + STRCPY(type, "Novell 8138"); + } + return EthClassUncommon; + case 0x86DD: + if (type) { + STRCPY(type, "IPv6"); + } + return EthClassUncommon; + case 0x876B: + if (type) { + STRCPY(type, "TCP/IP Compression [RFC1144]"); + } + return EthClassUncommon; + case 0x886f: + if (type) { + STRCPY(type, "Microsoft 886f"); + } + return EthClassCommon; + default: + if (type) { + SNPRINTF((type, 40, "unknown type 0x%04x", typeValue)); + } + return EthClassUnknown; + } + } else { + if (type) { + SNPRINTF((type, 40, "invalid value 0x%04x", typeValue)); + } + return EthClassUnknown; + } +} +#endif + +/* + * Checksum-related functions. In certain cases the payload of a UDP + * packet needs to be modified. The following functions are used to + * calculate the new checksum based on the old checksum and an offset + * of the changes. + */ + + +/* + *---------------------------------------------------------------------- + * + * SUM32 -- + * + * performs 2's complement sum of the high bits and low bits + * in a 32-bit word, resulting in a 16-bit number (with + * potentially additional bits containing overflow) + * + * Results: + * Returns result described above + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE uint32 +SUM32(uint32 in) { // IN: 32-bit number + return (in & 0xffff) + (in >> 16); +} + + +/* + *---------------------------------------------------------------------- + * + * CalcChecksumDiff -- + * + * Computes the differences between two checksums + * + * Results: + * Returns result described above + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static uint32 +CalcChecksumDiff(uint32 sumBefore, // IN: checksum before modification + uint32 sumAfter) // IN: checksum after modification +{ + uint32 diff; // stores resume to return + + sumBefore = SUM32(sumBefore); // Convert sum to 16-bit + overflow + sumBefore = SUM32(sumBefore); // Convert sum to 16-bit + sumAfter = SUM32(sumAfter); // Convert sum to 16-bit + overflow + sumAfter = SUM32(sumAfter); // Convert sum to 16-bit + + /* + * 2's complement versus 1's complement arthmetic requires the + * following piece of code. I don't completely understand + * why it's needed, but my sources (and my own testing) say it + * needs to be here. + */ + + if (sumBefore > sumAfter) { + --sumAfter; + } + + diff = sumAfter - sumBefore; // subtrace to get delta + diff = SUM32(diff); // incorporate overflow to get 16-bits + return diff; +} + + +/* + *---------------------------------------------------------------------- + * + * UpdateSum -- + * + * Computes a new internet checksum by using an existing + * checksum and a delta of changes to that checksum. + * + * Results: + * Returns new checksum + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static uint16 +UpdateSum(uint16 oricheck, // IN: old checksum + uint32 sumDiff) // IN: delta of changes +{ + uint32 sum; + uint16 sumShort; + if (sumDiff == 0) { + return oricheck; + } + + sum = ( ~ntohs(oricheck) & 0xffff); // undo net order & bit complement + sum += sumDiff; // add in difference + sum = SUM32(sum); // wrap any overflow + sum = SUM32(sum); // wrap any overflow (again; last wrap may cause overflow) + sumShort = ~(uint16)(sum); // truncate to 16-bits and complement bits + return htons(sumShort); // return result in network order +} + + +/* + *---------------------------------------------------------------------- + * + * GetSystemUptime -- + * + * Return current uptime of system, this is essentially a wrapper + * that checks for overflow. When + * overflow occurs the existing last used times reduced by half. + * As part of the solution, the returned value always has the + * highest bit turned on. + * + * Previously, this was a wrapper for NdisGetSystemUptime(). + * Recent updates to the DDK/WDK have confused this function - there + * is now a depricated 32-bit version and a 64-bit version only + * available on newer version of the OS. Rather than trying to be + * clever, we will use KeQueryTickCount instead. + * + * This function should only be called with the lock held. + * + * Results: + * Returns uptime of system (skewed so always in upper half + * of numeric range for 32-bits) + * + * Side effects: + * Updates the "last uptime" stored in adapter struct, and may + * modify the uptimes of all entries in the hash table. + * + *---------------------------------------------------------------------- + */ + +static SmacLastAccess +GetSystemUptime(SMACState *state) // IN: smac state +{ + SmacLastAccess currentUptime; + +#ifdef _WIN32 + { + LARGE_INTEGER arg; + KeQueryTickCount(&arg); + currentUptime = arg.QuadPart; + } +#else + currentUptime = SMACL_GetUptime(); +#endif + /* + * Force on the highest bit. This basically means that recent + * values have the high bit turned on, while values that were + * obtained prior to the last overflow will have the highest bit + * (and potentially other neighboring bits) turned off. + */ + + currentUptime |= (SmacLastAccess)1 << (sizeof currentUptime * 8 - 1); + + /* If overflow occurred, then reduce all existing values by half */ + if (currentUptime < state->lastUptimeRead) { + uint32 i; + VNETKdPrint((MODULE_NAME "GetSystemUptime: overflow detected, " + "adjusting counters\n")); + for (i = 0; i < SMAC_HASH_TABLE_SIZE; ++i) { + IPmacLookupEntry *entry = state->IPlookupTable[i]; + while (entry) { + entry->lastAccess >>= 1; /* reduce value by half */ + entry = entry->ipNext; + } + } + } + state->lastUptimeRead = currentUptime; + return currentUptime; +} + + +/* + *---------------------------------------------------------------------- + * + * GetPacketLength -- + * + * Returns the total length of data in a packet + * + * Results: + * returns length of packet + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE uint32 +GetPacketLength(SMACPacket *packet) // IN: packet +{ + ASSERT(packet); +#ifdef _WIN32 + return packet->buf1Len + packet->buf2Len; +#elif defined __linux__ + ASSERT(packet->skb); + return (uint32)SMACL_PacketLength(packet->skb); +#else /* __APPLE__ */ + ASSERT(packet->m); + return SMACL_PacketLength(packet->m); +#endif +} + + +/* + *---------------------------------------------------------------------- + * + * GetPacketData -- + * + * Copies select portion of packet + * + * Results: + * TRUE if data was safely copied, otherwise FALSE (e.g., offset + * too large, packet too small, etc). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Bool +GetPacketData(SMACPacket *packet, // IN: packet to copy from + uint32 offset, // IN: offset in packet to copy from + uint32 length, // IN: length to copy + void *data) // OUT: data (caller must pass in buffer >= length) +{ +#ifdef _WIN32 + uint32 copyOffset = 0; + uint32 copyLength = 0; +#endif + + ASSERT(packet); + ASSERT(data); + ASSERT(length > 0); + + /* check length, be sure to handle case where offset = -1, length > 0 */ + if (length == 0 || offset + length > GetPacketLength(packet) || + offset + length < offset) { + /* packet not long enough for data */ + return FALSE; + } + +#ifdef _WIN32 + /* if offset starts in the first buffer, then copy from first buffer */ + if (offset < packet->buf1Len) { + copyOffset = offset; + copyLength = (offset + length > packet->buf1Len)? + (packet->buf1Len - copyOffset):(length); + + MEMCPY(data, ((uint8*)packet->buf1) + copyOffset, copyLength); + offset = packet->buf1Len; /* advance offset to start of second buffer */ + + data = ((uint8*)data) + copyLength; + length -= copyLength; + } + /* copy any remaining data from second buffer */ + if (length) { + copyOffset = offset - packet->buf1Len; + copyLength = length; + MEMCPY(data, ((uint8*)packet->buf2) + copyOffset, copyLength); + } + +#elif __linux__ + + MEMCPY(data, packet->startOfData + offset, length); + +#else /* __APPLE__ */ + + SMACL_CopyDataFromPkt(packet->m, offset, data, length); + +#endif /* _WIN32 */ + + return TRUE; +} + + +/* + *---------------------------------------------------------------------- + * + * ClonePacket -- + * + * Makes a private copy of the incoming packet. This modified + * copy is private and can be modified at will. Caller is + * responsible for freeing the cloned packet. + * + * Results: + * TRUE if clone was successful, otherwise FALSE. + * + * Side effects: + * Duplicates a packet. + * + *---------------------------------------------------------------------- + */ + +static Bool +ClonePacket(SMACPackets *packets) // IN: struct in which to clone packet +{ +#ifdef _WIN32 + VNetPacket * packetClone = NULL; + + ASSERT(packets); + + packetClone = VNet_PacketAllocate(packets->orig.buf1Len + + packets->orig.buf2Len, + "SMAC_CheckPacketToHost"); + if (!packetClone) { + VNETKdPrint((MODULE_NAME " ToHost: couldn't clone packet\n")); + return FALSE; + } + + if (packets->orig.buf1Len) { + MEMCPY(packetClone->data, packets->orig.buf1, packets->orig.buf1Len); + } + if (packets->orig.buf2Len) { + MEMCPY(packetClone->data + packets->orig.buf1Len, packets->orig.buf2, + packets->orig.buf2Len); + } + + packets->clone.buf1 = packetClone->data; + packets->clone.buf1Len = packetClone->len; + packets->clone.buf2 = NULL; + packets->clone.buf2Len = 0; + packets->clonedPacket = packetClone; + return TRUE; + +#elif defined __linux__ + + packets->clone.skb = SMACL_DupPacket(packets->orig.skb); + if (packets->clone.skb) { + packets->clone.startOfData = (packets->orig.startOfData - + SMACL_PacketData(packets->orig.skb)) + + SMACL_PacketData(packets->clone.skb); + } else { + packets->clone.startOfData = NULL; + } + return packets->clone.skb != NULL; + +#else /* __APPLE__ */ + + /* + * Don't need to clone packet again. We could even get rid of "clone" from + * the SMACPackets struct, but this minimizes differences from other OSes. + */ + packets->clone.m = packets->orig.m; + return packets->clone.m != NULL; + +#endif /* _WIN32 */ +} + + +/* + *---------------------------------------------------------------------- + * + * CopyDataToClonedPacket -- + * + * Makes changes to the private clone copy of a packet. + * + * Results: + * TRUE if modification was successful, otherwise FALSE. + * + * Side effects: + * Modifies a packet. + * + *---------------------------------------------------------------------- + */ + +static Bool +CopyDataToClonedPacket(SMACPackets *packets, // IN: packets + const void * source, // IN: data to copy to packet + uint32 offset, // IN: dest offset at which to copy + uint32 length) // IN: length of data to copy +{ +#ifdef _WIN32 + ASSERT(packets); + ASSERT(packets->clone.buf1); + ASSERT(packets->clone.buf1Len > offset + length); + ASSERT(packets->clone.buf2 == NULL); + ASSERT(packets->clone.buf2Len == 0); + + /* + * For windows this code presumes that all of the clone packet's data is + * in the first buffer. + */ + + if (!packets || !packets->clone.buf1 || packets->clone.buf1Len + <= offset + length) { + ASSERT(0); // should never occur + return FALSE; + } + MEMCPY((uint8 *)(packets->clone.buf1) + offset, source, length); + +#elif defined __linux__ + + ASSERT(packets); + ASSERT(packets->clone.skb); + + MEMCPY((uint8 *)(packets->clone.startOfData) + offset, + source, length); + +#else /* __APPLE __ */ + + ASSERT(packets); + ASSERT(packets->clone.m); + SMACL_CopyDataToPkt(packets->clone.m, offset, source, length); + +#endif + + return TRUE; +} + + +/* + *---------------------------------------------------------------------- + * + * SetPacketByte -- + * + * Makes changes to a packet, either public or private + * + * Results: + * TRUE if modification was successful, otherwise FALSE. + * + * Side effects: + * Modifies a packet. + * + *---------------------------------------------------------------------- + */ + +static Bool +SetPacketByte(SMACPacket *packet, // IN: packet + uint32 offset, // IN: offset to change + uint8 data) // IN: data to set +{ + ASSERT(packet); + +#ifdef _WIN32 + /* check length, be sure to handle case where offset = -1, length > 0 */ + if (offset > GetPacketLength(packet)) { + /* packet not long enough for data */ + return FALSE; + } + + /* if offset starts in the first buffer, then copy from first buffer */ + if (offset < packet->buf1Len) { + ((uint8*)packet->buf1)[offset] = data; + } else { + offset -= packet->buf1Len; + ((uint8*)packet->buf2)[offset] = data; + } + +#elif __linux__ + + ASSERT(packet); + ASSERT(packet->skb); + + ((uint8*)packet->startOfData)[offset] = data; + +#else + + ASSERT(packet); + ASSERT(packet->m); + SMACL_CopyDataToPkt(packet->m, offset, &data, 1); + +#endif /* _WIN32 */ + + return TRUE; +} + + +/* + *---------------------------------------------------------------------- + * + * CopyDataForPacketFromHost -- + * + * When receiving data from the host, this function is used + * to make changes to the packet. Since the only changes we + * ever make are to replace one Ethernet MAC with another, this + * function currently just does MAC replacement. + * + * Results: + * TRUE if modification was successful, otherwise FALSE. + * + * Side effects: + * Modifies a packet. + * + *---------------------------------------------------------------------- + */ + +Bool +CopyDataForPacketFromHost(SMACPackets *packets, // IN/OUT: packets struct + uint32 changeNum, // IN: serialized # of change + uint32 offset, // IN: byte offset for change + const uint8 *macAddress) // IN: new MAC to add to packet +{ +#ifdef _WIN32 + MacReplacementTable *table = NULL; + ASSERT(packets); + ASSERT(macAddress); + + table = packets->table; + ASSERT(table); + ASSERT(changeNum == table->numOfOffsets); + UNREFERENCED_PARAMETER(changeNum); + + if (table->numOfOffsets == 0) { + MEMCPY(table->mac, macAddress, ETH_ALEN); + } + table->offsets[table->numOfOffsets++] = offset; + +#else /* _WIN32 */ + + /* clone packet if this is the first change */ + if (changeNum == 0 && !ClonePacket(packets)) { + VNETKdPrint((MODULE_NAME "FromHostIP: couldn't clone packet\n")); + return FALSE; + } + CopyDataToClonedPacket(packets, macAddress, offset, ETH_ALEN); +#endif /* _WIN32 */ + + return TRUE; +} diff -Nrup source/vmnet-only/linux/smac_compat.c source.edited/vmnet-only/linux/smac_compat.c --- source/vmnet-only/linux/smac_compat.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/smac_compat.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,524 @@ +/********************************************************* + * Copyright (C) 2005 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 + * + *********************************************************/ + +/* + * smac_compat.c -- + * + * This file defines an abstraction layer to handling + * differences among the Linux kernel and avoiding + * symbol match issues. + */ + +#include "driver-config.h" + +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include +#include // for spinlock_t + +#ifdef KERNEL_2_2 +#include +#else +#include +#endif +#include + +#include +#include +#include +#include "compat_skbuff.h" +#include + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include + +#include "vnetInt.h" +#include "vmnetInt.h" +#include "smac_compat.h" + +#ifdef VMX86_DEVEL +#define DBG 1 +#else +#undef DBG +#endif /* VMX86_DEVEL */ + + + +/* + *---------------------------------------------------------------------- + * SMACL_GetUptime -- + * + * Wrapper for jiffies. + * + * Results: + * Uptime in ticks + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +unsigned long SMACINT +SMACL_GetUptime() +{ + return jiffies; +} + +/* + *---------------------------------------------------------------------- + * SMACL_Memcpy -- + * + * Wrapper for memcpy(). + * + * Results: + * None. + * + * Side effects: + * Copies memory + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMACL_Memcpy(void *d, // IN: destination pointer + const void *s, // IN: source pointer + size_t l) // IN: length to copy +{ + memcpy(d, s, l); +} + + +/* + *---------------------------------------------------------------------- + * SMACL_Memcmp -- + * + * Wrapper for memcmp(). + * + * Results: + * refer to documentation for memcmp(). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int SMACINT +SMACL_Memcmp(const void *p1, // IN: pointer to data + const void *p2, // IN: pointer to data + size_t l) // IN: length to compare +{ + return memcmp(p1, p2, l); +} + + +/* + *---------------------------------------------------------------------- + * SMACL_Memset -- + * + * Wrapper for memset(). + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMACL_Memset(void *p1, // IN: pointer to data + int val, // IN: value to set + size_t l) // IN: length to set +{ + memset(p1, val, l); + return; +} + +/* + *---------------------------------------------------------------------- + * SMACL_Alloc -- + * + * Wrapper for kmalloc(). + * + * Results: + * Pointer to memory if successful, NULL otherwise + * + * Side effects: + * Allocates memory + * + *---------------------------------------------------------------------- + */ + +void* SMACINT +SMACL_Alloc(size_t size) // IN: size to allocate +{ + return kmalloc(size, GFP_ATOMIC); +} + + +/* + *---------------------------------------------------------------------- + * SMACL_Free -- + * + * Wrapper for kfree(). + * + * Results: + * None. + * + * Side effects: + * Frees memory + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMACL_Free(void *ptr) // IN: pointer to free +{ + kfree(ptr); +} + + +/* + *---------------------------------------------------------------------- + * SMACL_InitSpinlock -- + * + * Wrapper for spin_lock_init(). + * The reason we have to use void is to avoid dependency on kernel. + * The spinlock_t structure can change for different compilation options. + * + * Results: + * None. + * + * Side effects: + * see spin_lock_init() + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMACL_InitSpinlock(void **s) // IN: spinlock +{ + *s = kmalloc(sizeof(spinlock_t), GFP_ATOMIC); + spin_lock_init((spinlock_t *)*s); +} + + +/* + *---------------------------------------------------------------------- + * SMACL_AcquireSpinlock -- + * + * Wrapper for spin_lock_irqsave(). + * + * Results: + * None. + * + * Side effects: + * Grabs lock (see spin_lock_irqsave()) + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMACL_AcquireSpinlock(void **s, // IN: spinlock + unsigned long *flags) // IN/OUT: flags +{ + unsigned long f = *flags; + spin_lock_irqsave((spinlock_t *)*s, f); + *flags = f; +} + + +/* + *---------------------------------------------------------------------- + * SMACL_ReleaseSpinlock -- + * + * Wrapper for spin_unlock_irqrestore(). + * + * Results: + * None. + * + * Side effects: + * Ungrabs lock (see spin_unlock_irqrestore()) + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMACL_ReleaseSpinlock(void **s, // IN: spinlock + unsigned long *flags) // IN/OUT: flags +{ + unsigned long f = *flags; + spin_unlock_irqrestore((spinlock_t *)*s, f); + *flags = f; +} + + +#ifdef DBG +/* + *---------------------------------------------------------------------- + * SMACL_Print -- + * + * Wrapper for printk(). + * + * Results: + * None. + * + * Side effects: + * Creates output + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMACL_Print(const char * msg, // IN: format message + ...) // IN: params (currently ignored) +{ + char buf[1024]; + int len; + va_list ap; + + va_start(ap, msg); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) + len = vsnprintf(buf, sizeof buf, msg, ap); +#else + len = vsprintf(buf, msg, ap); +#endif + + va_end(ap); + buf[1023] = '\0'; + printk(KERN_DEBUG "%s", buf); +} + +#endif + +/* + *---------------------------------------------------------------------- + * SMACL_DupPacket -- + * + * Wrapper for skb_copy(). + * + * Results: + * Pointer to packet if successful, NULL otherwise + * + * Side effects: + * Creates a private duplicate of packet + * + *---------------------------------------------------------------------- + */ + +struct sk_buff* SMACINT +SMACL_DupPacket(struct sk_buff *skb) // IN: packet to duplicate +{ + return skb_copy(skb, GFP_ATOMIC); +} + +/* + *---------------------------------------------------------------------- + * SMACL_PacketData -- + * + * Wrapper to get data from sk_buff. This function might be + * a bit extreme, but it's good to be able to handle changes + * to the layout of the sk_buff struct. + * + * Results: + * Pointer to data in sk_buff. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void* SMACINT +SMACL_PacketData(struct sk_buff *skb) // IN: pointer to packet buffer +{ + return skb->data; +} + + +/* + *---------------------------------------------------------------------- + * SMACL_PacketLength -- + * + * Wrapper to get length of data in sk_buff. + * + * Results: + * Length stored in sk_buff. + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +unsigned int SMACINT +SMACL_PacketLength(struct sk_buff *skb) // IN: pointer to packet buffer +{ + /* + * wireless driver process the packet and processes the ethernet header + * and the length is reduced by the amount. We need the raw ethernet + * packet length hence add the ethernet header length + */ + return (unsigned int) (skb->len + ETH_HLEN); +} + + +/* + *---------------------------------------------------------------------- + * SMACL_LinearizeSkb -- + * + * Wrapper function to linearize an skb, if necessary. + * + * Results: + * non zero if skb is can't be converted to linear. + * 0 if skb is already linear or successfully converted. + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +int SMACINT +SMACL_LinearizeSkb(struct sk_buff* skb) // IN: packet to process +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) + if (skb_is_nonlinear(skb)) { + return compat_skb_linearize(skb); + } +#endif + return 0; +} + + +/* + *---------------------------------------------------------------------- + * SMACL_IsSkbHostBound -- + * + * Checks if the direction of the packet is host bound. + * + * Results: + * Returns non zero if host bound + * 0 for anything else + i + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +int SMACINT +SMACL_IsSkbHostBound(struct sk_buff* skb) // IN: packet to process +{ + return (skb->pkt_type == PACKET_HOST); +} + + +#ifdef DBG +/* + *---------------------------------------------------------------------- + * SMACL_PrintSkb -- + * + * Print information about the skb. + * + * Results: + * prints the sk_buff structure + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void SMACINT +SMACL_PrintSkb(struct sk_buff *skb, // IN: sk_buff structure + char *str) // IN: type of process +{ + LOG(4, (KERN_DEBUG "%s pointer %p shared? %d cloned? %d\n", + str, skb, skb_shared(skb), skb_cloned(skb))); + LOG(4, (KERN_DEBUG "next %p, prev %p\n", + skb->next, skb->prev)); + LOG(4, (KERN_DEBUG "sock %p, dev %p\n", + skb->sk, skb->dev)); + LOG(4, (KERN_DEBUG "pkt_type %x truesize %u protocol %u\n", + skb->pkt_type, skb->truesize, skb->protocol)); + LOG(4, (KERN_DEBUG "users %d, tail %p, end %p\n", + atomic_read(&skb->users), compat_skb_tail_pointer(skb), + compat_skb_end_pointer(skb))); +#if 0 +#define C skb->mac.raw + if(skb->mac.raw) { + LOG(4, (KERN_DEBUG "dest %02x:%02x:%02x:%02x:%02x:%02x" + " source %02x:%02x:%02x:%02x:%02x:%02x\n", + C[0],C[1],C[2],C[3],C[4],C[5] , + C[6],C[7],C[8],C[9],C[10],C[11])); + } +#undef C + if(skb->dst) { + LOG(4, (KERN_DEBUG "dst_entry->__refcount %d\n", + atomic_read(&(skb->dst->__refcnt)))); + } +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) + LOG(4, (KERN_DEBUG "dataref %d end\n", + atomic_read(&(skb_shinfo(skb)->dataref)))); +#endif + +} + +/* + *---------------------------------------------------------------------- + * SMACL_Snprintf -- + * + * Wrapper to do snprintf for debugging. + * + * Results: + * refer to VNetSnprintf in driver.c + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int SMACINT +SMACL_Snprintf(char *str, // OUT: resulting string + size_t size, // IN: length of 'result' in bytes + const char *format, // IN: format string + ...) // IN: (optional) +{ + int length; + va_list args; + + va_start(args, format); + length = VNetSnprintf(str, size, format, args); + va_end(args); + return length; +} +#endif diff -Nrup source/vmnet-only/linux/socket.c source.edited/vmnet-only/linux/socket.c --- source/vmnet-only/linux/socket.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/socket.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,33 @@ +/********************************************************* + * Copyright (C) 2004 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 + * + *********************************************************/ + +/* + * Detect whether there is 'sk_wmem_alloc' member in 'sock' + * It got renamed from wmem_alloc sometime during 2.5.x. + */ + +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +#include + +void *sock_wmem_alloc_test(struct sock* sk) { + return &sk->sk_wmem_alloc; +} +#endif diff -Nrup source/vmnet-only/linux/userif.c source.edited/vmnet-only/linux/userif.c --- source/vmnet-only/linux/userif.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/userif.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,1057 @@ +/********************************************************* + * Copyright (C) 1998 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" + +#define EXPORT_SYMTAB + +#include +#include +#include +#ifdef KERNEL_2_2 +# include +#else +# include +#endif +#include + +#include +#include +#include "compat_skbuff.h" +#include +#include +#include "compat_sock.h" + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) +#include +#endif + +#include "vnetInt.h" + +#include "compat_uaccess.h" +#include "compat_highmem.h" +#include "compat_mm.h" +#include "pgtbl.h" +#include "compat_wait.h" +#include "vmnetInt.h" +#include "vm_atomic.h" + +typedef struct VNetUserIFStats { + unsigned read; + unsigned written; + unsigned queued; + unsigned droppedDown; + unsigned droppedMismatch; + unsigned droppedOverflow; + unsigned droppedLargePacket; +} VNetUserIFStats; + +typedef struct VNetUserIF { + VNetPort port; + struct sk_buff_head packetQueue; + uint32* pollPtr; + Atomic_uint32* actPtr; + uint32 pollMask; + uint32 actMask; + uint32* recvClusterCount; + wait_queue_head_t waitQueue; + struct page* actPage; + struct page* pollPage; + struct page* recvClusterPage; + VNetUserIFStats stats; +} VNetUserIF; + +static void VNetUserIfUnsetupNotify(VNetUserIF *userIf); +static int VNetUserIfSetupNotify(VNetUserIF *userIf, VNet_Notify *vn); + +/* + *----------------------------------------------------------------------------- + * + * UserifLockPage -- + * + * Lock in core the physical page associated to a valid virtual + * address --hpreg + * + * Results: + * The page structure on success + * NULL on failure: memory pressure. Retry later + * + * Side effects: + * Loads page into memory + * Pre-2.4.19 version may temporarily lock another physical page + * + *----------------------------------------------------------------------------- + */ + +static INLINE struct page * +UserifLockPage(VA addr) // IN +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 19) + struct page *page = NULL; + int retval; + + down_read(¤t->mm->mmap_sem); + retval = get_user_pages(current, current->mm, addr, + 1, 1, 0, &page, NULL); + up_read(¤t->mm->mmap_sem); + + if (retval != 1) { + return NULL; + } + + return page; +#else + struct page *page; + struct page *check; + volatile int c; + + /* + * Establish a virtual to physical mapping by touching the physical + * page. Because the address is valid, there is no need to check the return + * value here --hpreg + */ + compat_get_user(c, (char *)addr); + + page = PgtblVa2Page(addr); + if (page == NULL) { + /* The mapping went away --hpreg */ + return NULL; + } + + /* Lock the physical page --hpreg */ + get_page(page); + + check = PgtblVa2Page(addr); + if (check != page) { + /* + * The mapping went away or was modified, so we didn't lock the right + * physical page --hpreg + */ + + /* Unlock the physical page --hpreg */ + put_page(page); + + return NULL; + } + + /* We locked the right physical page --hpreg */ + return page; +#endif +} + +/* + *----------------------------------------------------------------------------- + * + * VNetUserIfInvalidPointer -- + * + * Reports if pointer provided by user is definitely wrong, + * or only potentially wrong. + * + * Results: + * non-zero if pointer is definitely wrong, otherwise returns + * 0 if the pointer might be okay. + * + * Side effects: + * Might sleep. + * + *----------------------------------------------------------------------------- + */ + +static INLINE int +VNetUserIfInvalidPointer(VA uAddr, // IN: user-provided pointer + size_t size) // IN: anticipated size of data +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + return !access_ok(VERIFY_WRITE, (void *)uAddr, size); +#else + return verify_area(VERIFY_READ, (void *)uAddr, size) || + verify_area(VERIFY_WRITE, (void *)uAddr, size); +#endif +} + +/* + *----------------------------------------------------------------------------- + * + * VNetUserIfMapUint32Ptr -- + * + * Maps a portion of user-space memory into the kernel. + * + * Results: + * 0 on success + * < 0 on failure: the actual value determines the type of failure + * + * Side effects: + * Might sleep. + * + *----------------------------------------------------------------------------- + */ + +static INLINE int +VNetUserIfMapUint32Ptr(VA uAddr, // IN: pointer to user memory + struct page **p, // OUT: locked page + uint32 **ptr) // OUT: kernel mapped pointer +{ + if (VNetUserIfInvalidPointer(uAddr, sizeof (uint32)) || + (((uAddr + sizeof(uint32) - 1) & ~(PAGE_SIZE - 1)) != + (uAddr & ~(PAGE_SIZE - 1)))) { + return -EINVAL; + } + + *p = UserifLockPage(uAddr); + if (*p == NULL) { + return -EAGAIN; + } + + *ptr = (uint32 *)((char *)kmap(*p) + (uAddr & (PAGE_SIZE - 1))); + return 0; +} + +/* + *----------------------------------------------------------------------------- + * + * VNetUserIfSetupNotify -- + * + * Sets up notification by filling in pollPtr, actPtr, and recvClusterCount + * fields. + * + * Results: + * 0 on success + * < 0 on failure: the actual value determines the type of failure + * + * Side effects: + * Fields pollPtr, actPtr, recvClusterCount, pollPage, actPage, and + * recvClusterPage are filled in VNetUserIf structure. + * + *----------------------------------------------------------------------------- + */ + +static INLINE int +VNetUserIfSetupNotify(VNetUserIF *userIf, // IN + VNet_Notify *vn) // IN +{ + int retval; + + if (userIf->pollPtr || userIf->actPtr || userIf->recvClusterCount) { + LOG(0, (KERN_DEBUG "vmnet: Notification mechanism already active\n")); + return -EBUSY; + } + + if ((retval = VNetUserIfMapUint32Ptr((VA)vn->pollPtr, &userIf->pollPage, + &userIf->pollPtr)) < 0) { + return retval; + } + + if ((retval = VNetUserIfMapUint32Ptr((VA)vn->actPtr, &userIf->actPage, + (uint32 **)&userIf->actPtr)) < 0) { + VNetUserIfUnsetupNotify(userIf); + return retval; + } + + if ((retval = VNetUserIfMapUint32Ptr((VA)vn->recvClusterPtr, + &userIf->recvClusterPage, + &userIf->recvClusterCount)) < 0) { + VNetUserIfUnsetupNotify(userIf); + return retval; + } + + userIf->pollMask = vn->pollMask; + userIf->actMask = vn->actMask; + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * VNetUserIfUnsetupNotify -- + * + * Destroys permanent mapping for notify structure provided by user. + * + * Results: + * None. + * + * Side effects: + * Fields pollPtr, actPtr, recvClusterCount, etc. in VNetUserIf + * structure are cleared. + * + *---------------------------------------------------------------------- + */ + +static void +VNetUserIfUnsetupNotify(VNetUserIF *userIf) // IN +{ + if (userIf->pollPage) { + kunmap(userIf->pollPage); + put_page(userIf->pollPage); + } else { + LOG(0, (KERN_DEBUG "vmnet: pollPtr was already deactivated\n")); + } + if (userIf->actPage) { + kunmap(userIf->actPage); + put_page(userIf->actPage); + } else { + LOG(0, (KERN_DEBUG "vmnet: actPtr was already deactivated\n")); + } + if (userIf->recvClusterPage) { + kunmap(userIf->recvClusterPage); + put_page(userIf->recvClusterPage); + } else { + LOG(0, (KERN_DEBUG "vmnet: recvClusterPtr was already deactivated\n")); + } + userIf->pollPtr = NULL; + userIf->pollPage = NULL; + userIf->actPtr = NULL; + userIf->actPage = NULL; + userIf->recvClusterCount = NULL; + userIf->recvClusterPage = NULL; + userIf->pollMask = 0; + userIf->actMask = 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetUserIfFree -- + * + * Free the user interface port. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +VNetUserIfFree(VNetJack *this) // IN +{ + VNetUserIF *userIf = (VNetUserIF*)this; + struct sk_buff *skb; + + for (;;) { + skb = skb_dequeue(&userIf->packetQueue); + if (skb == NULL) { + break; + } + dev_kfree_skb(skb); + } + + if (userIf->pollPtr) { + VNetUserIfUnsetupNotify(userIf); + } + + if (this->procEntry) { + VNetProc_RemoveEntry(this->procEntry); + } + + kfree(userIf); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetUserIfReceive -- + * + * This jack is receiving a packet. Take appropriate action. + * + * Results: + * None. + * + * Side effects: + * Frees skb. + * + *---------------------------------------------------------------------- + */ + +static void +VNetUserIfReceive(VNetJack *this, // IN + struct sk_buff *skb) // IN +{ + VNetUserIF *userIf = (VNetUserIF*)this->private; + uint8 *dest = SKB_2_DESTMAC(skb); + + if (!UP_AND_RUNNING(userIf->port.flags)) { + userIf->stats.droppedDown++; + goto drop_packet; + } + + if (!VNetPacketMatch(dest, + userIf->port.paddr, + userIf->port.ladrf, + userIf->port.flags)) { + userIf->stats.droppedMismatch++; + goto drop_packet; + } + + if (skb_queue_len(&userIf->packetQueue) >= VNET_MAX_QLEN) { + userIf->stats.droppedOverflow++; + goto drop_packet; + } + + if (skb->len > ETHER_MAX_QUEUED_PACKET) { + userIf->stats.droppedLargePacket++; + goto drop_packet; + } + + userIf->stats.queued++; + + skb_queue_tail(&userIf->packetQueue, skb); + if (userIf->pollPtr) { + *userIf->pollPtr |= userIf->pollMask; + if (skb_queue_len(&userIf->packetQueue) >= (*userIf->recvClusterCount)) { + Atomic_Or(userIf->actPtr, userIf->actMask); + } + } + wake_up(&userIf->waitQueue); + return; + + drop_packet: + dev_kfree_skb(skb); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetUserIfProcRead -- + * + * Callback for read operation on this userif entry in vnets proc fs. + * + * Results: + * Length of read operation. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +VNetUserIfProcRead(char *page, // IN/OUT: buffer to write into + char **start, // OUT: 0 if file < 4k, else offset into + // page + off_t off, // IN: offset of read into the file + int count, // IN: maximum number of bytes to read + int *eof, // OUT: TRUE if there is nothing more to + // read + void *data) // IN: client data - not used +{ + VNetUserIF *userIf = (VNetUserIF*)data; + int len = 0; + + if (!userIf) { + return len; + } + + len += VNetPrintPort(&userIf->port, page+len); + + len += sprintf(page+len, "read %u written %u queued %u ", + userIf->stats.read, + userIf->stats.written, + userIf->stats.queued); + + len += sprintf(page+len, + "dropped.down %u dropped.mismatch %u " + "dropped.overflow %u dropped.largePacket %u", + userIf->stats.droppedDown, + userIf->stats.droppedMismatch, + userIf->stats.droppedOverflow, + userIf->stats.droppedLargePacket); + + len += sprintf(page+len, "\n"); + + *start = 0; + *eof = 1; + return len; +} + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) +/* + *---------------------------------------------------------------------- + * + * VNetCopyDatagram -- + * + * Copy part of datagram to userspace. + * + * Results: + * zero on success, + * -EFAULT if buffer is an invalid area + * + * Side effects: + * Data copied to the buffer. + * + *---------------------------------------------------------------------- + */ + +static int +VNetCopyDatagram(const struct sk_buff *skb, // IN: skb to copy + char *buf, // OUT: where to copy data + int len) // IN: length +{ + struct iovec iov = { + .iov_base = buf, + .iov_len = len, + }; + return skb_copy_datagram_iovec(skb, 0, &iov, len); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetCsumCopyDatagram -- + * + * Copy part of datagram to userspace doing checksum at same time. + * + * Do not mark this function INLINE, it is recursive! With all gcc's + * released up to now (<= gcc-3.3.1) inlining this function just + * consumes 120 more bytes of code and goes completely mad on + * register allocation, storing almost everything in the memory. + * + * Results: + * folded checksum (non-negative value) on success, + * -EINVAL if offset is too big, + * -EFAULT if buffer is an invalid area + * + * Side effects: + * Data copied to the buffer. + * + *---------------------------------------------------------------------- + */ + +static int +VNetCsumCopyDatagram(const struct sk_buff *skb, // IN: skb to copy + unsigned int offset, // IN: how many bytes skip + char *buf) // OUT: where to copy data +{ + unsigned int csum; + int err = 0; + int len = skb_headlen(skb) - offset; + char *curr = buf; + const skb_frag_t *frag; + + /* + * Something bad happened. We skip only up to skb->nh.raw, and skb->nh.raw + * must be in the header, otherwise we are in the big troubles. + */ + if (len < 0) { + return -EINVAL; + } + + csum = csum_and_copy_to_user(skb->data + offset, curr, len, 0, &err); + if (err) { + return err; + } + curr += len; + + for (frag = skb_shinfo(skb)->frags; + frag != skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags; + frag++) { + if (frag->size > 0) { + unsigned int tmpCsum; + const void *vaddr; + + vaddr = kmap(frag->page); + tmpCsum = csum_and_copy_to_user(vaddr + frag->page_offset, + curr, frag->size, 0, &err); + kunmap(frag->page); + if (err) { + return err; + } + csum = csum_block_add(csum, tmpCsum, curr - buf); + curr += frag->size; + } + } + + for (skb = skb_shinfo(skb)->frag_list; skb != NULL; skb = skb->next) { + int tmpCsum; + + tmpCsum = VNetCsumCopyDatagram(skb, 0, curr); + if (tmpCsum < 0) { + return tmpCsum; + } + /* Folded checksum must be inverted before we can use it */ + csum = csum_block_add(csum, tmpCsum ^ 0xFFFF, curr - buf); + curr += skb->len; + } + return csum_fold(csum); +} +#endif + + +/* + *---------------------------------------------------------------------- + * + * VNetCopyDatagramToUser -- + * + * Copy complete datagram to the user space. Fill correct checksum + * into the copied datagram if nobody did it yet. + * + * Results: + * On success byte count, on failure -EFAULT. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static INLINE_SINGLE_CALLER int +VNetCopyDatagramToUser(const struct sk_buff *skb, // IN + char *buf, // OUT + size_t count) // IN +{ + if (count > skb->len) { + count = skb->len; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 4) + if (copy_to_user(buf, skb->data, count)) { + return -EFAULT; + } +#else + /* + * If truncation occurs, we do not bother with checksumming - caller cannot + * verify checksum anyway in such case, and copy without checksum is + * faster. + */ + if (skb->pkt_type == PACKET_OUTGOING && /* Packet must be outgoing */ + skb->ip_summed == VM_TX_CHECKSUM_PARTIAL && /* Without checksum */ + compat_skb_network_header_len(skb) && /* We must know where header is */ + skb->len == count) { /* No truncation may occur */ + size_t skl; + int csum; + u_int16_t csum16; + + skl = compat_skb_csum_start(skb); + if (VNetCopyDatagram(skb, buf, skl)) { + return -EFAULT; + } + csum = VNetCsumCopyDatagram(skb, skl, buf + skl); + if (csum < 0) { + return csum; + } + csum16 = csum; + if (copy_to_user(buf + skl + compat_skb_csum_offset(skb), + &csum16, sizeof csum16)) { + return -EFAULT; + } + } else { + if (VNetCopyDatagram(skb, buf, count)) { + return -EFAULT; + } + } +#endif + return count; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetUserIfRead -- + * + * The virtual network's read file operation. Reads the next pending + * packet for this network connection. + * + * Results: + * On success the len of the packet received, + * else if no packet waiting and nonblocking 0, + * else -errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +VNetUserIfRead(VNetPort *port, // IN + struct file *filp, // IN + char *buf, // OUT + size_t count) // IN +{ + VNetUserIF *userIf = (VNetUserIF*)port->jack.private; + struct sk_buff *skb; + int ret; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&userIf->waitQueue, &wait); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + mb(); + skb = skb_peek(&userIf->packetQueue); + if (skb && (skb->len > count)) { + skb = NULL; + ret = -EMSGSIZE; + break; + } + ret = -EAGAIN; + skb = skb_dequeue(&userIf->packetQueue); + + if (userIf->pollPtr) { + if (skb_queue_empty(&userIf->packetQueue)) { + *userIf->pollPtr &= ~userIf->pollMask; + } +#if 0 + /* + * Disable this for now since the monitor likes to assert that + * actions are present and thus can't cope with them disappearing + * out from under it. See bug 47760. -Jeremy. 22 July 2004 + */ + + if (skb_queue_len(&userIf->packetQueue) < (*userIf->recvClusterCount) && + (Atomic_Read(userIf->actPtr) & userIf->actMask) != 0) { + Atomic_And(userIf->actPtr, ~userIf->actMask); + } +#endif + } + + if (skb != NULL || filp->f_flags & O_NONBLOCK) { + break; + } + ret = -EINTR; + if (signal_pending(current)) { + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&userIf->waitQueue, &wait); + if (! skb) { + return ret; + } + + userIf->stats.read++; + + count = VNetCopyDatagramToUser(skb, buf, count); + dev_kfree_skb(skb); + return count; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetUserIfWrite -- + * + * The virtual network's write file operation. Send the raw packet + * to the network. + * + * Results: + * On success the count of bytes written else errno. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +VNetUserIfWrite(VNetPort *port, // IN + struct file *filp, // IN + const char *buf, // IN + size_t count) // IN +{ + VNetUserIF *userIf = (VNetUserIF*)port->jack.private; + struct sk_buff *skb; + + /* + * Check size + */ + + if (count < sizeof (struct ethhdr) || + count > ETHER_MAX_QUEUED_PACKET) { + return -EINVAL; + } + + /* + * Required to enforce the downWhenAddrMismatch policy in the MAC + * layer. --hpreg + */ + if (!UP_AND_RUNNING(userIf->port.flags)) { + userIf->stats.droppedDown++; + return count; + } + + /* + * Allocate an sk_buff. + */ + + skb = dev_alloc_skb(count + 7); + if (skb == NULL) { + // XXX obey O_NONBLOCK? + return -ENOBUFS; + } + + skb_reserve(skb, 2); + + /* + * Copy the data and send it. + */ + + userIf->stats.written++; + if (copy_from_user(skb_put(skb, count), buf, count)) { + dev_kfree_skb(skb); + return -EFAULT; + } + + VNetSend(&userIf->port.jack, skb); + + return count; +} + + +/* + *----------------------------------------------------------------------------- + * + * VNetUserIfIoctl -- + * + * XXX + * + * Results: + * 0 on success + * -errno on failure + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static int +VNetUserIfIoctl(VNetPort *port, // IN + struct file *filp, // IN + unsigned int iocmd, // IN + unsigned long ioarg) // IN or OUT depending on iocmd +{ + VNetUserIF *userIf = (VNetUserIF*)port->jack.private; + + switch (iocmd) { + case SIOCSETNOTIFY: + return -EINVAL; + case SIOCSETNOTIFY2: +#ifdef VMX86_SERVER + /* + * This ioctl always return failure on ESX since we cannot map pages into + * the console os that are from the VMKernel address space which was the + * only case we used this. + */ + return -EINVAL; +#else // VMX86_SERVER + /* + * ORs pollMask into the integer pointed to by ptr if pending packet. Is + * cleared when all packets are drained. + */ + { + int retval; + VNet_Notify vn; + + if (copy_from_user(&vn, (void *)ioarg, sizeof vn)) { + return -EFAULT; + } + + if (vn.version != 3) { + return -EINVAL; + } + + retval = VNetUserIfSetupNotify(userIf, &vn); + if (retval < 0) { + return retval; + } + + break; + } +#endif // VMX86_SERVER + case SIOCUNSETNOTIFY: + if (!userIf->pollPtr) { + /* This should always happen on ESX. */ + return -EINVAL; + } + VNetUserIfUnsetupNotify(userIf); + break; + + case SIOCSIFFLAGS: + /* + * Drain queue when interface is no longer active. We drain the queue to + * avoid having old packets delivered to the guest when reneabled. + */ + + if (!UP_AND_RUNNING(userIf->port.flags)) { + struct sk_buff *skb; + + while ((skb = skb_dequeue(&userIf->packetQueue)) != NULL) { + dev_kfree_skb(skb); + } + + if (userIf->pollPtr) { + /* Clear the pending bit as no packets are pending at this point. */ + *userIf->pollPtr &= ~userIf->pollMask; + } + } + break; + + default: + return -ENOIOCTLCMD; + break; + } + + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetUserIfPoll -- + * + * The virtual network's file poll operation. + * + * Results: + * Return POLLIN if success, else sleep and return 0. + * FIXME: Should not we always return POLLOUT? + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +VNetUserIfPoll(VNetPort *port, // IN + struct file *filp, // IN + poll_table *wait) // IN +{ + VNetUserIF *userIf = (VNetUserIF*)port->jack.private; + + poll_wait(filp, &userIf->waitQueue, wait); + if (!skb_queue_empty(&userIf->packetQueue)) { + return POLLIN; + } + + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetUserIf_Create -- + * + * Create a user level port to the wonderful world of virtual + * networking. + * + * Results: + * Errno. Also returns an allocated port to connect to, + * NULL on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetUserIf_Create(VNetPort **ret) // OUT +{ + VNetUserIF *userIf; + static unsigned id = 0; + int retval; + + userIf = kmalloc(sizeof *userIf, GFP_USER); + if (!userIf) { + return -ENOMEM; + } + + /* + * Initialize fields. + */ + + userIf->port.id = id++; + + userIf->port.jack.peer = NULL; + userIf->port.jack.numPorts = 1; + VNetSnprintf(userIf->port.jack.name, sizeof userIf->port.jack.name, + "userif%u", userIf->port.id); + userIf->port.jack.private = userIf; + userIf->port.jack.index = 0; + userIf->port.jack.procEntry = NULL; + userIf->port.jack.free = VNetUserIfFree; + userIf->port.jack.rcv = VNetUserIfReceive; + userIf->port.jack.cycleDetect = NULL; + userIf->port.jack.portsChanged = NULL; + userIf->port.jack.isBridged = NULL; + userIf->pollPtr = NULL; + userIf->actPtr = NULL; + userIf->recvClusterCount = NULL; + userIf->pollPage = NULL; + userIf->actPage = NULL; + userIf->recvClusterPage = NULL; + userIf->pollMask = userIf->actMask = 0; + + /* + * Make proc entry for this jack. + */ + + retval = VNetProc_MakeEntry(userIf->port.jack.name, S_IFREG, + &userIf->port.jack.procEntry); + if (retval) { + if (retval == -ENXIO) { + userIf->port.jack.procEntry = NULL; + } else { + kfree(userIf); + return retval; + } + } else { + userIf->port.jack.procEntry->read_proc = VNetUserIfProcRead; + userIf->port.jack.procEntry->data = userIf; + } + + /* + * Rest of fields. + */ + + userIf->port.flags = IFF_RUNNING; + + memset(userIf->port.paddr, 0, sizeof userIf->port.paddr); + memset(userIf->port.ladrf, 0, sizeof userIf->port.ladrf); + + VNet_MakeMACAddress(&userIf->port); + + userIf->port.fileOpRead = VNetUserIfRead; + userIf->port.fileOpWrite = VNetUserIfWrite; + userIf->port.fileOpIoctl = VNetUserIfIoctl; + userIf->port.fileOpPoll = VNetUserIfPoll; + + skb_queue_head_init(&(userIf->packetQueue)); + init_waitqueue_head(&userIf->waitQueue); + + memset(&userIf->stats, 0, sizeof userIf->stats); + + *ret = (VNetPort*)userIf; + return 0; +} diff -Nrup source/vmnet-only/linux/vnetEvent.c source.edited/vmnet-only/linux/vnetEvent.c --- source/vmnet-only/linux/vnetEvent.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/vnetEvent.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,549 @@ +/********************************************************* + * Copyright (C) 2007 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 + * + *********************************************************/ + +/* + * vnetEvent.c -- + * + * The event notification mechanism for the vmnet module. It consists of + * mechanisms, senders, listeners, and events. A mechanism is the scope of + * a single notification mechanism. Within this scope, senders send events + * to listeners and listeners handle events by means of their registered + * event handler. + * + * Mechanisms, senders, and listeners can be created and destroyed in any + * order. The implementation ensures proper destruction independent of the + * destruction order. + * + * The event handlers registered by the listeners are not allowed to + * recursively enter the mechanism. The implementation enforces this rule. + * The event handlers are not allowed to block. + * + * Mechanisms, senders, and listeners are thread-safe, i.e. they can be + * accessed concurrently by multiple threads. Event handlers must be thread- + * safe. + * + * Callers into the event notification mechanism can assume that they are + * not called recursively by event handlers. Furthermore, they can assume + * that they do not block. + * + * Implementation Notes + * + * The mechanism, including senders, listeners, ands event lists are + * guarded by the mechanism's 'lock' spinlock. The listener's event + * handlers are called holding this lock. + * + * To avoid deadlock from event handlers recursively calling the + * notification mechanism, the mechanism's 'currentHandler' field stores the + * calling task during invocation of an event handler. + * + */ + +#include "vnetKernel.h" +#include "vnetEvent.h" + +typedef struct VNetEvent_EventNode VNetEvent_EventNode; + +struct VNetEvent_EventNode { + VNetEvent_EventNode *nextEvent; + VNet_EventHeader event; +}; + +#define EVENT_NODE_HEADER_SIZE offsetof(struct VNetEvent_EventNode, event) + +struct VNetEvent_Mechanism { + VNetKernel_SpinLock lock; /* mechanism lock */ + void *handlerTask; /* task calling an event handler */ + uint32 refCount; /* ref count */ + uint32 senderId; /* next sender id */ + VNetEvent_Sender *firstSender; /* first sender */ + VNetEvent_Listener *firstListener; /* first listener */ +}; + +struct VNetEvent_Sender { + VNetEvent_Mechanism *m; /* mechanism */ + uint32 senderId; /* sender id */ + VNetEvent_Sender *nextSender; /* next sender */ + VNetEvent_EventNode *firstEvent; /* first event */ +}; + +struct VNetEvent_Listener { + VNetEvent_Mechanism *m; /* mechanism */ + VNetEvent_Listener *nextListener; /* next listener */ + VNetEvent_Handler handler; /* event handler */ + void *data; /* event handler data */ + uint32 classMask; /* event handler class mask */ +}; + + +/* + *----------------------------------------------------------------------------- + * VNetEvent_Mechanism + *----------------------------------------------------------------------------- + */ + +/* + *----------------------------------------------------------------------------- + * + * VNetEvent_CreateMechanism -- + * + * Creates a mechanism. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VNetEvent_CreateMechanism(VNetEvent_Mechanism **m) // OUT: the new mechanism +{ + VNetEvent_Mechanism *t; + + /* allocate mechanism */ + t = VNetKernel_MemoryAllocate(sizeof *t); + if (t == NULL) { + return VNetKernel_ENOMEM; + } + + /* initialize mechanism */ + VNetKernel_SpinLockInit(&t->lock); + t->handlerTask = NULL; + t->refCount = 1; + t->senderId = 0; + t->firstSender = NULL; + t->firstListener = NULL; + + /* return mechanism */ + *m = t; + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * VNetEvent_DestroyMechanism -- + * + * Destroys a mechanism. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VNetEvent_DestroyMechanism(VNetEvent_Mechanism *m) // IN: a mechanism +{ + uint32 refCount; + + /* check handler recursion */ + if (m->handlerTask == VNetKernel_ThreadCurrent()) { + return VNetKernel_EBUSY; + } + + /* decrement ref count */ + VNetKernel_SpinLockAcquire(&m->lock); + refCount = --m->refCount; + VNetKernel_SpinLockRelease(&m->lock); + + /* free mechanism */ + if (refCount == 0) { + VNetKernel_SpinLockFree(&m->lock); + VNetKernel_MemoryFree(m); + } + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * VNetEvent_Sender + *----------------------------------------------------------------------------- + */ + +/* + *----------------------------------------------------------------------------- + * + * VNetEvent_CreateSender -- + * + * Creates a sender. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VNetEvent_CreateSender(VNetEvent_Mechanism *m, // IN: a mechanism + VNetEvent_Sender **s) // OUT: the new sender +{ + VNetEvent_Sender *t; + + /* check handler recursion */ + if (m->handlerTask == VNetKernel_ThreadCurrent()) { + return VNetKernel_EBUSY; + } + + /* allocate sender */ + t = VNetKernel_MemoryAllocate(sizeof *t); + if (t == NULL) { + return VNetKernel_ENOMEM; + } + + /* initialize sender and insert it into sender list */ + VNetKernel_SpinLockAcquire(&m->lock); + t->m = m; + m->refCount++; + t->senderId = m->senderId; + m->senderId++; + t->nextSender = m->firstSender; + m->firstSender = t; + t->firstEvent = NULL; + VNetKernel_SpinLockRelease(&m->lock); + + /* return sender */ + *s = t; + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * VNetEvent_DestroySender -- + * + * Destroys a sender. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VNetEvent_DestroySender(VNetEvent_Sender *s) // IN: a sender +{ + VNetEvent_Mechanism *m; + VNetEvent_Sender *p; + VNetEvent_Sender **q; + VNetEvent_EventNode *n; + + /* check handler recursion */ + m = s->m; + if (m->handlerTask == VNetKernel_ThreadCurrent()) { + return VNetKernel_EBUSY; + } + + /* remove sender from sender list */ + VNetKernel_SpinLockAcquire(&m->lock); + q = &m->firstSender; + while (TRUE) { + p = *q; + if (p == NULL) { + /* not found */ + VNetKernel_SpinLockRelease(&m->lock); + return VNetKernel_EINVAL; + } else if (p == s) { + /* found */ + break; + } + q = &p->nextSender; + } + *q = p->nextSender; + VNetKernel_SpinLockRelease(&m->lock); + VNetEvent_DestroyMechanism(m); + + /* free sender and events */ + n = s->firstEvent; + while (n != NULL) { + VNetEvent_EventNode *t = n; + n = n->nextEvent; + VNetKernel_MemoryFree(t); + } + VNetKernel_MemoryFree(s); + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * VNetEvent_GetSenderId -- + * + * Returns the sender id of a sender. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VNetEvent_GetSenderId(const VNetEvent_Sender *s, // IN: a sender + uint32 *senderId) // OUT: the sender id +{ + + /* we don't check handler recursion */ + + /* return senderId */ + *senderId = s->senderId; + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * VNetEvent_Send -- + * + * Sends an event to all listeners registered with a sender. The + * precondition 's->senderId == e->senderId' must hold. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VNetEvent_Send(VNetEvent_Sender *s, // IN: a sender + VNet_EventHeader *e) // IN: an event +{ + VNetEvent_Mechanism *m; + VNetEvent_EventNode *p; + VNetEvent_EventNode **q; + VNetEvent_Listener *l; + uint32 classSet; + + /* check handler recursion */ + m = s->m; + if (m->handlerTask == VNetKernel_ThreadCurrent()) { + return VNetKernel_EBUSY; + } + + /* precondition */ + if (s->senderId != e->senderId) { + return VNetKernel_EINVAL; + } + + /* lock */ + VNetKernel_SpinLockAcquire(&m->lock); + m->handlerTask = VNetKernel_ThreadCurrent(); + + /* find previously sent event */ + q = &s->firstEvent; + while (TRUE) { + p = *q; + if (p == NULL || + (p->event.eventId == e->eventId && p->event.type == e->type)) { + break; + } + q = &p->nextEvent; + } + + /* remove previously sent event */ + if (p != NULL && p->event.size != e->size) { + *q = p->nextEvent; + VNetKernel_MemoryFree(p); + p = NULL; + } + + /* insert new event into event list*/ + if (p == NULL) { + p = VNetKernel_MemoryAllocate(EVENT_NODE_HEADER_SIZE + e->size); + if (p == NULL) { + m->handlerTask = NULL; + VNetKernel_SpinLockRelease(&m->lock); + return VNetKernel_ENOMEM; + } + p->nextEvent = s->firstEvent; + s->firstEvent = p; + } + memcpy(&p->event, e, e->size); + + /* send event */ + classSet = e->classSet; + l = m->firstListener; + while (l != NULL) { + if ((classSet & l->classMask) != 0) { + l->handler(l->data, e); + } + l = l->nextListener; + } + + /* unlock */ + m->handlerTask = NULL; + VNetKernel_SpinLockRelease(&m->lock); + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * VNetEvent_Listener + *----------------------------------------------------------------------------- + */ + +/* + *----------------------------------------------------------------------------- + * + * VNetEvent_CreateListener -- + * + * Creates a listener and re-sends all existing events to the listener's + * event handler. The listener will receive events that satisfy + * 'event.class & classMask != 0'. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VNetEvent_CreateListener(VNetEvent_Mechanism *m, // IN: a mechanism + VNetEvent_Handler h, // IN: a handler + void *data, // IN: the handler's data + uint32 classMask, // IN: a class mask + VNetEvent_Listener **l) // OUT: the new listener +{ + VNetEvent_Listener *t; + VNetEvent_Sender *s; + VNetEvent_EventNode *e; + + /* check handler recursion */ + if (m->handlerTask == VNetKernel_ThreadCurrent()) { + return VNetKernel_EBUSY; + } + + /* allocate listener */ + t = VNetKernel_MemoryAllocate(sizeof *t); + if (t == NULL) { + return VNetKernel_ENOMEM; + } + + /* lock */ + VNetKernel_SpinLockAcquire(&m->lock); + m->handlerTask = VNetKernel_ThreadCurrent(); + + /* initialize listener and insert it into listener list */ + t->m = m; + m->refCount++; + t->nextListener = m->firstListener; + m->firstListener = t; + t->handler = h; + t->data = data; + t->classMask = classMask; + + /* creation done, so send all events */ + s = m->firstSender; + while (s != NULL) { + e = s->firstEvent; + while (e != NULL) { + if ((e->event.classSet & classMask) != 0) { + h(data, &e->event); + } + e = e->nextEvent; + } + s = s->nextSender; + } + + /* unlock */ + m->handlerTask = NULL; + VNetKernel_SpinLockRelease(&m->lock); + + /* return listener */ + *l = t; + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * VNetEvent_DestroyListener -- + * + * Destroys a listener. + * + * Results: + * Returns 0 if successful, or a negative value if an error occurs. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VNetEvent_DestroyListener(VNetEvent_Listener *l) // IN: a listener +{ + VNetEvent_Mechanism *m; + VNetEvent_Listener *p; + VNetEvent_Listener **q; + + /* check handler recursion */ + m = l->m; + if (m->handlerTask == VNetKernel_ThreadCurrent()) { + return VNetKernel_EBUSY; + } + + /* remove listener from listener list */ + VNetKernel_SpinLockAcquire(&m->lock); + q = &m->firstListener; + while (TRUE) { + p = *q; + if (p == NULL) { + /* not found */ + VNetKernel_SpinLockRelease(&m->lock); + return VNetKernel_EINVAL; + } else if (p == l) { + /* found */ + break; + } + q = &p->nextListener; + } + *q = p->nextListener; + VNetKernel_SpinLockRelease(&m->lock); + VNetEvent_DestroyMechanism(m); + + /* free listener */ + VNetKernel_MemoryFree(l); + return 0; +} diff -Nrup source/vmnet-only/linux/vnetUserListener.c source.edited/vmnet-only/linux/vnetUserListener.c --- source/vmnet-only/linux/vnetUserListener.c 1969-12-31 16:00:00.000000000 -0800 +++ source.edited/vmnet-only/linux/vnetUserListener.c 2010-05-09 20:09:36.000000000 -0700 @@ -0,0 +1,334 @@ +/********************************************************* + * Copyright (C) 2008 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 + * + *********************************************************/ + +/* + * vnetUserListener.c -- + * + * The user listener module implements an event queue that can be accessed + * by the vmx process. + * + * It registers an event listener with a given classMask. The listener + * enqueues events and the vmx process dequeues them. The vmx process can + * use blocking or non-blocking reads to consume the events. The user + * listener is thread safe. + */ + +#include "driver-config.h" /* must be first */ +#include +#include +#include "compat_skbuff.h" +#include "compat_wait.h" +#include "compat_sched.h" +#include "vnetInt.h" + +typedef struct VNetUserListener_EventNode VNetUserListener_EventNode; + +struct VNetUserListener_EventNode { + VNetUserListener_EventNode *nextEvent; + VNet_EventHeader event; +}; + +#define EVENT_NODE_HEADER_SIZE offsetof(struct VNetUserListener_EventNode, event) + +typedef struct VNetUserListener { + VNetPort port; /* base port/jack */ + VNetEvent_Listener *eventListener; /* event listener */ + struct semaphore lock; /* listener lock */ + wait_queue_head_t readerQueue; /* reader queue */ + VNetUserListener_EventNode *firstEvent; /* first event to be read */ + VNetUserListener_EventNode *lastEvent; /* last event to be read*/ +} VNetUserListener; + +static void VNetUserListenerFree(VNetJack *jack); +static void VNetUserListenerEventHandler(void *context, VNet_EventHeader *e); +static int VNetUserListenerRead(VNetPort *port, struct file *filp, char *buf, + size_t count); +static int VNetUserListenerPoll(VNetPort *port, struct file *filp, + poll_table *wait); + + +/* + *---------------------------------------------------------------------- + * + * VNetUserListener_Create -- + * + * Creates a user listener. Initializes the jack, the port, and itself. + * Finally, registers the event listener. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VNetUserListener_Create(uint32 classMask, // IN: the listener's class mask + VNetJack *hubJack, // IN: the future hub jack + VNetPort **port) // OUT: port to virtual hub +{ + static unsigned id = 0; + VNetUserListener *userListener; + int res; + + /* allocate user listener */ + userListener = kmalloc(sizeof *userListener, GFP_USER); + if (userListener == NULL) { + return -ENOMEM; + } + + /* initialize jack */ + userListener->port.jack.peer = NULL; + userListener->port.jack.numPorts = 1; + VNetSnprintf(userListener->port.jack.name, + sizeof userListener->port.jack.name, "userListener%u", id); + userListener->port.jack.private = userListener; + userListener->port.jack.index = 0; + userListener->port.jack.procEntry = NULL; + userListener->port.jack.free = VNetUserListenerFree; + userListener->port.jack.rcv = NULL; + userListener->port.jack.cycleDetect = NULL; + userListener->port.jack.portsChanged = NULL; + userListener->port.jack.isBridged = NULL; + + /* initialize port */ + userListener->port.id = id++; + userListener->port.flags = 0; + memset(userListener->port.paddr, 0, sizeof userListener->port.paddr); + memset(userListener->port.ladrf, 0, sizeof userListener->port.ladrf); + userListener->port.next = NULL; + userListener->port.fileOpRead = VNetUserListenerRead; + userListener->port.fileOpWrite = NULL; + userListener->port.fileOpIoctl = NULL; + userListener->port.fileOpPoll = VNetUserListenerPoll; + + /* initialize user listener */ + userListener->eventListener = NULL; + sema_init(&userListener->lock, 1); + init_waitqueue_head(&userListener->readerQueue); + userListener->firstEvent = NULL; + userListener->lastEvent = NULL; + + /* + * create listener, must be after initialization because it fires right away + * and populates the event queue, i.e. the event handler callback is called + * before create listener returns + */ + res = VNetHub_CreateListener(hubJack, VNetUserListenerEventHandler, + userListener, classMask, + &userListener->eventListener); + if (res != 0) { + LOG(0, (KERN_DEBUG "VNetUserListener_Create, can't create listener " + "(%d)\n", res)); + kfree(userListener); + return res; + } + + /* return listener */ + *port = (VNetPort*)userListener; + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetUserListenerFree -- + * + * Frees a user listenere. Unregisters the event listener and drains the + * event queue. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +VNetUserListenerFree(VNetJack *jack) // IN: jack to free +{ + VNetUserListener *userListener; + int res; + VNetUserListener_EventNode *p; + + /* destroy event listener */ + userListener = (VNetUserListener*)jack; + res = VNetEvent_DestroyListener(userListener->eventListener); + if (res != 0) { + LOG(0, (KERN_DEBUG "VNetUserListenerFree, can't destroy listener" + "(%d)\n", res)); + } + + /* clear event queue */ + down(&userListener->lock); + p = userListener->firstEvent; + while (p != NULL) { + VNetUserListener_EventNode *t = p; + p = p->nextEvent; + kfree(t); + } + up(&userListener->lock); + + /* free user listener */ + kfree(userListener); +} + + +/* + *---------------------------------------------------------------------- + * + * VNetUserListenerEventHandler -- + * + * Enqueues an event. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +VNetUserListenerEventHandler(void *context, // IN: the user listener + VNet_EventHeader *e) // IN: an event +{ + VNetUserListener *userListener; + VNetUserListener_EventNode *t; + + /* allocate and initialize event node */ + t = kmalloc(EVENT_NODE_HEADER_SIZE + e->size, GFP_USER); + if (t == NULL) { + LOG(0, (KERN_DEBUG "VNetUserListenerEventHandler, out of memory\n")); + return; + } + t->nextEvent = NULL; + memcpy(&t->event, e, e->size); + + /* append event to event list */ + userListener = (VNetUserListener*)context; + down(&userListener->lock); + if (userListener->lastEvent != NULL) { + userListener->lastEvent->nextEvent = t; + } else { + userListener->firstEvent = t; + } + userListener->lastEvent = t; + up(&userListener->lock); + + /* wake up readers */ + wake_up_interruptible(&userListener->readerQueue); +} + +/* + *---------------------------------------------------------------------- + * + * VNetUserListenerRead -- + * + * Dequeues an event. May or may not block depending of the filp flags. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +VNetUserListenerRead(VNetPort *port, // IN: the user listener + struct file *filp, // IN: the filp + char *buf, // OUT: the buffer + size_t count) // IN: the buffer size +{ + VNetUserListener *userListener; + VNetUserListener_EventNode *t; + size_t n; + int res; + + /* wait until there is data */ + userListener = (VNetUserListener*)port->jack.private; + down(&userListener->lock); + while (userListener->firstEvent == NULL) { + up(&userListener->lock); + + /* can we block? */ + if (filp->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + + /* wait until there is data or we get interrupted */ + if (wait_event_interruptible(userListener->readerQueue, + userListener->firstEvent != NULL)) { + return -ERESTARTSYS; + } + + down(&userListener->lock); + } + + /* remove event from event list */ + t = userListener->firstEvent; + userListener->firstEvent = t->nextEvent; + if (userListener->firstEvent == NULL) { + userListener->lastEvent = NULL; + } + up(&userListener->lock); + + /* return data and free event */ + n = t->event.size; + if (count < n) { + n = count; + } + res = copy_to_user(buf, &t->event, n); + kfree(t); + return res ? -EFAULT : n; +} + + +/* + *---------------------------------------------------------------------- + * + * VNetUserListenerPoll -- + * + * Polls an event. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +VNetUserListenerPoll(VNetPort *port, // IN: the user listener + struct file *filp, // IN: the filp + poll_table *wait) // IN: the poll table +{ + VNetUserListener *userListener = (VNetUserListener*)port->jack.private; + poll_wait(filp, &userListener->readerQueue, wait); + return userListener->firstEvent != NULL ? POLLIN | POLLRDNORM : 0; +} diff -Nrup source/vmnet-only/Makefile.kernel source.edited/vmnet-only/Makefile.kernel --- source/vmnet-only/Makefile.kernel 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/Makefile.kernel 2010-05-09 20:09:36.000000000 -0700 @@ -17,7 +17,9 @@ # ########################################################## -INCLUDE := -I$(SRCROOT) +INCLUDE := -I. +INCLUDE := -I$(SRCROOT)/include +INCLUDE += -I$(SRCROOT)/linux EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE) EXTRA_CFLAGS += $(call vm_check_build, $(SRCROOT)/epoll.c, -DVMW_HAVE_EPOLL, ) @@ -31,8 +33,9 @@ EXTRA_CFLAGS += $(call vm_check_build, $ obj-m += $(DRIVER).o -$(DRIVER)-y := driver.o hub.o userif.o netif.o bridge.o filter.o procfs.o smac_compat.o \ - smac.o vnetEvent.o vnetUserListener.o +$(DRIVER)-y := linux/driver.o linux/hub.o linux/userif.o linux/netif.o linux/bridge.o \ + linux/filter.o linux/procfs.o linux/smac_compat.o linux/smac.o \ + linux/vnetEvent.o linux/vnetUserListener.o #### #### Make Targets are beneath here. diff -Nrup source/vmnet-only/netdev_has_dev_net.c source.edited/vmnet-only/netdev_has_dev_net.c --- source/vmnet-only/netdev_has_dev_net.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/netdev_has_dev_net.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,37 +0,0 @@ -/********************************************************* - * Copyright (C) 2008 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 - * - *********************************************************/ - -/* - * Detect whether there is dev_net accessor for dev->nd_net. - * It appeared between 2.6.25 and 2.6.26-rc1. - */ - -#include -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) -# error This compile test intentionally fails. -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) -# include - -struct net * -vmware_dev_net(struct net_device *dev) -{ - return dev_net(dev); -} -#endif diff -Nrup source/vmnet-only/netdev_has_net.c source.edited/vmnet-only/netdev_has_net.c --- source/vmnet-only/netdev_has_net.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/netdev_has_net.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,43 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 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 - * - *********************************************************/ - -/* - * Detect whether there is separate net namespace. It got introduced after - * 2.6.23. If this builds, there are two arguments to __dev_get_by_name... - * For lower boundary use 2.6.23 - hopefully nobody crossports patch to - * older kernels. Note that this also affects sk_alloc interface - - * for that there are two versions: sk_alloc(net, family, gfp, proto, 1) for - * kernels 2.6.23 < x <= 2.6.24-rc1, and 4 argument version - * sk_alloc(net, family, gfp, proto) for 2.6.24-rc1 < x. We do ignore 2.6.24-rc1 - * as hopefully in few weeks all 2.6.24-rc1 users will be gone. - */ - -#include -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) -# error This compile test intentionally fails. -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) -# include - -struct net_device * -vmware_get_by_name(void) -{ - return __dev_get_by_name(0, "dummy"); -} -#endif diff -Nrup source/vmnet-only/net.h source.edited/vmnet-only/net.h --- source/vmnet-only/net.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/net.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,136 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -/************************************************************ - * - * net.h - * - * This file should contain all network global defines. - * No vlance/vmxnet/vnet/vmknet specific stuff should be - * put here only defines used/usable by all network code. - * --gustav - * - ************************************************************/ - -#ifndef VMWARE_DEVICES_NET_H -#define VMWARE_DEVICES_NET_H - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMEXT -#include "includeCheck.h" -#include "vm_device_version.h" - -#define ETHERNET_MTU 1518 -#define ETH_MIN_FRAME_LEN 60 - -#ifndef ETHER_ADDR_LEN -#define ETHER_ADDR_LEN 6 /* length of MAC address */ -#endif -#define ETH_HEADER_LEN 14 /* length of Ethernet header */ -#define IP_ADDR_LEN 4 /* length of IPv4 address */ -#define IP_HEADER_LEN 20 /* minimum length of IPv4 header */ - -#define ETHER_MAX_QUEUED_PACKET 1600 - - -/* - * State's that a NIC can be in currently we only use this - * in VLance but if we implement/emulate new adapters that - * we also want to be able to morph a new corresponding - * state should be added. - */ - -#define LANCE_CHIP 0x2934 -#define VMXNET_CHIP 0x4392 - -/* - * Size of reserved IO space needed by the LANCE adapter and - * the VMXNET adapter. If you add more ports to Vmxnet than - * there is reserved space you must bump VMXNET_CHIP_IO_RESV_SIZE. - * The sizes must be powers of 2. - */ - -#define LANCE_CHIP_IO_RESV_SIZE 0x20 -#define VMXNET_CHIP_IO_RESV_SIZE 0x40 - -#define MORPH_PORT_SIZE 4 - - -#ifdef USERLEVEL - -/* - *---------------------------------------------------------------------------- - * - * Net_AddAddrToLADRF -- - * - * Given a MAC address, sets the corresponding bit in the LANCE style - * Logical Address Filter 'ladrf'. - * The caller should have initialized the ladrf to all 0's, as this - * function only ORs on a bit in the array. - * 'addr' is presumed to be ETHER_ADDR_LEN in size; - * 'ladrf' is presumed to point to a 64-bit vector. - * - * Derived from a long history of derivations, originally inspired by - * sample code from the AMD "Network Products: Ethernet Controllers 1998 - * Data Book, Book 2", pages 1-53..1-55. - * - * Returns: - * None. - * - * Side effects: - * Updates 'ladrf'. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void -Net_AddAddrToLadrf(const uint8 *addr, // IN: pointer to MAC address - uint8 *ladrf) // IN/OUT: pointer to ladrf -{ -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ - - uint16 hashcode; - int32 crc = 0xffffffff; /* init CRC for each address */ - int32 j; - int32 bit; - int32 byte; - - ASSERT(addr); - ASSERT(ladrf); - - for (byte = 0; byte < ETHER_ADDR_LEN; byte++) { /* for each address byte */ - /* process each address bit */ - for (bit = *addr++, j = 0; - j < 8; - j++, bit >>= 1) { - crc = (crc << 1) ^ ((((crc < 0 ? 1 : 0) ^ bit) & 0x01) ? - CRC_POLYNOMIAL_BE : 0); - } - } - hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */ - for (j = 0; j < 5; j++) { /* ... in reverse order. */ - hashcode = (hashcode << 1) | ((crc>>=1) & 1); - } - - ladrf[hashcode >> 3] |= 1 << (hashcode & 0x07); -} - -#endif // USERLEVEL - -#endif // VMWARE_DEVICES_NET_H diff -Nrup source/vmnet-only/netif.c source.edited/vmnet-only/netif.c --- source/vmnet-only/netif.c 2010-05-09 20:06:53.000000000 -0700 +++ source.edited/vmnet-only/netif.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,755 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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" - -#define EXPORT_SYMTAB - -#include -#include -#include -#ifdef KERNEL_2_2 -# include -#else -# include -#endif -#include - -#include -#include -#include -#include "compat_skbuff.h" -#include -#include "compat_sock.h" - -#define __KERNEL_SYSCALLS__ -#include - -#include -#include - -#include "vnetInt.h" -#include "compat_netdevice.h" -#include "vmnetInt.h" - - -typedef struct VNetNetIF { - VNetPort port; - struct net_device *dev; - char devName[VNET_NAME_LEN]; - struct net_device_stats stats; -} VNetNetIF; - - -static void VNetNetIfFree(VNetJack *this); -static void VNetNetIfReceive(VNetJack *this, struct sk_buff *skb); -static Bool VNetNetIfCycleDetect(VNetJack *this, int generation); - -static int VNetNetifOpen(struct net_device *dev); -static int VNetNetifProbe(struct net_device *dev); -static int VNetNetifClose(struct net_device *dev); -static int VNetNetifStartXmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *VNetNetifGetStats(struct net_device *dev); -static int VNetNetifSetMAC(struct net_device *dev, void *addr); -static void VNetNetifSetMulticast(struct net_device *dev); -#if 0 -#ifdef KERNEL_2_3_43 -static void VNetNetifTxTimeout(struct net_device *dev); -#endif -#endif - -static int VNetNetIfProcRead(char *page, char **start, off_t off, - int count, int *eof, void *data); - -#ifndef KERNEL_2_3_43 -/* softnet API emulation */ - - -/* - *---------------------------------------------------------------------- - * - * netif_stop_queue -- - * - * Stops queue processing. - * - * Results: - * None. - * - *---------------------------------------------------------------------- - */ - -static inline void -netif_stop_queue(struct net_device *dev) // IN: -{ - dev->tbusy = 1; -} - - -/* - *---------------------------------------------------------------------- - * - * netif_start_queue -- - * - * Enables queue processing. It does not try to start received - * frames processing. - * - * Results: - * None. - * - *---------------------------------------------------------------------- - */ - -static inline void -netif_start_queue(struct net_device *dev) // IN: -{ - dev->tbusy = 0; -} - - -/* - *---------------------------------------------------------------------- - * - * netif_wake_queue -- - * - * Enables queue processing. It schedules receive queue processing. - * - * Results: - * None. - * - *---------------------------------------------------------------------- - */ - -static inline void -netif_wake_queue(struct net_device *dev) // IN: -{ - dev->tbusy = 0; - mark_bh(NET_BH); -} -#endif - - -#if 0 -#ifdef KERNEL_2_3_43 -/* - *---------------------------------------------------------------------- - * - * VNetNetIfTxTimeout -- - * - * Enables processing of Tx queue after it was stopped for so long. - * It should not happen with vmnet system. - * - * Results: - * None. - * - * Side effects: - * Tx queue enabled, message in log. - * - *---------------------------------------------------------------------- - */ - -static void -VNetNetifTxTimeout(struct net_device *dev) // IN: -{ - static int netRateLimit = 0; - - if (netRateLimit < 10) { - LOG(0, (KERN_NOTICE "%s: Transmit timeout\n", dev->name)); - netRateLimit++; - } - /* We cannot stuck due to hardware, so always wake up processing */ - netif_wake_queue(dev); -} -#endif -#endif - - -/* - *---------------------------------------------------------------------- - * - * VNetNetIfSetup -- - * - * Sets initial netdevice state. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) - -static const struct net_device_ops vnet_netdev_ops = { - - .ndo_init = VNetNetifProbe, - .ndo_open = VNetNetifOpen, - .ndo_start_xmit = VNetNetifStartXmit, - .ndo_stop = VNetNetifClose, - .ndo_get_stats = VNetNetifGetStats, - .ndo_set_mac_address = VNetNetifSetMAC, - .ndo_set_multicast_list = VNetNetifSetMulticast, -}; -#endif - -static void -VNetNetIfSetup(struct net_device *dev) // IN: -{ - ether_setup(dev); // turns on IFF_BROADCAST, IFF_MULTICAST -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) - dev->netdev_ops = &vnet_netdev_ops; -#else - dev->init = VNetNetifProbe; - dev->open = VNetNetifOpen; - dev->hard_start_xmit = VNetNetifStartXmit; - dev->stop = VNetNetifClose; - dev->get_stats = VNetNetifGetStats; - dev->set_mac_address = VNetNetifSetMAC; - dev->set_multicast_list = VNetNetifSetMulticast; -#endif - /* - * We cannot stuck... If someone will report problems under - * low memory conditions or some such, we should enable it. - */ -#if 0 - dev->tx_timeout = VNetNetifTxTimeout; - dev->watchdog_timeo = TX_TIMEOUT; -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetIf_Create -- - * - * Create a net level port to the wonderful world of virtual - * networking. - * - * Results: - * Errno. Also returns an allocated port to connect to, - * NULL on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetNetIf_Create(char *devName, // IN: - VNetPort **ret, // OUT: - int hubNum) // IN: -{ - VNetNetIF *netIf; - struct net_device *dev; - int retval = 0; - static unsigned id = 0; - - netIf = kmalloc(sizeof *netIf, GFP_KERNEL); - if (!netIf) { - retval = -ENOMEM; - goto out; - } - - /* - * Initialize fields. - */ - - netIf->port.id = id++; - netIf->port.next = NULL; - - netIf->port.jack.peer = NULL; - netIf->port.jack.numPorts = 1; - VNetSnprintf(netIf->port.jack.name, sizeof netIf->port.jack.name, - "netif%u", netIf->port.id); - netIf->port.jack.private = netIf; - netIf->port.jack.index = 0; - netIf->port.jack.procEntry = NULL; - netIf->port.jack.free = VNetNetIfFree; - netIf->port.jack.rcv = VNetNetIfReceive; - netIf->port.jack.cycleDetect = VNetNetIfCycleDetect; - netIf->port.jack.portsChanged = NULL; - netIf->port.jack.isBridged = NULL; - - /* - * Make proc entry for this jack. - */ - - retval = VNetProc_MakeEntry(netIf->port.jack.name, S_IFREG, - &netIf->port.jack.procEntry); - if (retval) { - if (retval == -ENXIO) { - netIf->port.jack.procEntry = NULL; - } else { - netIf->port.jack.procEntry = NULL; - goto out; - } - } else { - netIf->port.jack.procEntry->read_proc = VNetNetIfProcRead; - netIf->port.jack.procEntry->data = netIf; - } - - /* - * Rest of fields. - */ - - netIf->port.flags = IFF_RUNNING; - - memset(netIf->port.paddr, 0, sizeof netIf->port.paddr); - memset(netIf->port.ladrf, 0, sizeof netIf->port.ladrf); - - /* This will generate the reserved MAC address c0:00:?? where ?? == hubNum. */ - VMX86_BUILD_MAC(netIf->port.paddr, hubNum); - - /* Make sure the MAC is unique. */ - retval = VNetSetMACUnique(&netIf->port, netIf->port.paddr); - if (retval) { - goto out; - } - - netIf->port.fileOpRead = NULL; - netIf->port.fileOpWrite = NULL; - netIf->port.fileOpIoctl = NULL; - netIf->port.fileOpPoll = NULL; - - memset(&netIf->stats, 0, sizeof netIf->stats); - - memcpy(netIf->devName, devName, sizeof netIf->devName); - NULL_TERMINATE_STRING(netIf->devName); - - dev = compat_alloc_netdev(0, netIf->devName, VNetNetIfSetup); - if (!dev) { - retval = -ENOMEM; - goto out; - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) - dev->priv = netIf; -#endif /* 2.6.29 */ - - netIf->dev = dev; - - memcpy(dev->dev_addr, netIf->port.paddr, sizeof netIf->port.paddr); - - if (register_netdev(dev) != 0) { - LOG(0, (KERN_NOTICE "%s: could not register network device\n", devName)); - retval = -ENODEV; - goto outFreeDev; - } - - *ret = (VNetPort*)netIf; - return 0; - -outFreeDev: - compat_free_netdev(dev); -out: - if (netIf) { - if (netIf->port.jack.procEntry) { - VNetProc_RemoveEntry(netIf->port.jack.procEntry); - } - kfree(netIf); - } - return retval; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetIfFree -- - * - * Free the net interface port. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VNetNetIfFree(VNetJack *this) // IN: jack -{ - VNetNetIF *netIf = (VNetNetIF*)this; - - unregister_netdev(netIf->dev); - compat_free_netdev(netIf->dev); - if (this->procEntry) { - VNetProc_RemoveEntry(this->procEntry); - } - kfree(netIf); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetIfReceive -- - * - * This jack is receiving a packet. Take appropriate action. - * - * Results: - * None. - * - * Side effects: - * Frees skb. - * - *---------------------------------------------------------------------- - */ - -void -VNetNetIfReceive(VNetJack *this, // IN: jack - struct sk_buff *skb) // IN: packet -{ - VNetNetIF *netIf = (VNetNetIF*)this->private; - uint8 *dest = SKB_2_DESTMAC(skb); - - if (!NETDEV_UP_AND_RUNNING(netIf->dev)) { - goto drop_packet; - } - - if (!VNetPacketMatch(dest, - netIf->dev->dev_addr, - allMultiFilter, - netIf->dev->flags)) { - goto drop_packet; - } - - /* send to the host interface */ - skb->dev = netIf->dev; - skb->protocol = eth_type_trans(skb, netIf->dev); - netif_rx_ni(skb); - netIf->stats.rx_packets++; - - return; - - drop_packet: - dev_kfree_skb(skb); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetIfCycleDetect -- - * - * Cycle detection algorithm. - * - * Results: - * TRUE if a cycle was detected, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -VNetNetIfCycleDetect(VNetJack *this, // IN: jack - int generation) // IN: -{ - VNetNetIF *netIf = (VNetNetIF*)this->private; - return VNetCycleDetectIf(netIf->devName, generation); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetifOpen -- - * - * The virtual network's open dev operation. - * - * Results: - * errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetNetifOpen(struct net_device *dev) // IN: -{ - /* - * The host interface is not available if the hub is bridged. - * - * It's actually okay to support both. We just need - * to tag packets when VNetXmitPacket gives them to the interface - * so they can be dropped by VNetBridgeReceive(). - * - * if so return -EBUSY; - */ - - netif_start_queue(dev); -#ifndef KERNEL_2_3_43 - /* Softnet does not have interrupt hack ... */ - dev->interrupt = 0; - /* ... and sets start for us */ - dev->start = 1; -#endif - // xxx need to change flags - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetifProbe -- - * - * ??? - * - * Results: - * 0. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetNetifProbe(struct net_device *dev) // IN: unused -{ - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetifClose -- - * - * The virtual network's close dev operation. - * - * Results: - * errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetNetifClose(struct net_device *dev) // IN: -{ -#ifndef KERNEL_2_3_43 - /* Softnet generic layer clears it for us */ - dev->start = 0; -#endif - netif_stop_queue(dev); - // xxx need to change flags - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetifStartXmit -- - * - * The virtual network's start xmit dev operation. - * - * Results: - * ???, 0. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetNetifStartXmit(struct sk_buff *skb, // IN: - struct net_device *dev) // IN: -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) - VNetNetIF *netIf = (VNetNetIF*)dev->priv; -#else - VNetNetIF *netIf = netdev_priv(dev); -#endif /* 2.6.29 */ - - if(skb == NULL) { - return 0; - } - - /* - * Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - * If this ever occurs the queue layer is doing something evil! - */ - -#ifndef KERNEL_2_3_43 - /* Softnet does not play with tbusy... */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - { - LOG(0, (KERN_NOTICE "%s: transmitter access conflict.\n", dev->name)); - return 1; - } -#endif - VNetSend(&netIf->port.jack, skb); - - netIf->stats.tx_packets++; -#ifndef KERNEL_2_3_43 - dev->tbusy = 0; -#endif - dev->trans_start = jiffies; - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetifSetMAC -- - * - * Sets MAC address (i.e. via ifconfig) of netif device. - * - * Results: - * Errno. - * - * Side effects: - * The MAC address may be changed. - * - *---------------------------------------------------------------------- - */ - -int -VNetNetifSetMAC(struct net_device *dev, // IN: - void *p) // IN: -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) - VNetNetIF *netIf = (VNetNetIF*)dev->priv; -#else - VNetNetIF *netIf = netdev_priv(dev); -#endif /* 2.6.29 */ - - struct sockaddr const *addr = p; - if (!VMX86_IS_STATIC_MAC(addr->sa_data)) { - return -EINVAL; - } - memcpy(netIf->port.paddr, addr->sa_data, dev->addr_len); - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetifSetMulticast -- - * - * Sets or clears the multicast address list. This information - * comes from an array in dev->mc_list, and with a counter in - * dev->mc_count. - * - * Since host-only network ifaces can't be bridged, it's debatable - * whether this is at all useful, but at least now you can turn it - * on from ifconfig without getting an ioctl error. - * Results: - * Void. - * - * Side effects: - * Multicast address list might get changed. - * - *---------------------------------------------------------------------- - */ - -void -VNetNetifSetMulticast(struct net_device *dev) // IN: unused -{ -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetifGetStats -- - * - * The virtual network's get stats dev operation. - * - * Results: - * A struct full of stats. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -struct net_device_stats * -VNetNetifGetStats(struct net_device *dev) // IN: -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) - VNetNetIF *netIf = (VNetNetIF*)dev->priv; -#else - VNetNetIF *netIf = netdev_priv(dev); -#endif /* 2.6.29 */ - return &(netIf->stats); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetNetIfProcRead -- - * - * Callback for read operation on this netif entry in vnets proc fs. - * - * Results: - * Length of read operation. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetNetIfProcRead(char *page, // IN/OUT: buffer to write into - char **start, // OUT: 0 if file < 4k, else offset into page - off_t off, // IN: (unused) offset of read into the file - int count, // IN: (unused) maximum number of bytes to read - int *eof, // OUT: TRUE if there is nothing more to read - void *data) // IN: client data -{ - VNetNetIF *netIf = (VNetNetIF*)data; - int len = 0; - - if (!netIf) { - return len; - } - - len += VNetPrintPort(&netIf->port, page+len); - - len += sprintf(page+len, "dev %s ", netIf->devName); - - len += sprintf(page+len, "\n"); - - *start = 0; - *eof = 1; - return len; -} diff -Nrup source/vmnet-only/nfhook_uses_skb.c source.edited/vmnet-only/nfhook_uses_skb.c --- source/vmnet-only/nfhook_uses_skb.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/nfhook_uses_skb.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,45 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 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 - * - *********************************************************/ - -/* - * Detect whether nf_hookfn takes struct sk_buff* skb, or struct sk_buff** pskb. - * Kernels before 2.6.23 take pskb, kernels since 2.6.24 take skb, and we - * are not sure about 2.6.23 itself, as change occured between 2.6.23 and - * 2.6.24-rc1. - */ - -#include -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) -# error This compile test intentionally fails. -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) -# include - -nf_hookfn test_function; - -unsigned int -test_function(unsigned int hooknum, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*defn)(struct sk_buff*)) -{ - return 1234; -} -#endif diff -Nrup source/vmnet-only/pgtbl.h source.edited/vmnet-only/pgtbl.h --- source/vmnet-only/pgtbl.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/pgtbl.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,385 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __PGTBL_H__ -# define __PGTBL_H__ - - -#include "compat_highmem.h" -#include "compat_pgtable.h" -#include "compat_spinlock.h" -#include "compat_page.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 11) -# define compat_active_mm mm -#else -# define compat_active_mm active_mm -#endif - - -/* - *----------------------------------------------------------------------------- - * - * PgtblPte2MPN -- - * - * Returns the page structure associated to a Page Table Entry. - * - * This function is not allowed to schedule() because it can be called while - * holding a spinlock --hpreg - * - * Results: - * INVALID_MPN on failure - * mpn on success - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE MPN -PgtblPte2MPN(pte_t *pte) // IN -{ - if (pte_present(*pte) == 0) { - return INVALID_MPN; - } - return pte_pfn(*pte); -} - - -/* - *----------------------------------------------------------------------------- - * - * PgtblPte2Page -- - * - * Returns the page structure associated to a Page Table Entry. - * - * This function is not allowed to schedule() because it can be called while - * holding a spinlock --hpreg - * - * Results: - * The page structure if the page table entry points to a physical page - * NULL if the page table entry does not point to a physical page - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE struct page * -PgtblPte2Page(pte_t *pte) // IN -{ - if (pte_present(*pte) == 0) { - return NULL; - } - - return compat_pte_page(*pte); -} - - -/* - *----------------------------------------------------------------------------- - * - * PgtblPGD2PTELocked -- - * - * Walks through the hardware page tables to try to find the pte - * associated to a virtual address. - * - * Results: - * pte. Caller must call pte_unmap if valid pte returned. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE pte_t * -PgtblPGD2PTELocked(compat_pgd_t *pgd, // IN: PGD to start with - VA addr) // IN: Address in the virtual address - // space of that process -{ - compat_pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - if (compat_pgd_present(*pgd) == 0) { - return NULL; - } - - pud = compat_pud_offset(pgd, addr); - if (compat_pud_present(*pud) == 0) { - return NULL; - } - - pmd = pmd_offset_map(pud, addr); - if (pmd_present(*pmd) == 0) { - pmd_unmap(pmd); - return NULL; - } - - pte = pte_offset_map(pmd, addr); - pmd_unmap(pmd); - return pte; -} - - -/* - *----------------------------------------------------------------------------- - * - * PgtblVa2PTELocked -- - * - * Walks through the hardware page tables to try to find the pte - * associated to a virtual address. - * - * Results: - * pte. Caller must call pte_unmap if valid pte returned. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE pte_t * -PgtblVa2PTELocked(struct mm_struct *mm, // IN: Mm structure of a process - VA addr) // IN: Address in the virtual address - // space of that process -{ - return PgtblPGD2PTELocked(compat_pgd_offset(mm, addr), addr); -} - - -/* - *----------------------------------------------------------------------------- - * - * PgtblVa2MPNLocked -- - * - * Retrieve MPN for a given va. - * - * Caller must call pte_unmap if valid pte returned. The mm->page_table_lock - * must be held, so this function is not allowed to schedule() --hpreg - * - * Results: - * INVALID_MPN on failure - * mpn on success - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE MPN -PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process - VA addr) // IN: Address in the virtual address -{ - pte_t *pte; - - pte = PgtblVa2PTELocked(mm, addr); - if (pte != NULL) { - MPN mpn = PgtblPte2MPN(pte); - pte_unmap(pte); - return mpn; - } - return INVALID_MPN; -} - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -/* - *----------------------------------------------------------------------------- - * - * PgtblKVa2MPNLocked -- - * - * Retrieve MPN for a given kernel va. - * - * Caller must call pte_unmap if valid pte returned. The mm->page_table_lock - * must be held, so this function is not allowed to schedule() --hpreg - * - * Results: - * INVALID_MPN on failure - * mpn on success - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE MPN -PgtblKVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a caller - VA addr) // IN: Address in the virtual address -{ - pte_t *pte; - - pte = PgtblPGD2PTELocked(compat_pgd_offset_k(mm, addr), addr); - if (pte != NULL) { - MPN mpn = PgtblPte2MPN(pte); - pte_unmap(pte); - return mpn; - } - return INVALID_MPN; -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * PgtblVa2PageLocked -- - * - * Return the "page" struct for a given va. - * - * Results: - * struct page or NULL. The mm->page_table_lock must be held, so this - * function is not allowed to schedule() --hpreg - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE struct page * -PgtblVa2PageLocked(struct mm_struct *mm, // IN: Mm structure of a process - VA addr) // IN: Address in the virtual address -{ - pte_t *pte; - - pte = PgtblVa2PTELocked(mm, addr); - if (pte != NULL) { - struct page *page = PgtblPte2Page(pte); - pte_unmap(pte); - return page; - } else { - return NULL; - } -} - - -/* - *----------------------------------------------------------------------------- - * - * PgtblVa2MPN -- - * - * Walks through the hardware page tables of the current process to try to - * find the page structure associated to a virtual address. - * - * Results: - * Same as PgtblVa2MPNLocked() - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE int -PgtblVa2MPN(VA addr) // IN -{ - struct mm_struct *mm; - MPN mpn; - - /* current->mm is NULL for kernel threads, so use active_mm. */ - mm = current->compat_active_mm; - if (compat_get_page_table_lock(mm)) { - spin_lock(compat_get_page_table_lock(mm)); - } - mpn = PgtblVa2MPNLocked(mm, addr); - if (compat_get_page_table_lock(mm)) { - spin_unlock(compat_get_page_table_lock(mm)); - } - return mpn; -} - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -/* - *----------------------------------------------------------------------------- - * - * PgtblKVa2MPN -- - * - * Walks through the hardware page tables of the current process to try to - * find the page structure associated to a virtual address. - * - * Results: - * Same as PgtblVa2MPNLocked() - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE int -PgtblKVa2MPN(VA addr) // IN -{ - struct mm_struct *mm; - MPN mpn; - - mm = current->compat_active_mm; - if (compat_get_page_table_lock(mm)) { - spin_lock(compat_get_page_table_lock(mm)); - } - mpn = PgtblKVa2MPNLocked(mm, addr); - if (compat_get_page_table_lock(mm)) { - spin_unlock(compat_get_page_table_lock(mm)); - } - return mpn; -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * PgtblVa2Page -- - * - * Walks through the hardware page tables of the current process to try to - * find the page structure associated to a virtual address. - * - * Results: - * Same as PgtblVa2PageLocked() - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE struct page * -PgtblVa2Page(VA addr) // IN -{ - struct mm_struct *mm; - struct page *page; - - mm = current->compat_active_mm; - if (compat_get_page_table_lock(mm)) { - spin_lock(compat_get_page_table_lock(mm)); - } - page = PgtblVa2PageLocked(mm, addr); - if (compat_get_page_table_lock(mm)) { - spin_unlock(compat_get_page_table_lock(mm)); - } - return page; -} - - -#endif /* __PGTBL_H__ */ diff -Nrup source/vmnet-only/procfs.c source.edited/vmnet-only/procfs.c --- source/vmnet-only/procfs.c 2009-10-20 17:31:32.000000000 -0700 +++ source.edited/vmnet-only/procfs.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,402 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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" - -#define EXPORT_SYMTAB - -#include -#include -#include -#ifdef KERNEL_2_2 -# include -#else -# include -#endif -#include - -#include -#include -#include -#include "compat_skbuff.h" -#include -#include -#include "compat_sock.h" - -#define __KERNEL_SYSCALLS__ -#include - -#include -#include - -#include "vnetInt.h" - - -#if defined(CONFIG_PROC_FS) - -static int VNetProcMakeEntryInt(VNetProcEntry *parent, char *name, int mode, - VNetProcEntry **ret); -static void VNetProcRemoveEntryInt(VNetProcEntry *node, VNetProcEntry *parent); -#ifndef KERNEL_2_3_25 -static void VNetProcModCount(struct inode *inode, int fill); -#endif - -static VNetProcEntry *base = NULL; - - -/* - *---------------------------------------------------------------------- - * - * VNetProc_Init -- - * - * Initialize the vnets procfs entries. - * - * Results: - * errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetProc_Init(void) -{ - int retval; - - retval = VNetProcMakeEntryInt(NULL, "vmnet", S_IFDIR, &base); - if (retval) { - return retval; - } - -#ifndef KERNEL_2_3_25 - base->fill_inode = VNetProcModCount; -#endif - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetProc_Cleanup -- - * - * Cleanup the vnets proc filesystem entries. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VNetProc_Cleanup(void) -{ - VNetProcRemoveEntryInt(base, NULL); - base = NULL; -} - -#ifndef KERNEL_2_3_25 -/* - *---------------------------------------------------------------------- - * - * VNetProcModCount -- - * - * Callback for the vnets proc filesystem. This gets called when - * the inode goes into or out of service. For example when someone - * cd's to the vmnet directory. We must put a use count on the module - * so that its doesn't go away. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ -void -VNetProcModCount(struct inode *inode, // IN: - int fill) // IN: -{ - VNetIncrModCount((fill) ? 1 : -1); -} -#endif - -/* - *---------------------------------------------------------------------- - * - * VNetProcMakeEntryInt -- - * - * Make an entry in the vnets proc file system. - * - * Results: - * errno. If errno is 0 and ret is non NULL then ret is filled - * in with the resulting proc entry. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetProcMakeEntryInt(VNetProcEntry *parent, // IN: - char *name, // IN: - int mode, // IN: - VNetProcEntry **ret) // OUT: -{ - VNetProcEntry *ent; -#ifndef KERNEL_2_3_29 - int retval; - - if (ret) { - *ret = NULL; - } - - ent = kmalloc(sizeof *ent, GFP_KERNEL); - if (!ent) { - return -ENOMEM; - } - - memset(ent, 0, sizeof *ent); - - if (mode == S_IFDIR) { - mode |= S_IRUGO | S_IXUGO; - } else if (mode == S_IFREG) { - mode |= S_IRUGO; - } - - ent->low_ino = 0; - ent->name = name; - ent->namelen = strlen(name); - ent->mode = mode; - - if (S_ISDIR(mode)) { - ent->nlink = 2; - } else { - ent->nlink = 1; - } - - if (!parent) { - parent = &proc_root; - } - - retval = proc_register(parent, ent); - if (retval) { - kfree(ent); - return retval; - } - - if (ret) { - *ret = ent; - } -#else /* KERNEL_2_3_29 */ - ent = create_proc_entry(name, mode, parent); - *ret = ent; - if (!ent) - return -ENOMEM; -#endif /* KERNEL_2_3_29 */ - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetProcRemoveEntryInt -- - * - * Remove a previously installed proc entry. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VNetProcRemoveEntryInt(VNetProcEntry *node, - VNetProcEntry *parent) -{ - if (node) { -#ifndef KERNEL_2_3_29 - if (!parent) { - parent = &proc_root; - } - proc_unregister(parent, node->low_ino); - kfree(node); -#else /* KERNEL_2_3_29 */ - remove_proc_entry(node->name, parent); -#endif /* KERNEL_2_3_29 */ - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetProc_MakeEntry -- - * - * Make an entry in the vnets proc file system. - * - * Results: - * errno. If errno is 0 and ret is non NULL then ret is filled - * in with the resulting proc entry. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetProc_MakeEntry(char *name, // IN: - int mode, // IN: - VNetProcEntry **ret) // OUT: -{ - return VNetProcMakeEntryInt(base, name, mode, ret); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetProc_RemoveEntry -- - * - * Remove a previously installed proc entry. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VNetProc_RemoveEntry(VNetProcEntry *node) -{ - VNetProcRemoveEntryInt(node, base); -} - - -#else /* CONFIG_PROC_FS */ - - -/* - *---------------------------------------------------------------------- - * - * VNetProc_Init -- - * - * Initialize the vnets procfs entries. - * - * Results: - * errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetProc_Init(void) -{ - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetProc_Cleanup -- - * - * Cleanup the vnets proc filesystem entries. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VNetProc_Cleanup(void) -{ -} - - -/* - *---------------------------------------------------------------------- - * - * VNetProc_MakeEntry -- - * - * Make an entry in the vnets proc file system. - * - * Results: - * errno. If errno is 0 and ret is non NULL then ret is filled - * in with the resulting proc entry. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetProc_MakeEntry(char *name, - int mode, - VNetProcEntry **ret) -{ - return -ENXIO; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetProc_RemoveEntry -- - * - * Remove a previously installed proc entry. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VNetProc_RemoveEntry(VNetProcEntry *parent) -{ -} - -#endif /* CONFIG_PROC_FS */ diff -Nrup source/vmnet-only/setnice.c source.edited/vmnet-only/setnice.c --- source/vmnet-only/setnice.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/setnice.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,32 +0,0 @@ -/********************************************************* - * Copyright (C) 2005 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 - * - *********************************************************/ - -/* - * set_user_nice appeared in 2.4.21. But some distros - * backported it to older kernels. - */ -#include -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 21) -#include - -void test(void) { - set_user_nice(current, -20); -} -#endif diff -Nrup source/vmnet-only/sk_alloc.c source.edited/vmnet-only/sk_alloc.c --- source/vmnet-only/sk_alloc.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/sk_alloc.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,39 +0,0 @@ -/********************************************************* - * Copyright (C) 2005 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 - * - *********************************************************/ - -/* - * Detect whether sk_alloc takes a struct proto * as third parameter. - * This API change was introduced between 2.6.12-rc1 and 2.6.12-rc2. - */ - -#include -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13) -#include - -static struct proto test_proto = { - .name = "TEST", -}; - -struct sock * -vmware_sk_alloc(void) -{ - return sk_alloc(PF_NETLINK, 0, &test_proto, 1); -} -#endif diff -Nrup source/vmnet-only/skblin.c source.edited/vmnet-only/skblin.c --- source/vmnet-only/skblin.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/skblin.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,41 +0,0 @@ -/********************************************************* - * 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 - * - *********************************************************/ - -/* - * Detect whether skb_linearize takes one or two arguments. - */ - -#include -#include - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17) -/* - * Since 2.6.18 all kernels have single-argument skb_linearize. For - * older kernels use autodetection. Not using autodetection on newer - * kernels saves us from compile failure on some post 2.6.18 kernels - * which do not have selfcontained skbuff.h. - */ - -#include - -int test_skb_linearize(struct sk_buff *skb) -{ - return skb_linearize(skb); -} - -#endif diff -Nrup source/vmnet-only/smac.c source.edited/vmnet-only/smac.c --- source/vmnet-only/smac.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/smac.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,3792 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -/* - * smac.c -- - * - * This file defines functionality that allows the - * bridge to be used across links that do - * not support promiscuous mode, or to not provide the - * ability to transmit ethernet frames whose MAC source - * address does not match the hardware's MAC address. - * - * This code extension basically forces the bridge to - * use a single MAC, thus the name SMAC. - */ - -/* platform-dependent includes */ - -#ifdef _WIN32 - -#define BINARY_COMPATIBLE 0 // NT-only driver (optimizes some NDIS calls) -#include - -#include "vnetInt.h" - -#else /* _WIN32 */ - -#undef __KERNEL__ //To prevent including any kernel specific stuff - -#ifdef VMX86_DEVEL -#define DBG 1 -#else -#undef DBG -#endif /* VMX86_DEVEL */ - -#ifdef __APPLE__ -#include -#include -#endif - -#include "smac_compat.h" - -#endif /* _WIN32 */ - -/* platform-independent includes */ -#include "smac.h" -#include "vm_basic_defs.h" - -#define SMAC_MODULE "SMAC: " -#define MODULE_NAME SMAC_MODULE - -/* platform-dependent defines */ -#ifdef _WIN32 -#define ALLOCATEMEMORY(a,b) VNet_AllocateMemoryWithTag((a),(b)) -#define FREEMEMORY(a) VNet_FreeMemory((a)) -#define MEMCPY(a,b,c) NdisMoveMemory((a),(b),(c)) -#define MEMSET(a,b,c) NdisFillMemory((a),(c),(b)) - -#define SPINLOCKINIT() do { } while (0) -#define INITSPINLOCK(a) do { NdisAllocateSpinLock( (a) ); } while(0) -#define RAISEIRQL() do { irql = KeRaiseIrqlToDpcLevel(); } while(0) -#define ACQUIRESPINLOCK(a) do { ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \ - NdisDprAcquireSpinLock( (a) ); } while(0) -#define RELEASESPINLOCK(a) do { NdisDprReleaseSpinLock( (a) ); } while(0) -#define LOWERIRQL() do { KeLowerIrql(irql); } while(0) -#define FREESPINLOCK(a) do { NdisFreeSpinLock( (a) ); } while(0) -#define ASSERTLOCKHELD() ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL) -#define SNPRINTF(a) (_snprintf a) - -#elif defined __linux__ || defined __APPLE__ - -#define ALLOCATEMEMORY(a,b) SMACL_Alloc((a)) -#define MEMCPY(a,b,c) SMACL_Memcpy((a),(b),(c)) -#define MEMSET(a,b,c) SMACL_Memset((a),(b),(c)) - -#define INITSPINLOCK(a) SMACL_InitSpinlock( (a) ) -#define RAISEIRQL() do { } while (0) -#define LOWERIRQL() do { } while (0) -#define ASSERTLOCKHELD() do { } while (0) - -#define UNREFERENCED_PARAMETER(a) { (a) = (a); } - -/* - * The following are defined to create OS dependent versions of - * functionality available on Windows. - */ - -#undef ASSERT - -#ifdef DBG -#define VNETKdPrint(a) (SMACL_Print a) -#define ASSERT(a) do {if (!(a)) {VNETKdPrint(("ASSERT FAILED: "#a));}} while(0) -#else -#define VNETKdPrint(a) do { } while (0) -#define ASSERT(a) do { } while (0) -#endif - -#define VNETKdPrintCall(a) VNETKdPrint((MODULE_NAME "Calling : %s\n", a)) -#define VNETKdPrintReturn(a) VNETKdPrint((MODULE_NAME "Returned : %s\n", a)) - -#ifndef MAC_EQ -#define MAC_EQ(a,b) (SMACL_Memcmp((a),(b),ETH_ALEN)==0) -#endif /* MAC_EQ */ - -#define IS_MULTICAST(_hdr) ((_hdr)[0] & 0x1) -#define IS_BROADCAST(_a) \ - ((_a)[0] == 0xff && (_a)[1] == 0xff && (_a)[2] == 0xff && \ - (_a)[3] == 0xff && (_a)[4] == 0xff && (_a)[5] == 0xff) - -#ifdef __linux__ -#define FREEMEMORY(a) SMACL_Free((a)) -#define SPINLOCKINIT() unsigned long flags -#define FREESPINLOCK(a) SMACL_Free(*a) -#define ACQUIRESPINLOCK(a) SMACL_AcquireSpinlock( (a), &flags) -#define RELEASESPINLOCK(a) SMACL_ReleaseSpinlock( (a), &flags) -#define SNPRINTF(a) (SMACL_Snprintf a) -#else /* __APPLE__ */ -#define FREEMEMORY(a) SMACL_Free((a), sizeof *(a)) -#define SPINLOCKINIT() do { } while (0) -#define FREESPINLOCK(a) SMACL_FreeSpinlock( (a) ) -#define ACQUIRESPINLOCK(a) SMACL_AcquireSpinlock( *(a) ) -#define RELEASESPINLOCK(a) SMACL_ReleaseSpinlock( *(a) ) -#define SNPRINTF(a) (snprintf a) -#endif - -#else -#error "unknown platform" -#endif /* _WIN32 */ - -/* Offsets/lengths for IP, UDP, and ARP headers */ -#define IP_HEADER_LEN 20 -#define IP_HEADER_DEST_ADDR_OFFSET 16 -#define IP_HEADER_SRC_ADDR_OFFSET 12 -#define IP_HEADER_FLAGS_OFFSET 6 -#define IP_HEADER_PROTO_OFFSET 9 -#define UDP_HEADER_LEN 8 -#define ARP_HEADER_LEN 28 -#define ARP_SENDER_MAC_OFFSET 8 -#define ARP_SENDER_IP_OFFSET 14 -#define ARP_TARGET_MAC_OFFSET 18 -#define ARP_TARGET_IP_OFFSET 24 - -#define IP_ADDR_BROADCAST 0xFFFFFFFF - -/* - * To limit the amount of kernel log information, define - * WIRELESS_BE_QUIET or WIRELESS_BE_VERY_QUIET. The former - * reduces the logging to a point where the host system isn't - * bogged down with logging all the details of broadcast traffic - * coming in from the company network. The latter define will - * completely turn off wireless logging. - */ - -#define WIRELESS_BE_VERY_QUIET -//#define WIRELESS_BE_QUIET - -#ifdef WIRELESS_BE_VERY_QUIET -#define WW_VNETKdPrint(a) -#define W_VNETKdPrint(a) -#else // WIRELESS_BE_VERY_QUIET - -#ifdef WIRELESS_BE_QUIET -#define WW_VNETKdPrint(a) -#define W_VNETKdPrint(a) VNETKdPrint(a) -#else // WIRELESS_BE_QUIET -#define WW_VNETKdPrint(a) VNETKdPrint(a) -#define W_VNETKdPrint(a) VNETKdPrint(a) -#endif // WIRELESS_BE_QUIET - -#endif // WIRELESS_BE_VERY_QUIET - -/* - * Host-to-Network / Network-to-Host byte-order routines - * - * Macro and function versions provided; offers tradeoff between - * speed, compile-time versus run-time, and type checking - */ - -#ifdef __APPLE__ -#undef HTONL -#undef NTOHL -#undef HTONS -#undef NTOHS -#endif /* __APPLE__ */ - -#define HTONL(i) (((uint32)i)>>24 | (i)<<24 | ((i)&0x00ff0000)>>8 | \ - ((i)&0x0000ff00)<<8) -#define NTOHL(i) HTONL(i) -#define HTONS(i) (((uint16)i)>>8 | (i)<<8) -#define NTOHS(i) HTONS(i) - -#ifndef __APPLE__ -static INLINE_SINGLE_CALLER uint32 -htonl(uint32 i) { - return HTONL(i); -} -static INLINE_SINGLE_CALLER uint32 -ntohl(uint32 i) { - return NTOHL(i); -} -static INLINE_SINGLE_CALLER uint16 -htons(uint16 i) { - return HTONS(i); -} -static INLINE_SINGLE_CALLER uint16 -ntohs(uint16 i) { - return NTOHS(i); -} -#endif /* __APPLE__ */ - -/* - * Create 8-bit IP hash, currently by adding up each of the 4 octets - */ - -#define IP_HASH(i) ( (((i>>24)&0xff)+((i>>16)&0xff)+((i>>8)&0xff)+\ - ((i>>0)&0xff)) & SMAC_HASH_MASK ) - -/* - * IPmacLookupEntry: defines entry in IP/MAC hash tables for finding which - * IP corresonds to which MAC - */ - -#ifdef _WIN32 -typedef uint64 SmacLastAccess; -#define LAST_ACCESS_FORMAT "%"FMT64"u" // format of lastAccess for printf() -#else -typedef unsigned long SmacLastAccess; -#define LAST_ACCESS_FORMAT "%lu" // format of lastAccess for printf() -#endif /* _WIN32 */ - -typedef struct IPmacLookupEntry { - struct IPmacLookupEntry *ipNext; // pointer to next item in bucket in IP hash table - uint32 IPv4address; // IPv4 address - // uint8 IPv6address[16]; // IPv6 address (for future support) - uint8 mac[ETH_ALEN]; // ethernet MAC address - SmacLastAccess lastAccess; // estimated time of entry's last use -} IPmacLookupEntry; - -/* - * EthernetHeader: struct that corresponds with common ethernet header - * (an ethernet frame that contians a VLAN header has different - * format: 2 additional bytes after srcAddr) - */ - -typedef struct EthernetHeader { - uint8 destAddr[ETH_ALEN]; // destination MAC - uint8 srcAddr[ETH_ALEN]; // source MAC - uint16 lengthType; // length/type field -} EthernetHeader; - -/* - * EthClass: used to classify the various ethernet media types - * into a small group of classes. - */ - -typedef enum { - EthClassIllegal = 0x345, // media type in an unrefined/reserved range - EthClassCommon, // means known but no special handling needed - EthClassUncommon, // like common, but should trigger more debug printouts - EthClassUnknown, // not specifically known/handled), but a legal type - EthClassIP, // IPv4 type - EthClassARP, // one of the various ARP protocols - EthClassVLAN // VLAN type -} EthClass; - -/* - * SMACState: encapsulates all wireless state for a specific host adapter - */ - -#define SMAC_HASH_TABLE_SIZE 256 // length of table, must be power of 2 -#define SMAC_HASH_MASK (SMAC_HASH_TABLE_SIZE - 1) // hash bits - -typedef struct SMACState { -#ifdef _WIN32 - NDIS_SPIN_LOCK smacSpinLock; // spinlock that protects wireless state -#else /* _WIN32 */ - void *smacSpinLock; // spinlock that protects wireless state -#endif /* _WIN32 */ - SmacLastAccess lastUptimeRead; // used to track uptime counter overflow - struct IPmacLookupEntry * IPlookupTable[SMAC_HASH_TABLE_SIZE]; // IP hash table IP->MAC - uint32 numberOfIPandMACEntries; // # of hash table entries - uint32 lastIPadded; // last IP added to hash - uint8 lastMACadded[ETH_ALEN]; // last MAC added to hash - struct IPmacLookupEntry * lastEntryAdded; // ptr to cache entry (to update timestamp) - Bool smacFowardUnknownPackets; // forward "all" packets? (typically doesn't) - uint8 macAddress[ETH_ALEN]; // pointer to host MAC address -} SMACState; - -/* - * Function prototypes - */ - -static INLINE uint32 SUM32(uint32 in); -static uint32 CalcChecksumDiff(uint32 sumBefore, uint32 sumAfter); -static uint16 UpdateSum(uint16 oricheck, uint32 sumDiff); - -static INLINE IPmacLookupEntry *LookupByIPNoAcquireLock(SMACState *state, - uint32 addr); -static Bool LookupByIP(SMACState *state, uint32 addr, uint8 *macAddress); - -static INLINE Bool RemoveIPfromHashTableNoAcquireLock(SMACState *state, - IPmacLookupEntry *entryToRemove); - -static void TrimLookupTableIfNecessary(SMACState *state); - -static INLINE void SetCacheEntry(SMACState *state, IPmacLookupEntry *entry); - -static Bool AddIPv4andMACcombo(SMACState *state, uint32 addr, uint8 *mac); - -static void ProcessOutgoingIPv4Packet(SMACPacket *packet, uint32 ethHeaderLen); -#ifdef DBG -static void ProcessIncomingIPv4Packet(SMACPacket *packet, - Bool knownMacForIp); -#endif -static SmacLastAccess GetSystemUptime(SMACState *state); - -/* get information from packet */ -static INLINE uint32 GetPacketLength(SMACPacket *packet); -static Bool GetPacketData(SMACPacket *packet, uint32 offset, - uint32 length, void *data); - -/* set information in packet */ -static Bool SetPacketByte(SMACPacket *packet, uint32 offset, - uint8 data); - -/* clone source / write data to clone */ -static Bool ClonePacket(SMACPackets *packets); -static Bool CopyDataToClonedPacket(SMACPackets *packets, const void *source, - uint32 offset, uint32 length); - -/* write data to source (on Windows) / write data to clone (on Linux) */ -static Bool CopyDataForPacketFromHost(SMACPackets *packets, uint32 changeNum, - uint32 offset, const uint8 *macAddress); - -static EthClass LookupTypeClass(uint16 typeValue); -#ifdef DBG -static EthClass LookupTypeName(uint16 typeValue, char *type); -#endif - -/* - * IP hash table routines: the following routines pertain to operations - * on the IP hash table. SMACState->smacSpinLock should be held when reading or - * writing data in the hash table. A read/write lock might be better - * but the locks are usually held for a brief period of time. - * - * 'lastIPadded' and 'lastMACadded' are used to cache the last entry that - * was added to the hash table. For most packets we attempt to add IP/MAC - * information from that packet to the hash table. In most cases (especially - * during file transfers) the entry will already be added to the table so we - * cache the last addition to minimize overhead. The cache information is - * not used for lookups, only to make adds more efficient. - */ - - -/* - *---------------------------------------------------------------------- - * - * LookupByIP -- - * LookupByIPNoAcquireLock -- - * - * Lookup entry or MAC address that corresponds to the - * specified IP address. Locking and non-locking versions - * are provided. The non-locking version returns the actual - * table entry, while the locking version only returns the - * actual MAC address (to avoid reference counting). - * - * Results: - * Nonlocking: pointer to entry (if found), otherwise NULL - * Locking: TRUE if MAC found, otherwise FALSE - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE IPmacLookupEntry * -LookupByIPNoAcquireLock(SMACState *state, // IN: state - uint32 addr) // IN: IP to lookup -{ - uint8 hash = IP_HASH(addr); - IPmacLookupEntry *curr = state->IPlookupTable[hash]; // get bucket - - ASSERT(SMAC_HASH_TABLE_SIZE == 256); - - /* - * Search thru bucket for match - */ - - while (curr && curr->IPv4address != addr) { - curr = curr->ipNext; - } - return curr; -} - - -static Bool -LookupByIP(SMACState *state, // IN: adapter - uint32 addr, // IN: IP to lookup - uint8 *macAddress) // OUT: (optional) MAC of IP (uint8[ETH_ALEN]) -{ - IPmacLookupEntry *entry; - SPINLOCKINIT(); - - WW_VNETKdPrint((MODULE_NAME "LookupByIP: told to find %d.%d.%d.%d\n", - addr&0xff, (addr>>8)&0xff, (addr>>16)&0xff, (addr>>24)&0xff)); - - ACQUIRESPINLOCK(&state->smacSpinLock); - entry = LookupByIPNoAcquireLock(state, addr); - if (entry != NULL && macAddress != NULL) { - MEMCPY(macAddress, entry->mac, ETH_ALEN); - } - RELEASESPINLOCK(&state->smacSpinLock); - return entry != NULL; -} - - -/* - *---------------------------------------------------------------------- - * - * RemoveIPfromHashTable -- - * RemoveIPfromHashTableNoAcquireLock -- - * - * Removed specified entry from the IP hash table. Function - * presumes that specified table entry still contains the IP - * address that was used to add the entry to the hash table. - * Locking and no-locking version of function are provided - * - * This function doesn't check whether the cached entry is - * being removed (and thus won't reset the cached entry). This - * code is primarily used to remove the oldest entry, and by - * definition the cached entry is the newest (i.e., it's never - * the oldest and thus won't be removed). - * - * Results: - * TRUE if entry removed, FALSE otherwise. - * - * Side effects: - * May remove entry from IP hash table. Actual entry is not - * modified nor deallocated by this function. - * - *---------------------------------------------------------------------- - */ - -static INLINE Bool -RemoveIPfromHashTableNoAcquireLock(SMACState *state, // IN: state - IPmacLookupEntry * entryToRemove) // IN: packet -{ - uint8 ipHashToRemove; - IPmacLookupEntry * prev = NULL, *entry; - - ASSERT(entryToRemove); - ASSERT(SMAC_HASH_TABLE_SIZE == 256); - - ipHashToRemove = IP_HASH(entryToRemove->IPv4address); - entry = state->IPlookupTable[ipHashToRemove]; // get bucket - - /* - * locate and remove old IP entry from bucket - */ - - while (entry) { - if (entry == entryToRemove) { - if (prev) { - W_VNETKdPrint((MODULE_NAME "RemoveIPfromHashTable: removed IP " - "entry from middle of bucket\n")); - prev->ipNext = entry->ipNext; - } else { - W_VNETKdPrint((MODULE_NAME "RemoveIPfromHashTable: removed IP " - "entry from front of bucket\n")); - state->IPlookupTable[ipHashToRemove] = entry->ipNext; - } - return TRUE; - } else { - prev = entry; - entry = entry->ipNext; - } - } - return FALSE; -} - - -/* - *---------------------------------------------------------------------- - * - * TrimLookupTableIfNecessary -- - * - * If the number of entries in the IP and MAC tables exceeds a - * specified value (currently 20), then we remove and deallocate - * an entry--ideally the entry which has been used least recently - * is removed. The code presumes that this function will be called - * anytime a new entry is added, thus we should never need to - * remove more than one entry per function call. - * - * Function presumes that state lock is held while this function - * is called. - * - * Results: - * None. - * - * Side effects: - * May remove and deallocates an entry from the IP and MAC hash - * tables. - * - *---------------------------------------------------------------------- - */ - -static void -TrimLookupTableIfNecessary(SMACState *state) // IN: smac state -{ - IPmacLookupEntry * oldestEntry = NULL; // oldest entry found - SmacLastAccess oldestUpdate = ~0; // age of oldest entry - SmacLastAccess currentUptime = 0; // time since the system was booted - int i; - - VNETKdPrintCall(("TrimLookupTableIfNecessary")); - ASSERT(state); - ASSERT(SMAC_HASH_TABLE_SIZE == 256); - ASSERTLOCKHELD(); - - if (state->numberOfIPandMACEntries <= 20) { // if not too many entries - VNETKdPrint((MODULE_NAME "TrimLookupTableIfNeccessary: number of " - "entries is small: %d\n", state->numberOfIPandMACEntries)); - return; - } - - VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: " - "reducing # of entries\n")); - - currentUptime = GetSystemUptime(state); /* must be called with lock held */ - - VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: current uptime is " - LAST_ACCESS_FORMAT "\n", currentUptime)); - - /* - * NOTE: this code presumes that no system will ever be up long enough - * for the uptime to wrap. To get around this assumption we could try to - * determine "oldest" by computing which entry has the largest difference - * from the current updtime. However, there are no guarantees that this - * metric is any more accurate. Given that we never expect more than 20 - * entries to ever exist, I won't implement a more sophisiticated - * mechanism at this time. - */ - - /* - * Search thru entire table to find oldest uptime, and remove it - */ - - for (i = 0; i < SMAC_HASH_TABLE_SIZE; ++i) { - IPmacLookupEntry *currentEntry = state->IPlookupTable[i]; - while (currentEntry) { - if (currentEntry->lastAccess < oldestUpdate) { // if older than candidate - - /* - * Skip cached entry since the entry was used most recently, but its - * timestamp might be old since the timestamp is only updated after - * the entry is no longer cached (i.e., something else is now the newest) - * - * This code will only be executed if at least 20 entries exist, so there - * must be some much better candidates elsewhere in the table. - */ - - if (currentEntry == state->lastEntryAdded) { - VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: oldest " - "candidate is the cached entry, so skipping\n")); - } else { - VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: current " - "oldest candidate: %d.%d.%d.%d time " LAST_ACCESS_FORMAT "\n", - (currentEntry->IPv4address)&0xff, - (currentEntry->IPv4address>>8)&0xff, - (currentEntry->IPv4address>>16)&0xff, - (currentEntry->IPv4address>>24)&0xff, - currentEntry->lastAccess)); - oldestEntry = currentEntry; - oldestUpdate = currentEntry->lastAccess; - } - } - if (currentEntry->lastAccess > currentUptime) { - VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: " - "ERROR: last access " LAST_ACCESS_FORMAT - " > current uptime " LAST_ACCESS_FORMAT "\n", - currentEntry->lastAccess, currentUptime)); - } - - currentEntry = currentEntry->ipNext; - } - } - - if (oldestEntry) { - VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: found oldest " - "candidate: %d.%d.%d.%d time " LAST_ACCESS_FORMAT "\n", - (oldestEntry->IPv4address) & 0xff, - ((oldestEntry->IPv4address)>>8) & 0xff, - ((oldestEntry->IPv4address)>>16) & 0xff, - ((oldestEntry->IPv4address)>>24) & 0xff, - oldestEntry->lastAccess)); - if (!RemoveIPfromHashTableNoAcquireLock(state, oldestEntry)) { - VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: could not " - "find entry in IP table\n")); - ASSERT(0); // should never occur - } else { - FREEMEMORY(oldestEntry); - --state->numberOfIPandMACEntries; - } - } - else { - VNETKdPrint((MODULE_NAME "TrimLookupTableIfNecessary: " - "found no entry to remove!!\n")); - } - - VNETKdPrintReturn(("TrimLookupTableIfNecessary")); - return; -} - - -/* - *---------------------------------------------------------------------- - * - * SetCacheEntry -- - * - * Sets the cached MAC/IP entry for an adapter, and updates the - * access time for the previous cache entry (if any). The cache - * is used to avoid the overhead of checking for the existance of, - * for the purposes of adding, a MAC/IP entry that has already - * been added recently. - * - * Function is called with state->smacSpinLock held. - * - * Results: - * None. - * - * Side effects: - * Modified the cached entry for the adapter, and updates the - * access time for the previous cache entry (if any) - * - *---------------------------------------------------------------------- - */ - -static INLINE void -SetCacheEntry(SMACState *state, // IN: smac state - IPmacLookupEntry *entry) // IN: entry to cache -{ - ASSERT(state); - ASSERT(entry); - - /* - * Set new cached entry, but first set the current cache entry's - * access time to the current time - */ - - if (state->lastEntryAdded) { - state->lastEntryAdded->lastAccess = GetSystemUptime(state); - } - - state->lastIPadded = entry->IPv4address; - MEMCPY(state->lastMACadded, entry->mac, ETH_ALEN); - state->lastEntryAdded = entry; - entry->lastAccess = GetSystemUptime(state); -} - - -/* - *---------------------------------------------------------------------- - * - * AddIPv4andMACcombo -- - * - * Adds an entry for a paired MAC/IPv4 into the IP and MAC - * hash tables. - * - * Results: - * TRUE if added, updated, or already present, FALSE on error. - * - * Side effects: - * Allocates a new table entry and adds it to the IP and MAC - * hash tables. - * - *---------------------------------------------------------------------- - */ - -static Bool -AddIPv4andMACcombo(SMACState *state, // IN: smac state - uint32 addr, // IN: IPv4 address to add - uint8 *mac) // IN: ethernet MAC to add -{ - Bool result = TRUE; - IPmacLookupEntry *entryIP = NULL; - SPINLOCKINIT(); - - /* - * If the current IP/MAC is the same as the immediately prior add, then - * return and don't bother to process this request. - */ - - VNETKdPrint((MODULE_NAME "AddIPMAC: told to add %d.%d.%d.%d " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - addr&0xff, (addr>>8)&0xff, - (addr>>16)&0xff, (addr>>24)&0xff, - mac[0]&0xff, mac[1]&0xff, mac[2]&0xff, - mac[3]&0xff, mac[4]&0xff, mac[5]&0xff)); - ASSERTLOCKHELD(); - ASSERT(SMAC_HASH_TABLE_SIZE == 256); - - if (addr == state->lastIPadded && MAC_EQ(mac, state->lastMACadded)) { - VNETKdPrint((MODULE_NAME "AddIPMAC: cache says already present\n")); - return TRUE; - } - - /* - * Don't allow an IP of 0.0.0.0 or 255.255.255.255 to be added. In fact, - * consider deleting any existing MAC entry that was provided, since the - * IP is apparently no longer in use. - */ - - if (!addr || addr == IP_ADDR_BROADCAST) { - VNETKdPrint((MODULE_NAME "AddIPMAC: trying to add IP 0.0.0.0 or " - "255.255.255.255, disallowing add & removing MAC entry\n")); - return TRUE; - } - - ACQUIRESPINLOCK(&state->smacSpinLock); - - /* - * Lookup table entry for specified IP addr and ethernet MAC. - */ - - entryIP = LookupByIPNoAcquireLock(state, addr); - - /* - * If an entry for the specified IP addr was found, and the MACs match, - * then we don't need to add a new entry nor modify any existing entries - * and can return immediately. - */ - - if (entryIP && MAC_EQ(entryIP->mac, mac)) { - VNETKdPrint((MODULE_NAME "AddIPMAC: entry already exists, " - "and matches current IP/MAC\n")); - - /* - * Update the cached entry to this new request. - */ - - SetCacheEntry(state, entryIP); - goto exit; - } - - /* - * If no table entry was found for the IP, then this is a completely new add - * (also, no changes need to made to pre-existing table entries). - */ - - if (!entryIP) { - uint8 ipHash = IP_HASH(addr); - - IPmacLookupEntry *entry = (IPmacLookupEntry*) - ALLOCATEMEMORY(sizeof *entry, REORDER_TAG('SMle')); - VNETKdPrint((MODULE_NAME "AddIPMACnew: neither MAC or IP is in table," - " so adding new entry for " - "%d.%d.%d.%d %02x:%02x:%02x:%02x:%02x:%02x\n", - addr&0xff,(addr>>8)&0xff, (addr>>16)&0xff, (addr>>24)&0xff, - mac[0]&0xff, mac[1]&0xff, mac[2]&0xff, mac[3]&0xff, - mac[4]&0xff, mac[5]&0xff)); - - if (!entry) { - // entry allocation error - VNETKdPrint((MODULE_NAME "AddIPMACnew: Failed to allocate " - " MAC/IP entry\n")); - result = FALSE; - goto exit; - } - - ++state->numberOfIPandMACEntries; - - // initialize the contents of the table entry - entry->IPv4address = addr; - entry->lastAccess = 0; /* initialize to 0 for sanity, although it's not vital */ - - MEMCPY(entry->mac, mac, ETH_ALEN); - - // add entry to IP hash table - entry->ipNext = state->IPlookupTable[ipHash]; - state->IPlookupTable[ipHash] = entry; - - VNETKdPrint((MODULE_NAME "AddIPMACnew: entry allocated, and added\n")); - SetCacheEntry(state, entry); - TrimLookupTableIfNecessary(state); - - } else { - - /* - * If table entry was found for IP, but the MACs don't match, then this means - * that a new/different ethernet device/MAC is using the IP address. We need - * to update the contents of the table entry to specify the new MAC - */ - - VNETKdPrint((MODULE_NAME "AddIPMACmacmod: IP has changed from known " - "MAC %02x:%02x:%02x:%02x:%02x:%02x to new unknown " - "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - entryIP->mac[0]&0xff, entryIP->mac[1]&0xff, - entryIP->mac[2]&0xff, entryIP->mac[3]&0xff, - entryIP->mac[4]&0xff, entryIP->mac[5]&0xff, - mac[0]&0xff, mac[1]&0xff, mac[2]&0xff, mac[3]&0xff, - mac[4]&0xff, mac[5]&0xff)); - - // update MAC in the table entry - MEMCPY(entryIP->mac, mac, ETH_ALEN); - - // update which was the last IP/MAC combo to be added - SetCacheEntry(state, entryIP); - // no new entry added, so no need to call TrimLookupTableIfNecessary() - } - -exit: - - RELEASESPINLOCK(&state->smacSpinLock); - return result; -} - - -/* - * Overview of functions: - * - * "LookupTypeClass" and "LookupTypeName" are used to identify an - * ethernet frame's type, esentially IP, ARP, or neither. - * "LookupTypeName" is used for debugging purposes, since it also - * returns a string representing the name of the type. - * - * When the bridge wishes to send a packet to the host/network, it - * calls "SMAC_CheckPacketToHost", which essentially handles the - * link layer and ARP. If the packet is IPv4 then it calls - * ProcessOutgoingIPv4Packet to analyze (and potentially modify) - * the packet. Currently ProcessOutgoingIPv4Packet only turns on - * the broadcast flag for DHCP client packets. - * - * When the bridge receives a packet from the host/network, it - * calls "SMAC_CheckPacketFromHost", which essentially handles the - * link layer and ARP. If the packet is IPv4 then it calls - * ProcessIncomingIPv4Packet to analyze (and potentially modify) - * the packet. - * - * On Linux, the packet modifications are made to a private clone - * of the network packet. We don't want to modify a packet from - * the host, nor do we want to make modifications in a way that's - * visible to VMs on the same subnet. - * - * On Windows, we only clone packets that are headed towards the host. - * Packets from the host can be modified since they're already a private - * copy. However, we might not have the whole packet and thus need to - * store the changes in a separate table until the whole packet is - * received (at which time the modifications can then be made). - * - * On Mac OS, the packet modifications are made to the original network packet, - * since the packet passed to us is already pre-cloned and private and can be - * modified here. So cloning is faked by simply setting the clone to be a - * pointer to the original packet. - */ - - -/* - *---------------------------------------------------------------------- - * - * SMAC_CheckPacketFromHost -- - * - * Examines the contents of a packet that has been received from - * the network. On Windows the function will provide suggestions - * (via table) for where MAC substitution should occur. - * Function supports IP, ARP, RARP, IARP, and DHCP. On Linux the - * function will clone the packet and make modifications to the - * clone (the caller is responsible for freeing the original and - * the cloned packets). - * - * NOTE: On Windows this function presumes it is called at DISPATCH_LEVEL - * - * Results: - * Returns 'PacketStatusForwardPacket' if packet should/can be - * received, 'PacketStatusDropPacket' if packet should be filtered - * and not received, PacketStatusTooShort if insufficient data - * provided to process packet (suggested action it to receive - * packet in its entirety, and call this function - * again on the whole packet) - * - * Side effects: - * May add/modify the adapter's MAC/IP hash tables. May clone a - * packet if function returns PacketStatusForwardPacket. - * - *---------------------------------------------------------------------- - */ - -PacketStatus SMACINT -SMAC_CheckPacketFromHost(SMACState *state, // IN: pointer to state - SMACPackets *packets) // IN/OUT: packet to process -{ - EthernetHeader eh; - EthClass typeClass; - SMACPacket *packet = NULL; // original packet from host - - ASSERT(state); - ASSERT(packets); - - WW_VNETKdPrint((MODULE_NAME "FromHost: Called\n")); - - ASSERTLOCKHELD(); - -#ifdef _WIN32 - { - MacReplacementTable *macTable = packets->table; - ASSERT(macTable); - macTable->numOfOffsets = 0; - } -#endif /* _WIN32 */ - - packet = &(packets->orig); - -#ifdef __linux__ - if (SMACL_LinearizeSkb(packet->skb)) { - VNETKdPrint((MODULE_NAME "FromHost: Failed to Linearize packet, dropping\n")); - return PacketStatusDropPacket; - } -#endif /* __linux__ */ - - - /* - * Read in the Ethernet header, and return failure if this - * is a runt packet that doesn't have a whole header - */ - - ASSERT(sizeof eh == ETH_HLEN); - if (!GetPacketData(packet, 0, sizeof eh, &eh)) { - VNETKdPrint((MODULE_NAME "FromHost: Packet missing eth header\n")); - return PacketStatusDropPacket; // instruct bridge to drop this runt packet - } - -#ifdef __linux__ - /* - * Reject the duplicate packet (occurs only in Infrastructure mode) - * - * When the vm is communicating with the host, the host arp table - * would have the vm's mac address same as the physical hw address. - * so when SMAC_PacketFromHost is called it will create a duplicate of - * the packet and let the original pass as is, this original packet - * would then be transmitted on the network, where the AP would return - * it back to us because it matches the hardware address , this is the - * duplicate packet we are talking about. - */ - if (SMACL_IsSkbHostBound(packet->skb) && - MAC_EQ(state->macAddress, eh.srcAddr)) { - W_VNETKdPrint((MODULE_NAME "FromHostIP: incoming request has " - "same mac as destination, so blackholing\n")); - return PacketStatusDropPacket; - } -#endif - - /* - * Lookup the ethernet media type of the packet - */ - - typeClass = LookupTypeClass(ntohs(eh.lengthType)); - - /* - * For reference, the VLAN support was removed since it was determined that - * for Windows, such information would be present only in the OOB area of a - * NDIS packet, and thus no specific support/handling for VLAN is required - * for that OS. - * - * For any other OS, we need to add support to the vmnet driver for that OS - * to allow VLAN tagged frames. - */ - -#if 0 - - /* - * If broadcast, then allow packet with no further checks. We might be - * able to actually enable this code, depending on how we want to handle - * DHCP replies. Currently DHCP replies don't need to be processed, so - * it's probably okay to enable this. Currently it's disabled so that - * the debug statements can continue to give us information about each - * packet. - */ - - if (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr)) { - return PacketStatusForwardPacket; - } - -#endif /* 0 */ - - /* - * DEBUG: if not IP & not ARP - */ - - if (typeClass != EthClassIP && typeClass != EthClassARP) { - - /* - * If not a common/known media type, then print a status - * message and return - */ - -#ifdef DBG - if (typeClass != EthClassCommon) { // print only if not a common type - char type[50] = ""; // holds textual name of type - LookupTypeName(ntohs(eh.lengthType), type); // lookup ethernet type - VNETKdPrint((MODULE_NAME "FromHost: non-IP & non-ARP %s " - "%02x:%02x:%02x:%02x:%02x:%02x -> " - "%02x:%02x:%02x:%02x:%02x:%02x %s\n", - (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr))? - "(b|m)cast":"ucast", - eh.srcAddr[0], eh.srcAddr[1], eh.srcAddr[2], - eh.srcAddr[3], eh.srcAddr[4], eh.srcAddr[5], - eh.destAddr[0], eh.destAddr[1], eh.destAddr[2], - eh.destAddr[3], eh.destAddr[4], eh.destAddr[5], type)); - } -#endif /* DBG */ - - /* - * Let these unrecognized packets through only if they are broadcast or - * multicast. Drop unicast packets because it's easier to debug a lack - * of traffic than damaged traffic. - */ - - if (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr)) { - VNETKdPrint((MODULE_NAME "FromHost: Forward unrecognized " - "non-arp/ip b/mcast\n")); - return PacketStatusForwardPacket; - } else { -#ifdef DBG - char type[50] = ""; // holds textual name of type - LookupTypeName(ntohs(eh.lengthType), type); - VNETKdPrint((MODULE_NAME "FromHost: Dropping unrecognized " - "unicast non-IP & non-ARP unicast packet: %s\n", type)); - VNETKdPrint((MODULE_NAME "FromHost: the non-IP & non-ARP is " - "%02x:%02x:%02x:%02x:%02x:%02x -> " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - eh.srcAddr[0], eh.srcAddr[1], eh.srcAddr[2], - eh.srcAddr[3], eh.srcAddr[4], eh.srcAddr[5], - eh.destAddr[0], eh.destAddr[1], eh.destAddr[2], - eh.destAddr[3], eh.destAddr[4], eh.destAddr[5])); -#endif - /* - * Drop non-IP/non-ARP unicast packets, unless we've been - * requested to forward unknown/unrecognized packets. - */ - - if (state->smacFowardUnknownPackets) { - return PacketStatusForwardPacket; - } else { - return PacketStatusDropPacket; - } - } - } - - /* - * If IP packet, then lookup ethernet MAC based on dest IP and replace - * dest ethernet MAC with that of the lookup table entry - */ - - if (typeClass == EthClassIP) { // if IP packet - uint8 ipHeader[IP_HEADER_LEN]; // IP header - uint32 ipVer; // IP header ver - uint32 ipHeaderLen; // IP header length - - /* Verify that we have at least a whole, minimal IP header */ - if (!GetPacketData(packet, ETH_HLEN, sizeof ipHeader, ipHeader)) { - VNETKdPrint((MODULE_NAME "FromHostIP: Got type IP, " - "but only have partial IP header\n")); - return PacketStatusTooShort; - } - - ipVer = ipHeader[0] >> 4; // IP header ver - ipHeaderLen = 4 * (ipHeader[0] & 0xf); // IP header length - - /* - * Verify basic fields in IP header - */ - - if (ipVer != 4 || ipHeaderLen < 20 || - (GetPacketLength(packet) - ETH_HLEN) < ipHeaderLen) { - VNETKdPrint((MODULE_NAME "FromHostIP: got an IP version %d, " - "or len %d < reported len %d\n", ipVer, - GetPacketLength(packet) - ETH_HLEN, ipHeaderLen)); - if ((GetPacketLength(packet) - ETH_HLEN) < ipHeaderLen) { - - /* - * insufficient data -- process anyway since we have the necessary - * amount of information (first 20 bytes) to process this packet? - */ - - VNETKdPrint((MODULE_NAME "FromHostIP: got an IP " - "that's too short\n")); - return PacketStatusTooShort; - } else { - VNETKdPrint((MODULE_NAME "FromHostIP: got an IP " - "that's unrecognised\n")); - return PacketStatusDropPacket; // invalid/unrecognized data - } - } - - /* - * broadcast/multicast processing: don't modify dest MAC but check if the - * payload should be modified - * - * unicast processing: modify MAC (if packet destined for VM) and check if - * the payload should be modified - */ - - if (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr)) { - - /* - * Check if payload should be modified. - */ - - /* - * NOTE: ProcessIncomingIPv4Packet doesn't currently modify packets, - * so in an actual product release we can remove this call. - */ - -#ifdef DBG - ProcessIncomingIPv4Packet(packet, FALSE); -#endif - W_VNETKdPrint((MODULE_NAME "FromHostIP: forward b/mcast IP\n")); - return PacketStatusForwardPacket; - - } else { // unicast ethernet - - uint32 destIP; - Bool foundMac; - uint8 vmMacAddress[ETH_ALEN]; - - destIP = *((uint32*)(ipHeader + IP_HEADER_DEST_ADDR_OFFSET)); - - /* - * For unicast IP processing: lookup MAC based on IP addr - */ - - foundMac = LookupByIP(state, destIP, vmMacAddress); - - if (!foundMac && destIP == IP_ADDR_BROADCAST) { - /* - * If IP destination address is the IP limited broadcast address - * '255.255.255.255', then SMAC the unicast ethernet MAC address into - * the ethernet broadcast MAC address 'ff:ff:ff:ff:ff:ff' and forward - * the packet. - * - * Certain DHCP Servers/Relay Agents choose to ignore the - * recommendations of RFC 1542 "Clarifications and Extensions for the - * Bootstrap Protocol" section 4.1.2, and send DHCP Offers/ACKs to a - * unicast ethernet address in response to DHCP Discovers/Requests - * with the "Broadcast" flag set. See PRs 224129, 172947. - * - * Other than such packets, there shouldn't be any other IPv4 packets - * sent to the IP limited broadcast address but not to the ethernet - * broadcast address, but even if there are, we'll forward such - * packets onto the VNet and let the guests decide what to do about - * them. - */ - MEMSET(vmMacAddress, 0xFF, ETH_ALEN); - foundMac = TRUE; - } - - if (foundMac) { // if IP is known on VNet, then substitute MAC - W_VNETKdPrint((MODULE_NAME "FromHostIP: would assign MAC" - " of %d.%d.%d.%d to packet\n", - (destIP>> 0)&0xff, (destIP>> 8)&0xff, - (destIP>>16)&0xff, (destIP>>24)&0xff)); - - /* - * Eth dest MAC needs to be corrected - */ - - if (!CopyDataForPacketFromHost(packets, 0, 0, vmMacAddress)) { - VNETKdPrint((MODULE_NAME "FromHostIP: couldn't clone packet\n")); - return PacketStatusDropPacket; - } - - /* - * NOTE: ProcessIncomingIPv4Packet doesn't currently modify packets, - * so in an actual product release we can remove this call. - */ - -#ifdef DBG - ProcessIncomingIPv4Packet(packet, foundMac); -#endif /* DBG */ - W_VNETKdPrint((MODULE_NAME "FromHostIP: forward IP\n")); - return PacketStatusForwardPacket; - } else { // IP is unknown on VNet - VNETKdPrint((MODULE_NAME "FromHostIP: could not find IP " - "%d.%d.%d.%d in lookup, so drop\n", - (destIP>>0)&0xff, (destIP>>8)&0xff, - (destIP>>16)&0xff, (destIP>>24)&0xff)); - if (state->smacFowardUnknownPackets) { - return PacketStatusForwardPacket; - } else { - return PacketStatusDropPacket; // drop packet - } - } // end IP addr lookup - } // end unicast - } // end IP - - /* - * If ARP packet, then lookup ethernet MAC based on dest IP and replace - * dest ethernet MAC (and potentially ARP MAC) with that of the lookup table entry - */ - - else { // if ARP packet: typeClass == EthClassARP - uint32 arpHeaderWord1; // first word in ARP header - uint32 arpHeaderWord2; // second word in ARP header - - if (GetPacketLength(packet) < ETH_HLEN + ARP_HEADER_LEN) { - VNETKdPrint((MODULE_NAME "FromHostARP: ARP packet is insufficient " - "length of IPv4 and Ethernet, expected %d got %d\n", - ETH_HLEN + ARP_HEADER_LEN, GetPacketLength(packet))); - return PacketStatusTooShort; - } - - /* - * Verify the first word of ARP header (hardcoded for ethernet and IPv4) - * - * I recently added IEEE802 support. These types of ARP requests were - * observed on the company network, so someone uses them. As long as - * the address lengths are the same then I imagine that the processing - * is identical and we can handle them (lengths are checked as part - * of processing the second word of ARP header). - */ - - if (!GetPacketData(packet, ETH_HLEN, sizeof arpHeaderWord1, - &arpHeaderWord1)) { - VNETKdPrint((MODULE_NAME "FromHostARP: couldn't read " - "ARP header #1\n")); - return PacketStatusTooShort; - } - - if (arpHeaderWord1 != HTONL(0x00010800) /* ethernet */ && - arpHeaderWord1 != HTONL(0x00060800) /* ieee802 */ ) { - VNETKdPrint((MODULE_NAME "FromHostARP: ARP header1 appears " - "wrong, got %08x\n", arpHeaderWord1)); - return PacketStatusDropPacket; - } - - /* - * Perform action based on opcode in second word of ARP header. - */ - - if (!GetPacketData(packet, ETH_HLEN + sizeof arpHeaderWord1, - sizeof arpHeaderWord2, &arpHeaderWord2)) { - VNETKdPrint((MODULE_NAME "FromHostARP: couldn't read " - "ARP header #2\n")); - return PacketStatusTooShort; - } - -#ifdef DBG - - /* - * DEBUG: print general information about the packet - */ - - switch (arpHeaderWord2) { - case NTOHL(0x06040001): - WW_VNETKdPrint((MODULE_NAME "FromHostARP: " - "ARP header2 indicates ARP request\n")); - break; - case NTOHL(0x06040002): - W_VNETKdPrint((MODULE_NAME "FromHostARP: " - "ARP header2 indicates ARP reply\n")); - break; - case NTOHL(0x06040003): - VNETKdPrint((MODULE_NAME "FromHostARP: " - "ARP header2 indicates RARP request\n")); - break; - case NTOHL(0x06040004): - VNETKdPrint((MODULE_NAME "FromHostARP: " - "ARP header2 indicates RARP reply\n")); - break; - case NTOHL(0x06040008): - VNETKdPrint((MODULE_NAME "FromHostARP: " - "ARP header2 indicates IARP request\n")); - break; - case NTOHL(0x06040009): - VNETKdPrint((MODULE_NAME "FromHostARP: " - "ARP header2 indicates IARP reply\n")); - break; - default: - VNETKdPrint((MODULE_NAME "FromHostARP: " - "ARP header2 indicates unknown opcode\n")); - break; - } - - { - uint8 data[ETH_ALEN + 4] = {0}; // MAC and IP in one contiguous buffer - if (GetPacketData(packet, ETH_HLEN + ARP_SENDER_MAC_OFFSET, - sizeof data, data)) { - WW_VNETKdPrint((MODULE_NAME "FromHostARP: sender MAC is " - "%02x:%02x:%02x:%02x:%02x:%02x IP is %d.%d.%d.%d\n", - ((unsigned char*)data)[0]&0xff, ((unsigned char*)data)[1]&0xff, - ((unsigned char*)data)[2]&0xff, ((unsigned char*)data)[3]&0xff, - ((unsigned char*)data)[4]&0xff, ((unsigned char*)data)[5]&0xff, - ((unsigned char*)data)[6]&0xff, ((unsigned char*)data)[7]&0xff, - ((unsigned char*)data)[8]&0xff, ((unsigned char*)data)[9]&0xff)); - } else { - VNETKdPrint((MODULE_NAME "FromHostARP: couldn't read " - "sender MAC/IP\n")); - } - - if (GetPacketData(packet, ETH_HLEN + ARP_TARGET_MAC_OFFSET, - sizeof data, data)) { - WW_VNETKdPrint((MODULE_NAME "FromHostARP: target MAC is " - "%02x:%02x:%02x:%02x:%02x:%02x IP is %d.%d.%d.%d\n", - ((unsigned char*)data)[0]&0xff, ((unsigned char*)data)[1]&0xff, - ((unsigned char*)data)[2]&0xff, ((unsigned char*)data)[3]&0xff, - ((unsigned char*)data)[4]&0xff, ((unsigned char*)data)[5]&0xff, - ((unsigned char*)data)[6]&0xff, ((unsigned char*)data)[7]&0xff, - ((unsigned char*)data)[8]&0xff, ((unsigned char*)data)[9]&0xff)); - } else { - VNETKdPrint((MODULE_NAME "FromHostARP: couldn't read " - "target MAC/IP\n")); - } - } - -#endif - - /* - * ARP handling for *incoming traffic* - * - * ARP: host wants to know the MAC that corresponds to a particular IP - * 1 ARP request: - * ALLOW CONDITIONALLY: if dest eth mac broadcast then nothing to modify, - * otherwise need to patch ucast dest eth mac. - * 2 ARP reply: - * ALLOW IF BROADCAST: broadcast so nothing to modify (except ARP dest MAC?) - * ALLOW IF LOOKUP: lookup dstIP and mofify dstMAC (ðDestMAC) to match VM - * - * RARP: host knows its MAC and wants to find out which IP it is assigned - * 3 RARP request: can't store , - * ALLOW CONDITIONALLY: if dest eth mac broadcast then nothing to modify, - * otherwise need to patch ucast dest eth mac. - * 4 RARP reply: - * ALLOW IF BROADCAST: broadcast so nothing to modify (except ARP dest MAC?) - * ALLOW IF LOOKUP: lookup dstIP and modify dstMAC (ðDestMAC) to match VM - * - * IARP: host knows a peer's MAC and wants to determine its IP address - * 8 IARP request: - * ALLOW CONDITIONALLY: if dest eth mac broadcast then nothing to modify, - * otherwise need to patch ucast dest eth mac. - * 9 IARP reply: - * ALLOW IF BROADCAST: broadcast so nothing to modify (except ARP dest MAC?) - * ALLOW IF LOOKUP: lookup dstIP and modify dstMAC (ðDestMAC) to match VM - */ - - if (arpHeaderWord2 == HTONL(0x06040001) || // If ARP request - arpHeaderWord2 == HTONL(0x06040003) || // If RARP request - arpHeaderWord2 == HTONL(0x06040008)) { // If IARP request - - uint32 targetAddr; - uint32 sourceAddr; - Bool foundIP; - - if (!GetPacketData(packet, ETH_HLEN + ARP_TARGET_IP_OFFSET, - sizeof targetAddr, &targetAddr) || - !GetPacketData(packet, ETH_HLEN + ARP_SENDER_IP_OFFSET, - sizeof sourceAddr, &sourceAddr)) { - VNETKdPrint((MODULE_NAME "FromHostARP: " - "couldn't read target and/or sourceAddr\n")); - return PacketStatusTooShort; - } - - /* - * Some host configurations will require allowing packet loopback, meaning - * that we'll see the packets that we're transmitting. Since we're performing - * MAC tricks, the guest could see its own ARP request--this echoed ARP request - * will contain the host's wireless MAC, and thus the guest OS might think that - * there is a address conflict. Thus, if we receive an ARP request whose source - * IP address is a known VM, and the MAC is the wireless hardware, then the - * ARP request is dropped. This will allow address conflicts to be detected - * when a conflict exists with another device, but it prevents conflict - * detection when the conflict is present on/within the host. - */ - - foundIP = LookupByIP(state, sourceAddr, NULL); - if (foundIP) { // if known IP is contained within request - uint8 packetMac[ETH_ALEN]; - VNETKdPrint((MODULE_NAME "FromHostARP: observed a " - "incoming request from an IP we know about\n")); - - if (!GetPacketData(packet, ETH_HLEN + ARP_SENDER_MAC_OFFSET, - sizeof packetMac, packetMac)) { - VNETKdPrint((MODULE_NAME "FromHostARP: " - "couldn't read MAC\n")); - return PacketStatusTooShort; - } - - /* - * Check if the sender MAC is using the wireless MAC - */ - - if (MAC_EQ(state->macAddress, packetMac)) { - - /* - * Sender is using wireless MAC, so drop packet - * -- the reasons for this are stated above in the large comment block. - */ - - VNETKdPrint((MODULE_NAME "FromHostARP: incoming request using " - "wireless hardware addr, so blackholing\n")); - return PacketStatusDropPacket; - } - /* - * Requester IP matches a VM IP, but the source MAC is different. - * This is apparently a true conflict with another network peer, so - * we'll forward the packet - */ - VNETKdPrint((MODULE_NAME "FromHostARP: incoming request using " - "non-wireless-hardware-addr, may conflict--allowing\n")); - } else { - /* - * We don't have information about the source (typical case), - * so forward the packet. - */ - WW_VNETKdPrint((MODULE_NAME "FromHostARP: got ARP, no record of " - "source so forward\n")); - } - - if (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr)) { - /* dest mac is broacast, so can just forward */ - return PacketStatusForwardPacket; - } else if (!MAC_EQ(state->macAddress, eh.destAddr)) { - VNETKdPrint((MODULE_NAME "FromHostARP: incoming request using " - "non-wireless-hardware-addr eth dest MAC, dropping\n")); - return PacketStatusDropPacket; - } else { - Bool foundMac; - uint8 vmMacAddress[ETH_ALEN]; - - /* - * Someone sent request to VM with the host's destination MAC, - * so need to patch this with the VM's MAC so the VM can reply. - */ - - /* - * Unicast destination--lookup MAC in table. If entry exists then - * do MAC replacement and return. Otherwise, drop the packet - */ - - foundMac = LookupByIP(state, targetAddr, vmMacAddress); - if (!foundMac) { - W_VNETKdPrint((MODULE_NAME "FromHostARP: target IP in request ARP was" - " NOT found in table, presuming for another peer\n")); - return PacketStatusDropPacket; - } - - VNETKdPrint((MODULE_NAME "FromHostARP: target IP in " - "request ARP was found in table\n")); - -#ifdef DBG - { - uint8 packetMac[ETH_ALEN]; - if (!GetPacketData(packet, ETH_HLEN + ARP_TARGET_MAC_OFFSET, - sizeof packetMac, packetMac)) { - VNETKdPrint((MODULE_NAME "FromHostARP: " - "couldn't read MAC\n")); - return PacketStatusTooShort; - } - W_VNETKdPrint((MODULE_NAME "FromHostARP: will modify request " - "ARP ETH MAC %02x.%02x.%02x.%02x.%02x.%02x " - "dest address and ARP target address " - "%02x.%02x.%02x.%02x.%02x.%02x to " - "match VM %02x.%02x.%02x.%02x.%02x.%02x\n", - eh.destAddr[0], eh.destAddr[1], eh.destAddr[2], - eh.destAddr[3], eh.destAddr[4], eh.destAddr[5], - packetMac[0], packetMac[1], packetMac[2], - packetMac[3], packetMac[4], packetMac[5], - vmMacAddress[0], vmMacAddress[1], vmMacAddress[2], - vmMacAddress[3], vmMacAddress[4], vmMacAddress[5])); - } -#endif - /* - * Copy in the MAC that will be written to eth dest MAC. - */ - - if (!CopyDataForPacketFromHost(packets, 0, 0, vmMacAddress)) { - W_VNETKdPrint((MODULE_NAME "FromHostIP: couldn't clone request packet\n")); - return PacketStatusDropPacket; - } - return PacketStatusForwardPacket; - } - } - - if (arpHeaderWord2 == HTONL(0x06040002) || // If ARP reply - arpHeaderWord2 == HTONL(0x06040004) || // If RARP reply - arpHeaderWord2 == HTONL(0x06040009)) { // If IARP reply - uint32 targetAddr; - Bool foundMac; - uint8 vmMacAddress[ETH_ALEN]; - - if (!GetPacketData(packet, ETH_HLEN + ARP_TARGET_IP_OFFSET, - sizeof targetAddr, &targetAddr)) { - VNETKdPrint((MODULE_NAME "FromHostARP: couldn't target IP\n")); - return PacketStatusTooShort; - } - - /* - * If broadcast then return because we don't need to modify anything - */ - - if (IS_MULTICAST(eh.destAddr) || IS_BROADCAST(eh.destAddr)) { - VNETKdPrint((MODULE_NAME "FromHostARP: observed a " - "broadcast ARP, RARP, or IARP reply packet\n")); - - /* - * Don't need to make changes since target MAC is the broadcast addr - */ - - /* - * Ethernet MAC is broadcast, but the dest ARP address might - * be unicast (in fact, it likely is), so we should patch the - * destination ARP MAC address?? - */ - - foundMac = LookupByIP(state, targetAddr, vmMacAddress); - if (foundMac) { - uint8 packetMac[ETH_ALEN]; - - VNETKdPrint((MODULE_NAME "FromHostARP: target IP in " - "broadcast reply ARP was found in table\n")); - - if (!GetPacketData(packet, ETH_HLEN + ARP_TARGET_MAC_OFFSET, - sizeof packetMac, packetMac)) { - VNETKdPrint((MODULE_NAME "FromHostARP: " - "couldn't read MAC\n")); - return PacketStatusTooShort; - } - - W_VNETKdPrint((MODULE_NAME "FromHostARP: will modify reply " - "ARP target address %02x.%02x.%02x.%02x.%02x.%02x to " - "match VM %02x.%02x.%02x.%02x.%02x.%02x\n", - packetMac[0], packetMac[1], packetMac[2], - packetMac[3], packetMac[4], packetMac[5], - vmMacAddress[0], vmMacAddress[1], vmMacAddress[2], - vmMacAddress[3], vmMacAddress[4], vmMacAddress[5])); - - /* - * Copy in the MAC that will be written to ARP dest MAC - */ - - if (!CopyDataForPacketFromHost(packets, 0, - ETH_HLEN + ARP_TARGET_MAC_OFFSET, - vmMacAddress)) { - VNETKdPrint((MODULE_NAME "FromHostIP: couldn't " - "clone packet\n")); - return PacketStatusDropPacket; - } - return PacketStatusForwardPacket; - } else { - W_VNETKdPrint((MODULE_NAME "FromHostARP: target IP in broadcast " - "reply ARP was NOT found in table\n")); - return PacketStatusForwardPacket; - } - } - - W_VNETKdPrint((MODULE_NAME "FromHostARP: target IP is %d.%d.%d.%d\n", - (targetAddr)&0xff, (targetAddr>>8)&0xff, - (targetAddr>>16)&0xff, (targetAddr>>24)&0xff)); -#ifdef DBG - { - uint32 senderAddr; - if (!GetPacketData(packet, ETH_HLEN + ARP_SENDER_IP_OFFSET, - sizeof senderAddr, &senderAddr)) { - VNETKdPrint((MODULE_NAME "FromHostARP: couldn't " - "read IP addr\n")); - return PacketStatusTooShort; - } - W_VNETKdPrint((MODULE_NAME "FromHostARP: sender IP %d.%d.%d.%d\n", - (senderAddr&0xff), (senderAddr>>8)&0xff, - (senderAddr>>16)&0xff, (senderAddr>>24)&0xff)); - } -#endif - - /* - * Unicast destination--lookup MAC in table. If entry exists then - * do MAC replacement and return. Otherwise, drop the packet - */ - - // see if the reply is for a host that we're aware of, and modify as necessary - foundMac = LookupByIP(state, targetAddr, vmMacAddress); - if (foundMac) { - VNETKdPrint((MODULE_NAME "FromHostARP: target IP in " - "reply ARP was found in table\n")); - -#ifdef DBG - { - uint8 packetMac[ETH_ALEN]; - if (!GetPacketData(packet, ETH_HLEN + ARP_TARGET_MAC_OFFSET, - sizeof packetMac, packetMac)) { - VNETKdPrint((MODULE_NAME "FromHostARP: " - "couldn't read MAC\n")); - return PacketStatusTooShort; - } - W_VNETKdPrint((MODULE_NAME "FromHostARP: will modify reply " - "ARP ETH MAC %02x.%02x.%02x.%02x.%02x.%02x " - "dest address and ARP target address " - "%02x.%02x.%02x.%02x.%02x.%02x to " - "match VM %02x.%02x.%02x.%02x.%02x.%02x\n", - eh.destAddr[0], eh.destAddr[1], eh.destAddr[2], - eh.destAddr[3], eh.destAddr[4], eh.destAddr[5], - packetMac[0], packetMac[1], packetMac[2], - packetMac[3], packetMac[4], packetMac[5], - vmMacAddress[0], vmMacAddress[1], vmMacAddress[2], - vmMacAddress[3], vmMacAddress[4], vmMacAddress[5])); - } -#endif - /* - * Copy in the MAC that will be written to eth - * dest MAC and ARP dest MAC - */ - - if (!CopyDataForPacketFromHost(packets, 0, 0, vmMacAddress)) { - W_VNETKdPrint((MODULE_NAME "FromHostIP: couldn't " - "clone packet\n")); - return PacketStatusDropPacket; - } - if (!CopyDataForPacketFromHost(packets, 1, - ETH_HLEN + ARP_TARGET_MAC_OFFSET, - vmMacAddress)) { - W_VNETKdPrint((MODULE_NAME "FromHostIP: " - "couldn't clone packet #2\n")); - return PacketStatusDropPacket; - } - - return PacketStatusForwardPacket; - } else { - W_VNETKdPrint((MODULE_NAME "FromHostARP: target IP in reply ARP was" - " NOT found in table, presuming for another peer\n")); - return PacketStatusDropPacket; - } - } - VNETKdPrint((MODULE_NAME "FromHostARP: unrecognized ARP type %08x\n", - arpHeaderWord2)); - return PacketStatusDropPacket; - } -} - - -/* - *---------------------------------------------------------------------- - * - * SMAC_CheckPacketToHost -- - * - * Modifies packet contents to be suitable for transmission over - * a wireless network. Function supports IP, ARP, RARP, IARP. - * Function will support DHCP in the future. This function clones - * the source packet, modifies the clone packet in situations - * where the packet should be forwarded to the host. - * - * NOTE: On Windows this function presumes it is called at DISPATCH_LEVEL - * - * Results: - * Returns 'PacketStatusTooShort' if insufficient data to process - * packet (suggest packet drop), 'PacketStatusDropPacket' if the - * packet should be dropped, or 'PacketStatusForwardPacket' if - * the packet should be forwarded. - * - * Side effects: - * Modifies contents of network packet, if nessary. - * - *---------------------------------------------------------------------- - */ - -PacketStatus SMACINT -SMAC_CheckPacketToHost(SMACState *state, // IN: pointer to state - SMACPackets *packets) // IN/OUT: packet to process; cloned/modified packet -{ - uint8 buf[sizeof(EthernetHeader) + 4]; /* allocate extra 4 for VLAN headers */ - EthernetHeader *eh = (EthernetHeader*)buf; - uint32 ethHeaderLen = ETH_HLEN; // tracks length of ethernet header - SMACPacket *packet = NULL; - EthClass typeClass; // classification of ethernet frame's type - - ASSERT(state); - - W_VNETKdPrint((MODULE_NAME "ToHost: Called\n")); - ASSERTLOCKHELD(); - ASSERT(sizeof(EthernetHeader) == ETH_HLEN); - - packet = &(packets->orig); - ASSERT(packet); - -#ifdef __linux__ - if (SMACL_LinearizeSkb(packet->skb)) { - VNETKdPrint((MODULE_NAME "ToHost: Failed to Linearize packet, dropping\n")); - return PacketStatusDropPacket; - } -#endif /* __linux__ */ - - /* - * Verify that we have at least a minimal packet - */ - - if (!GetPacketData(packet, 0, ethHeaderLen, eh)) { - VNETKdPrint((MODULE_NAME "ToHost: Packet missing eth header\n")); - return PacketStatusTooShort; - } - - /* - * Lookup the ethernet media type of the packet - */ - - typeClass = LookupTypeClass(ntohs(eh->lengthType)); - - /* - * If packet type is a VLAN header, then adjust pointers and - * decode the "real" media type which follows the VLAN header - */ - - if (typeClass == EthClassVLAN) { - uint16 actualType = 0; - - ethHeaderLen +=4; - if (!GetPacketData(packet, 0, ethHeaderLen, eh)) { - VNETKdPrint((MODULE_NAME " ToHost: Packet is using VLAN header, " - "but supplied header is too small\n")); - return PacketStatusTooShort; - } - - actualType = *(uint16*)(((uint8*)&(eh->lengthType)) + 4); - - VNETKdPrint((MODULE_NAME " ToHost: Taking special measures for VLAN\n")); - typeClass = LookupTypeClass(ntohs(actualType)); - } - - /* - * If the packet is not type IP or ARP, then drop the packet - * unless it is a broadcast packet (broadcast packets don't - * require much manipulating, so they should be safe to let thru). - */ - - if (typeClass != EthClassIP && typeClass != EthClassARP) { - - /* - * DEBUG: if not a common/known media type, then print a status message - */ - -#ifdef DBG - if (typeClass != EthClassCommon) { - char type[50] = ""; // holds textual name of type - if (ethHeaderLen == ETH_HLEN) { // if not a vlan packet - LookupTypeName(ntohs(eh->lengthType), type); - } else { // if a vlan packet - uint16 actualType = *(uint16*)(((uint8*)&(eh->lengthType)) + 4); - LookupTypeName(ntohs(actualType), type); - } - VNETKdPrint((MODULE_NAME " ToHost: non-IP & non-ARP " - "%02x:%02x:%02x:%02x:%02x:%02x -> " - "%02x:%02x:%02x:%02x:%02x:%02x %s\n", - eh->srcAddr[0]&0xff, eh->srcAddr[1]&0xff, - eh->srcAddr[2]&0xff, eh->srcAddr[3]&0xff, - eh->srcAddr[4]&0xff, eh->srcAddr[5]&0xff, - eh->destAddr[0]&0xff, eh->destAddr[1]&0xff, - eh->destAddr[2]&0xff, eh->destAddr[3]&0xff, - eh->destAddr[4]&0xff, eh->destAddr[5]&0xff, type)); - } -#endif - - /* - * Let these unrecognized packets through only if they are broadcast or - * multicast, and drop unicast packets (it's easier/debug loss of traffic - * versus corrupted/invalid traffic). - */ - - if (IS_MULTICAST(eh->destAddr) || IS_BROADCAST(eh->destAddr)) { - - /* - * Modify the source address to be that of the wireless hardware, so - * that this packet can be transmitted. First we need to duplicate - * the packet so that other VMs don't get confused about MACs that - * arbitrarily change between the VM's MAC and the host's MAC. - */ - - if (!ClonePacket(packets)) { - VNETKdPrint((MODULE_NAME " ToHost: couldn't clone packet\n")); - return PacketStatusDropPacket; - } - - CopyDataToClonedPacket(packets, state->macAddress, - ETH_ALEN /* offset for source MAC */, - ETH_ALEN /* length */); - return PacketStatusForwardPacket; - } else { - - /* - * Drop the packet, but first display a status message indicating - * that we're dropping this packet (largely so we know what kind/type - * of traffic that we are dropping - */ - -#ifdef DBG - char type[50] = ""; // holds textual name of type - if (ethHeaderLen == ETH_HLEN) { // if not a vlan packet - LookupTypeName(ntohs(eh->lengthType), type); - } else { // if a vlan packet - uint16 actualType = *(uint16*)(((uint8*) & (eh->lengthType)) + 4); - LookupTypeName(ntohs(actualType), type); - } - VNETKdPrint((MODULE_NAME " ToHost: Dropping unrecognized " - "unicast non-IP & non-ARP unicast packet: %s\n", type)); - VNETKdPrint((MODULE_NAME " ToHost: the non-IP & non-ARP is " - "%02x:%02x:%02x:%02x:%02x:%02x -> " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - eh->srcAddr[0]&0xff, eh->srcAddr[1]&0xff, - eh->srcAddr[2]&0xff, eh->srcAddr[3]&0xff, - eh->srcAddr[4]&0xff, eh->srcAddr[5]&0xff, - eh->destAddr[0]&0xff, eh->destAddr[1]&0xff, - eh->destAddr[2]&0xff, eh->destAddr[3]&0xff, - eh->destAddr[4]&0xff, eh->destAddr[5]&0xff)); -#endif - return PacketStatusDropPacket; - } - } - - /* - * If IPv4 packet, then store in lookup - * table and replace source ethernet MAC with that of the wireless hardware - */ - - if (typeClass == EthClassIP) { - uint8 ipHeader[IP_HEADER_LEN]; - - uint32 ipVer; // version of IP header - uint32 ipHeaderLen; // reported length of IP header - - uint16 ipLen; // reported length of IP packet - uint32 ipSrcAddr; // source address - - /* - * If have contents of at least a minimal IP packet header - */ - - if (!GetPacketData(packet, ethHeaderLen, sizeof ipHeader, ipHeader)) { - VNETKdPrint((MODULE_NAME " ToHostIP: got an IP type, " - "but incomplete header\n")); - return PacketStatusTooShort; - } - - ipVer = ipHeader[0]>>4; // version of IP header - ipHeaderLen = 4 * (ipHeader[0]&0xf); // reported length of IP header - - ipLen = ntohs(*(uint16*)(ipHeader + 2)); // packet len - ipSrcAddr = *((uint32*)(ipHeader + IP_HEADER_SRC_ADDR_OFFSET)); - /* - * Verify basic fields in IP header - */ - - if (ipVer != 4 || ipHeaderLen < IP_HEADER_LEN || - GetPacketLength(packet) < ethHeaderLen + ipHeaderLen) { - VNETKdPrint((MODULE_NAME " ToHostIP: got an IP version %d, " - "or len %d < reported len %d\n", ipVer, - GetPacketLength(packet), ethHeaderLen + ipHeaderLen)); - return PacketStatusDropPacket; - } - - W_VNETKdPrint((MODULE_NAME " ToHostIP: processing IP packet\n")); - - /* - * Store IP/MAC combo in lookup table, that way we can replace - * the MAC when any replies to this IP are received - */ - - if (!AddIPv4andMACcombo(state, ipSrcAddr, eh->srcAddr)) { - return PacketStatusDropPacket; - } - - /* - * Replace source MAC with wireless hardware MAC - */ - - W_VNETKdPrint((MODULE_NAME " ToHostIP: modifying ETH MAC " - "%02x.%02x.%02x.%02x.%02x.%02x source address to match " - "wireless hardware %02x.%02x.%02x.%02x.%02x.%02x \n", - eh->srcAddr[0]&0xff, eh->srcAddr[1]&0xff, - eh->srcAddr[2]&0xff, eh->srcAddr[3]&0xff, - eh->srcAddr[4]&0xff, eh->srcAddr[5]&0xff, - state->macAddress[0]&0xff, state->macAddress[1]&0xff, - state->macAddress[2]&0xff, state->macAddress[3]&0xff, - state->macAddress[4]&0xff, state->macAddress[5]&0xff)); - - { - /* - * Duplicate the packet so that other VMs don't get confused about - * MACs that arbitrarily change between the VM's MAC and the host's - * MAC. - */ - - if (!ClonePacket(packets)) { - VNETKdPrint((MODULE_NAME " ToHostIP: couldn't clone packet\n")); - return PacketStatusDropPacket; - } - - CopyDataToClonedPacket(packets, state->macAddress, - ETH_ALEN /* offset for source MAC */, - ETH_ALEN /* length */); - - /* - * Make any necessary modifications to packet payload - */ - - ProcessOutgoingIPv4Packet(&(packets->clone), ethHeaderLen); - - return PacketStatusForwardPacket; - } - } - - /* - * If ARP packet, then store in - * lookup table (if possible) and replace source ethernet MAC (and source - * ARP MAC, if appropriate) with that of the wireless hardware - */ - - else { // typeClass == EthClassARP - uint32 arpHeaderWord1; // first word of ARP header - uint32 arpHeaderWord2; // second word of ARP header - - /* - * Verify that packet meets minimum length expectations, the ARP header - * is 7 words for ethernet and IPv4, but the length may actually be 60 - * due to ethernet's minimum length requirements. - */ - - if (GetPacketLength(packet) < ethHeaderLen + ARP_HEADER_LEN) { - VNETKdPrint((MODULE_NAME " ToHostARP: ARP packet is insufficient " - "length of IPv4 and Ethernet, expected %d got %d\n", - ethHeaderLen + ARP_HEADER_LEN, GetPacketLength(packet))); - return PacketStatusDropPacket; - } - - /* - * Verify the first word of the ARP header (hardcoded for ethernet and IPv4) - * - * I recently added IEEE802 support. These types of ARP requests were - * observed on the company network, so someone uses them. As long as - * the address lengths are the same then I imagine that the processing - * is identical and we can handle them (lengths are checked as part - * of processing the second word of ARP header). - */ - - if (!GetPacketData(packet, ethHeaderLen, sizeof arpHeaderWord1, - &arpHeaderWord1) || - !GetPacketData(packet, ethHeaderLen + sizeof arpHeaderWord1, - sizeof arpHeaderWord2, &arpHeaderWord2)) { - VNETKdPrint((MODULE_NAME "ToHostARP: ARP header couldnt be loaded\n")); - return PacketStatusDropPacket; - } - - if (arpHeaderWord1 != HTONL(0x00010800) /* ethernet */ && - arpHeaderWord1 != HTONL(0x00060800) /* ieee802 */ ) { - VNETKdPrint((MODULE_NAME " ToHostARP: ARP header appears wrong, " - "got %08x\n", arpHeaderWord1)); - return PacketStatusDropPacket; - } - - /* - * Perform action based on opcode in second word of ARP header. - * DEBUG: print general information about the packet - */ - -#ifdef DBG - switch (arpHeaderWord2) { - case NTOHL(0x06040001): - W_VNETKdPrint((MODULE_NAME " ToHostARP: " - "ARP header2 indicates ARP request\n")); - break; - case NTOHL(0x06040002): - W_VNETKdPrint((MODULE_NAME " ToHostARP: " - "ARP header2 indicates ARP reply\n")); - break; - case NTOHL(0x06040003): - VNETKdPrint((MODULE_NAME " ToHostARP: " - "ARP header2 indicates RARP request\n")); - break; - case NTOHL(0x06040004): - VNETKdPrint((MODULE_NAME " ToHostARP: " - "ARP header2 indicates RARP reply\n")); - break; - case NTOHL(0x06040008): - VNETKdPrint((MODULE_NAME " ToHostARP: " - "ARP header2 indicates IARP request\n")); - break; - case NTOHL(0x06040009): - VNETKdPrint((MODULE_NAME " ToHostARP: " - "ARP header2 indicates IARP reply\n")); - break; - default: - VNETKdPrint((MODULE_NAME " ToHostARP: " - "ARP header2 indicates unknown opcode\n")); - break; - } - - { - uint8 packetMac[ETH_ALEN]; - uint8 packetIP[4]; - - if (!GetPacketData(packet, ethHeaderLen + ARP_SENDER_MAC_OFFSET, - sizeof packetMac, packetMac)) { - VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read MAC\n")); - return PacketStatusTooShort; - } - if (!GetPacketData(packet, ethHeaderLen + ARP_SENDER_IP_OFFSET, - sizeof packetIP, packetIP)) { - VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read IP\n")); - return PacketStatusTooShort; - } - - W_VNETKdPrint((MODULE_NAME " ToHostARP: sender MAC is " - "%02x:%02x:%02x:%02x:%02x:%02x IP is %d.%d.%d.%d\n", - packetMac[0], packetMac[1], packetMac[2], - packetMac[3], packetMac[4], packetMac[5], - packetIP[0], packetIP[1], packetIP[2], packetIP[3])); - - if (!GetPacketData(packet, ethHeaderLen + ARP_TARGET_MAC_OFFSET, - sizeof packetMac, packetMac)) { - VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read MAC\n")); - return PacketStatusTooShort; - } - if (!GetPacketData(packet, ethHeaderLen + ARP_TARGET_IP_OFFSET, - sizeof packetIP, packetIP)) { - VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read IP\n")); - return PacketStatusTooShort; - } - - W_VNETKdPrint((MODULE_NAME " ToHostARP: target MAC is " - "%02x:%02x:%02x:%02x:%02x:%02x IP is %d.%d.%d.%d\n", - packetMac[0], packetMac[1], packetMac[2], - packetMac[3], packetMac[4], packetMac[5], - packetIP[0], packetIP[1], packetIP[2], packetIP[3])); - } -#endif - - /* - * ARP handling for *outgoing traffic* - * - * ARP: host wants to know the MAC that corresponds to a particular IP - * 1 ARP request: store source , - * modify source MAC in eth & ARP - * 2 ARP reply: store source , - * modify source MAC in eth & ARP - * - * RARP: host knows its MAC and wants to find out which IP it is - * assigned (simple form of DHCP) - * 3 RARP request: can't store , - * should modify srcMAC but response would be MAC/IP of host - * I'm tempted to blackhole this packet, but for now I will just modify - * the eth MAC and allow it to be sent - * -- for now, presuming that lookup done on second srcMAC, but packet - * sent to first srcMAC (in other words, like IARP). This may - * be more correct / interoperable, but we still won't be able to - * handle RARP replies properly unless they are broadcasted. - * 4 RARP reply: store source , - * modify source MAC in eth & ARP - * - * IARP: host knows a peer's MAC and wants to determine its IP address - * 8 IARP request: store source , - * modify source MAC in eth & ARP - * 9 IARP reply: store source , - * modify source MAC in eth & ARP - */ - - if (arpHeaderWord2 == HTONL(0x06040001) || - arpHeaderWord2 == HTONL(0x06040002) || - arpHeaderWord2 == HTONL(0x06040003) || - arpHeaderWord2 == HTONL(0x06040004) || - arpHeaderWord2 == HTONL(0x06040008) || - arpHeaderWord2 == HTONL(0x06040009)) { - - if (arpHeaderWord2 != HTONL(0x06040003)) { // don't store MAC/IP for RARP req. - uint32 IPaddr; - uint8 packetMac[ETH_ALEN]; - - W_VNETKdPrint((MODULE_NAME " ToHostARP: adding MAC/IP " - "combo to lookup table\n")); - - /* read IP */ - if (!GetPacketData(packet, ethHeaderLen + ARP_SENDER_IP_OFFSET, - sizeof IPaddr, &IPaddr)) { - VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read IP\n")); - return PacketStatusTooShort; - } - - /* read MAC */ - if (!GetPacketData(packet, ethHeaderLen + ARP_SENDER_MAC_OFFSET, - sizeof packetMac, packetMac)) { - VNETKdPrint((MODULE_NAME " ToHostARP: couldn't read MAC\n")); - return PacketStatusTooShort; - } - - /* - * Store combo in table. For MAC we could also use - * (char*)(packet)+ETH_ALEN, but it's more consistent with the ARP - * protocol to use the MAC located within the packet - */ - - if (!AddIPv4andMACcombo(state, IPaddr, packetMac)) { - return PacketStatusDropPacket; - } - } - - /* - * First we need to duplicate the packet so that other VMs don't - * get confused about MACs that arbitrarily change between the - * VM's MAC and the host's MAC. - */ - - { - if (!ClonePacket(packets)) { - VNETKdPrint((MODULE_NAME " ToHostARP: couldn't " - "clone packet\n")); - return PacketStatusDropPacket; - } - - /* - * Substitute sender ethernet MAC with the wireless hardware's MAC - */ - - W_VNETKdPrint((MODULE_NAME " ToHostARP: modifying ETH MAC " - "%02x.%02x.%02x.%02x.%02x.%02x source address to match" - " wireless hardware %02x.%02x.%02x.%02x.%02x.%02x \n", - eh->srcAddr[0]&0xff, eh->srcAddr[1]&0xff, - eh->srcAddr[2]&0xff, eh->srcAddr[3]&0xff, - eh->srcAddr[4]&0xff, eh->srcAddr[5]&0xff, - state->macAddress[0]&0xff, state->macAddress[1]&0xff, - state->macAddress[2]&0xff, state->macAddress[3]&0xff, - state->macAddress[4]&0xff, state->macAddress[5]&0xff)); - - CopyDataToClonedPacket(packets, state->macAddress, ETH_ALEN /* offset */, - ETH_ALEN /* length */); - - /* - * Modify ARP source MAC - */ - - // substitute sender MAC with the wireless hardware's MAC -#ifdef DBG - { - uint8 packetMac[ETH_ALEN]; - if (!GetPacketData(packet, ethHeaderLen + ARP_SENDER_MAC_OFFSET, - sizeof packetMac, packetMac)) { - VNETKdPrint((MODULE_NAME " ToHostARP: " - "couldn't read MAC\n")); - return PacketStatusTooShort; - } - - W_VNETKdPrint((MODULE_NAME " ToHostARP: modifying ETH ARP " - "%02x.%02x.%02x.%02x.%02x.%02x source address to match " - "wireless hardware %02x.%02x.%02x.%02x.%02x.%02x \n", - packetMac[0], packetMac[1], packetMac[2], - packetMac[3], packetMac[4], packetMac[5], - state->macAddress[0], state->macAddress[1], - state->macAddress[2], state->macAddress[3], - state->macAddress[4], state->macAddress[5])); - } -#endif - - CopyDataToClonedPacket(packets, state->macAddress, - ethHeaderLen + ARP_SENDER_MAC_OFFSET /* offset */, - ETH_ALEN /* length */); - return PacketStatusForwardPacket; - } - } - - VNETKdPrint((MODULE_NAME " ToHostARP: unrecognized ARP type %08x\n", - arpHeaderWord2)); - return PacketStatusDropPacket; - } -} - - -/* - *---------------------------------------------------------------------- - * - * ProcessOutgoingIPv4Packet -- - * - * This function is used to examine IPv4 packets, and make any - * adjustments (if necessary) to the IP header and/or payload. - * The caller should have determined that the packet is IPv4 - * before calling this function. - * - * Currently this function just makes sure that the broadcast - * bit is set on outgoing client DHCP packets that are being - * sent to a server. - * - * Results: - * None. - * - * Side effects: - * May modify the contents of the packet. Length should be - * unchanged. - * - *---------------------------------------------------------------------- - */ - -static void -ProcessOutgoingIPv4Packet(SMACPacket *packet, // IN: cloned packet to process - uint32 ethHeaderLen) // IN: length of ethernet header -{ - uint8 proto; // protocol within ip - uint16 ipFlags; // flags and offset - - /* - * Should certain checks, e.g., IP version field, be checked here, - * or assume that caller has already performed this check? - */ - - // check should have been performed by caller - ASSERT(GetPacketLength(packet) >= IP_HEADER_LEN + ethHeaderLen); - - if (!GetPacketData(packet, ethHeaderLen + IP_HEADER_PROTO_OFFSET, - sizeof proto, &proto)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get protocol\n")); - ASSERT(0); // should never occur - return; - } - - if (!GetPacketData(packet, ethHeaderLen + IP_HEADER_FLAGS_OFFSET, - sizeof ipFlags, &ipFlags)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get flags\n")); - ASSERT(0); // should never occur - return; - } - - /* - * Verify offset=0 and M=0: mask off "fragment" flag, - * all others should be zero. This is to ensure that we're processing - * only the front of the actual packet (i.e., validate that what we - * think if offset 0 is really offset 0). - */ - - if (ipFlags & HTONS((uint16)(0xbfff))) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got a fragmented IP " - "(ipFlags %04x), so not performing higher-level processing\n", - ipFlags)); - return; - } - - /* - * NOTE: the following switch statement can be replaced with a single - * check for proto==17, since UDP is the only non-debug case - */ - - switch (proto) { - case 1: { // ICMP -#ifdef DBG - uint8 ipHeader[IP_HEADER_LEN]; - uint32 ipHeaderLen = 0; - uint32 ipVer = 0; - uint16 ipLen = 0; - uint8 typeField = 0; - uint8 codeField = 0; - - /* Verify that we have at least a whole, minimal IP header */ - if (!GetPacketData(packet, ethHeaderLen, sizeof ipHeader, ipHeader)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get IP\n")); - return; - } - - ipHeaderLen = 4 * (ipHeader[0] & 0xf); // version of IP header - ipVer = ipHeader[0] >> 4; // length of IP header - ipLen = ntohs(*(uint16*)(ipHeader + 2)); // total datagram len - - if (ipVer == 4 && GetPacketLength(packet) >= - ipHeaderLen + ethHeaderLen + 2 * 4 && - GetPacketData(packet, ethHeaderLen + ipHeaderLen, - sizeof typeField, &typeField) && - GetPacketData(packet, ethHeaderLen + ipHeaderLen + 1, - sizeof codeField, &codeField)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got ICMP, " - "type = %d, code = %d,\n", typeField, codeField)); - } else { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got ICMP, " - "but couldn't process\n")); - } -#endif /* DBG */ - return; - } - case 2: // IGMP - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got IGMP\n")); - return; - case 4: // IP in IP - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got IP in IP\n")); - return; - case 6: // TCP - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got TCP\n")); - return; - case 17: { // UDP - uint8 ipHeaderFirstByte; - uint32 ipHeaderLen; // length of IP header - uint16 srcPort; // UDP source port - uint16 destPort; // UDP dest port - - if (!GetPacketData(packet, ethHeaderLen, - sizeof ipHeaderFirstByte, &ipHeaderFirstByte)) { - VNETKdPrint((MODULE_NAME "FromHostIP: Failed to get IP length\n")); - return; - } - - ipHeaderLen = 4 * (ipHeaderFirstByte & 0xf); // version of IP header - - W_VNETKdPrint((MODULE_NAME "ProcessOutgoing: got UDP\n")); - - /* - * Verify that sufficient data for UDP packet header is present - */ - - if (GetPacketLength(packet) < ethHeaderLen + ipHeaderLen + UDP_HEADER_LEN) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: UDP header not present\n")); - return; - } - - /* - * decode the source and destination ports in UDP header - */ - - if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen, - sizeof srcPort, &srcPort) || - !GetPacketData(packet, ethHeaderLen + ipHeaderLen + 2, - sizeof destPort, &destPort)) { - VNETKdPrint((MODULE_NAME "FromHostIP: Failed to get UDP ports\n")); - return; - } - - srcPort = ntohs(srcPort); - destPort = ntohs(destPort); - -#ifdef DBG - { - uint8 srcAddr[4]; - uint8 destAddr[4]; - - if (!GetPacketData(packet, ethHeaderLen + IP_HEADER_SRC_ADDR_OFFSET, - sizeof srcAddr, srcAddr) || - !GetPacketData(packet, ethHeaderLen + IP_HEADER_DEST_ADDR_OFFSET, - sizeof destAddr, destAddr)) { - VNETKdPrint((MODULE_NAME "FromHostIP: Failed to get IP addrs\n")); - ASSERT(0); // should never happen - } else { - W_VNETKdPrint((MODULE_NAME "ProcessOutgoing: got UDP, " - "src %d.%d.%d.%d %d dest %d.%d.%d.%d %d\n", - srcAddr[0], srcAddr[1], srcAddr[2], srcAddr[3], srcPort, - destAddr[0], destAddr[1], destAddr[2], destAddr[3], - destPort)); - } - } -#endif - - if (destPort == 67) { // if destined for DHCP server port - uint32 firstDHCPword; - uint16 dhcpFlags; - - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got client " - "DHCP packet destined for a server\n")); - - /* - * Should this really be 300, or something smaller (like the maximum - * length that we'll actually index into the DHCP data)? - */ - - if (GetPacketLength(packet) < ethHeaderLen + ipHeaderLen + - UDP_HEADER_LEN + 300) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: packet " - "too small for DHCP\n")); - return; - } - - /* - * Verify that the first word in the DHCP header matches - * out expectations - */ - - if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen + - UDP_HEADER_LEN, sizeof firstDHCPword, &firstDHCPword)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get first " - "DHCP word\n")); - return; - } - - firstDHCPword = NTOHL(firstDHCPword); - if ((firstDHCPword & 0xffffff00) != 0x01010600) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: DHCP " - "first word appears incorrect\n")); - return; - } - - /* - * Turn on the broadcast flag, just in case. This - * instructs/requests that the server broadcast the reply - * back, which is a nice way to avoid the issue about - * whether to set chaddr to the VM MAC or the wireless MAC. - * - * If chaddr is set to wireless MAC then we'd receive the reply, - * but the DHCP server might confuse us with the host and send - * us a copy of the host's current IP address assignment. This - * confusion should be occur if all OSes used the client identifier - * extension, but we can't rely on this. - * - * If chaddr is set to VM MAC then no alias confusion should occur, - * but the reply might be unicast to the VM's MAC (in which case - * we might not , or will not, receive the reply). To avoid the - * receive issue, it's easiest to just set the broadcast packet - * if it's not already set. - * - * One potential downside is that the VM might be expecting a unicast - * reply, and it's unclear whether it can or will handling a - * broadcast reply properly. We can special case this support, if - * necessary. - */ - - if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen + - UDP_HEADER_LEN + 10, sizeof dhcpFlags, &dhcpFlags)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " - "DHCP flags\n")); - return; - } - - dhcpFlags = ntohs(dhcpFlags); - if (dhcpFlags & 0x8000) { // if flag already set, then no work to do - VNETKdPrint((MODULE_NAME "ProcessOutgoing: DHCP broadcast " - "bit is already set\n")); - } else { - - /* - * Get the original checksum - */ - - uint16 oriChecksum; - - if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen + 6, - sizeof oriChecksum, &oriChecksum)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " - "UDP checksum\n")); - return; - } - oriChecksum = ntohs(oriChecksum); - - VNETKdPrint((MODULE_NAME "ProcessOutgoing: DHCP broadcast bit " - "NOT set, need to do so\n")); - - if (oriChecksum) { // if checksum specified - - /* - * Compute the checksum over the word that we're about to change - */ - - uint32 sumBefore; // checksum before - uint32 sumAfter; // checksum after changes - uint32 sumDiff; // difference in checksum - uint16 newChecksum; // new checksum - - /* checksum bytes 8-11 */ - - if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen + - UDP_HEADER_LEN + 8, - sizeof sumBefore, &sumBefore)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " - "UDP checksum before\n")); - return; - } - - sumBefore = SUM32(sumBefore); // checksum before - - VNETKdPrint((MODULE_NAME "ProcessOutgoing: DHCP UDP checksum " - "is present, changing flags and checksum\n")); - - /* - * Set the actual flag in bytes 10 and 11 - */ - - dhcpFlags |= 0x8000; - - if (!SetPacketByte(packet, ethHeaderLen + ipHeaderLen + - UDP_HEADER_LEN + 11, dhcpFlags & 0xff) || - !SetPacketByte(packet, ethHeaderLen + ipHeaderLen + - UDP_HEADER_LEN + 10, dhcpFlags >> 8)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't set " - "new UDP flags\n")); - return; - } - - /* - * Compute the checksum over the word that we have just changed - */ - - /* checksum (again) bytes 8-11 */ - - if (!GetPacketData(packet, ethHeaderLen + ipHeaderLen + - UDP_HEADER_LEN + 8, - sizeof sumAfter, &sumAfter)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " - "UDP checksum after\n")); - ASSERT(0); // should never occur - return; - } - - sumAfter = SUM32(sumAfter); - - /* - * Compute difference/delta between old and new checksums - */ - - sumDiff = CalcChecksumDiff(sumBefore, sumAfter); - - /* - * Compute new checksum, based on delta from existing checksum - */ - - newChecksum = UpdateSum(oriChecksum, sumDiff); - - /* - * Verify that the new checksum isn't 0 (in which case make it ~0) - */ - - if (!newChecksum) { - newChecksum = 0xffff; - } - - /* - * Write back the new checksum - */ - - if (!SetPacketByte(packet, ethHeaderLen + ipHeaderLen + 6, - newChecksum >> 8) || - !SetPacketByte(packet, ethHeaderLen + ipHeaderLen + 7, - newChecksum & 0xff)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't set " - "new UDP checksum\n")); - return; - } - } else { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: DHCP UDP " - "checksum is NOT present, changing only flags\n")); - /* - * Set the actual flag without modifying checksum - */ - - dhcpFlags |= 0x8000; - if (!SetPacketByte(packet, ethHeaderLen + ipHeaderLen + - UDP_HEADER_LEN + 11, dhcpFlags & 0xff) || - !SetPacketByte(packet, ethHeaderLen + ipHeaderLen + - UDP_HEADER_LEN + 10, dhcpFlags >> 8)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't set " - "new UDP flags, non-checksum case\n")); - return; - } - } - } - -#ifdef DBG - { - uint32 IPDestAddr; - if (!GetPacketData(packet, ethHeaderLen + IP_HEADER_DEST_ADDR_OFFSET, - sizeof IPDestAddr, &IPDestAddr)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " - "IP dest addr\n")); - return; - } - - if (IPDestAddr == IP_ADDR_BROADCAST) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: server-bound DHCP " - "packet is broadcast\n")); - } else { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: server-bound DHCP " - "packet is unicast\n")); - } - } -#endif - return; - } else if (destPort == 68) { // if packet for destined DHCP client port -#ifdef DBG - uint32 IPDestAddr = 0; - if (!GetPacketData(packet, ethHeaderLen + IP_HEADER_DEST_ADDR_OFFSET, - sizeof IPDestAddr, &IPDestAddr)) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: couldn't get " - "IP dest addr\n")); - return; - } - - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got server " - "DHCP packet destined for a client\n")); - - if (IPDestAddr == IP_ADDR_BROADCAST) { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: client-bound " - "DHCP packet is broadcast\n")); - } else { - VNETKdPrint((MODULE_NAME "ProcessOutgoing: client-bound " - "DHCP packet is unicast\n")); - } -#endif /* DBG */ - return; - } else { - W_VNETKdPrint((MODULE_NAME "ProcessOutgoing: got UDP srcPort " - "%d destPort %d\n", srcPort, destPort)); - return; - } - } - case 27: // RDP - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got RDP\n")); - return; - case 41: // IPv6 - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got IPv6\n")); - return; - case 51: // Authentication Header - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got Authentication Header\n")); - return; - case 55: // Mobile IP - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got Mobile IP\n")); - return; - case 103: // PIM - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got PIM\n")); - return; - case 111: // IPX in IP - VNETKdPrint((MODULE_NAME "ProcessOutgoing: got IPX in IP\n")); - return; - default: - VNETKdPrint((MODULE_NAME "ProcessOutgoing: Unknown/unhandled " - "service reported by IP packet\n")); - return; - } -} - - -/* - *---------------------------------------------------------------------- - * - * ProcessIncomingIPv4Packet -- - * - * This function is used to examine IPv4 packets, and make any - * adjustments (if necessary) to the IP header and/or payload. - * The third paramter is optional (specify NULL if not provided). - * - * Currently **this function does nothing** but print out debug - * information about the contents of the IP packet - * - * Results: - * None. - * - * Side effects: - * May modify the contents of the packet. Length should be - * unchanged. - * - *---------------------------------------------------------------------- - */ - -/* - * NOTE: this abstraction doesn't match reality because we may only have - * a partial packet received so far. But, since we're not modifying the - * packet (and only trying to ID/classify it) then this shouldn't matter. - */ - -#ifdef DBG - -static void -ProcessIncomingIPv4Packet(SMACPacket *packet, // IN/OUT: incoming packet - Bool knownMacForIp) // IN: IP is present in table? -{ - uint8 proto; // protocol within ip - uint16 ipFlags; // offset and flags - - /* - * Should certain checks, e.g., IP version field, be checked here, - * or assume that caller has already performed this check? - */ - - /* - * Presuming that caller has performed checks, and that IP header - * comes exactly ETH_HLEN bytes into the packet - */ - - if (GetPacketLength(packet) < ETH_HLEN + IP_HEADER_LEN) { - return; - } - - if (!GetPacketData(packet, ETH_HLEN + IP_HEADER_PROTO_OFFSET, sizeof proto, - &proto)) { - VNETKdPrint((MODULE_NAME "ProcessIncoming: couldn't get protocol\n")); - return; - } - - if (!GetPacketData(packet, ETH_HLEN + IP_HEADER_FLAGS_OFFSET, sizeof ipFlags, - &ipFlags)) { - VNETKdPrint((MODULE_NAME "ProcessIncoming: couldn't get ip flags\n")); - return; - } - - /* - * Verify offset=0 and M=0: mask off "fragment" flag, - * all others should be zero - */ - - if (ipFlags & HTONS(~(uint16)(0x4000))) { - VNETKdPrint((MODULE_NAME "ProcessIncoming: got a fragmented IP " - "(ipFlags %04x), so not performing higher-level processing\n", - ipFlags)); - return; - } - - switch (proto) { - case 1: { // ICMP - uint32 ipHeaderLen = 0; // length of IP header - uint32 ipVer = 0; // version of IP header - uint16 ipLen = 0; // total length of datagram - uint8 firstByte = '\0'; // used to safely read from packet - - if (!GetPacketData(packet, ETH_HLEN, sizeof firstByte, &firstByte)) { - VNETKdPrint((MODULE_NAME "ProcessIncoming: ICMP read ver error\n")); - return; - } - ipHeaderLen = 4 * (firstByte & 0xf); // length of IP header - ipVer = firstByte>>4; // version of IP header - - if (!GetPacketData(packet, ETH_HLEN + 2, sizeof ipLen, &ipLen)) { - VNETKdPrint((MODULE_NAME "ProcessIncoming: ICMP read len error\n")); - return; - } - ipLen = ntohs(ipLen); - - if (ipVer == 4 && GetPacketLength(packet) >= - ipHeaderLen + 2 * 4 + ETH_HLEN) { - uint8 typeField = 0; - uint8 codeField = 0; - if (!GetPacketData(packet, ETH_HLEN + ipHeaderLen, - sizeof typeField, &typeField) || - !GetPacketData(packet, ETH_HLEN + ipHeaderLen + 1, - sizeof codeField, &codeField)) { - VNETKdPrint((MODULE_NAME "ProcessIncoming: ICMP " - "read ICMP error\n")); - return; - } - - W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got ICMP, " - "type = %d, code = %d,\n", typeField, codeField)); - } else { - VNETKdPrint((MODULE_NAME "ProcessIncoming: got ICMP, " - "but couldn't process\n")); - } - return; - } - case 2: // IGMP - W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got IGMP\n")); - return; - case 4: // IP in IP - VNETKdPrint((MODULE_NAME "ProcessIncoming: got IP in IP\n")); - return; - case 6: // TCP - W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got TCP\n")); - return; - case 17: { // UDP - uint32 ipHeaderLen = 0; // length of IP header - uint32 ipVer = 0; // version of IP header - uint16 ipLen = 0; // total length of datagram - uint8 firstByte; // used to safely read from packet - - if (!GetPacketData(packet, ETH_HLEN, sizeof firstByte, &firstByte)) { - VNETKdPrint((MODULE_NAME "ProcessIncoming: ICMP read ver error\n")); - ASSERT(0); - return; - } - ipHeaderLen = 4 * (firstByte&0xf); // length of IP header - ipVer = firstByte >> 4; // version of IP header - - /* - * verifify that IP fragment offset is 0 - */ - - if (!GetPacketData(packet, ETH_HLEN + 2, sizeof ipLen, &ipLen)) { - VNETKdPrint((MODULE_NAME "ProcessIncoming: ICMP read len error\n")); - ASSERT(0); - return; - } - ipLen = ntohs(ipLen); - - W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got UDP, " - "IP ver %d, header len %d," - "overall len %d\n", ipVer, ipHeaderLen, ipLen)); - - if (ipVer == 4 && GetPacketLength(packet) >= - ipHeaderLen + 2 * 4 + ETH_HLEN) { - uint16 srcPort = 0; - uint16 destPort = 0; - uint8 srcAddr[4]; - uint8 destAddr[4]; - - if (!GetPacketData(packet, ipHeaderLen + ETH_HLEN, - sizeof srcPort, &srcPort) || - !GetPacketData(packet, ipHeaderLen + ETH_HLEN + 2, - sizeof destPort, &destPort)) { - VNETKdPrint((MODULE_NAME "ProcessIncoming: read " - "UDP header error\n")); - ASSERT(0); - return; - } - - srcPort = ntohs(srcPort); - destPort = ntohs(destPort); - - if (!GetPacketData(packet, ETH_HLEN + IP_HEADER_SRC_ADDR_OFFSET, - sizeof srcAddr, srcAddr) || - !GetPacketData(packet, ETH_HLEN + IP_HEADER_DEST_ADDR_OFFSET, - sizeof destAddr, destAddr)) { - VNETKdPrint((MODULE_NAME "ProcessIncoming: couldn't read " - "source and/or dest IP addr\n")); - return; - } - - W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got UDP, src " - "%d.%d.%d.%d %d dest %d.%d.%d.%d %d\n", - srcAddr[0], srcAddr[1], srcAddr[2], srcAddr[3], - srcPort, destAddr[0], destAddr[1], destAddr[2], - destAddr[3], destPort)); - - if (destPort == 67) { - - if (knownMacForIp) { - W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got client DHCP " - "packet destined for THIS server\n")); - } else { - W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got client DHCP " - "packet destined for a server\n")); - } - - } else if (destPort == 68) { - - if (knownMacForIp) { - W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got server DHCP " - "packet destined for THIS client\n")); - } else { - W_VNETKdPrint((MODULE_NAME "ProcessIncoming: got server DHCP " - "packet destined for a client\n")); - } - - } - } - return; - } - case 27: // RDP - VNETKdPrint((MODULE_NAME "ProcessIncoming: got RDP\n")); - return; - case 41: // IPv6 - VNETKdPrint((MODULE_NAME "ProcessIncoming: got IPv6\n")); - return; - case 51: // Authentication Header - VNETKdPrint((MODULE_NAME "ProcessIncoming: got Authentication Header\n")); - return; - case 55: // Mobile IP - VNETKdPrint((MODULE_NAME "ProcessIncoming: got Mobile IP\n")); - return; - case 103: // PIM - VNETKdPrint((MODULE_NAME "ProcessIncoming: got PIM\n")); - return; - case 111: // IPX in IP - VNETKdPrint((MODULE_NAME "ProcessIncoming: got IPX in IP\n")); - return; - default: - VNETKdPrint((MODULE_NAME "ProcessIncoming: Unknown/unhandled service " - "reported by IP packet\n")); - return; - } -} - -#endif /* DBG */ - -/* - *---------------------------------------------------------------------- - * - * SMAC_InitState -- - * - * Initialize adapter SMAC state. Presumes that the - * supplied adapter object has already been initialized to zero. - * - * Results: - * None. - * - * Side effects: - * Initializes adapter SMAC state. - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMAC_InitState(SMACState **ptr) // OUT: pointer to alloced/inited state -{ - SMACState * state; - VNETKdPrintCall(("SMAC_InitState")); - ASSERT(ptr); - - state = ALLOCATEMEMORY(sizeof *state, REORDER_TAG('SMAC')); - if (state == NULL) { - *ptr = NULL; - return; - } - - MEMSET(state, 0, sizeof *state); - - VNETKdPrint((MODULE_NAME "SMAC_InitState: state %p\n", state)); - - INITSPINLOCK(&(state->smacSpinLock)); -#ifndef _WIN32 - if (state->smacSpinLock == NULL) { - VNETKdPrint((MODULE_NAME "SMAC_InitState: coudln't initialize spinlock." - "Freeing state.\n")); - FREEMEMORY(state); - state = NULL; - } -#endif - VNETKdPrintReturn(("SMAC_InitState")); - *ptr = state; -} - - -/* - *---------------------------------------------------------------------- - * - * SMAC_SetMac -- - * - * Set MAC stored in SMAC state. Presumes that the - * supplied SMAC state has already been initialized. - * - * Results: - * None. - * - * Side effects: - * Sets MAC in SMAC state. - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMAC_SetMac(SMACState *state, // IN: state to update - uint8 *mac) // IN: pointer to host adapter's MAC -{ - VNETKdPrintCall(("SMAC_SetMac")); - ASSERT(state); - - VNETKdPrint((MODULE_NAME "SMAC_SetMac: state %p mac %p\n", - state, mac)); -#ifdef DBG - if (mac) { - VNETKdPrint((MODULE_NAME - "mac 0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - } -#endif - - /* - * There's likely some atomicity issues here, but grabbing a lock - * here won't help since the readers won't be grabbing a lock. - * The only time an update can occur with traffic being processed - * is on Linux, which I don't see as a big deal given the lack - * of demand for this feature on that OS. - */ - - if (mac) { - MEMCPY(state->macAddress, mac, ETH_ALEN); - } else { - MEMSET(state->macAddress, 0, ETH_ALEN); - } - VNETKdPrintReturn(("SMAC_SetMac")); -} - - -/* - *---------------------------------------------------------------------- - * - * SMAC_SetForwardUnknownPackets -- - * - * Initialize adapter SMAC state. Presumes that the - * supplied adapter object has already been initialized to zero. - * - * Results: - * None. - * - * Side effects: - * Initializes adapter SMAC state. - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMAC_SetForwardUnknownPackets(SMACState *state, // IN: pointer to smac state - Bool forwardUnknown) // IN: T/F to forward -{ - VNETKdPrintCall(("SMAC_SetForwardUnknownPackets")); - ASSERT(state); - state->smacFowardUnknownPackets = forwardUnknown; - VNETKdPrintReturn(("SMAC_SetForwardUnknownPackets")); -} - - -/* - *---------------------------------------------------------------------- - * - * SMAC_CleanupState -- - * - * Deallocates adapter SMAC state. - * - * Results: - * None - * - * Side effects: - * Deallocates adapter SMAC state. - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMAC_CleanupState(SMACState **ptr) // IN: state to dealloc -{ - uint32 i = 0; - SMACState *state; -#ifdef _WIN32 - KIRQL irql; -#endif - SPINLOCKINIT(); - - VNETKdPrintCall(("SMAC_CleanupState")); - ASSERT(ptr); - - state = *ptr; - if (state == NULL) { - return; - } - *ptr = NULL; - - RAISEIRQL(); - ACQUIRESPINLOCK(&state->smacSpinLock); - - for (i = 0; i < SMAC_HASH_TABLE_SIZE; ++i) { - IPmacLookupEntry * entry = state->IPlookupTable[i]; - while (entry) { - IPmacLookupEntry * next = entry->ipNext; - VNETKdPrintCall(("--deleted entry\n")); - FREEMEMORY(entry); - --state->numberOfIPandMACEntries; - entry = next; - } - } - if (state->numberOfIPandMACEntries != 0) { - VNETKdPrint((MODULE_NAME "SMAC_CleanupState: " - "entry count is non-zero: %d\n", - state->numberOfIPandMACEntries)); - ASSERT(state->numberOfIPandMACEntries == 0); - } - - RELEASESPINLOCK(&state->smacSpinLock); - FREESPINLOCK(&state->smacSpinLock); - LOWERIRQL(); - FREEMEMORY(state); - - VNETKdPrintReturn(("SMAC_CleanupState")); -} - - -/* - *---------------------------------------------------------------------- - * - * LookupTypeClass -- - * - * Examines and classifies the protocol type of an ethernet frame - * - * Results: - * Returns the appropriate EthClass classification for the - * specified ethernet media type. - * - * - * Side effects: - * May modify the contents of the packet. Length should be - * unchanged. - * - *---------------------------------------------------------------------- - */ - -EthClass -LookupTypeClass(unsigned short typeValue) // IN: ethernet type -{ - if (typeValue <=1500) { - return EthClassCommon; - } - if (typeValue >= 0x600) { - switch (typeValue) { - case 0x0800: // IPv4 - return EthClassIP; - case 0x0806: // ARP - return EthClassARP; - case 0x0BAD: // Banyan Vines - return EthClassUncommon; - case 0x2000: // Cisco CDP - return EthClassCommon; - case 0x6002: // DEC MOP Remote Console - case 0x6558: // Trans Ether Bridging [RFC1701] - case 0x6559: // Raw Frame Relay [RFC1701] - return EthClassUncommon; - case 0x8035: // Reverse ARP - return EthClassARP; - case 0x809B: // AppleTalk - case 0x80F3: // AppleTalk AARP - return EthClassUncommon; - case 0x8100: // VLAN special type - return EthClassVLAN; - case 0x8137: // Novell 8137 - case 0x8138: // Novell 8138 - case 0x86DD: // IPv6 - case 0x876B: // TCP/IP Compression [RFC1144] - return EthClassUncommon; - case 0x886f: // Microsoft 886f - return EthClassCommon; - default: - return EthClassUnknown; - } - } else { - return EthClassUnknown; - } -} - - -#ifdef DBG - -/* - *---------------------------------------------------------------------- - * - * LookupTypeName -- - * - * Examines and classifies the protocol type of an ethernet frame - * - * Results: - * Provides textual name of type in 'type' pointer. - * Returns the appropriate EthClass classification for the - * specified ethernet media type. - * - * - * Side effects: - * May modify the contents of the packet. Length should be - * unchanged. - * - *---------------------------------------------------------------------- - */ - -EthClass -LookupTypeName(unsigned short typeValue, // IN: ethernet type - char * type) // IN/OUT: string to store type name -{ - if (typeValue <=1500) { - SNPRINTF((type, 15, "length %d", typeValue)); - return EthClassCommon; - } -#ifdef _WIN32 -#define STRCPY(a,b) strcpy(a,b) -#else -#define STRCPY(a,b) MEMCPY(a, b, sizeof b) -#endif - if (typeValue >= 0x600) { - switch (typeValue) { - case 0x0800: - if (type) { - STRCPY(type, "IPv4"); - } - return EthClassIP; - case 0x0806: - if (type) { - STRCPY(type, "ARP"); - } - return EthClassARP; - case 0x0BAD: - if (type) { - STRCPY(type, "Banyan VINES"); - } - return EthClassUncommon; - case 0x2000: - if (type) { - STRCPY(type, "Cisco CDP"); - } - return EthClassCommon; - case 0x6002: - if (type) { - STRCPY(type, "DEC MOP Remote Console"); - } - return EthClassUncommon; - case 0x6558: - if (type) { - STRCPY(type, "Trans Ether Bridging [RFC1701]"); - } - return EthClassUncommon; - case 0x6559: - if (type) { - STRCPY(type, "Raw Frame Relay [RFC1701]"); - } - return EthClassUncommon; - case 0x8035: - if (type) { - STRCPY(type, "Reverse ARP"); - } - return EthClassARP; - case 0x809B: - if (type) { - STRCPY(type, "AppleTalk"); - } - return EthClassUncommon; - case 0x80F3: - if (type) { - STRCPY(type, "AppleTalk AARP"); - } - return EthClassUncommon; - case 0x8100: - if (type) { - STRCPY(type, "VLAN special type"); - } - return EthClassVLAN; - case 0x8137: - if (type) { - STRCPY(type, "Novell 8137"); - } - return EthClassUncommon; - case 0x8138: - if (type) { - STRCPY(type, "Novell 8138"); - } - return EthClassUncommon; - case 0x86DD: - if (type) { - STRCPY(type, "IPv6"); - } - return EthClassUncommon; - case 0x876B: - if (type) { - STRCPY(type, "TCP/IP Compression [RFC1144]"); - } - return EthClassUncommon; - case 0x886f: - if (type) { - STRCPY(type, "Microsoft 886f"); - } - return EthClassCommon; - default: - if (type) { - SNPRINTF((type, 40, "unknown type 0x%04x", typeValue)); - } - return EthClassUnknown; - } - } else { - if (type) { - SNPRINTF((type, 40, "invalid value 0x%04x", typeValue)); - } - return EthClassUnknown; - } -} -#endif - -/* - * Checksum-related functions. In certain cases the payload of a UDP - * packet needs to be modified. The following functions are used to - * calculate the new checksum based on the old checksum and an offset - * of the changes. - */ - - -/* - *---------------------------------------------------------------------- - * - * SUM32 -- - * - * performs 2's complement sum of the high bits and low bits - * in a 32-bit word, resulting in a 16-bit number (with - * potentially additional bits containing overflow) - * - * Results: - * Returns result described above - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE uint32 -SUM32(uint32 in) { // IN: 32-bit number - return (in & 0xffff) + (in >> 16); -} - - -/* - *---------------------------------------------------------------------- - * - * CalcChecksumDiff -- - * - * Computes the differences between two checksums - * - * Results: - * Returns result described above - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static uint32 -CalcChecksumDiff(uint32 sumBefore, // IN: checksum before modification - uint32 sumAfter) // IN: checksum after modification -{ - uint32 diff; // stores resume to return - - sumBefore = SUM32(sumBefore); // Convert sum to 16-bit + overflow - sumBefore = SUM32(sumBefore); // Convert sum to 16-bit - sumAfter = SUM32(sumAfter); // Convert sum to 16-bit + overflow - sumAfter = SUM32(sumAfter); // Convert sum to 16-bit - - /* - * 2's complement versus 1's complement arthmetic requires the - * following piece of code. I don't completely understand - * why it's needed, but my sources (and my own testing) say it - * needs to be here. - */ - - if (sumBefore > sumAfter) { - --sumAfter; - } - - diff = sumAfter - sumBefore; // subtrace to get delta - diff = SUM32(diff); // incorporate overflow to get 16-bits - return diff; -} - - -/* - *---------------------------------------------------------------------- - * - * UpdateSum -- - * - * Computes a new internet checksum by using an existing - * checksum and a delta of changes to that checksum. - * - * Results: - * Returns new checksum - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static uint16 -UpdateSum(uint16 oricheck, // IN: old checksum - uint32 sumDiff) // IN: delta of changes -{ - uint32 sum; - uint16 sumShort; - if (sumDiff == 0) { - return oricheck; - } - - sum = ( ~ntohs(oricheck) & 0xffff); // undo net order & bit complement - sum += sumDiff; // add in difference - sum = SUM32(sum); // wrap any overflow - sum = SUM32(sum); // wrap any overflow (again; last wrap may cause overflow) - sumShort = ~(uint16)(sum); // truncate to 16-bits and complement bits - return htons(sumShort); // return result in network order -} - - -/* - *---------------------------------------------------------------------- - * - * GetSystemUptime -- - * - * Return current uptime of system, this is essentially a wrapper - * that checks for overflow. When - * overflow occurs the existing last used times reduced by half. - * As part of the solution, the returned value always has the - * highest bit turned on. - * - * Previously, this was a wrapper for NdisGetSystemUptime(). - * Recent updates to the DDK/WDK have confused this function - there - * is now a depricated 32-bit version and a 64-bit version only - * available on newer version of the OS. Rather than trying to be - * clever, we will use KeQueryTickCount instead. - * - * This function should only be called with the lock held. - * - * Results: - * Returns uptime of system (skewed so always in upper half - * of numeric range for 32-bits) - * - * Side effects: - * Updates the "last uptime" stored in adapter struct, and may - * modify the uptimes of all entries in the hash table. - * - *---------------------------------------------------------------------- - */ - -static SmacLastAccess -GetSystemUptime(SMACState *state) // IN: smac state -{ - SmacLastAccess currentUptime; - -#ifdef _WIN32 - { - LARGE_INTEGER arg; - KeQueryTickCount(&arg); - currentUptime = arg.QuadPart; - } -#else - currentUptime = SMACL_GetUptime(); -#endif - /* - * Force on the highest bit. This basically means that recent - * values have the high bit turned on, while values that were - * obtained prior to the last overflow will have the highest bit - * (and potentially other neighboring bits) turned off. - */ - - currentUptime |= (SmacLastAccess)1 << (sizeof currentUptime * 8 - 1); - - /* If overflow occurred, then reduce all existing values by half */ - if (currentUptime < state->lastUptimeRead) { - uint32 i; - VNETKdPrint((MODULE_NAME "GetSystemUptime: overflow detected, " - "adjusting counters\n")); - for (i = 0; i < SMAC_HASH_TABLE_SIZE; ++i) { - IPmacLookupEntry *entry = state->IPlookupTable[i]; - while (entry) { - entry->lastAccess >>= 1; /* reduce value by half */ - entry = entry->ipNext; - } - } - } - state->lastUptimeRead = currentUptime; - return currentUptime; -} - - -/* - *---------------------------------------------------------------------- - * - * GetPacketLength -- - * - * Returns the total length of data in a packet - * - * Results: - * returns length of packet - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE uint32 -GetPacketLength(SMACPacket *packet) // IN: packet -{ - ASSERT(packet); -#ifdef _WIN32 - return packet->buf1Len + packet->buf2Len; -#elif defined __linux__ - ASSERT(packet->skb); - return (uint32)SMACL_PacketLength(packet->skb); -#else /* __APPLE__ */ - ASSERT(packet->m); - return SMACL_PacketLength(packet->m); -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * GetPacketData -- - * - * Copies select portion of packet - * - * Results: - * TRUE if data was safely copied, otherwise FALSE (e.g., offset - * too large, packet too small, etc). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -GetPacketData(SMACPacket *packet, // IN: packet to copy from - uint32 offset, // IN: offset in packet to copy from - uint32 length, // IN: length to copy - void *data) // OUT: data (caller must pass in buffer >= length) -{ -#ifdef _WIN32 - uint32 copyOffset = 0; - uint32 copyLength = 0; -#endif - - ASSERT(packet); - ASSERT(data); - ASSERT(length > 0); - - /* check length, be sure to handle case where offset = -1, length > 0 */ - if (length == 0 || offset + length > GetPacketLength(packet) || - offset + length < offset) { - /* packet not long enough for data */ - return FALSE; - } - -#ifdef _WIN32 - /* if offset starts in the first buffer, then copy from first buffer */ - if (offset < packet->buf1Len) { - copyOffset = offset; - copyLength = (offset + length > packet->buf1Len)? - (packet->buf1Len - copyOffset):(length); - - MEMCPY(data, ((uint8*)packet->buf1) + copyOffset, copyLength); - offset = packet->buf1Len; /* advance offset to start of second buffer */ - - data = ((uint8*)data) + copyLength; - length -= copyLength; - } - /* copy any remaining data from second buffer */ - if (length) { - copyOffset = offset - packet->buf1Len; - copyLength = length; - MEMCPY(data, ((uint8*)packet->buf2) + copyOffset, copyLength); - } - -#elif __linux__ - - MEMCPY(data, packet->startOfData + offset, length); - -#else /* __APPLE__ */ - - SMACL_CopyDataFromPkt(packet->m, offset, data, length); - -#endif /* _WIN32 */ - - return TRUE; -} - - -/* - *---------------------------------------------------------------------- - * - * ClonePacket -- - * - * Makes a private copy of the incoming packet. This modified - * copy is private and can be modified at will. Caller is - * responsible for freeing the cloned packet. - * - * Results: - * TRUE if clone was successful, otherwise FALSE. - * - * Side effects: - * Duplicates a packet. - * - *---------------------------------------------------------------------- - */ - -static Bool -ClonePacket(SMACPackets *packets) // IN: struct in which to clone packet -{ -#ifdef _WIN32 - VNetPacket * packetClone = NULL; - - ASSERT(packets); - - packetClone = VNet_PacketAllocate(packets->orig.buf1Len + - packets->orig.buf2Len, - "SMAC_CheckPacketToHost"); - if (!packetClone) { - VNETKdPrint((MODULE_NAME " ToHost: couldn't clone packet\n")); - return FALSE; - } - - if (packets->orig.buf1Len) { - MEMCPY(packetClone->data, packets->orig.buf1, packets->orig.buf1Len); - } - if (packets->orig.buf2Len) { - MEMCPY(packetClone->data + packets->orig.buf1Len, packets->orig.buf2, - packets->orig.buf2Len); - } - - packets->clone.buf1 = packetClone->data; - packets->clone.buf1Len = packetClone->len; - packets->clone.buf2 = NULL; - packets->clone.buf2Len = 0; - packets->clonedPacket = packetClone; - return TRUE; - -#elif defined __linux__ - - packets->clone.skb = SMACL_DupPacket(packets->orig.skb); - if (packets->clone.skb) { - packets->clone.startOfData = (packets->orig.startOfData - - SMACL_PacketData(packets->orig.skb)) + - SMACL_PacketData(packets->clone.skb); - } else { - packets->clone.startOfData = NULL; - } - return packets->clone.skb != NULL; - -#else /* __APPLE__ */ - - /* - * Don't need to clone packet again. We could even get rid of "clone" from - * the SMACPackets struct, but this minimizes differences from other OSes. - */ - packets->clone.m = packets->orig.m; - return packets->clone.m != NULL; - -#endif /* _WIN32 */ -} - - -/* - *---------------------------------------------------------------------- - * - * CopyDataToClonedPacket -- - * - * Makes changes to the private clone copy of a packet. - * - * Results: - * TRUE if modification was successful, otherwise FALSE. - * - * Side effects: - * Modifies a packet. - * - *---------------------------------------------------------------------- - */ - -static Bool -CopyDataToClonedPacket(SMACPackets *packets, // IN: packets - const void * source, // IN: data to copy to packet - uint32 offset, // IN: dest offset at which to copy - uint32 length) // IN: length of data to copy -{ -#ifdef _WIN32 - ASSERT(packets); - ASSERT(packets->clone.buf1); - ASSERT(packets->clone.buf1Len > offset + length); - ASSERT(packets->clone.buf2 == NULL); - ASSERT(packets->clone.buf2Len == 0); - - /* - * For windows this code presumes that all of the clone packet's data is - * in the first buffer. - */ - - if (!packets || !packets->clone.buf1 || packets->clone.buf1Len - <= offset + length) { - ASSERT(0); // should never occur - return FALSE; - } - MEMCPY((uint8 *)(packets->clone.buf1) + offset, source, length); - -#elif defined __linux__ - - ASSERT(packets); - ASSERT(packets->clone.skb); - - MEMCPY((uint8 *)(packets->clone.startOfData) + offset, - source, length); - -#else /* __APPLE __ */ - - ASSERT(packets); - ASSERT(packets->clone.m); - SMACL_CopyDataToPkt(packets->clone.m, offset, source, length); - -#endif - - return TRUE; -} - - -/* - *---------------------------------------------------------------------- - * - * SetPacketByte -- - * - * Makes changes to a packet, either public or private - * - * Results: - * TRUE if modification was successful, otherwise FALSE. - * - * Side effects: - * Modifies a packet. - * - *---------------------------------------------------------------------- - */ - -static Bool -SetPacketByte(SMACPacket *packet, // IN: packet - uint32 offset, // IN: offset to change - uint8 data) // IN: data to set -{ - ASSERT(packet); - -#ifdef _WIN32 - /* check length, be sure to handle case where offset = -1, length > 0 */ - if (offset > GetPacketLength(packet)) { - /* packet not long enough for data */ - return FALSE; - } - - /* if offset starts in the first buffer, then copy from first buffer */ - if (offset < packet->buf1Len) { - ((uint8*)packet->buf1)[offset] = data; - } else { - offset -= packet->buf1Len; - ((uint8*)packet->buf2)[offset] = data; - } - -#elif __linux__ - - ASSERT(packet); - ASSERT(packet->skb); - - ((uint8*)packet->startOfData)[offset] = data; - -#else - - ASSERT(packet); - ASSERT(packet->m); - SMACL_CopyDataToPkt(packet->m, offset, &data, 1); - -#endif /* _WIN32 */ - - return TRUE; -} - - -/* - *---------------------------------------------------------------------- - * - * CopyDataForPacketFromHost -- - * - * When receiving data from the host, this function is used - * to make changes to the packet. Since the only changes we - * ever make are to replace one Ethernet MAC with another, this - * function currently just does MAC replacement. - * - * Results: - * TRUE if modification was successful, otherwise FALSE. - * - * Side effects: - * Modifies a packet. - * - *---------------------------------------------------------------------- - */ - -Bool -CopyDataForPacketFromHost(SMACPackets *packets, // IN/OUT: packets struct - uint32 changeNum, // IN: serialized # of change - uint32 offset, // IN: byte offset for change - const uint8 *macAddress) // IN: new MAC to add to packet -{ -#ifdef _WIN32 - MacReplacementTable *table = NULL; - ASSERT(packets); - ASSERT(macAddress); - - table = packets->table; - ASSERT(table); - ASSERT(changeNum == table->numOfOffsets); - UNREFERENCED_PARAMETER(changeNum); - - if (table->numOfOffsets == 0) { - MEMCPY(table->mac, macAddress, ETH_ALEN); - } - table->offsets[table->numOfOffsets++] = offset; - -#else /* _WIN32 */ - - /* clone packet if this is the first change */ - if (changeNum == 0 && !ClonePacket(packets)) { - VNETKdPrint((MODULE_NAME "FromHostIP: couldn't clone packet\n")); - return FALSE; - } - CopyDataToClonedPacket(packets, macAddress, offset, ETH_ALEN); -#endif /* _WIN32 */ - - return TRUE; -} diff -Nrup source/vmnet-only/smac_compat.c source.edited/vmnet-only/smac_compat.c --- source/vmnet-only/smac_compat.c 2009-10-20 17:31:32.000000000 -0700 +++ source.edited/vmnet-only/smac_compat.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,524 +0,0 @@ -/********************************************************* - * Copyright (C) 2005 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 - * - *********************************************************/ - -/* - * smac_compat.c -- - * - * This file defines an abstraction layer to handling - * differences among the Linux kernel and avoiding - * symbol match issues. - */ - -#include "driver-config.h" - -#ifdef MODVERSIONS -#include -#endif - -#include -#include -#include -#include // for spinlock_t - -#ifdef KERNEL_2_2 -#include -#else -#include -#endif -#include - -#include -#include -#include -#include "compat_skbuff.h" -#include - -#define __KERNEL_SYSCALLS__ -#include - -#include -#include - -#include "vnetInt.h" -#include "vmnetInt.h" -#include "smac_compat.h" - -#ifdef VMX86_DEVEL -#define DBG 1 -#else -#undef DBG -#endif /* VMX86_DEVEL */ - - - -/* - *---------------------------------------------------------------------- - * SMACL_GetUptime -- - * - * Wrapper for jiffies. - * - * Results: - * Uptime in ticks - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -unsigned long SMACINT -SMACL_GetUptime() -{ - return jiffies; -} - -/* - *---------------------------------------------------------------------- - * SMACL_Memcpy -- - * - * Wrapper for memcpy(). - * - * Results: - * None. - * - * Side effects: - * Copies memory - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMACL_Memcpy(void *d, // IN: destination pointer - const void *s, // IN: source pointer - size_t l) // IN: length to copy -{ - memcpy(d, s, l); -} - - -/* - *---------------------------------------------------------------------- - * SMACL_Memcmp -- - * - * Wrapper for memcmp(). - * - * Results: - * refer to documentation for memcmp(). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int SMACINT -SMACL_Memcmp(const void *p1, // IN: pointer to data - const void *p2, // IN: pointer to data - size_t l) // IN: length to compare -{ - return memcmp(p1, p2, l); -} - - -/* - *---------------------------------------------------------------------- - * SMACL_Memset -- - * - * Wrapper for memset(). - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMACL_Memset(void *p1, // IN: pointer to data - int val, // IN: value to set - size_t l) // IN: length to set -{ - memset(p1, val, l); - return; -} - -/* - *---------------------------------------------------------------------- - * SMACL_Alloc -- - * - * Wrapper for kmalloc(). - * - * Results: - * Pointer to memory if successful, NULL otherwise - * - * Side effects: - * Allocates memory - * - *---------------------------------------------------------------------- - */ - -void* SMACINT -SMACL_Alloc(size_t size) // IN: size to allocate -{ - return kmalloc(size, GFP_ATOMIC); -} - - -/* - *---------------------------------------------------------------------- - * SMACL_Free -- - * - * Wrapper for kfree(). - * - * Results: - * None. - * - * Side effects: - * Frees memory - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMACL_Free(void *ptr) // IN: pointer to free -{ - kfree(ptr); -} - - -/* - *---------------------------------------------------------------------- - * SMACL_InitSpinlock -- - * - * Wrapper for spin_lock_init(). - * The reason we have to use void is to avoid dependency on kernel. - * The spinlock_t structure can change for different compilation options. - * - * Results: - * None. - * - * Side effects: - * see spin_lock_init() - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMACL_InitSpinlock(void **s) // IN: spinlock -{ - *s = kmalloc(sizeof(spinlock_t), GFP_ATOMIC); - spin_lock_init((spinlock_t *)*s); -} - - -/* - *---------------------------------------------------------------------- - * SMACL_AcquireSpinlock -- - * - * Wrapper for spin_lock_irqsave(). - * - * Results: - * None. - * - * Side effects: - * Grabs lock (see spin_lock_irqsave()) - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMACL_AcquireSpinlock(void **s, // IN: spinlock - unsigned long *flags) // IN/OUT: flags -{ - unsigned long f = *flags; - spin_lock_irqsave((spinlock_t *)*s, f); - *flags = f; -} - - -/* - *---------------------------------------------------------------------- - * SMACL_ReleaseSpinlock -- - * - * Wrapper for spin_unlock_irqrestore(). - * - * Results: - * None. - * - * Side effects: - * Ungrabs lock (see spin_unlock_irqrestore()) - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMACL_ReleaseSpinlock(void **s, // IN: spinlock - unsigned long *flags) // IN/OUT: flags -{ - unsigned long f = *flags; - spin_unlock_irqrestore((spinlock_t *)*s, f); - *flags = f; -} - - -#ifdef DBG -/* - *---------------------------------------------------------------------- - * SMACL_Print -- - * - * Wrapper for printk(). - * - * Results: - * None. - * - * Side effects: - * Creates output - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMACL_Print(const char * msg, // IN: format message - ...) // IN: params (currently ignored) -{ - char buf[1024]; - int len; - va_list ap; - - va_start(ap, msg); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) - len = vsnprintf(buf, sizeof buf, msg, ap); -#else - len = vsprintf(buf, msg, ap); -#endif - - va_end(ap); - buf[1023] = '\0'; - printk(KERN_DEBUG "%s", buf); -} - -#endif - -/* - *---------------------------------------------------------------------- - * SMACL_DupPacket -- - * - * Wrapper for skb_copy(). - * - * Results: - * Pointer to packet if successful, NULL otherwise - * - * Side effects: - * Creates a private duplicate of packet - * - *---------------------------------------------------------------------- - */ - -struct sk_buff* SMACINT -SMACL_DupPacket(struct sk_buff *skb) // IN: packet to duplicate -{ - return skb_copy(skb, GFP_ATOMIC); -} - -/* - *---------------------------------------------------------------------- - * SMACL_PacketData -- - * - * Wrapper to get data from sk_buff. This function might be - * a bit extreme, but it's good to be able to handle changes - * to the layout of the sk_buff struct. - * - * Results: - * Pointer to data in sk_buff. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void* SMACINT -SMACL_PacketData(struct sk_buff *skb) // IN: pointer to packet buffer -{ - return skb->data; -} - - -/* - *---------------------------------------------------------------------- - * SMACL_PacketLength -- - * - * Wrapper to get length of data in sk_buff. - * - * Results: - * Length stored in sk_buff. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -unsigned int SMACINT -SMACL_PacketLength(struct sk_buff *skb) // IN: pointer to packet buffer -{ - /* - * wireless driver process the packet and processes the ethernet header - * and the length is reduced by the amount. We need the raw ethernet - * packet length hence add the ethernet header length - */ - return (unsigned int) (skb->len + ETH_HLEN); -} - - -/* - *---------------------------------------------------------------------- - * SMACL_LinearizeSkb -- - * - * Wrapper function to linearize an skb, if necessary. - * - * Results: - * non zero if skb is can't be converted to linear. - * 0 if skb is already linear or successfully converted. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int SMACINT -SMACL_LinearizeSkb(struct sk_buff* skb) // IN: packet to process -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) - if (skb_is_nonlinear(skb)) { - return compat_skb_linearize(skb); - } -#endif - return 0; -} - - -/* - *---------------------------------------------------------------------- - * SMACL_IsSkbHostBound -- - * - * Checks if the direction of the packet is host bound. - * - * Results: - * Returns non zero if host bound - * 0 for anything else - i - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int SMACINT -SMACL_IsSkbHostBound(struct sk_buff* skb) // IN: packet to process -{ - return (skb->pkt_type == PACKET_HOST); -} - - -#ifdef DBG -/* - *---------------------------------------------------------------------- - * SMACL_PrintSkb -- - * - * Print information about the skb. - * - * Results: - * prints the sk_buff structure - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void SMACINT -SMACL_PrintSkb(struct sk_buff *skb, // IN: sk_buff structure - char *str) // IN: type of process -{ - LOG(4, (KERN_DEBUG "%s pointer %p shared? %d cloned? %d\n", - str, skb, skb_shared(skb), skb_cloned(skb))); - LOG(4, (KERN_DEBUG "next %p, prev %p\n", - skb->next, skb->prev)); - LOG(4, (KERN_DEBUG "sock %p, dev %p\n", - skb->sk, skb->dev)); - LOG(4, (KERN_DEBUG "pkt_type %x truesize %u protocol %u\n", - skb->pkt_type, skb->truesize, skb->protocol)); - LOG(4, (KERN_DEBUG "users %d, tail %p, end %p\n", - atomic_read(&skb->users), compat_skb_tail_pointer(skb), - compat_skb_end_pointer(skb))); -#if 0 -#define C skb->mac.raw - if(skb->mac.raw) { - LOG(4, (KERN_DEBUG "dest %02x:%02x:%02x:%02x:%02x:%02x" - " source %02x:%02x:%02x:%02x:%02x:%02x\n", - C[0],C[1],C[2],C[3],C[4],C[5] , - C[6],C[7],C[8],C[9],C[10],C[11])); - } -#undef C - if(skb->dst) { - LOG(4, (KERN_DEBUG "dst_entry->__refcount %d\n", - atomic_read(&(skb->dst->__refcnt)))); - } -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) - LOG(4, (KERN_DEBUG "dataref %d end\n", - atomic_read(&(skb_shinfo(skb)->dataref)))); -#endif - -} - -/* - *---------------------------------------------------------------------- - * SMACL_Snprintf -- - * - * Wrapper to do snprintf for debugging. - * - * Results: - * refer to VNetSnprintf in driver.c - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int SMACINT -SMACL_Snprintf(char *str, // OUT: resulting string - size_t size, // IN: length of 'result' in bytes - const char *format, // IN: format string - ...) // IN: (optional) -{ - int length; - va_list args; - - va_start(args, format); - length = VNetSnprintf(str, size, format, args); - va_end(args); - return length; -} -#endif diff -Nrup source/vmnet-only/smac_compat.h source.edited/vmnet-only/smac_compat.h --- source/vmnet-only/smac_compat.h 2009-10-20 17:31:32.000000000 -0700 +++ source.edited/vmnet-only/smac_compat.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,63 +0,0 @@ -/********************************************************* - * Copyright (C) 2005 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 - * - *********************************************************/ - -/* - * smac_compat.h -- - * - * This file defines an abstraction layer to handling - * differences among the Linux kernel and avoiding - * symbol match issues. - */ - -#ifndef _SMAC_COMPAT_H_ -#define _SMAC_COMPAT_H_ - -#include "vm_basic_types.h" - -#if defined(__x86_64__) -#define SMACINT -#else -#define SMACINT __attribute__((cdecl, regparm(3))) -#endif - -void SMACINT SMACL_Memcpy(void *d, const void *s, size_t l); -int SMACINT SMACL_Memcmp(const void *p1, const void *p2, size_t l); -void SMACINT SMACL_Memset(void *p1, int val, size_t l); -void* SMACINT SMACL_Alloc(size_t s); -void SMACINT SMACL_Free(void *p); - -unsigned long SMACINT SMACL_GetUptime(void); - -void SMACINT SMACL_InitSpinlock(void **s); -void SMACINT SMACL_AcquireSpinlock(void **s, unsigned long *flags); -void SMACINT SMACL_ReleaseSpinlock(void **s, unsigned long *flags); - - -struct sk_buff* SMACINT SMACL_DupPacket(struct sk_buff *skb); -void* SMACINT SMACL_PacketData(struct sk_buff *skb); -unsigned int SMACINT SMACL_PacketLength(struct sk_buff *skb); -int SMACINT SMACL_LinearizeSkb(struct sk_buff *skb); -int SMACINT SMACL_IsSkbHostBound(struct sk_buff *skb); -#ifdef DBG -void SMACINT SMACL_Print(const char *m, ...); -void SMACINT SMACL_PrintSkb(struct sk_buff *skb, char *type); -int SMACINT SMACL_Snprintf(char *str, size_t size, const char *format, ...); -#endif /* DBG */ - -#endif /* _SMAC_COMPAT_H */ - diff -Nrup source/vmnet-only/smac.h source.edited/vmnet-only/smac.h --- source/vmnet-only/smac.h 2009-10-20 17:31:32.000000000 -0700 +++ source.edited/vmnet-only/smac.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,109 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -/* - * smac.h -- - * - * This file declares functionality that allows the - * bridge to be used across links that do - * not support promiscuous mode, nor provide the - * ability to transmit ethernet frames whose MAC source - * address does not match the hardware's MAC address. - */ - -#ifndef _SMAC_H_ -#define _SMAC_H_ - -#ifdef _WIN32 -#include "vnetInt.h" -#else /* _WIN32 */ - -#include "vm_basic_types.h" - -/* linux header files include too much garbage, so just define if needed */ -#ifndef ETH_ALEN -#define ETH_ALEN 6 -#endif /* ETH_ALEN */ - -#ifndef ETH_HLEN -#define ETH_HLEN 14 -#endif /* ETH_HLEN */ - -#endif /* _WIN32 */ - -#if defined __linux__ && !defined __x86_64__ -#define SMACINT __attribute__((cdecl, regparm(3))) -#else -#define SMACINT -#endif - -typedef enum { - PacketStatusTooShort = 0x4546, // insuficient data to process packet - PacketStatusDropPacket, // bridge should drop packet - PacketStatusForwardPacket // bridge should accept/process/forward packet -} PacketStatus; - -struct SMACState; - -void SMACINT -SMAC_InitState(struct SMACState **ptr); // IN: state to alloc/init -void SMACINT -SMAC_SetMac(struct SMACState *state, uint8 *mac); // IN: state, and host MAC -void SMACINT -SMAC_CleanupState(struct SMACState **ptr); // IN: state to cleanup/dealloc - -/* - * Structure is used to separate out differences - * between packets on different OSes. - */ - -#ifdef _WIN32 -/* defines Windows versions of SMACPacket and SMACPackets */ -#include "smac_win.h" -#else /* _WIN32 */ -/* non-WIN32 versions of these structs */ -typedef struct SMACPacket { -#ifdef __linux__ - struct sk_buff *skb; // packet - void *startOfData; // handles non-uniform start of data in sk_buff -#else - mbuf_t m; // packet -#endif -} SMACPacket; - -typedef struct SMACPackets { - SMACPacket orig; // IN: packet - SMACPacket clone; // OUT: packet -} SMACPackets; -#endif /* _WIN32 */ - -PacketStatus SMACINT -SMAC_CheckPacketFromHost(struct SMACState *state, // IN: pointer to smac state - SMACPackets *packets); // IN/OUT: packet(s) to process - -PacketStatus SMACINT -SMAC_CheckPacketToHost(struct SMACState *state, // IN: pointer to smac state - SMACPackets *packets); // IN/OUT: packet(s) to process - -void SMACINT -SMAC_SetForwardUnknownPackets(struct SMACState *state, // IN: pointer to smac state - Bool forwardUnknown); // IN: T/F to forward - -#endif // _SMAC_H_ - - diff -Nrup source/vmnet-only/socket.c source.edited/vmnet-only/socket.c --- source/vmnet-only/socket.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/socket.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,33 +0,0 @@ -/********************************************************* - * Copyright (C) 2004 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 - * - *********************************************************/ - -/* - * Detect whether there is 'sk_wmem_alloc' member in 'sock' - * It got renamed from wmem_alloc sometime during 2.5.x. - */ - -#include -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -#include - -void *sock_wmem_alloc_test(struct sock* sk) { - return &sk->sk_wmem_alloc; -} -#endif diff -Nrup source/vmnet-only/userif.c source.edited/vmnet-only/userif.c --- source/vmnet-only/userif.c 2009-10-20 17:31:32.000000000 -0700 +++ source.edited/vmnet-only/userif.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1057 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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" - -#define EXPORT_SYMTAB - -#include -#include -#include -#ifdef KERNEL_2_2 -# include -#else -# include -#endif -#include - -#include -#include -#include "compat_skbuff.h" -#include -#include -#include "compat_sock.h" - -#define __KERNEL_SYSCALLS__ -#include - -#include -#include - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) -#include -#endif - -#include "vnetInt.h" - -#include "compat_uaccess.h" -#include "compat_highmem.h" -#include "compat_mm.h" -#include "pgtbl.h" -#include "compat_wait.h" -#include "vmnetInt.h" -#include "vm_atomic.h" - -typedef struct VNetUserIFStats { - unsigned read; - unsigned written; - unsigned queued; - unsigned droppedDown; - unsigned droppedMismatch; - unsigned droppedOverflow; - unsigned droppedLargePacket; -} VNetUserIFStats; - -typedef struct VNetUserIF { - VNetPort port; - struct sk_buff_head packetQueue; - uint32* pollPtr; - Atomic_uint32* actPtr; - uint32 pollMask; - uint32 actMask; - uint32* recvClusterCount; - wait_queue_head_t waitQueue; - struct page* actPage; - struct page* pollPage; - struct page* recvClusterPage; - VNetUserIFStats stats; -} VNetUserIF; - -static void VNetUserIfUnsetupNotify(VNetUserIF *userIf); -static int VNetUserIfSetupNotify(VNetUserIF *userIf, VNet_Notify *vn); - -/* - *----------------------------------------------------------------------------- - * - * UserifLockPage -- - * - * Lock in core the physical page associated to a valid virtual - * address --hpreg - * - * Results: - * The page structure on success - * NULL on failure: memory pressure. Retry later - * - * Side effects: - * Loads page into memory - * Pre-2.4.19 version may temporarily lock another physical page - * - *----------------------------------------------------------------------------- - */ - -static INLINE struct page * -UserifLockPage(VA addr) // IN -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 19) - struct page *page = NULL; - int retval; - - down_read(¤t->mm->mmap_sem); - retval = get_user_pages(current, current->mm, addr, - 1, 1, 0, &page, NULL); - up_read(¤t->mm->mmap_sem); - - if (retval != 1) { - return NULL; - } - - return page; -#else - struct page *page; - struct page *check; - volatile int c; - - /* - * Establish a virtual to physical mapping by touching the physical - * page. Because the address is valid, there is no need to check the return - * value here --hpreg - */ - compat_get_user(c, (char *)addr); - - page = PgtblVa2Page(addr); - if (page == NULL) { - /* The mapping went away --hpreg */ - return NULL; - } - - /* Lock the physical page --hpreg */ - get_page(page); - - check = PgtblVa2Page(addr); - if (check != page) { - /* - * The mapping went away or was modified, so we didn't lock the right - * physical page --hpreg - */ - - /* Unlock the physical page --hpreg */ - put_page(page); - - return NULL; - } - - /* We locked the right physical page --hpreg */ - return page; -#endif -} - -/* - *----------------------------------------------------------------------------- - * - * VNetUserIfInvalidPointer -- - * - * Reports if pointer provided by user is definitely wrong, - * or only potentially wrong. - * - * Results: - * non-zero if pointer is definitely wrong, otherwise returns - * 0 if the pointer might be okay. - * - * Side effects: - * Might sleep. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int -VNetUserIfInvalidPointer(VA uAddr, // IN: user-provided pointer - size_t size) // IN: anticipated size of data -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - return !access_ok(VERIFY_WRITE, (void *)uAddr, size); -#else - return verify_area(VERIFY_READ, (void *)uAddr, size) || - verify_area(VERIFY_WRITE, (void *)uAddr, size); -#endif -} - -/* - *----------------------------------------------------------------------------- - * - * VNetUserIfMapUint32Ptr -- - * - * Maps a portion of user-space memory into the kernel. - * - * Results: - * 0 on success - * < 0 on failure: the actual value determines the type of failure - * - * Side effects: - * Might sleep. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int -VNetUserIfMapUint32Ptr(VA uAddr, // IN: pointer to user memory - struct page **p, // OUT: locked page - uint32 **ptr) // OUT: kernel mapped pointer -{ - if (VNetUserIfInvalidPointer(uAddr, sizeof (uint32)) || - (((uAddr + sizeof(uint32) - 1) & ~(PAGE_SIZE - 1)) != - (uAddr & ~(PAGE_SIZE - 1)))) { - return -EINVAL; - } - - *p = UserifLockPage(uAddr); - if (*p == NULL) { - return -EAGAIN; - } - - *ptr = (uint32 *)((char *)kmap(*p) + (uAddr & (PAGE_SIZE - 1))); - return 0; -} - -/* - *----------------------------------------------------------------------------- - * - * VNetUserIfSetupNotify -- - * - * Sets up notification by filling in pollPtr, actPtr, and recvClusterCount - * fields. - * - * Results: - * 0 on success - * < 0 on failure: the actual value determines the type of failure - * - * Side effects: - * Fields pollPtr, actPtr, recvClusterCount, pollPage, actPage, and - * recvClusterPage are filled in VNetUserIf structure. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int -VNetUserIfSetupNotify(VNetUserIF *userIf, // IN - VNet_Notify *vn) // IN -{ - int retval; - - if (userIf->pollPtr || userIf->actPtr || userIf->recvClusterCount) { - LOG(0, (KERN_DEBUG "vmnet: Notification mechanism already active\n")); - return -EBUSY; - } - - if ((retval = VNetUserIfMapUint32Ptr((VA)vn->pollPtr, &userIf->pollPage, - &userIf->pollPtr)) < 0) { - return retval; - } - - if ((retval = VNetUserIfMapUint32Ptr((VA)vn->actPtr, &userIf->actPage, - (uint32 **)&userIf->actPtr)) < 0) { - VNetUserIfUnsetupNotify(userIf); - return retval; - } - - if ((retval = VNetUserIfMapUint32Ptr((VA)vn->recvClusterPtr, - &userIf->recvClusterPage, - &userIf->recvClusterCount)) < 0) { - VNetUserIfUnsetupNotify(userIf); - return retval; - } - - userIf->pollMask = vn->pollMask; - userIf->actMask = vn->actMask; - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * VNetUserIfUnsetupNotify -- - * - * Destroys permanent mapping for notify structure provided by user. - * - * Results: - * None. - * - * Side effects: - * Fields pollPtr, actPtr, recvClusterCount, etc. in VNetUserIf - * structure are cleared. - * - *---------------------------------------------------------------------- - */ - -static void -VNetUserIfUnsetupNotify(VNetUserIF *userIf) // IN -{ - if (userIf->pollPage) { - kunmap(userIf->pollPage); - put_page(userIf->pollPage); - } else { - LOG(0, (KERN_DEBUG "vmnet: pollPtr was already deactivated\n")); - } - if (userIf->actPage) { - kunmap(userIf->actPage); - put_page(userIf->actPage); - } else { - LOG(0, (KERN_DEBUG "vmnet: actPtr was already deactivated\n")); - } - if (userIf->recvClusterPage) { - kunmap(userIf->recvClusterPage); - put_page(userIf->recvClusterPage); - } else { - LOG(0, (KERN_DEBUG "vmnet: recvClusterPtr was already deactivated\n")); - } - userIf->pollPtr = NULL; - userIf->pollPage = NULL; - userIf->actPtr = NULL; - userIf->actPage = NULL; - userIf->recvClusterCount = NULL; - userIf->recvClusterPage = NULL; - userIf->pollMask = 0; - userIf->actMask = 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetUserIfFree -- - * - * Free the user interface port. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -VNetUserIfFree(VNetJack *this) // IN -{ - VNetUserIF *userIf = (VNetUserIF*)this; - struct sk_buff *skb; - - for (;;) { - skb = skb_dequeue(&userIf->packetQueue); - if (skb == NULL) { - break; - } - dev_kfree_skb(skb); - } - - if (userIf->pollPtr) { - VNetUserIfUnsetupNotify(userIf); - } - - if (this->procEntry) { - VNetProc_RemoveEntry(this->procEntry); - } - - kfree(userIf); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetUserIfReceive -- - * - * This jack is receiving a packet. Take appropriate action. - * - * Results: - * None. - * - * Side effects: - * Frees skb. - * - *---------------------------------------------------------------------- - */ - -static void -VNetUserIfReceive(VNetJack *this, // IN - struct sk_buff *skb) // IN -{ - VNetUserIF *userIf = (VNetUserIF*)this->private; - uint8 *dest = SKB_2_DESTMAC(skb); - - if (!UP_AND_RUNNING(userIf->port.flags)) { - userIf->stats.droppedDown++; - goto drop_packet; - } - - if (!VNetPacketMatch(dest, - userIf->port.paddr, - userIf->port.ladrf, - userIf->port.flags)) { - userIf->stats.droppedMismatch++; - goto drop_packet; - } - - if (skb_queue_len(&userIf->packetQueue) >= VNET_MAX_QLEN) { - userIf->stats.droppedOverflow++; - goto drop_packet; - } - - if (skb->len > ETHER_MAX_QUEUED_PACKET) { - userIf->stats.droppedLargePacket++; - goto drop_packet; - } - - userIf->stats.queued++; - - skb_queue_tail(&userIf->packetQueue, skb); - if (userIf->pollPtr) { - *userIf->pollPtr |= userIf->pollMask; - if (skb_queue_len(&userIf->packetQueue) >= (*userIf->recvClusterCount)) { - Atomic_Or(userIf->actPtr, userIf->actMask); - } - } - wake_up(&userIf->waitQueue); - return; - - drop_packet: - dev_kfree_skb(skb); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetUserIfProcRead -- - * - * Callback for read operation on this userif entry in vnets proc fs. - * - * Results: - * Length of read operation. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VNetUserIfProcRead(char *page, // IN/OUT: buffer to write into - char **start, // OUT: 0 if file < 4k, else offset into - // page - off_t off, // IN: offset of read into the file - int count, // IN: maximum number of bytes to read - int *eof, // OUT: TRUE if there is nothing more to - // read - void *data) // IN: client data - not used -{ - VNetUserIF *userIf = (VNetUserIF*)data; - int len = 0; - - if (!userIf) { - return len; - } - - len += VNetPrintPort(&userIf->port, page+len); - - len += sprintf(page+len, "read %u written %u queued %u ", - userIf->stats.read, - userIf->stats.written, - userIf->stats.queued); - - len += sprintf(page+len, - "dropped.down %u dropped.mismatch %u " - "dropped.overflow %u dropped.largePacket %u", - userIf->stats.droppedDown, - userIf->stats.droppedMismatch, - userIf->stats.droppedOverflow, - userIf->stats.droppedLargePacket); - - len += sprintf(page+len, "\n"); - - *start = 0; - *eof = 1; - return len; -} - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) -/* - *---------------------------------------------------------------------- - * - * VNetCopyDatagram -- - * - * Copy part of datagram to userspace. - * - * Results: - * zero on success, - * -EFAULT if buffer is an invalid area - * - * Side effects: - * Data copied to the buffer. - * - *---------------------------------------------------------------------- - */ - -static int -VNetCopyDatagram(const struct sk_buff *skb, // IN: skb to copy - char *buf, // OUT: where to copy data - int len) // IN: length -{ - struct iovec iov = { - .iov_base = buf, - .iov_len = len, - }; - return skb_copy_datagram_iovec(skb, 0, &iov, len); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetCsumCopyDatagram -- - * - * Copy part of datagram to userspace doing checksum at same time. - * - * Do not mark this function INLINE, it is recursive! With all gcc's - * released up to now (<= gcc-3.3.1) inlining this function just - * consumes 120 more bytes of code and goes completely mad on - * register allocation, storing almost everything in the memory. - * - * Results: - * folded checksum (non-negative value) on success, - * -EINVAL if offset is too big, - * -EFAULT if buffer is an invalid area - * - * Side effects: - * Data copied to the buffer. - * - *---------------------------------------------------------------------- - */ - -static int -VNetCsumCopyDatagram(const struct sk_buff *skb, // IN: skb to copy - unsigned int offset, // IN: how many bytes skip - char *buf) // OUT: where to copy data -{ - unsigned int csum; - int err = 0; - int len = skb_headlen(skb) - offset; - char *curr = buf; - const skb_frag_t *frag; - - /* - * Something bad happened. We skip only up to skb->nh.raw, and skb->nh.raw - * must be in the header, otherwise we are in the big troubles. - */ - if (len < 0) { - return -EINVAL; - } - - csum = csum_and_copy_to_user(skb->data + offset, curr, len, 0, &err); - if (err) { - return err; - } - curr += len; - - for (frag = skb_shinfo(skb)->frags; - frag != skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags; - frag++) { - if (frag->size > 0) { - unsigned int tmpCsum; - const void *vaddr; - - vaddr = kmap(frag->page); - tmpCsum = csum_and_copy_to_user(vaddr + frag->page_offset, - curr, frag->size, 0, &err); - kunmap(frag->page); - if (err) { - return err; - } - csum = csum_block_add(csum, tmpCsum, curr - buf); - curr += frag->size; - } - } - - for (skb = skb_shinfo(skb)->frag_list; skb != NULL; skb = skb->next) { - int tmpCsum; - - tmpCsum = VNetCsumCopyDatagram(skb, 0, curr); - if (tmpCsum < 0) { - return tmpCsum; - } - /* Folded checksum must be inverted before we can use it */ - csum = csum_block_add(csum, tmpCsum ^ 0xFFFF, curr - buf); - curr += skb->len; - } - return csum_fold(csum); -} -#endif - - -/* - *---------------------------------------------------------------------- - * - * VNetCopyDatagramToUser -- - * - * Copy complete datagram to the user space. Fill correct checksum - * into the copied datagram if nobody did it yet. - * - * Results: - * On success byte count, on failure -EFAULT. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE_SINGLE_CALLER int -VNetCopyDatagramToUser(const struct sk_buff *skb, // IN - char *buf, // OUT - size_t count) // IN -{ - if (count > skb->len) { - count = skb->len; - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 4) - if (copy_to_user(buf, skb->data, count)) { - return -EFAULT; - } -#else - /* - * If truncation occurs, we do not bother with checksumming - caller cannot - * verify checksum anyway in such case, and copy without checksum is - * faster. - */ - if (skb->pkt_type == PACKET_OUTGOING && /* Packet must be outgoing */ - skb->ip_summed == VM_TX_CHECKSUM_PARTIAL && /* Without checksum */ - compat_skb_network_header_len(skb) && /* We must know where header is */ - skb->len == count) { /* No truncation may occur */ - size_t skl; - int csum; - u_int16_t csum16; - - skl = compat_skb_csum_start(skb); - if (VNetCopyDatagram(skb, buf, skl)) { - return -EFAULT; - } - csum = VNetCsumCopyDatagram(skb, skl, buf + skl); - if (csum < 0) { - return csum; - } - csum16 = csum; - if (copy_to_user(buf + skl + compat_skb_csum_offset(skb), - &csum16, sizeof csum16)) { - return -EFAULT; - } - } else { - if (VNetCopyDatagram(skb, buf, count)) { - return -EFAULT; - } - } -#endif - return count; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetUserIfRead -- - * - * The virtual network's read file operation. Reads the next pending - * packet for this network connection. - * - * Results: - * On success the len of the packet received, - * else if no packet waiting and nonblocking 0, - * else -errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VNetUserIfRead(VNetPort *port, // IN - struct file *filp, // IN - char *buf, // OUT - size_t count) // IN -{ - VNetUserIF *userIf = (VNetUserIF*)port->jack.private; - struct sk_buff *skb; - int ret; - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&userIf->waitQueue, &wait); - for (;;) { - current->state = TASK_INTERRUPTIBLE; - mb(); - skb = skb_peek(&userIf->packetQueue); - if (skb && (skb->len > count)) { - skb = NULL; - ret = -EMSGSIZE; - break; - } - ret = -EAGAIN; - skb = skb_dequeue(&userIf->packetQueue); - - if (userIf->pollPtr) { - if (skb_queue_empty(&userIf->packetQueue)) { - *userIf->pollPtr &= ~userIf->pollMask; - } -#if 0 - /* - * Disable this for now since the monitor likes to assert that - * actions are present and thus can't cope with them disappearing - * out from under it. See bug 47760. -Jeremy. 22 July 2004 - */ - - if (skb_queue_len(&userIf->packetQueue) < (*userIf->recvClusterCount) && - (Atomic_Read(userIf->actPtr) & userIf->actMask) != 0) { - Atomic_And(userIf->actPtr, ~userIf->actMask); - } -#endif - } - - if (skb != NULL || filp->f_flags & O_NONBLOCK) { - break; - } - ret = -EINTR; - if (signal_pending(current)) { - break; - } - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&userIf->waitQueue, &wait); - if (! skb) { - return ret; - } - - userIf->stats.read++; - - count = VNetCopyDatagramToUser(skb, buf, count); - dev_kfree_skb(skb); - return count; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetUserIfWrite -- - * - * The virtual network's write file operation. Send the raw packet - * to the network. - * - * Results: - * On success the count of bytes written else errno. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VNetUserIfWrite(VNetPort *port, // IN - struct file *filp, // IN - const char *buf, // IN - size_t count) // IN -{ - VNetUserIF *userIf = (VNetUserIF*)port->jack.private; - struct sk_buff *skb; - - /* - * Check size - */ - - if (count < sizeof (struct ethhdr) || - count > ETHER_MAX_QUEUED_PACKET) { - return -EINVAL; - } - - /* - * Required to enforce the downWhenAddrMismatch policy in the MAC - * layer. --hpreg - */ - if (!UP_AND_RUNNING(userIf->port.flags)) { - userIf->stats.droppedDown++; - return count; - } - - /* - * Allocate an sk_buff. - */ - - skb = dev_alloc_skb(count + 7); - if (skb == NULL) { - // XXX obey O_NONBLOCK? - return -ENOBUFS; - } - - skb_reserve(skb, 2); - - /* - * Copy the data and send it. - */ - - userIf->stats.written++; - if (copy_from_user(skb_put(skb, count), buf, count)) { - dev_kfree_skb(skb); - return -EFAULT; - } - - VNetSend(&userIf->port.jack, skb); - - return count; -} - - -/* - *----------------------------------------------------------------------------- - * - * VNetUserIfIoctl -- - * - * XXX - * - * Results: - * 0 on success - * -errno on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -VNetUserIfIoctl(VNetPort *port, // IN - struct file *filp, // IN - unsigned int iocmd, // IN - unsigned long ioarg) // IN or OUT depending on iocmd -{ - VNetUserIF *userIf = (VNetUserIF*)port->jack.private; - - switch (iocmd) { - case SIOCSETNOTIFY: - return -EINVAL; - case SIOCSETNOTIFY2: -#ifdef VMX86_SERVER - /* - * This ioctl always return failure on ESX since we cannot map pages into - * the console os that are from the VMKernel address space which was the - * only case we used this. - */ - return -EINVAL; -#else // VMX86_SERVER - /* - * ORs pollMask into the integer pointed to by ptr if pending packet. Is - * cleared when all packets are drained. - */ - { - int retval; - VNet_Notify vn; - - if (copy_from_user(&vn, (void *)ioarg, sizeof vn)) { - return -EFAULT; - } - - if (vn.version != 3) { - return -EINVAL; - } - - retval = VNetUserIfSetupNotify(userIf, &vn); - if (retval < 0) { - return retval; - } - - break; - } -#endif // VMX86_SERVER - case SIOCUNSETNOTIFY: - if (!userIf->pollPtr) { - /* This should always happen on ESX. */ - return -EINVAL; - } - VNetUserIfUnsetupNotify(userIf); - break; - - case SIOCSIFFLAGS: - /* - * Drain queue when interface is no longer active. We drain the queue to - * avoid having old packets delivered to the guest when reneabled. - */ - - if (!UP_AND_RUNNING(userIf->port.flags)) { - struct sk_buff *skb; - - while ((skb = skb_dequeue(&userIf->packetQueue)) != NULL) { - dev_kfree_skb(skb); - } - - if (userIf->pollPtr) { - /* Clear the pending bit as no packets are pending at this point. */ - *userIf->pollPtr &= ~userIf->pollMask; - } - } - break; - - default: - return -ENOIOCTLCMD; - break; - } - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetUserIfPoll -- - * - * The virtual network's file poll operation. - * - * Results: - * Return POLLIN if success, else sleep and return 0. - * FIXME: Should not we always return POLLOUT? - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VNetUserIfPoll(VNetPort *port, // IN - struct file *filp, // IN - poll_table *wait) // IN -{ - VNetUserIF *userIf = (VNetUserIF*)port->jack.private; - - poll_wait(filp, &userIf->waitQueue, wait); - if (!skb_queue_empty(&userIf->packetQueue)) { - return POLLIN; - } - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetUserIf_Create -- - * - * Create a user level port to the wonderful world of virtual - * networking. - * - * Results: - * Errno. Also returns an allocated port to connect to, - * NULL on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetUserIf_Create(VNetPort **ret) // OUT -{ - VNetUserIF *userIf; - static unsigned id = 0; - int retval; - - userIf = kmalloc(sizeof *userIf, GFP_USER); - if (!userIf) { - return -ENOMEM; - } - - /* - * Initialize fields. - */ - - userIf->port.id = id++; - - userIf->port.jack.peer = NULL; - userIf->port.jack.numPorts = 1; - VNetSnprintf(userIf->port.jack.name, sizeof userIf->port.jack.name, - "userif%u", userIf->port.id); - userIf->port.jack.private = userIf; - userIf->port.jack.index = 0; - userIf->port.jack.procEntry = NULL; - userIf->port.jack.free = VNetUserIfFree; - userIf->port.jack.rcv = VNetUserIfReceive; - userIf->port.jack.cycleDetect = NULL; - userIf->port.jack.portsChanged = NULL; - userIf->port.jack.isBridged = NULL; - userIf->pollPtr = NULL; - userIf->actPtr = NULL; - userIf->recvClusterCount = NULL; - userIf->pollPage = NULL; - userIf->actPage = NULL; - userIf->recvClusterPage = NULL; - userIf->pollMask = userIf->actMask = 0; - - /* - * Make proc entry for this jack. - */ - - retval = VNetProc_MakeEntry(userIf->port.jack.name, S_IFREG, - &userIf->port.jack.procEntry); - if (retval) { - if (retval == -ENXIO) { - userIf->port.jack.procEntry = NULL; - } else { - kfree(userIf); - return retval; - } - } else { - userIf->port.jack.procEntry->read_proc = VNetUserIfProcRead; - userIf->port.jack.procEntry->data = userIf; - } - - /* - * Rest of fields. - */ - - userIf->port.flags = IFF_RUNNING; - - memset(userIf->port.paddr, 0, sizeof userIf->port.paddr); - memset(userIf->port.ladrf, 0, sizeof userIf->port.ladrf); - - VNet_MakeMACAddress(&userIf->port); - - userIf->port.fileOpRead = VNetUserIfRead; - userIf->port.fileOpWrite = VNetUserIfWrite; - userIf->port.fileOpIoctl = VNetUserIfIoctl; - userIf->port.fileOpPoll = VNetUserIfPoll; - - skb_queue_head_init(&(userIf->packetQueue)); - init_waitqueue_head(&userIf->waitQueue); - - memset(&userIf->stats, 0, sizeof userIf->stats); - - *ret = (VNetPort*)userIf; - return 0; -} diff -Nrup source/vmnet-only/vm_atomic.h source.edited/vmnet-only/vm_atomic.h --- source/vmnet-only/vm_atomic.h 2010-05-09 20:08:42.000000000 -0700 +++ source.edited/vmnet-only/vm_atomic.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,2049 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -/* - * vm_atomic.h -- - * - * Atomic power - */ - -#ifndef _ATOMIC_H_ -#define _ATOMIC_H_ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_VMMEXT -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMNIXMOD -#define INCLUDE_ALLOW_VMKDRIVERS -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_DISTRIBUTE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMIROM -#include "includeCheck.h" - -#include "vm_basic_types.h" - - -/* Basic atomic type: 32 bits */ -typedef struct Atomic_uint32 { - volatile uint32 value; -} Atomic_uint32; - - -/* Basic atomic type: 64 bits */ -typedef struct Atomic_uint64 { - volatile uint64 value; -} Atomic_uint64 ALIGNED(8); - - -/* - * Prototypes for msft atomics. These are defined & inlined by the - * compiler so no function definition is needed. The prototypes are - * needed for c++. Since amd64 compiler doesn't support inline asm we - * have to use these. Unfortunately, we still have to use some inline asm - * for the 32 bit code since the and/or/xor implementations didn't show up - * untill xp or 2k3. - * - * The declarations for the intrinsic functions were taken from ntddk.h - * in the DDK. The declarations must match otherwise the 64-bit c++ - * compiler will complain about second linkage of the intrinsic functions. - * We define the intrinsic using the basic types corresponding to the - * Windows typedefs. This avoids having to include windows header files - * to get to the windows types. - */ -#if defined(_MSC_VER) && _MSC_VER >= 1310 -#ifdef __cplusplus -extern "C" { -#endif -long _InterlockedExchange(long volatile*, long); -long _InterlockedCompareExchange(long volatile*, long, long); -long _InterlockedExchangeAdd(long volatile*, long); -long _InterlockedDecrement(long volatile*); -long _InterlockedIncrement(long volatile*); -#pragma intrinsic(_InterlockedExchange, _InterlockedCompareExchange) -#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedDecrement) -#pragma intrinsic(_InterlockedIncrement) - -#if defined(VM_X86_64) -long _InterlockedAnd(long volatile*, long); -__int64 _InterlockedAnd64(__int64 volatile*, __int64); -long _InterlockedOr(long volatile*, long); -__int64 _InterlockedOr64(__int64 volatile*, __int64); -long _InterlockedXor(long volatile*, long); -__int64 _InterlockedXor64(__int64 volatile*, __int64); -__int64 _InterlockedExchangeAdd64(__int64 volatile*, __int64); -__int64 _InterlockedIncrement64(__int64 volatile*); -__int64 _InterlockedDecrement64(__int64 volatile*); -__int64 _InterlockedExchange64(__int64 volatile*, __int64); -__int64 _InterlockedCompareExchange64(__int64 volatile*, __int64, __int64); -#if !defined(_WIN64) -#pragma intrinsic(_InterlockedAnd, _InterlockedAnd64) -#pragma intrinsic(_InterlockedOr, _InterlockedOr64) -#pragma intrinsic(_InterlockedXor, _InterlockedXor64) -#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedIncrement64) -#pragma intrinsic(_InterlockedDecrement64, _InterlockedExchange64) -#pragma intrinsic(_InterlockedCompareExchange64) -#endif /* !_WIN64 */ -#endif /* __x86_64__ */ - -#ifdef __cplusplus -} -#endif -#endif /* _MSC_VER */ - - -/* Convert a volatile int to Atomic_uint32. */ -static INLINE Atomic_uint32 * -Atomic_VolatileToAtomic(volatile uint32 *var) -{ - return (Atomic_uint32 *)var; -} - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Init, Atomic_SetFence, AtomicUseFence -- - * - * Determine whether an lfence intruction is executed after - * every locked instruction. - * - * Certain AMD processes have a bug (see bug 107024) that - * requires an lfence after every locked instruction. - * - * The global variable AtomicUseFence controls whether lfence - * is used (see AtomicEpilogue). - * - * Atomic_SetFence sets AtomicUseFence to the given value. - * - * Atomic_Init computes and sets AtomicUseFence. - * It does not take into account the number of processors. - * - * The rationale for all this complexity is that Atomic_Init - * is the easy-to-use interface. It can be called a number - * of times cheaply, and does not depend on other libraries. - * However, because the number of CPUs is difficult to compute, - * it does without it and always assumes there are more than one. - * - * For programs that care or have special requirements, - * Atomic_SetFence can be called directly, in addition to Atomic_Init. - * It overrides the effect of Atomic_Init, and can be called - * before, after, or between calls to Atomic_Init. - * - *----------------------------------------------------------------------------- - */ - -// The freebsd assembler doesn't know the lfence instruction -#if defined(__GNUC__) && \ - __GNUC__ >= 3 && \ - !defined(BSD_VERSION) && \ - (!defined(MODULE) || defined(__VMKERNEL_MODULE__)) && \ - !defined(__APPLE__) /* PR136775 */ -#define ATOMIC_USE_FENCE -#endif - -#if defined(VMATOMIC_IMPORT_DLLDATA) -VMX86_EXTERN_DATA Bool AtomicUseFence; -#else -EXTERN Bool AtomicUseFence; -#endif - -EXTERN Bool atomicFenceInitialized; - -void AtomicInitFence(void); - -static INLINE void -Atomic_Init(void) -{ -#ifdef ATOMIC_USE_FENCE - if (!atomicFenceInitialized) { - AtomicInitFence(); - } -#endif -} - -static INLINE void -Atomic_SetFence(Bool fenceAfterLock) /* IN: TRUE to enable lfence */ - /* FALSE to disable. */ -{ - AtomicUseFence = fenceAfterLock; -#if defined(__VMKERNEL__) - extern void Atomic_SetFenceVMKAPI(Bool fenceAfterLock); - Atomic_SetFenceVMKAPI(fenceAfterLock); -#endif - atomicFenceInitialized = TRUE; -} - - -/* Conditionally execute fence after interlocked instruction. */ -static INLINE void -AtomicEpilogue(void) -{ -#ifdef ATOMIC_USE_FENCE - if (UNLIKELY(AtomicUseFence)) { - asm volatile ("lfence" ::: "memory"); - } -#endif -} - - -/* - * All the assembly code is tricky and written conservatively. - * For example, to make sure gcc won't introduce copies, - * we force the addressing mode like this: - * - * "xchgl %0, (%1)" - * : "=r" (val) - * : "r" (&var->value), - * "0" (val) - * : "memory" - * - * - edward - * - * Actually - turns out that gcc never generates memory aliases (it - * still does generate register aliases though), so we can be a bit - * more agressive with the memory constraints. The code above can be - * modified like this: - * - * "xchgl %0, %1" - * : "=r" (val), - * "=m" (var->value), - * : "0" (val), - * "1" (var->value) - * - * The advantages are that gcc can use whatever addressing mode it - * likes to access the memory value, and that we dont have to use a - * way-too-generic "memory" clobber as there is now an explicit - * declaration that var->value is modified. - * - * see also /usr/include/asm/atomic.h to convince yourself this is a - * valid optimization. - * - * - walken - */ - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Read -- - * - * Read - * - * Results: - * The value of the atomic variable. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint32 -Atomic_Read(Atomic_uint32 const *var) // IN -{ - return var->value; -} -#define Atomic_Read32 Atomic_Read - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Write -- - * - * Write - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Write(Atomic_uint32 *var, // IN - uint32 val) // IN -{ - var->value = val; -} -#define Atomic_Write32 Atomic_Write - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_ReadWrite -- - * - * Read followed by write - * - * Results: - * The value of the atomic variable before the write. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint32 -Atomic_ReadWrite(Atomic_uint32 *var, // IN - uint32 val) // IN -#ifdef __GNUC__ -{ - /* Checked against the Intel manual and GCC --walken */ - __asm__ __volatile__( - "xchgl %0, %1" -# if VM_ASM_PLUS - : "=r" (val), - "+m" (var->value) - : "0" (val) -# else - : "=r" (val), - "=m" (var->value) - : "0" (val), - "1" (var->value) -# endif - ); - AtomicEpilogue(); - return val; -} -#elif defined(_MSC_VER) && _MSC_VER >= 1310 -{ - return _InterlockedExchange((long *)&var->value, (long)val); -} -#elif defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4035) // disable no-return warning -{ - __asm mov eax, val - __asm mov ebx, var - __asm xchg [ebx]Atomic_uint32.value, eax - // eax is the return value, this is documented to work - edward -} -#pragma warning(pop) -#else -#error No compiler defined for Atomic_ReadWrite -#endif -#define Atomic_ReadWrite32 Atomic_ReadWrite - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_ReadIfEqualWrite -- - * - * Compare exchange: Read variable, if equal to oldVal, write newVal - * - * Results: - * The value of the atomic variable before the write. - * - * Side effects: - * The variable may be modified. - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint32 -Atomic_ReadIfEqualWrite(Atomic_uint32 *var, // IN - uint32 oldVal, // IN - uint32 newVal) // IN -#ifdef __GNUC__ -{ - uint32 val; - - /* Checked against the Intel manual and GCC --walken */ - __asm__ __volatile__( - "lock; cmpxchgl %2, %1" -# if VM_ASM_PLUS - : "=a" (val), - "+m" (var->value) - : "r" (newVal), - "0" (oldVal) -# else - : "=a" (val), - "=m" (var->value) - : "r" (newVal), - "0" (oldVal) - /* - * "1" (var->value): results in inconsistent constraints on gcc 2.7.2.3 - * when compiling enterprise-2.2.17-14-RH7.0-update. - * The constraint has been commented out for now. We may consider doing - * this systematically, but we need to be sure it is the right thing to - * do. However, it is also possible that the offending use of this asm - * function will be removed in the near future in which case we may - * decide to reintroduce the constraint instead. hpreg & agesen. - */ -# endif - : "cc" - ); - AtomicEpilogue(); - return val; -} -#elif defined(_MSC_VER) && _MSC_VER >= 1310 -{ - return _InterlockedCompareExchange((long *)&var->value, - (long)newVal, - (long)oldVal); -} -#elif defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4035) // disable no-return warning -{ - __asm mov eax, oldVal - __asm mov ebx, var - __asm mov ecx, newVal - __asm lock cmpxchg [ebx]Atomic_uint32.value, ecx - // eax is the return value, this is documented to work - edward -} -#pragma warning(pop) -#else -#error No compiler defined for Atomic_ReadIfEqualWrite -#endif -#define Atomic_ReadIfEqualWrite32 Atomic_ReadIfEqualWrite - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_ReadIfEqualWrite64 -- - * - * Compare exchange: Read variable, if equal to oldVal, write newVal - * - * Results: - * The value of the atomic variable before the write. - * - * Side effects: - * The variable may be modified. - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint64 -Atomic_ReadIfEqualWrite64(Atomic_uint64 *var, // IN - uint64 oldVal, // IN - uint64 newVal) // IN -{ -#if defined(__GNUC__) - uint64 val; - - /* Checked against the AMD manual and GCC --hpreg */ - __asm__ __volatile__( - "lock; cmpxchgq %2, %1" - : "=a" (val), - "+m" (var->value) - : "r" (newVal), - "0" (oldVal) - : "cc" - ); - AtomicEpilogue(); - return val; -#elif defined(_MSC_VER) - return _InterlockedCompareExchange64((__int64 *)&var->value, - (__int64)newVal, - (__int64)oldVal); -#else -#error No compiler defined for Atomic_ReadIfEqualWrite64 -#endif -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_And -- - * - * Atomic read, bitwise AND with a value, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_And(Atomic_uint32 *var, // IN - uint32 val) // IN -{ -#ifdef __GNUC__ - /* Checked against the Intel manual and GCC --walken */ - __asm__ __volatile__( - "lock; andl %1, %0" -# if VM_ASM_PLUS - : "+m" (var->value) - : "ri" (val) -# else - : "=m" (var->value) - : "ri" (val), - "0" (var->value) -# endif - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) -#if defined(__x86_64__) - _InterlockedAnd((long *)&var->value, (long)val); -#else - __asm mov eax, val - __asm mov ebx, var - __asm lock and [ebx]Atomic_uint32.value, eax -#endif -#else -#error No compiler defined for Atomic_And -#endif -} -#define Atomic_And32 Atomic_And - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_And64 -- - * - * Atomic read, bitwise AND with a value, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_And64(Atomic_uint64 *var, // IN - uint64 val) // IN -{ -#if defined(__GNUC__) - /* Checked against the AMD manual and GCC --hpreg */ - __asm__ __volatile__( - "lock; andq %1, %0" - : "+m" (var->value) - : "ri" (val) - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) - _InterlockedAnd64((__int64 *)&var->value, (__int64)val); -#else -#error No compiler defined for Atomic_And64 -#endif -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Or -- - * - * Atomic read, bitwise OR with a value, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Or(Atomic_uint32 *var, // IN - uint32 val) // IN -{ -#ifdef __GNUC__ - /* Checked against the Intel manual and GCC --walken */ - __asm__ __volatile__( - "lock; orl %1, %0" -# if VM_ASM_PLUS - : "+m" (var->value) - : "ri" (val) -# else - : "=m" (var->value) - : "ri" (val), - "0" (var->value) -# endif - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) -#if defined(__x86_64__) - _InterlockedOr((long *)&var->value, (long)val); -#else - __asm mov eax, val - __asm mov ebx, var - __asm lock or [ebx]Atomic_uint32.value, eax -#endif -#else -#error No compiler defined for Atomic_Or -#endif -} -#define Atomic_Or32 Atomic_Or - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_Or64 -- - * - * Atomic read, bitwise OR with a value, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Or64(Atomic_uint64 *var, // IN - uint64 val) // IN -{ -#if defined(__GNUC__) - /* Checked against the AMD manual and GCC --hpreg */ - __asm__ __volatile__( - "lock; orq %1, %0" - : "+m" (var->value) - : "ri" (val) - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) - _InterlockedOr64((__int64 *)&var->value, (__int64)val); -#else -#error No compiler defined for Atomic_Or64 -#endif -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Xor -- - * - * Atomic read, bitwise XOR with a value, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Xor(Atomic_uint32 *var, // IN - uint32 val) // IN -{ -#ifdef __GNUC__ - /* Checked against the Intel manual and GCC --walken */ - __asm__ __volatile__( - "lock; xorl %1, %0" -# if VM_ASM_PLUS - : "+m" (var->value) - : "ri" (val) -# else - : "=m" (var->value) - : "ri" (val), - "0" (var->value) -# endif - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) -#if defined(__x86_64__) - _InterlockedXor((long *)&var->value, (long)val); -#else - __asm mov eax, val - __asm mov ebx, var - __asm lock xor [ebx]Atomic_uint32.value, eax -#endif -#else -#error No compiler defined for Atomic_Xor -#endif -} -#define Atomic_Xor32 Atomic_Xor - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_Xor64 -- - * - * Atomic read, bitwise XOR with a value, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Xor64(Atomic_uint64 *var, // IN - uint64 val) // IN -{ -#if defined(__GNUC__) - /* Checked against the AMD manual and GCC --hpreg */ - __asm__ __volatile__( - "lock; xorq %1, %0" - : "+m" (var->value) - : "ri" (val) - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) - _InterlockedXor64((__int64 *)&var->value, (__int64)val); -#else -#error No compiler defined for Atomic_Xor64 -#endif -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Add -- - * - * Atomic read, add a value, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Add(Atomic_uint32 *var, // IN - uint32 val) // IN -{ -#ifdef __GNUC__ - /* Checked against the Intel manual and GCC --walken */ - __asm__ __volatile__( - "lock; addl %1, %0" -# if VM_ASM_PLUS - : "+m" (var->value) - : "ri" (val) -# else - : "=m" (var->value) - : "ri" (val), - "0" (var->value) -# endif - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) && _MSC_VER >= 1310 - _InterlockedExchangeAdd((long *)&var->value, (long)val); -#elif defined(_MSC_VER) - __asm mov eax, val - __asm mov ebx, var - __asm lock add [ebx]Atomic_uint32.value, eax -#else -#error No compiler defined for Atomic_Add -#endif -} -#define Atomic_Add32 Atomic_Add - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_Add64 -- - * - * Atomic read, add a value, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Add64(Atomic_uint64 *var, // IN - uint64 val) // IN -{ -#if defined(__GNUC__) - /* Checked against the AMD manual and GCC --hpreg */ - __asm__ __volatile__( - "lock; addq %1, %0" - : "+m" (var->value) - : "ri" (val) - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) - _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)val); -#else -#error No compiler defined for Atomic_Add64 -#endif -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Sub -- - * - * Atomic read, subtract a value, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Sub(Atomic_uint32 *var, // IN - uint32 val) // IN -{ -#ifdef __GNUC__ - /* Checked against the Intel manual and GCC --walken */ - __asm__ __volatile__( - "lock; subl %1, %0" -# if VM_ASM_PLUS - : "+m" (var->value) - : "ri" (val) -# else - : "=m" (var->value) - : "ri" (val), - "0" (var->value) -# endif - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) && _MSC_VER >= 1310 - _InterlockedExchangeAdd((long *)&var->value, (long)-val); -#elif defined(_MSC_VER) - __asm mov eax, val - __asm mov ebx, var - __asm lock sub [ebx]Atomic_uint32.value, eax -#else -#error No compiler defined for Atomic_Sub -#endif -} -#define Atomic_Sub32 Atomic_Sub - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_Sub64 -- - * - * Atomic read, subtract a value, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Sub64(Atomic_uint64 *var, // IN - uint64 val) // IN -{ -#ifdef __GNUC__ - /* Checked against the AMD manual and GCC --hpreg */ - __asm__ __volatile__( - "lock; subq %1, %0" - : "+m" (var->value) - : "ri" (val) - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) - _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)-val); -#else -#error No compiler defined for Atomic_Sub64 -#endif -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Inc -- - * - * Atomic read, increment, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Inc(Atomic_uint32 *var) // IN -{ -#ifdef __GNUC__ - /* Checked against the Intel manual and GCC --walken */ - __asm__ __volatile__( - "lock; incl %0" -# if VM_ASM_PLUS - : "+m" (var->value) - : -# else - : "=m" (var->value) - : "0" (var->value) -# endif - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) && _MSC_VER >= 1310 - _InterlockedIncrement((long *)&var->value); -#elif defined(_MSC_VER) - __asm mov ebx, var - __asm lock inc [ebx]Atomic_uint32.value -#else -#error No compiler defined for Atomic_Inc -#endif -} -#define Atomic_Inc32 Atomic_Inc - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_Inc64 -- - * - * Atomic read, increment, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Inc64(Atomic_uint64 *var) // IN -{ -#if defined(__GNUC__) - /* Checked against the AMD manual and GCC --hpreg */ - __asm__ __volatile__( - "lock; incq %0" - : "+m" (var->value) - : - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) - _InterlockedIncrement64((__int64 *)&var->value); -#else -#error No compiler defined for Atomic_Inc64 -#endif -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Dec -- - * - * Atomic read, decrement, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Dec(Atomic_uint32 *var) // IN -{ -#ifdef __GNUC__ - /* Checked against the Intel manual and GCC --walken */ - __asm__ __volatile__( - "lock; decl %0" -# if VM_ASM_PLUS - : "+m" (var->value) - : -# else - : "=m" (var->value) - : "0" (var->value) -# endif - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) && _MSC_VER >= 1310 - _InterlockedDecrement((long *)&var->value); -#elif defined(_MSC_VER) - __asm mov ebx, var - __asm lock dec [ebx]Atomic_uint32.value -#else -#error No compiler defined for Atomic_Dec -#endif -} -#define Atomic_Dec32 Atomic_Dec - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_Dec64 -- - * - * Atomic read, decrement, write. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Dec64(Atomic_uint64 *var) // IN -{ -#if defined(__GNUC__) - /* Checked against the AMD manual and GCC --hpreg */ - __asm__ __volatile__( - "lock; decq %0" - : "+m" (var->value) - : - : "cc" - ); - AtomicEpilogue(); -#elif defined(_MSC_VER) - _InterlockedDecrement64((__int64 *)&var->value); -#else -#error No compiler defined for Atomic_Dec64 -#endif -} -#endif - - -/* - * Note that the technique below can be used to implement ReadX(), where X is - * an arbitrary mathematical function. - */ - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_FetchAndOr -- - * - * Atomic read (returned), bitwise OR with a value, write. - * - * Results: - * The value of the variable before the operation. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint32 -Atomic_FetchAndOr(Atomic_uint32 *var, // IN - uint32 val) // IN -{ - uint32 res; - - do { - res = var->value; - } while (res != Atomic_ReadIfEqualWrite(var, res, res | val)); - - return res; -} - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_FetchAndAnd -- - * - * Atomic read (returned), bitwise And with a value, write. - * - * Results: - * The value of the variable before the operation. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint32 -Atomic_FetchAndAnd(Atomic_uint32 *var, // IN - uint32 val) // IN -{ - uint32 res; - - do { - res = var->value; - } while (res != Atomic_ReadIfEqualWrite(var, res, res & val)); - - return res; -} -#define Atomic_ReadOr32 Atomic_FetchAndOr - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_ReadOr64 -- - * - * Atomic read (returned), bitwise OR with a value, write. - * - * Results: - * The value of the variable before the operation. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint64 -Atomic_ReadOr64(Atomic_uint64 *var, // IN - uint64 val) // IN -{ - uint64 res; - - do { - res = var->value; - } while (res != Atomic_ReadIfEqualWrite64(var, res, res | val)); - - return res; -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_FetchAndAddUnfenced -- - * - * Atomic read (returned), add a value, write. - * - * If you have to implement FetchAndAdd() on an architecture other than - * x86 or x86-64, you might want to consider doing something similar to - * Atomic_FetchAndOr(). - * - * The "Unfenced" version of Atomic_FetchAndInc never executes - * "lfence" after the interlocked operation. - * - * Results: - * The value of the variable before the operation. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint32 -Atomic_FetchAndAddUnfenced(Atomic_uint32 *var, // IN - uint32 val) // IN -#ifdef __GNUC__ -{ - /* Checked against the Intel manual and GCC --walken */ - __asm__ __volatile__( -# if VM_ASM_PLUS - "lock; xaddl %0, %1" - : "=r" (val), - "+m" (var->value) - : "0" (val) - : "cc" -# else - "lock; xaddl %0, (%1)" - : "=r" (val) - : "r" (&var->value), - "0" (val) - : "cc", "memory" -# endif - ); - return val; -} -#elif defined(_MSC_VER) && _MSC_VER >= 1310 -{ - return _InterlockedExchangeAdd((long *)&var->value, (long)val); -} -#elif defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4035) // disable no-return warning -{ - __asm mov eax, val - __asm mov ebx, var - __asm lock xadd [ebx]Atomic_uint32.value, eax -} -#pragma warning(pop) -#else -#error No compiler defined for Atomic_FetchAndAdd -#endif -#define Atomic_ReadAdd32 Atomic_FetchAndAdd - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_FetchAndAdd -- - * - * Atomic read (returned), add a value, write. - * - * If you have to implement FetchAndAdd() on an architecture other than - * x86 or x86-64, you might want to consider doing something similar to - * Atomic_FetchAndOr(). - * - * Unlike "Unfenced" version, this one may execute the "lfence" after - * interlocked operation. - * - * Results: - * The value of the variable before the operation. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint32 -Atomic_FetchAndAdd(Atomic_uint32 *var, // IN - uint32 val) // IN -#ifdef __GNUC__ -{ - val = Atomic_FetchAndAddUnfenced(var, val); - AtomicEpilogue(); - return val; -} -#else -{ - return Atomic_FetchAndAddUnfenced(var, val); -} -#endif - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_ReadAdd64 -- - * - * Atomic read (returned), add a value, write. - * - * Results: - * The value of the variable before the operation. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint64 -Atomic_ReadAdd64(Atomic_uint64 *var, // IN - uint64 val) // IN -{ -#if defined(__GNUC__) - /* Checked against the AMD manual and GCC --hpreg */ - __asm__ __volatile__( - "lock; xaddq %0, %1" - : "=r" (val), - "+m" (var->value) - : "0" (val) - : "cc" - ); - AtomicEpilogue(); - return val; -#elif defined(_MSC_VER) - return _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)val); -#else -#error No compiler defined for Atomic_ReadAdd64 -#endif -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_FetchAndInc -- - * - * Atomic read (returned), increment, write. - * - * Results: - * The value of the variable before the operation. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint32 -Atomic_FetchAndInc(Atomic_uint32 *var) // IN -{ - return Atomic_FetchAndAdd(var, 1); -} -#define Atomic_ReadInc32 Atomic_FetchAndInc - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_ReadInc64 -- - * - * Atomic read (returned), increment, write. - * - * Results: - * The value of the variable before the operation. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint64 -Atomic_ReadInc64(Atomic_uint64 *var) // IN -{ - return Atomic_ReadAdd64(var, 1); -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_FetchAndDec -- - * - * Atomic read (returned), decrement, write. - * - * Results: - * The value of the variable before the operation. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint32 -Atomic_FetchAndDec(Atomic_uint32 *var) // IN -{ - return Atomic_FetchAndAdd(var, (uint32)-1); -} -#define Atomic_ReadDec32 Atomic_FetchAndDec - - -#if defined(__x86_64__) -/* - *----------------------------------------------------------------------------- - * - * Atomic_ReadDec64 -- - * - * Atomic read (returned), decrement, write. - * - * Results: - * The value of the variable before the operation. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint64 -Atomic_ReadDec64(Atomic_uint64 *var) // IN -{ - return Atomic_ReadAdd64(var, CONST64U(-1)); -} -#endif - - -/* - * Usage of this helper struct is strictly reserved to the following - * function. --hpreg - */ -typedef struct { - uint32 lowValue; - uint32 highValue; -} S_uint64; - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_CMPXCHG64 -- - * - * Compare exchange: Read variable, if equal to oldVal, write newVal - * - * XXX: Ensure that if this function is to be inlined by gcc, it is - * compiled with -fno-strict-aliasing. Otherwise it will break. - * Unfortunately we know that gcc 2.95.3 (used to build the FreeBSD 3.2 - * Tools) does not honor -fno-strict-aliasing. As a workaround, we avoid - * inlining the function entirely for versions of gcc under 3.0. - * - * Results: - * TRUE if equal, FALSE if not equal - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -#if defined(__GNUC__) && __GNUC__ < 3 -static Bool -#else -static INLINE Bool -#endif -Atomic_CMPXCHG64(Atomic_uint64 *var, // IN/OUT - uint64 const *oldVal, // IN - uint64 const *newVal) // IN -#ifdef __GNUC__ -{ - Bool equal; - - /* Checked against the Intel manual and GCC --walken */ -#ifdef VMM64 - uint64 dummy; - __asm__ __volatile__( - "lock; cmpxchgq %3, %0" "\n\t" - "sete %1" - : "+m" (*var), - "=qm" (equal), - "=a" (dummy) - : "r" (*newVal), - "2" (*oldVal) - : "cc" - ); -#else /* 32-bit version */ - int dummy1, dummy2; -# if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. -# if defined __GNUC__ && __GNUC__ < 3 // Part of #188541 - for RHL 6.2 etc. - __asm__ __volatile__( - "xchg %%ebx, %6\n\t" - "mov (%%ebx), %%ecx\n\t" - "mov (%%ebx), %%ebx\n\t" - "lock; cmpxchg8b (%3)\n\t" - "xchg %%ebx, %6\n\t" - "sete %0" - : "=a" (equal), "=d" (dummy2), "=D" (dummy1) - : "S" (var), "0" (((S_uint64 const *)oldVal)->lowValue), - "1" (((S_uint64 const *)oldVal)->highValue), "D" (newVal) - : "ecx", "cc", "memory" - ); -# else - __asm__ __volatile__( - "xchgl %%ebx, %6" "\n\t" - // %3 is a register to make sure it cannot be %ebx-relative. - "lock; cmpxchg8b (%3)" "\n\t" - "xchgl %%ebx, %6" "\n\t" - // Must come after restoring %ebx: %0 could be %ebx-relative. - "sete %0" - : "=qm" (equal), - "=a" (dummy1), - "=d" (dummy2) - : "r" (var), - "1" (((S_uint64 const *)oldVal)->lowValue), - "2" (((S_uint64 const *)oldVal)->highValue), - // Cannot use "m" here: 'newVal' is read-only. - "r" (((S_uint64 const *)newVal)->lowValue), - "c" (((S_uint64 const *)newVal)->highValue) - : "cc", "memory" - ); -# endif -# else - __asm__ __volatile__( - "lock; cmpxchg8b %0" "\n\t" - "sete %1" -# if VM_ASM_PLUS - : "+m" (*var), -# else - : "=m" (*var), -# endif - "=qm" (equal), - "=a" (dummy1), - "=d" (dummy2) - : "2" (((S_uint64 const *)oldVal)->lowValue), - "3" (((S_uint64 const *)oldVal)->highValue), - "b" (((S_uint64 const *)newVal)->lowValue), - "c" (((S_uint64 const *)newVal)->highValue) - : "cc" - ); -# endif -#endif - AtomicEpilogue(); - return equal; -} -#elif defined(_MSC_VER) -#if defined(__x86_64__) -{ - return *oldVal == _InterlockedCompareExchange64((__int64 *)&var->value, - (__int64)*newVal, - (__int64)*oldVal); -} -#else -#pragma warning(push) -#pragma warning(disable : 4035) // disable no-return warning -{ - __asm mov esi, var - __asm mov edx, oldVal - __asm mov ecx, newVal - __asm mov eax, [edx]S_uint64.lowValue - __asm mov edx, [edx]S_uint64.highValue - __asm mov ebx, [ecx]S_uint64.lowValue - __asm mov ecx, [ecx]S_uint64.highValue - __asm lock cmpxchg8b [esi] - __asm sete al - __asm movzx eax, al - // eax is the return value, this is documented to work - edward -} -#pragma warning(pop) -#endif -#else -#error No compiler defined for Atomic_CMPXCHG64 -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_CMPXCHG32 -- - * - * Compare exchange: Read variable, if equal to oldVal, write newVal - * - * Results: - * TRUE if equal, FALSE if not equal - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE Bool -Atomic_CMPXCHG32(Atomic_uint32 *var, // IN/OUT - uint32 oldVal, // IN - uint32 newVal) // IN -{ -#ifdef __GNUC__ - Bool equal; - - uint32 dummy; - __asm__ __volatile__( - "lock; cmpxchgl %3, %0" "\n\t" - "sete %1" -# if VM_ASM_PLUS - : "+m" (*var), - "=qm" (equal), - "=a" (dummy) - : "r" (newVal), - "2" (oldVal) -# else - : "=m" (*var), - "=qm" (equal), - "=a" (dummy) - : /*"0" (*var), */ - "r" (newVal), - "2" (oldVal) -# endif - : "cc" - ); - AtomicEpilogue(); - return equal; -#else - return (Atomic_ReadIfEqualWrite(var, oldVal, newVal) == oldVal); -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Read64 -- - * - * Read and return. - * - * Results: - * The value of the atomic variable. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint64 -Atomic_Read64(Atomic_uint64 const *var) // IN -#if defined(__x86_64__) -{ - return var->value; -} -#elif defined(__GNUC__) && defined(__i386__) /* GCC on x86 */ -{ - uint64 value; - /* - * Since cmpxchg8b will replace the contents of EDX:EAX with the - * value in memory if there is no match, we need only execute the - * instruction once in order to atomically read 64 bits from - * memory. The only constraint is that ECX:EBX must have the same - * value as EDX:EAX so that if the comparison succeeds. We - * intentionally don't tell gcc that we are using ebx and ecx as we - * don't modify them and do not care what value they store. - */ - __asm__ __volatile__( - "mov %%ebx, %%eax" "\n\t" - "mov %%ecx, %%edx" "\n\t" - "lock; cmpxchg8b %1" - : "=&A" (value) - : "m" (*var) - : "cc" - ); - AtomicEpilogue(); - return value; -} -#elif defined(_MSC_VER) /* MSC (assume on x86 for now) */ -# pragma warning(push) -# pragma warning(disable : 4035) // disable no-return warning -{ - __asm mov ecx, var - __asm mov edx, ecx - __asm mov eax, ebx - __asm lock cmpxchg8b [ecx] - // edx:eax is the return value; this is documented to work. --mann -} -# pragma warning(pop) -#else -# error No compiler defined for Atomic_Read64 -#endif - - -/* - *---------------------------------------------------------------------- - * - * Atomic_FetchAndAdd64 -- - * - * Atomically adds a 64-bit integer to another - * - * Results: - * Returns the old value just prior to the addition - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static INLINE uint64 -Atomic_FetchAndAdd64(Atomic_uint64 *var, // IN/OUT - uint64 addend) // IN -{ - uint64 oldVal; - uint64 newVal; - - do { - oldVal = var->value; - newVal = oldVal + addend; - } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); - - return oldVal; -} - - -/* - *---------------------------------------------------------------------- - * - * Atomic_FetchAndInc64 -- - * - * Atomically increments a 64-bit integer - * - * Results: - * Returns the old value just prior to incrementing - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static INLINE uint64 -Atomic_FetchAndInc64(Atomic_uint64 *var) // IN/OUT -{ - return Atomic_FetchAndAdd64(var, 1); -} - - -/* - *---------------------------------------------------------------------- - * - * Atomic_FetchAndDec64 -- - * - * Atomically decrements a 64-bit integer - * - * Results: - * Returns the old value just prior to decrementing - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static INLINE uint64 -Atomic_FetchAndDec64(Atomic_uint64 *var) // IN/OUT -{ - uint64 oldVal; - uint64 newVal; - - do { - oldVal = var->value; - newVal = oldVal - 1; - } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); - - return oldVal; -} - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_ReadWrite64 -- - * - * Read followed by write - * - * Results: - * The value of the atomic variable before the write. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint64 -Atomic_ReadWrite64(Atomic_uint64 *var, // IN - uint64 val) // IN -{ -#if defined(__x86_64__) -#if defined(__GNUC__) - /* Checked against the AMD manual and GCC --hpreg */ - __asm__ __volatile__( - "xchgq %0, %1" - : "=r" (val), - "+m" (var->value) - : "0" (val) - ); - AtomicEpilogue(); - return val; -#elif defined(_MSC_VER) - return _InterlockedExchange64((__int64 *)&var->value, (__int64)val); -#else -#error No compiler defined for Atomic_ReadWrite64 -#endif -#else - uint64 oldVal; - - do { - oldVal = var->value; - } while (!Atomic_CMPXCHG64(var, &oldVal, &val)); - - return oldVal; -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_Write64 -- - * - * Write - * - * Results: - * None. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_Write64(Atomic_uint64 *var, // IN - uint64 val) // IN -{ -#if defined(__x86_64__) - var->value = val; -#else - (void)Atomic_ReadWrite64(var, val); -#endif -} - - -/* - * Template code for the Atomic_ type and its operators. - * - * The cast argument is an intermedia type cast to make some - * compilers stop complaining about casting uint32 <-> void *, - * even though we only do it in the 32-bit case so they are always - * the same size. So for val of type uint32, instead of - * (void *)val, we have (void *)(uintptr_t)val. - * The specific problem case is the Windows ddk compiler - * (as used by the SVGA driver). -- edward - */ - -#define MAKE_ATOMIC_TYPE(name, size, in, out, cast) \ - typedef Atomic_uint ## size Atomic_ ## name; \ - \ - \ - static INLINE out \ - Atomic_Read ## name(Atomic_ ## name const *var) \ - { \ - return (out)(cast)Atomic_Read ## size(var); \ - } \ - \ - \ - static INLINE void \ - Atomic_Write ## name(Atomic_ ## name *var, \ - in val) \ - { \ - Atomic_Write ## size(var, (uint ## size)(cast)val); \ - } \ - \ - \ - static INLINE out \ - Atomic_ReadWrite ## name(Atomic_ ## name *var, \ - in val) \ - { \ - return (out)(cast)Atomic_ReadWrite ## size(var, \ - (uint ## size)(cast)val); \ - } \ - \ - \ - static INLINE out \ - Atomic_ReadIfEqualWrite ## name(Atomic_ ## name *var, \ - in oldVal, \ - in newVal) \ - { \ - return (out)(cast)Atomic_ReadIfEqualWrite ## size(var, \ - (uint ## size)(cast)oldVal, (uint ## size)(cast)newVal); \ - } \ - \ - \ - static INLINE void \ - Atomic_And ## name(Atomic_ ## name *var, \ - in val) \ - { \ - Atomic_And ## size(var, (uint ## size)(cast)val); \ - } \ - \ - \ - static INLINE void \ - Atomic_Or ## name(Atomic_ ## name *var, \ - in val) \ - { \ - Atomic_Or ## size(var, (uint ## size)(cast)val); \ - } \ - \ - \ - static INLINE void \ - Atomic_Xor ## name(Atomic_ ## name *var, \ - in val) \ - { \ - Atomic_Xor ## size(var, (uint ## size)(cast)val); \ - } \ - \ - \ - static INLINE void \ - Atomic_Add ## name(Atomic_ ## name *var, \ - in val) \ - { \ - Atomic_Add ## size(var, (uint ## size)(cast)val); \ - } \ - \ - \ - static INLINE void \ - Atomic_Sub ## name(Atomic_ ## name *var, \ - in val) \ - { \ - Atomic_Sub ## size(var, (uint ## size)(cast)val); \ - } \ - \ - \ - static INLINE void \ - Atomic_Inc ## name(Atomic_ ## name *var) \ - { \ - Atomic_Inc ## size(var); \ - } \ - \ - \ - static INLINE void \ - Atomic_Dec ## name(Atomic_ ## name *var) \ - { \ - Atomic_Dec ## size(var); \ - } \ - \ - \ - static INLINE out \ - Atomic_ReadOr ## name(Atomic_ ## name *var, \ - in val) \ - { \ - return (out)(cast)Atomic_ReadOr ## size(var, (uint ## size)(cast)val); \ - } \ - \ - \ - static INLINE out \ - Atomic_ReadAdd ## name(Atomic_ ## name *var, \ - in val) \ - { \ - return (out)(cast)Atomic_ReadAdd ## size(var, (uint ## size)(cast)val); \ - } \ - \ - \ - static INLINE out \ - Atomic_ReadInc ## name(Atomic_ ## name *var) \ - { \ - return (out)(cast)Atomic_ReadInc ## size(var); \ - } \ - \ - \ - static INLINE out \ - Atomic_ReadDec ## name(Atomic_ ## name *var) \ - { \ - return (out)(cast)Atomic_ReadDec ## size(var); \ - } - - -/* - * Since we use a macro to generate these definitions, it is hard to look for - * them. So DO NOT REMOVE THIS COMMENT and keep it up-to-date. --hpreg - * - * Atomic_Ptr - * Atomic_ReadPtr -- - * Atomic_WritePtr -- - * Atomic_ReadWritePtr -- - * Atomic_ReadIfEqualWritePtr -- - * Atomic_AndPtr -- - * Atomic_OrPtr -- - * Atomic_XorPtr -- - * Atomic_AddPtr -- - * Atomic_SubPtr -- - * Atomic_IncPtr -- - * Atomic_DecPtr -- - * Atomic_ReadOrPtr -- - * Atomic_ReadAddPtr -- - * Atomic_ReadIncPtr -- - * Atomic_ReadDecPtr -- - * - * Atomic_Int - * Atomic_ReadInt -- - * Atomic_WriteInt -- - * Atomic_ReadWriteInt -- - * Atomic_ReadIfEqualWriteInt -- - * Atomic_AndInt -- - * Atomic_OrInt -- - * Atomic_XorInt -- - * Atomic_AddInt -- - * Atomic_SubInt -- - * Atomic_IncInt -- - * Atomic_DecInt -- - * Atomic_ReadOrInt -- - * Atomic_ReadAddInt -- - * Atomic_ReadIncInt -- - * Atomic_ReadDecInt -- - */ -#if defined(__x86_64__) -MAKE_ATOMIC_TYPE(Ptr, 64, void const *, void *, uintptr_t) -MAKE_ATOMIC_TYPE(Int, 64, int, int, int) -#else -MAKE_ATOMIC_TYPE(Ptr, 32, void const *, void *, uintptr_t) -MAKE_ATOMIC_TYPE(Int, 32, int, int, int) -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Atomic_MFence -- - * - * Implements mfence in terms of a lock xor. The reason for implementing - * our own mfence is that not all of our supported cpus have an assembly - * mfence (P3, Athlon). We put it here to avoid duplicating code which is - * also why it is prefixed with "Atomic_". - * - * Results: - * None. - * - * Side effects: - * Cause loads and stores prior to this to be globally - * visible. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Atomic_MFence(void) -{ - Atomic_uint32 fence; - Atomic_Xor(&fence, 0x1); -} - -#endif // ifndef _ATOMIC_H_ diff -Nrup source/vmnet-only/vm_basic_asm.h source.edited/vmnet-only/vm_basic_asm.h --- source/vmnet-only/vm_basic_asm.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vm_basic_asm.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,832 +0,0 @@ -/********************************************************* - * Copyright (C) 2003 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 - * - *********************************************************/ - -/* - * vm_basic_asm.h - * - * Basic asm macros - */ - -#ifndef _VM_BASIC_ASM_H_ -#define _VM_BASIC_ASM_H_ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_VMMEXT -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMNIXMOD -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_DISTRIBUTE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMIROM -#include "includeCheck.h" - -#include "vm_basic_types.h" -#include "x86cpuid.h" - -#ifdef VM_X86_64 -#include "vm_basic_asm_x86_64.h" -#else -#include "vm_basic_asm_x86.h" -#endif - - -/* - * x86-64 windows doesn't support inline asm so we have to use these - * intrinsic functions defined in the compiler. Not all of these are well - * documented. There is an array in the compiler dll (c1.dll) which has - * an array of the names of all the intrinsics minus the leading - * underscore. Searching around in the ntddk.h file can also be helpful. - * - * The declarations for the intrinsic functions were taken from the DDK. - * Our declarations must match the ddk's otherwise the 64-bit c++ compiler - * will complain about second linkage of the intrinsic functions. - * We define the intrinsic using the basic types corresponding to the - * Windows typedefs. This avoids having to include windows header files - * to get to the windows types. - */ -#ifdef _MSC_VER -#ifdef __cplusplus -extern "C" { -#endif -/* - * It seems x86 & x86-64 windows still implements these intrinsic - * functions. The documentation for the x86-64 suggest the - * __inbyte/__outbyte intrinsics eventhough the _in/_out work fine and - * __inbyte/__outbyte aren't supported on x86. - */ -int _inp(unsigned short); -unsigned short _inpw(unsigned short); -unsigned long _inpd(unsigned short); - -int _outp(unsigned short, int); -unsigned short _outpw(unsigned short, unsigned short); -unsigned long _outpd(uint16, unsigned long); -#pragma intrinsic(_inp, _inpw, _inpd, _outp, _outpw, _outpw, _outpd) -void _ReadWriteBarrier(void); -#pragma intrinsic(_ReadWriteBarrier) - -#ifdef VM_X86_64 -/* - * intrinsic functions only supported by x86-64 windows as of 2k3sp1 - */ -void __cpuid(unsigned int*, unsigned int); -unsigned __int64 __rdtsc(void); -void __stosw(unsigned short*, unsigned short, size_t); -void __stosd(unsigned long*, unsigned long, size_t); -#pragma intrinsic(__cpuid, __rdtsc, __stosw, __stosd) - -/* - * intrinsic functions supported by x86-64 windows and newer x86 - * compilers (13.01.2035 for _BitScanForward). - */ -unsigned char _BitScanForward(unsigned long*, unsigned long); -void _mm_pause(void); -#pragma intrinsic(_BitScanForward, _mm_pause) -#endif /* VM_X86_64 */ - -#ifdef __cplusplus -} -#endif -#endif /* _MSC_VER */ - - -#ifdef __GNUC__ // { - -/* - * Checked against the Intel manual and GCC --hpreg - * - * volatile because reading from port can modify the state of the underlying - * hardware. - * - * Note: The undocumented %z construct doesn't work (internal compiler error) - * with gcc-2.95.1 - */ - -#define __GCC_IN(s, type, name) \ -static INLINE type \ -name(uint16 port) \ -{ \ - type val; \ - \ - __asm__ __volatile__( \ - "in" #s " %w1, %0" \ - : "=a" (val) \ - : "Nd" (port) \ - ); \ - \ - return val; \ -} - -__GCC_IN(b, uint8, INB) -__GCC_IN(w, uint16, INW) -__GCC_IN(l, uint32, IN32) - - -/* - * Checked against the Intel manual and GCC --hpreg - * - * Note: The undocumented %z construct doesn't work (internal compiler error) - * with gcc-2.95.1 - */ - -#define __GCC_OUT(s, s2, port, val) do { \ - __asm__( \ - "out" #s " %" #s2 "1, %w0" \ - : \ - : "Nd" (port), "a" (val) \ - ); \ -} while (0) - -#define OUTB(port, val) __GCC_OUT(b, b, port, val) -#define OUTW(port, val) __GCC_OUT(w, w, port, val) -#define OUT32(port, val) __GCC_OUT(l, , port, val) - - -#define GET_CURRENT_EIP(_eip) \ - __asm__ __volatile("call 0\n\tpopl %0" : "=r" (_eip): ); - - -/* - * Checked against the Intel manual and GCC --hpreg - * - * Need __volatile__ and "memory" since CPUID has a synchronizing effect. - * The CPUID may also change at runtime (APIC flag, etc). - * - */ - -static INLINE void -__GET_CPUID(int eax, // IN - CPUIDRegs *regs) // OUT -{ - __asm__ __volatile__( -#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. - "movl %%ebx, %1" "\n\t" - "cpuid" "\n\t" - "xchgl %%ebx, %1" - : "=a" (regs->eax), "=&rm" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx) -#else - "cpuid" - : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx) -#endif - : "a" (eax) - : "memory" - ); -} - -static INLINE void -__GET_CPUID2(int eax, // IN - int ecx, // IN - CPUIDRegs *regs) // OUT -{ - __asm__ __volatile__( -#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. - "movl %%ebx, %1" "\n\t" - "cpuid" "\n\t" - "xchgl %%ebx, %1" - : "=a" (regs->eax), "=&rm" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx) -#else - "cpuid" - : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx) -#endif - : "a" (eax), "c" (ecx) - : "memory" - ); -} - -static INLINE uint32 -__GET_EAX_FROM_CPUID(int eax) // IN -{ -#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. - uint32 ebx; - - __asm__ __volatile__( - "movl %%ebx, %1" "\n\t" - "cpuid" "\n\t" - "xchgl %%ebx, %1" - : "=a" (eax), "=&rm" (ebx) - : "a" (eax) - : "memory", "%ecx", "%edx" - ); -#else - __asm__ __volatile__( - "cpuid" - : "=a" (eax) - : "a" (eax) - : "memory", "%ebx", "%ecx", "%edx" - ); -#endif - - return eax; -} - -static INLINE uint32 -__GET_EBX_FROM_CPUID(int eax) // IN -{ - uint32 ebx; - - __asm__ __volatile__( -#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. - "movl %%ebx, %1" "\n\t" - "cpuid" "\n\t" - "xchgl %%ebx, %1" - : "=a" (eax), "=&rm" (ebx) -#else - "cpuid" - : "=a" (eax), "=b" (ebx) -#endif - : "a" (eax) - : "memory", "%ecx", "%edx" - ); - - return ebx; -} - -static INLINE uint32 -__GET_ECX_FROM_CPUID(int eax) // IN -{ - uint32 ecx; -#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. - uint32 ebx; - - __asm__ __volatile__( - "movl %%ebx, %1" "\n\t" - "cpuid" "\n\t" - "xchgl %%ebx, %1" - : "=a" (eax), "=&rm" (ebx), "=c" (ecx) - : "a" (eax) - : "memory", "%edx" - ); -#else - - __asm__ __volatile__( - "cpuid" - : "=a" (eax), "=c" (ecx) - : "a" (eax) - : "memory", "%ebx", "%edx" - ); -#endif - - return ecx; -} - -static INLINE uint32 -__GET_EDX_FROM_CPUID(int eax) // IN -{ - uint32 edx; -#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. - uint32 ebx; - - __asm__ __volatile__( - "movl %%ebx, %1" "\n\t" - "cpuid" "\n\t" - "xchgl %%ebx, %1" - : "=a" (eax), "=&rm" (ebx), "=d" (edx) - : "a" (eax) - : "memory", "%ecx" - ); -#else - - __asm__ __volatile__( - "cpuid" - : "=a" (eax), "=d" (edx) - : "a" (eax) - : "memory", "%ebx", "%ecx" - ); -#endif - - return edx; -} - - -static INLINE uint32 -__GET_EAX_FROM_CPUID4(int ecx) // IN -{ - uint32 eax; -#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. - uint32 ebx; - - __asm__ __volatile__( - "movl %%ebx, %1" "\n\t" - "cpuid" "\n\t" - "xchgl %%ebx, %1" - : "=a" (eax), "=&rm" (ebx), "=c" (ecx) - : "a" (4), "c" (ecx) - : "memory", "%edx" - ); -#else - - __asm__ __volatile__( - "cpuid" - : "=a" (eax), "=c" (ecx) - : "a" (4), "c" (ecx) - : "memory", "%ebx", "%edx" - ); -#endif - - return eax; -} - -#elif defined(_MSC_VER) // } { -static INLINE uint8 -INB(uint16 port) -{ - return (uint8)_inp(port); -} -static INLINE void -OUTB(uint16 port, uint8 value) -{ - _outp(port, value); -} -static INLINE uint16 -INW(uint16 port) -{ - return _inpw(port); -} -static INLINE void -OUTW(uint16 port, uint16 value) -{ - _outpw(port, value); -} -static INLINE uint32 -IN32(uint16 port) -{ - return _inpd(port); -} -static INLINE void -OUT32(uint16 port, uint32 value) -{ - _outpd(port, value); -} - -#ifndef VM_X86_64 -#ifdef NEAR -#undef NEAR -#endif - -#define GET_CURRENT_EIP(_eip) do { \ - __asm call NEAR PTR $+5 \ - __asm pop eax \ - __asm mov _eip, eax \ -} while (0) -#endif - -static INLINE void -__GET_CPUID(int input, CPUIDRegs *regs) -{ -#ifdef VM_X86_64 - __cpuid((unsigned int *)regs, input); -#else - __asm push esi - __asm push ebx - __asm push ecx - __asm push edx - - __asm mov eax, input - __asm mov esi, regs - __asm _emit 0x0f __asm _emit 0xa2 - __asm mov 0x0[esi], eax - __asm mov 0x4[esi], ebx - __asm mov 0x8[esi], ecx - __asm mov 0xC[esi], edx - - __asm pop edx - __asm pop ecx - __asm pop ebx - __asm pop esi -#endif -} - -#ifdef VM_X86_64 - -/* - * No inline assembly in Win64. Implemented in bora/lib/user in - * cpuidMasm64.asm. - */ - -extern void -__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs); - -#else // VM_X86_64 - -static INLINE void -__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs) -{ - __asm push esi - __asm push ebx - __asm push ecx - __asm push edx - - __asm mov eax, inputEax - __asm mov ecx, inputEcx - __asm mov esi, regs - __asm _emit 0x0f __asm _emit 0xa2 - __asm mov 0x0[esi], eax - __asm mov 0x4[esi], ebx - __asm mov 0x8[esi], ecx - __asm mov 0xC[esi], edx - - __asm pop edx - __asm pop ecx - __asm pop ebx - __asm pop esi -} -#endif - -static INLINE uint32 -__GET_EAX_FROM_CPUID(int input) -{ -#ifdef VM_X86_64 - CPUIDRegs regs; - __cpuid((unsigned int *)®s, input); - return regs.eax; -#else - uint32 output; - - //NOT_TESTED(); - __asm push ebx - __asm push ecx - __asm push edx - - __asm mov eax, input - __asm _emit 0x0f __asm _emit 0xa2 - __asm mov output, eax - - __asm pop edx - __asm pop ecx - __asm pop ebx - - return output; -#endif -} - -static INLINE uint32 -__GET_EBX_FROM_CPUID(int input) -{ -#ifdef VM_X86_64 - CPUIDRegs regs; - __cpuid((unsigned int *)®s, input); - return regs.ebx; -#else - uint32 output; - - //NOT_TESTED(); - __asm push ebx - __asm push ecx - __asm push edx - - __asm mov eax, input - __asm _emit 0x0f __asm _emit 0xa2 - __asm mov output, ebx - - __asm pop edx - __asm pop ecx - __asm pop ebx - - return output; -#endif -} - -static INLINE uint32 -__GET_ECX_FROM_CPUID(int input) -{ -#ifdef VM_X86_64 - CPUIDRegs regs; - __cpuid((unsigned int *)®s, input); - return regs.ecx; -#else - uint32 output; - - //NOT_TESTED(); - __asm push ebx - __asm push ecx - __asm push edx - - __asm mov eax, input - __asm _emit 0x0f __asm _emit 0xa2 - __asm mov output, ecx - - __asm pop edx - __asm pop ecx - __asm pop ebx - - return output; -#endif -} - -static INLINE uint32 -__GET_EDX_FROM_CPUID(int input) -{ -#ifdef VM_X86_64 - CPUIDRegs regs; - __cpuid((unsigned int *)®s, input); - return regs.edx; -#else - uint32 output; - - //NOT_TESTED(); - __asm push ebx - __asm push ecx - __asm push edx - - __asm mov eax, input - __asm _emit 0x0f __asm _emit 0xa2 - __asm mov output, edx - - __asm pop edx - __asm pop ecx - __asm pop ebx - - return output; -#endif -} - -#ifdef VM_X86_64 - -/* - * No inline assembly in Win64. Implemented in bora/lib/user in - * cpuidMasm64.asm. - */ - -extern uint32 -__GET_EAX_FROM_CPUID4(int inputEcx); - -#else // VM_X86_64 - -static INLINE uint32 -__GET_EAX_FROM_CPUID4(int inputEcx) -{ - uint32 output; - - //NOT_TESTED(); - __asm push ebx - __asm push ecx - __asm push edx - - __asm mov eax, 4 - __asm mov ecx, inputEcx - __asm _emit 0x0f __asm _emit 0xa2 - __asm mov output, eax - - __asm pop edx - __asm pop ecx - __asm pop ebx - - return output; -} - -#endif // VM_X86_64 - -#else // } -#error -#endif - -#define CPUID_FOR_SIDE_EFFECTS() ((void)__GET_EAX_FROM_CPUID(0)) - -static INLINE void -__GET_CPUID4(int inputEcx, CPUIDRegs *regs) -{ - __GET_CPUID2(4, inputEcx, regs); -} - -/* The first parameter is used as an rvalue and then as an lvalue. */ -#define GET_CPUID(_ax, _bx, _cx, _dx) { \ - CPUIDRegs regs; \ - __GET_CPUID(_ax, ®s); \ - _ax = regs.eax; \ - _bx = regs.ebx; \ - _cx = regs.ecx; \ - _dx = regs.edx; \ -} - - -/* Sequence recommended by Intel for the Pentium 4. */ -#define INTEL_MICROCODE_VERSION() ( \ - __SET_MSR(MSR_BIOS_SIGN_ID, 0), \ - __GET_EAX_FROM_CPUID(1), \ - __GET_MSR(MSR_BIOS_SIGN_ID)) - - -#ifdef _MSC_VER -static INLINE int -ffs(uint32 bitVector) -{ - int idx; - if (!bitVector) { - return 0; - } -#ifdef VM_X86_64 - _BitScanForward((unsigned long*)&idx, (unsigned long)bitVector); -#else - __asm bsf eax, bitVector - __asm mov idx, eax -#endif - return idx+1; -} -#endif - -#ifdef __GNUC__ -static INLINE void * -uint16set(void *dst, uint16 val, size_t count) -{ - int dummy0; - int dummy1; - - __asm__ __volatile__("\t" - "cld" "\n\t" - "rep ; stosw" "\n" - : "=c" (dummy0), "=D" (dummy1) - : "0" (count), "1" (dst), "a" (val) - : "memory", "cc" - ); - - return dst; -} - -static INLINE void * -uint32set(void *dst, uint32 val, size_t count) -{ - int dummy0; - int dummy1; - - __asm__ __volatile__("\t" - "cld" "\n\t" - "rep ; stosl" "\n" - : "=c" (dummy0), "=D" (dummy1) - : "0" (count), "1" (dst), "a" (val) - : "memory", "cc" - ); - - return dst; -} - -#elif defined(_MSC_VER) - -static INLINE void * -uint16set(void *dst, uint16 val, size_t count) -{ -#ifdef VM_X86_64 - __stosw((uint16*)dst, val, count); -#else - __asm { pushf; - mov ax, val; - mov ecx, count; - mov edi, dst; - cld; - rep stosw; - popf; - } -#endif - return dst; -} - -static INLINE void * -uint32set(void *dst, uint32 val, size_t count) -{ -#ifdef VM_X86_64 - __stosd((unsigned long*)dst, (unsigned long)val, count); -#else - __asm { pushf; - mov eax, val; - mov ecx, count; - mov edi, dst; - cld; - rep stosd; - popf; - } -#endif - return dst; -} - -#else -#error "No compiler defined for uint*set" -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Bswap -- - * - * Swap the 4 bytes of "v" as follows: 3210 -> 0123. - * - *----------------------------------------------------------------------------- - */ - -#ifdef __GNUC__ // { -static INLINE uint32 -Bswap(uint32 v) -{ - /* Checked against the Intel manual and GCC --hpreg */ - __asm__( - "bswap %0" - : "=r" (v) - : "0" (v) - ); - return v; -} -#endif // } - -#ifdef __GNUC__ // { -/* - * COMPILER_MEM_BARRIER prevents the compiler from re-ordering memory - * references accross the barrier. NOTE: It does not generate any - * instruction, so the CPU is free to do whatever it wants to... - */ -#define COMPILER_MEM_BARRIER() __asm__ __volatile__ ("": : :"memory") -#elif defined(_MSC_VER) // } { -#define COMPILER_MEM_BARRIER() _ReadWriteBarrier() -#endif // } - - -/* - * PAUSE is a P4 instruction that improves spinlock power+performance; - * on non-P4 IA32 systems, the encoding is interpreted as a REPZ-NOP. - * Use volatile to avoid NOP removal. - */ -static INLINE void -PAUSE(void) -#ifdef __GNUC__ -{ - __asm__ __volatile__( "pause" :); -} -#elif defined(_MSC_VER) -#ifdef VM_X86_64 -{ - _mm_pause(); -} -#else /* VM_X86_64 */ -#pragma warning( disable : 4035) -{ - __asm _emit 0xf3 __asm _emit 0x90 -} -#pragma warning (default: 4035) -#endif /* VM_X86_64 */ -#else /* __GNUC__ */ -#error No compiler defined for PAUSE -#endif - - -/* - * Checked against the Intel manual and GCC --hpreg - * - * volatile because the tsc always changes without the compiler knowing it. - */ -static INLINE uint64 -RDTSC(void) -#ifdef __GNUC__ -{ -#ifdef VM_X86_64 - uint64 tscLow; - uint64 tscHigh; - - __asm__ __volatile__( - "rdtsc" - : "=a" (tscLow), "=d" (tscHigh) - ); - - return tscHigh << 32 | tscLow; -#else - uint64 tim; - - __asm__ __volatile__( - "rdtsc" - : "=A" (tim) - ); - - return tim; -#endif -} -#elif defined(_MSC_VER) -#ifdef VM_X86_64 -{ - return __rdtsc(); -} -#else -#pragma warning( disable : 4035) -{ - __asm _emit 0x0f __asm _emit 0x31 -} -#pragma warning (default: 4035) -#endif /* VM_X86_64 */ -#else /* __GNUC__ */ -#error No compiler defined for RDTSC -#endif /* __GNUC__ */ - -#endif diff -Nrup source/vmnet-only/vm_basic_asm_x86_64.h source.edited/vmnet-only/vm_basic_asm_x86_64.h --- source/vmnet-only/vm_basic_asm_x86_64.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vm_basic_asm_x86_64.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,336 +0,0 @@ -/********************************************************* - * Copyright (C) 1998-2004 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 - * - *********************************************************/ - -/* - * vm_basic_asm_x86_64.h - * - * Basic x86_64 asm macros. - */ - -#ifndef _VM_BASIC_ASM_X86_64_H_ -#define _VM_BASIC_ASM_X86_64_H_ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_VMMEXT -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_DISTRIBUTE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMNIXMOD -#include "includeCheck.h" - -#ifndef VM_X86_64 -#error "This file is x86-64 only!" -#endif - -#ifdef _MSC_VER - -#ifdef __cplusplus -extern "C" { -#endif -uint64 _umul128(uint64 multiplier, uint64 multiplicand, - uint64 *highProduct); -int64 _mul128(int64 multiplier, int64 multiplicand, - int64 *highProduct); -uint64 __shiftright128(uint64 lowPart, uint64 highPart, uint8 shift); -#ifdef __cplusplus -} -#endif - -#pragma intrinsic(_umul128, _mul128, __shiftright128) - -#endif // _MSC_VER - -/* - * FXSAVE/FXRSTOR - * save/restore SIMD/MMX fpu state - * - * The pointer passed in must be 16-byte aligned. - * - * Intel and AMD processors behave differently w.r.t. fxsave/fxrstor. Intel - * processors unconditionally save the exception pointer state (instruction - * ptr., data ptr., and error instruction opcode). FXSAVE_ES1 and FXRSTOR_ES1 - * work correctly for Intel processors. - * - * AMD processors only save the exception pointer state if ES=1. This leads to a - * security hole whereby one process/VM can inspect the state of another process - * VM. The AMD recommended workaround involves clobbering the exception pointer - * state unconditionally, and this is implemented in FXRSTOR_AMD_ES0. Note that - * FXSAVE_ES1 will only save the exception pointer state for AMD processors if - * ES=1. - * - * The workaround (FXRSTOR_AMD_ES0) only costs 1 cycle more than just doing an - * fxrstor, on both AMD Opteron and Intel Core CPUs. - */ -#if defined(__GNUC__) - -static INLINE void -FXSAVE_ES1(uint8 *save) -{ - __asm__ __volatile__ ("fxsaveq %0 \n" : "=m" (*save) : : "memory"); -} - -static INLINE void -FXSAVE_COMPAT_ES1(uint8 *save) -{ - __asm__ __volatile__ ("fxsave %0 \n" : "=m" (*save) : : "memory"); -} - -static INLINE void -FXRSTOR_ES1(const uint8 *load) -{ - __asm__ __volatile__ ("fxrstorq %0 \n" : : "m" (*load) : "memory"); -} - -static INLINE void -FXRSTOR_COMPAT_ES1(const uint8 *load) -{ - __asm__ __volatile__ ("fxrstor %0 \n" : : "m" (*load) : "memory"); -} - -static INLINE void -FXRSTOR_AMD_ES0(const uint8 *load) -{ - uint64 dummy = 0; - - __asm__ __volatile__ - ("fnstsw %%ax \n" // Grab x87 ES bit - "bt $7,%%ax \n" // Test ES bit - "jnc 1f \n" // Jump if ES=0 - "fnclex \n" // ES=1. Clear it so fild doesn't trap - "1: \n" - "ffree %%st(7) \n" // Clear tag bit - avoid poss. stack overflow - "fildl %0 \n" // Dummy Load from "safe address" changes all - // x87 exception pointers. - "fxrstorq %1 \n" - : - : "m" (dummy), "m" (*load) - : "ax", "memory"); -} - -#endif /* __GNUC__ */ - - -/* - *----------------------------------------------------------------------------- - * - * Mul64x3264 -- - * - * Unsigned integer by fixed point multiplication: - * result = multiplicand * multiplier >> shift - * - * Unsigned 64-bit integer multiplicand. - * Unsigned 32-bit fixed point multiplier, represented as - * multiplier >> shift, where shift < 64. - * Unsigned 64-bit integer product. - * - * Implementation: - * Multiply 64x64 bits to yield a full 128-bit product. - * Shift result in RDX:RAX right by "shift". - * Return the low-order 64 bits of the above. - * - * Result: - * Product - * - *----------------------------------------------------------------------------- - */ - -#if defined(__GNUC__) - -static INLINE uint64 -Mul64x3264(uint64 multiplicand, - uint32 multiplier, - uint32 shift) -{ - uint64 result, dummy; - const uint64 multiplier64 = multiplier; - - asm("mulq %3 \n\t" - "shrdq %1, %0 \n\t" - : "=a" (result), - "=d" (dummy) - : "0" (multiplier64), - "rm" (multiplicand), - "c" (shift) - : "cc"); - return result; -} - -#elif defined(_MSC_VER) - -static INLINE uint64 -Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) -{ - uint64 tmplo, tmphi; - tmplo = _umul128(multiplicand, multiplier, &tmphi); - return __shiftright128(tmplo, tmphi, (uint8) shift); -} - -#endif - -/* - *----------------------------------------------------------------------------- - * - * Muls64x32s64 -- - * - * Signed integer by fixed point multiplication: - * result = multiplicand * multiplier >> shift - * - * Signed 64-bit integer multiplicand. - * Unsigned 32-bit fixed point multiplier, represented as - * multiplier >> shift, where shift < 64. - * Signed 64-bit integer product. - * - * Implementation: - * Multiply 64x64 bits to yield a full 128-bit product. - * Shift result in RDX:RAX right by "shift". - * Return the low-order 64 bits of the above. - * - * Note: using an unsigned shift instruction is correct because - * shift < 64 and we return only the low 64 bits of the shifted - * result. - * - * Result: - * Product - * - *----------------------------------------------------------------------------- - */ - -#if defined(__GNUC__) - -static inline int64 -Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) -{ - int64 result, dummy; - const int64 multiplier64 = multiplier; - - asm("imulq %3 \n\t" - "shrdq %1, %0 \n\t" - : "=a" (result), - "=d" (dummy) - : "0" (multiplier64), - "rm" (multiplicand), - "c" (shift) - : "cc"); - return result; -} - -#elif defined(_MSC_VER) - -static INLINE int64 -Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) -{ - int64 tmplo, tmphi; - tmplo = _mul128(multiplicand, multiplier, &tmphi); - return __shiftright128(tmplo, tmphi, (uint8) shift); -} - -#endif - - -#if defined(__GNUC__) - -static INLINE void * -uint64set(void *dst, uint64 val, uint64 count) -{ - int dummy0; - int dummy1; - __asm__ __volatile__("\t" - "cld" "\n\t" - "rep ; stosq" "\n" - : "=c" (dummy0), "=D" (dummy1) - : "0" (count), "1" (dst), "a" (val) - : "memory", "cc"); - return dst; -} - -#endif - -/* - *----------------------------------------------------------------------------- - * - * Div643232 -- - * - * Unsigned integer division: - * The dividend is 64-bit wide - * The divisor is 32-bit wide - * The quotient is 32-bit wide - * - * Use this function if you are certain that the quotient will fit in 32 bits, - * If that is not the case, a #DE exception was generated in 32-bit version, - * but not in this 64-bit version. So please be careful. - * - * Results: - * Quotient and remainder - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -#if defined(__GNUC__) || defined(_MSC_VER) - -static INLINE void -Div643232(uint64 dividend, // IN - uint32 divisor, // IN - uint32 *quotient, // OUT - uint32 *remainder) // OUT -{ - *quotient = (uint32)(dividend / divisor); - *remainder = (uint32)(dividend % divisor); -} - -#endif - -/* - *----------------------------------------------------------------------------- - * - * Div643264 -- - * - * Unsigned integer division: - * The dividend is 64-bit wide - * The divisor is 32-bit wide - * The quotient is 64-bit wide - * - * Results: - * Quotient and remainder - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -#if defined(__GNUC__) - -static INLINE void -Div643264(uint64 dividend, // IN - uint32 divisor, // IN - uint64 *quotient, // OUT - uint32 *remainder) // OUT -{ - *quotient = dividend / divisor; - *remainder = dividend % divisor; -} - -#endif - -#endif // _VM_BASIC_ASM_X86_64_H_ diff -Nrup source/vmnet-only/vm_basic_asm_x86.h source.edited/vmnet-only/vm_basic_asm_x86.h --- source/vmnet-only/vm_basic_asm_x86.h 2010-05-09 20:08:42.000000000 -0700 +++ source.edited/vmnet-only/vm_basic_asm_x86.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,500 +0,0 @@ -/********************************************************* - * Copyright (C) 1998-2003 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 - * - *********************************************************/ - -/* - * vm_basic_asm_x86.h - * - * Basic IA32 asm macros - */ - -#ifndef _VM_BASIC_ASM_X86_H_ -#define _VM_BASIC_ASM_X86_H_ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_VMMEXT -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMNIXMOD -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_DISTRIBUTE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMIROM -#include "includeCheck.h" - -#ifdef VM_X86_64 -/* - * The gcc inline asm uses the "A" constraint which differs in 32 & 64 - * bit mode. 32 bit means eax and edx, 64 means rax or rdx. - */ -#error "x86-64 not supported" -#endif - - - - -/* - * from linux: usr/include/asm/io.h - */ -#ifdef __GNUC__ -#ifndef __SLOW_DOWN_IO -#ifdef SLOW_IO_BY_JUMPING -#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") -#else -#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") -#endif -#endif -#elif defined(_MSC_VER) -#ifdef SLOW_IO_BY_JUMPING -#define __SLOW_DOWN_IO __asm jmp SHORT $+2 __asm jmp SHORT $+2 -#else -#define __SLOW_DOWN_IO __asm out 80h,al -#endif -#else -#error -#endif - -#ifdef REALLY_SLOW_IO -#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; } -#else -#define SLOW_DOWN_IO __SLOW_DOWN_IO -#endif - -/* - * FXSAVE/FXRSTOR - * save/restore SIMD/MMX fpu state - * - * The pointer passed in must be 16-byte aligned. - * - * Intel and AMD processors behave differently w.r.t. fxsave/fxrstor. Intel - * processors unconditionally save the exception pointer state (instruction - * ptr., data ptr., and error instruction opcode). FXSAVE_ES1 and FXRSTOR_ES1 - * work correctly for Intel processors. - * - * AMD processors only save the exception pointer state if ES=1. This leads to a - * security hole whereby one process/VM can inspect the state of another process - * VM. The AMD recommended workaround involves clobbering the exception pointer - * state unconditionally, and this is implemented in FXRSTOR_AMD_ES0. Note that - * FXSAVE_ES1 will only save the exception pointer state for AMD processors if - * ES=1. - * - * The workaround (FXRSTOR_AMD_ES0) only costs 1 cycle more than just doing an - * fxrstor, on both AMD Opteron and Intel Core CPUs. - */ -#if defined(__GNUC__) -static INLINE void -FXSAVE_ES1(uint8 *save) -{ - __asm__ __volatile__ ("fxsave %0\n" : "=m" (*save) : : "memory"); -} - -static INLINE void -FXRSTOR_ES1(const uint8 *load) -{ - __asm__ __volatile__ ("fxrstor %0\n" : : "m" (*load) : "memory"); -} - -static INLINE void -FXRSTOR_AMD_ES0(const uint8 *load) -{ - uint64 dummy = 0; - - __asm__ __volatile__ - ("fnstsw %%ax \n" // Grab x87 ES bit - "bt $7,%%ax \n" // Test ES bit - "jnc 1f \n" // Jump if ES=0 - "fnclex \n" // ES=1. Clear it so fild doesn't trap - "1: \n" - "ffree %%st(7) \n" // Clear tag bit - avoid poss. stack overflow - "fildl %0 \n" // Dummy Load from "safe address" changes all - // x87 exception pointers. - "fxrstor %1 \n" - : - : "m" (dummy), "m" (*load) - : "ax", "memory"); -} -#endif /* __GNUC__ */ - -/* - *----------------------------------------------------------------------------- - * - * Div643232 -- - * - * Unsigned integer division: - * The dividend is 64-bit wide - * The divisor is 32-bit wide - * The quotient is 32-bit wide - * - * Use this function if you are certain that: - * o Either the quotient will fit in 32 bits, - * o Or your code is ready to handle a #DE exception indicating overflow. - * If that is not the case, then use Div643264(). --hpreg - * - * Results: - * Quotient and remainder - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -#if defined(__GNUC__) - -static INLINE void -Div643232(uint64 dividend, // IN - uint32 divisor, // IN - uint32 *quotient, // OUT - uint32 *remainder) // OUT -{ - /* Checked against the Intel manual and GCC --hpreg */ - __asm__( - "divl %4" - : "=a" (*quotient), - "=d" (*remainder) - : "0" ((uint32)dividend), - "1" ((uint32)(dividend >> 32)), - "rm" (divisor) - : "cc" - ); -} - -#elif defined(_MSC_VER) - -static INLINE void -Div643232(uint64 dividend, // IN - uint32 divisor, // IN - uint32 *quotient, // OUT - uint32 *remainder) // OUT -{ - /* Written and tested by mann, checked by dbudko and hpreg */ - __asm { - mov eax, DWORD PTR [dividend] - mov edx, DWORD PTR [dividend+4] - div DWORD PTR [divisor] - mov edi, DWORD PTR [quotient] - mov [edi], eax - mov edi, DWORD PTR [remainder] - mov [edi], edx - } -} - -#else -#error No compiler defined for Div643232 -#endif - - -#if defined(__GNUC__) -/* - *----------------------------------------------------------------------------- - * - * Div643264 -- - * - * Unsigned integer division: - * The dividend is 64-bit wide - * The divisor is 32-bit wide - * The quotient is 64-bit wide --hpreg - * - * Results: - * Quotient and remainder - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -Div643264(uint64 dividend, // IN - uint32 divisor, // IN - uint64 *quotient, // OUT - uint32 *remainder) // OUT -{ - uint32 hQuotient; - uint32 lQuotient; - - /* Checked against the Intel manual and GCC --hpreg */ - __asm__( - "divl %5" "\n\t" - "movl %%eax, %0" "\n\t" - "movl %4, %%eax" "\n\t" - "divl %5" - : "=&rm" (hQuotient), - "=a" (lQuotient), - "=d" (*remainder) - : "1" ((uint32)(dividend >> 32)), - "g" ((uint32)dividend), - "rm" (divisor), - "2" (0) - : "cc" - ); - *quotient = (uint64)hQuotient << 32 | lQuotient; -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * Mul64x3264 -- - * - * Unsigned integer by fixed point multiplication: - * Unsigned 64-bit integer multiplicand. - * Unsigned 32-bit fixed point multiplier, represented as - * multiplier >> shift, where shift < 64. - * Unsigned 64-bit integer product. - * - * Implementation: - * Multiply 64x32 bits to yield a full 96-bit product. - * Shift right by shift. - * Return the low-order 64 bits of the result. - * - * Result: - * Product - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -#if defined(__GNUC__) - -static INLINE uint64 -Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) -{ - uint64 result; - uint32 tmp1, tmp2; - // ASSERT(shift >= 0 && shift < 64); - - /* - * Written and tested by mann, improved with suggestions by hpreg. - * - * The main improvement over the previous version is that the test - * of shift against 32 is moved out of the asm and into C code. - * This lets the compiler delete the test and one of the - * alternative code sequences in the case where shift is a - * constant. It also lets us use the best code sequence in each - * alternative, rather than a compromise. The downside is that in - * the non-constant case, this version takes slightly more code - * space. - * - * Note on the constraints: We don't really want multiplicand to - * start in %edx:%eax as the =A constraint dictates; in fact, we'd - * prefer any *other* two registers. But gcc doesn't have - * constraint syntax for any other register pair, and trying to - * constrain ((uint32) multiplicand) to one place and (multiplicand - * >> 32) to another generates *really* bad code -- gcc is just not - * smart enough, at least in the version we are currently using. - */ - if (shift < 32) { - asm("mov %%eax, %2 \n\t" // Save lo(multiplicand) in tmp2 - "mov %%edx, %%eax \n\t" // Get hi(multiplicand) - "mull %4 \n\t" // p2 = hi(multiplicand) * multiplier - "xchg %%eax, %2 \n\t" // Save lo(p2) in tmp2, get lo(multiplicand) - "mov %%edx, %1 \n\t" // Save hi(p2) in tmp1 - "mull %4 \n\t" // p1 = lo(multiplicand) * multiplier - "addl %2, %%edx \n\t" // hi(p1) += lo(p2) - "adcl $0, %1 \n\t" // hi(p2) += carry from previous step - "shrdl %%edx, %%eax \n\t" // result = hi(p2):hi(p1):lo(p1) >> shift - "shrdl %1, %%edx" - : "=A" (result), - "=&r" (tmp1), // use in shrdl requires it to be a register - "=&r" (tmp2) // could be "=&rm" but "m" is slower - : "0" (multiplicand), - "rm" (multiplier), - "c" (shift) - : "cc" - ); - } else { - asm("mov %%edx, %2 \n\t" // Save hi(multiplicand) in tmp2 - "mull %4 \n\t" // p1 = lo(multiplicand) * multiplier - "mov %%edx, %1 \n\t" // Save hi(p1) in tmp1 - "mov %2, %%eax \n\t" // Discard lo(p1), get hi(multiplicand) - "mull %4 \n\t" // p2 = hi(multiplicand) * multiplier - "addl %1, %%eax \n\t" // lo(p2) += hi(p1) - "adcl $0, %%edx \n\t" // hi(p2) += carry from previous step - "shrdl %%edx, %%eax \n\t" // result = p2 >> (shift & 31) - "shrl %%cl, %%edx" - : "=A" (result), - "=&r" (tmp1), // could be "=&rm" but "m" is slower - "=&r" (tmp2) // could be "=&rm" but "m" is slower - : "0" (multiplicand), - "rm" (multiplier), - "c" (shift) - : "cc" - ); - } - return result; -} - -#elif defined(_MSC_VER) -#pragma warning(disable: 4035) - -static INLINE uint64 -Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) -{ - // ASSERT(shift >= 0 && shift < 64); - - /* Written and tested by mann, checked by dbudko and hpreg */ - __asm { - mov eax, DWORD PTR [multiplicand+4] // Get hi(multiplicand) - mul DWORD PTR [multiplier] // p2 = hi(multiplicand) * multiplier - mov ecx, eax // Save lo(p2) - mov ebx, edx // Save hi(p2) - mov eax, DWORD PTR [multiplicand] // Get lo(multiplicand) - mul DWORD PTR [multiplier+0] // p1 = lo(multiplicand) * multiplier - add edx, ecx // hi(p1) += lo(p2) - adc ebx, 0 // hi(p2) += carry from previous step - mov ecx, DWORD PTR [shift] // Get shift - cmp ecx, 32 // shift < 32? - jl SHORT l2 // Go if so - mov eax, edx // result = hi(p2):hi(p1) >> (shift & 31) - mov edx, ebx - shrd eax, edx, cl - shr edx, cl - jmp SHORT l3 - l2: - shrd eax, edx, cl // result = hi(p2):hi(p1):lo(p1) >> shift - shrd edx, ebx, cl - l3: - } - // return with result in edx:eax -} - -#pragma warning(default: 4035) -#else -#error No compiler defined for Mul64x3264 -#endif - -/* - *----------------------------------------------------------------------------- - * - * Muls64x32s64 -- - * - * Signed integer by fixed point multiplication: - * Signed 64-bit integer multiplicand. - * Unsigned 32-bit fixed point multiplier, represented as - * multiplier >> shift, where shift < 64. - * Signed 64-bit integer product. - * - * Implementation: - * Multiply 64x32 bits to yield a full 96-bit product. - * Shift right by the location of the binary point. - * Return the low-order 64 bits of the result. - * - * Result: - * Product - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -#if defined(__GNUC__) - -static INLINE int64 -Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) -{ - int64 result; - uint32 tmp1, tmp2; - // ASSERT(shift >= 0 && shift < 64); - - /* Written and tested by mann, checked by dbudko and hpreg */ - /* XXX hpreg suggested some improvements that we haven't converged on yet */ - asm("mov %%eax, %2\n\t" // Save lo(multiplicand) - "mov %%edx, %%eax\n\t" // Get hi(multiplicand) - "test %%eax, %%eax\n\t" // Check sign of multiplicand - "jl 0f\n\t" // Go if negative - "mull %4\n\t" // p2 = hi(multiplicand) * multiplier - "jmp 1f\n" - "0:\n\t" - "mull %4\n\t" // p2 = hi(multiplicand) * multiplier - "sub %4, %%edx\n" // hi(p2) += -1 * multiplier - "1:\n\t" - "xchg %%eax, %2\n\t" // Save lo(p2), get lo(multiplicand) - "mov %%edx, %1\n\t" // Save hi(p2) - "mull %4\n\t" // p1 = lo(multiplicand) * multiplier - "addl %2, %%edx\n\t" // hi(p1) += lo(p2) - "adcl $0, %1\n\t" // hi(p2) += carry from previous step - "cmpl $32, %%ecx\n\t" // shift < 32? - "jl 2f\n\t" // Go if so - "mov %%edx, %%eax\n\t" // result = hi(p2):hi(p1) >> (shift & 31) - "mov %1, %%edx\n\t" - "shrdl %%edx, %%eax\n\t" - "sarl %%cl, %%edx\n\t" - "jmp 3f\n" - "2:\n\t" - "shrdl %%edx, %%eax\n\t" // result = hi(p2):hi(p1):lo(p1) >> shift - "shrdl %1, %%edx\n" - "3:\n\t" - : "=A" (result), "=&r" (tmp1), "=&r" (tmp2) - : "0" (multiplicand), "rm" (multiplier), "c" (shift) - : "cc"); - return result; -} - -#elif defined(_MSC_VER) -#pragma warning(disable: 4035) - -static INLINE int64 -Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) -{ - //ASSERT(shift >= 0 && shift < 64); - - /* Written and tested by mann, checked by dbudko and hpreg */ - __asm { - mov eax, DWORD PTR [multiplicand+4] // Get hi(multiplicand) - test eax, eax // Check sign of multiplicand - jl SHORT l0 // Go if negative - mul DWORD PTR [multiplier] // p2 = hi(multiplicand) * multiplier - jmp SHORT l1 - l0: - mul DWORD PTR [multiplier] // p2 = hi(multiplicand) * multiplier - sub edx, DWORD PTR [multiplier] // hi(p2) += -1 * multiplier - l1: - mov ecx, eax // Save lo(p2) - mov ebx, edx // Save hi(p2) - mov eax, DWORD PTR [multiplicand] // Get lo(multiplicand) - mul DWORD PTR [multiplier] // p1 = lo(multiplicand) * multiplier - add edx, ecx // hi(p1) += lo(p2) - adc ebx, 0 // hi(p2) += carry from previous step - mov ecx, DWORD PTR [shift] // Get shift - cmp ecx, 32 // shift < 32? - jl SHORT l2 // Go if so - mov eax, edx // result = hi(p2):hi(p1) >> (shift & 31) - mov edx, ebx - shrd eax, edx, cl - sar edx, cl - jmp SHORT l3 - l2: - shrd eax, edx, cl // result = hi(p2):hi(p1):lo(p1) << shift - shrd edx, ebx, cl - l3: - } - // return with result in edx:eax -} - -#pragma warning(default: 4035) -#else -#error No compiler defined for Muls64x32s64 -#endif - - -#endif diff -Nrup source/vmnet-only/vm_basic_defs.h source.edited/vmnet-only/vm_basic_defs.h --- source/vmnet-only/vm_basic_defs.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vm_basic_defs.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,570 +0,0 @@ -/********************************************************* - * Copyright (C) 2003 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 - * - *********************************************************/ - -/* - * vm_basic_defs.h -- - * - * Standard macros for VMware source code. - */ - -#ifndef _VM_BASIC_DEFS_H_ -#define _VM_BASIC_DEFS_H_ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_VMMEXT -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMNIXMOD -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_VMKDRIVERS -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_DISTRIBUTE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMIROM -#include "includeCheck.h" -#include "vm_basic_types.h" // For INLINE. - -#if defined _WIN32 && defined USERLEVEL - #include /* - * We re-define offsetof macro from stddef, make - * sure that its already defined before we do it - */ - #include // for Sleep() and LOWORD() etc. -#endif - - -/* - * Simple macros - */ - -#if defined __APPLE__ && !defined KERNEL -# include -#else -// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning -// XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings -#ifndef offsetof -#ifdef __cplusplus -#define offsetof(s,m) (size_t)&(((s *)0)->m) -#else -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif -#endif -#endif // __APPLE__ - -#ifndef ARRAYSIZE -#define ARRAYSIZE(a) (sizeof (a) / sizeof *(a)) -#endif - -#ifndef MIN -#define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) -#endif - -/* The Solaris 9 cross-compiler complains about these not being used */ -#ifndef sun -static INLINE int -Min(int a, int b) -{ - return a < b ? a : b; -} -#endif - -#ifndef MAX -#define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) -#endif - -#ifndef sun -static INLINE int -Max(int a, int b) -{ - return a > b ? a : b; -} -#endif - -#define ROUNDUP(x,y) (((x) + (y) - 1) / (y) * (y)) -#define ROUNDDOWN(x,y) ((x) / (y) * (y)) -#define ROUNDUPBITS(x, bits) (((uintptr_t) (x) + MASK(bits)) & ~MASK(bits)) -#define ROUNDDOWNBITS(x, bits) ((uintptr_t) (x) & ~MASK(bits)) -#define CEILING(x, y) (((x) + (y) - 1) / (y)) -#if defined __APPLE__ -#include -#undef MASK -#endif -#define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */ -#define DWORD_ALIGN(x) ((((x)+3) >> 2) << 2) -#define QWORD_ALIGN(x) ((((x)+4) >> 3) << 3) - -#define IMPLIES(a,b) (!(a) || (b)) - -/* - * Not everybody (e.g., the monitor) has NULL - */ - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - - -/* - * Token concatenation - * - * The C preprocessor doesn't prescan arguments when they are - * concatenated or stringified. So we need extra levels of - * indirection to convince the preprocessor to expand its - * arguments. - */ - -#define CONC(x, y) x##y -#define XCONC(x, y) CONC(x, y) -#define XXCONC(x, y) XCONC(x, y) -#define MAKESTR(x) #x -#define XSTR(x) MAKESTR(x) - - -/* - * Page operations - * - * It has been suggested that these definitions belong elsewhere - * (like x86types.h). However, I deem them common enough - * (since even regular user-level programs may want to do - * page-based memory manipulation) to be here. - * -- edward - */ - -#ifndef PAGE_SHIFT // { -#if defined VM_I386 - #define PAGE_SHIFT 12 -#elif defined __APPLE__ - #define PAGE_SHIFT 12 -#else - #error -#endif -#endif // } - -#ifndef PAGE_SIZE -#define PAGE_SIZE (1<> PAGE_SHIFT) -#endif - -#ifndef BYTES_2_PAGES -#define BYTES_2_PAGES(_nbytes) ((_nbytes) >> PAGE_SHIFT) -#endif - -#ifndef PAGES_2_BYTES -#define PAGES_2_BYTES(_npages) (((uint64)(_npages)) << PAGE_SHIFT) -#endif - -#ifndef MBYTES_2_PAGES -#define MBYTES_2_PAGES(_nbytes) ((_nbytes) << (20 - PAGE_SHIFT)) -#endif - -#ifndef PAGES_2_MBYTES -#define PAGES_2_MBYTES(_npages) ((_npages) >> (20 - PAGE_SHIFT)) -#endif - -#ifndef VM_PAE_LARGE_PAGE_SHIFT -#define VM_PAE_LARGE_PAGE_SHIFT 21 -#endif - -#ifndef VM_PAE_LARGE_PAGE_SIZE -#define VM_PAE_LARGE_PAGE_SIZE (1 << VM_PAE_LARGE_PAGE_SHIFT) -#endif - -#ifndef VM_PAE_LARGE_PAGE_MASK -#define VM_PAE_LARGE_PAGE_MASK (VM_PAE_LARGE_PAGE_SIZE - 1) -#endif - -#ifndef VM_PAE_LARGE_2_SMALL_PAGES -#define VM_PAE_LARGE_2_SMALL_PAGES (BYTES_2_PAGES(VM_PAE_LARGE_PAGE_SIZE)) -#endif - -/* - * Word operations - */ - -#ifndef LOWORD -#define LOWORD(_dw) ((_dw) & 0xffff) -#endif -#ifndef HIWORD -#define HIWORD(_dw) (((_dw) >> 16) & 0xffff) -#endif - -#ifndef LOBYTE -#define LOBYTE(_w) ((_w) & 0xff) -#endif -#ifndef HIBYTE -#define HIBYTE(_w) (((_w) >> 8) & 0xff) -#endif - -#define HIDWORD(_qw) ((uint32)((_qw) >> 32)) -#define LODWORD(_qw) ((uint32)(_qw)) -#define QWORD(_hi, _lo) ((((uint64)(_hi)) << 32) | ((uint32)(_lo))) - - -/* - * Deposit a field _src at _pos bits from the right, - * with a length of _len, into the integer _target. - */ - -#define DEPOSIT_BITS(_src,_pos,_len,_target) { \ - unsigned mask = ((1 << _len) - 1); \ - unsigned shiftedmask = ((1 << _len) - 1) << _pos; \ - _target = (_target & ~shiftedmask) | ((_src & mask) << _pos); \ -} - - -/* - * Get return address. - */ - -#ifdef _MSC_VER -#ifdef __cplusplus -extern "C" -#endif -void *_ReturnAddress(void); -#pragma intrinsic(_ReturnAddress) -#define GetReturnAddress() _ReturnAddress() -#elif __GNUC__ -#define GetReturnAddress() __builtin_return_address(0) -#endif - - -#ifdef __GNUC__ -#ifndef sun - -/* - * Get the frame pointer. We use this assembly hack instead of - * __builtin_frame_address() due to a bug introduced in gcc 4.1.1 - */ -static INLINE_SINGLE_CALLER uintptr_t -GetFrameAddr(void) -{ - uintptr_t bp; -#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0)) - bp = (uintptr_t)__builtin_frame_address(0); -#elif (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 3) -# if defined(VMM64) || defined(VM_X86_64) - __asm__ __volatile__("movq %%rbp, %0\n" : "=g" (bp)); -# else - __asm__ __volatile__("movl %%ebp, %0\n" : "=g" (bp)); -# endif -#else - __asm__ __volatile__( -#ifdef __linux__ - ".print \"This newer version of GCC may or may not have the " - "__builtin_frame_address bug. Need to update this. " - "See bug 147638.\"\n" - ".abort" -#else /* MacOS */ - ".abort \"This newer version of GCC may or may not have the " - "__builtin_frame_address bug. Need to update this. " - "See bug 147638.\"\n" -#endif - : "=g" (bp) - ); -#endif - return bp; -} - - -/* - * Returns the frame pointer of the calling function. - * Equivalent to __builtin_frame_address(1). - */ -static INLINE_SINGLE_CALLER uintptr_t -GetCallerFrameAddr(void) -{ - return *(uintptr_t*)GetFrameAddr(); -} - -#endif // sun -#endif // __GNUC__ - - - - -#ifdef USERLEVEL // { - -/* - * Note this might be a problem on NT b/c while sched_yield guarantees it - * moves you to the end of your priority list, Sleep(0) offers no such - * guarantee. Bummer. --Jeremy. - */ - -#if defined(N_PLAT_NLM) || defined(__FreeBSD__) -/* We do not have YIELD() as we do not need it yet... */ -#elif defined(_WIN32) -# define YIELD() Sleep(0) -#else -# include // For sched_yield. Don't ask. --Jeremy. -# define YIELD() sched_yield() -#endif - - -/* - * Standardize some Posix names on Windows. - */ - -#ifdef _WIN32 // { - -#define snprintf _snprintf -#define vsnprintf _vsnprintf - -static INLINE void -sleep(unsigned int sec) -{ - Sleep(sec * 1000); -} - -static INLINE void -usleep(unsigned long usec) -{ - Sleep(CEILING(usec, 1000)); -} - -typedef int pid_t; -#define F_OK 0 -#define X_OK 1 -#define W_OK 2 -#define R_OK 4 - -#endif // } - -/* - * Macro for username comparison. - */ - -#ifdef _WIN32 // { -#define USERCMP(x,y) Str_Strcasecmp(x,y) -#else -#define USERCMP(x,y) strcmp(x,y) -#endif // } - - -#endif // } - -#ifndef va_copy - -#ifdef _WIN32 - -/* - * Windows needs va_copy. This works for both 32 and 64-bit Windows - * based on inspection of how varags.h from the Visual C CRTL is - * implemented. (Future versions of the RTL may break this). - */ - -#define va_copy(dest, src) ((dest) = (src)) - -#elif defined(__APPLE__) && defined(KERNEL) - -/* - * MacOS kernel-mode needs va_copy. Based on inspection of stdarg.h - * from the MacOSX10.4u.sdk kernel framework, this should work. - * (Future versions of the SDK may break this). - */ - -#define va_copy(dest, src) ((dest) = (src)) - -#elif defined(__GNUC__) && (__GNUC__ < 3) - -/* - * Old versions of gcc recognize __va_copy, but not va_copy. - */ - -#define va_copy(dest, src) __va_copy(dest, src) - -#endif // _WIN32 - -#endif // va_copy - -/* - * This one is outside USERLEVEL because it's used by - * files compiled into the Windows hgfs driver or the display - * driver. - */ - -#ifdef _WIN32 -#define PATH_MAX 256 -#ifndef strcasecmp -#define strcasecmp(_s1,_s2) _stricmp((_s1),(_s2)) -#endif -#ifndef strncasecmp -#define strncasecmp(_s1,_s2,_n) _strnicmp((_s1),(_s2),(_n)) -#endif -#endif - -/* - * Convenience macro for COMMUNITY_SOURCE - */ -#undef EXCLUDE_COMMUNITY_SOURCE -#ifdef COMMUNITY_SOURCE - #define EXCLUDE_COMMUNITY_SOURCE(x) -#else - #define EXCLUDE_COMMUNITY_SOURCE(x) x -#endif - -#undef COMMUNITY_SOURCE_INTEL_SECRET -#if !defined(COMMUNITY_SOURCE) || defined(INTEL_SOURCE) -/* - * It's ok to include INTEL_SECRET source code for non-commsrc, - * or for drops directed at Intel. - */ - #define COMMUNITY_SOURCE_INTEL_SECRET -#endif - -/* - * Convenience macros and definitions. Can often be used instead of #ifdef. - */ - -#undef DEBUG_ONLY -#undef SL_DEBUG_ONLY -#undef VMX86_SL_DEBUG -#ifdef VMX86_DEBUG -#define vmx86_debug 1 -#define DEBUG_ONLY(x) x -/* - * Be very, very, very careful with SL_DEBUG. Pls ask ganesh or min before - * using it. - */ -#define VMX86_SL_DEBUG -#define vmx86_sl_debug 1 -#define SL_DEBUG_ONLY(x) x -#else -#define vmx86_debug 0 -#define DEBUG_ONLY(x) -#define vmx86_sl_debug 0 -#define SL_DEBUG_ONLY(x) -#endif - -#ifdef VMX86_STATS -#define vmx86_stats 1 -#define STATS_ONLY(x) x -#else -#define vmx86_stats 0 -#define STATS_ONLY(x) -#endif - -#ifdef VMX86_DEVEL -#define vmx86_devel 1 -#define DEVEL_ONLY(x) x -#else -#define vmx86_devel 0 -#define DEVEL_ONLY(x) -#endif - -#ifdef VMX86_LOG -#define vmx86_log 1 -#define LOG_ONLY(x) x -#else -#define vmx86_log 0 -#define LOG_ONLY(x) -#endif - -#ifdef VMX86_VMM_SERIAL_LOGGING -#define vmx86_vmm_serial_log 1 -#define VMM_SERIAL_LOG_ONLY(x) x -#else -#define vmx86_vmm_serial_log 0 -#define VMM_SERIAL_LOG_ONLY(x) -#endif - -#ifdef VMX86_SERVER -#define vmx86_server 1 -#define SERVER_ONLY(x) x -#define HOSTED_ONLY(x) -#else -#define vmx86_server 0 -#define SERVER_ONLY(x) -#define HOSTED_ONLY(x) x -#endif - -#ifdef VMX86_WGS -#define vmx86_wgs 1 -#define WGS_ONLY(x) x -#else -#define vmx86_wgs 0 -#define WGS_ONLY(x) -#endif - -#ifdef VMKERNEL -#define vmkernel 1 -#define VMKERNEL_ONLY(x) x -#else -#define vmkernel 0 -#define VMKERNEL_ONLY(x) -#endif - -#ifdef _WIN32 -#define WIN32_ONLY(x) x -#define POSIX_ONLY(x) -#else -#define WIN32_ONLY(x) -#define POSIX_ONLY(x) x -#endif - -#ifdef VMM -#define VMM_ONLY(x) x -#define USER_ONLY(x) -#else -#define VMM_ONLY(x) -#define USER_ONLY(x) x -#endif - -/* VMVISOR ifdef only allowed in the vmkernel */ -#ifdef VMKERNEL -#ifdef VMVISOR -#define vmvisor 1 -#define VMVISOR_ONLY(x) x -#else -#define vmvisor 0 -#define VMVISOR_ONLY(x) -#endif -#endif - -#ifdef _WIN32 -#define VMW_INVALID_HANDLE INVALID_HANDLE_VALUE -#else -#define VMW_INVALID_HANDLE -1 -#endif - -#ifdef _WIN32 -#define fsync(fd) _commit(fd) -#define fileno(f) _fileno(f) -#else -#endif - -#endif // ifndef _VM_BASIC_DEFS_H_ diff -Nrup source/vmnet-only/vm_basic_types.h source.edited/vmnet-only/vm_basic_types.h --- source/vmnet-only/vm_basic_types.h 2010-05-09 20:08:42.000000000 -0700 +++ source.edited/vmnet-only/vm_basic_types.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,847 +0,0 @@ -/********************************************************* - * Copyright (C) 1998-2008 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 - * - *********************************************************/ - -/* - * - * vm_basic_types.h -- - * - * basic data types. - */ - - -#ifndef _VM_BASIC_TYPES_H_ -#define _VM_BASIC_TYPES_H_ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_VMMEXT -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMNIXMOD -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_VMKDRIVERS -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_DISTRIBUTE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMIROM -#include "includeCheck.h" - -/* STRICT ANSI means the Xserver build and X defines Bool differently. */ -#if !defined(__STRICT_ANSI__) || defined(__FreeBSD__) -typedef char Bool; -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#define IsBool(x) (((x) & ~1) == 0) -#define IsBool2(x, y) ((((x) | (y)) & ~1) == 0) - -/* - * Macros __i386__ and __ia64 are intrinsically defined by GCC - */ -#ifdef __i386__ -#define VM_I386 -#endif - -#ifdef _WIN64 -#define __x86_64__ -#endif - -#ifdef __x86_64__ -#define VM_X86_64 -#define VM_I386 -#define vm_x86_64 (1) -#else -#define vm_x86_64 (0) -#endif - - - -#ifdef _WIN32 -/* safe assumption for a while */ -#define VM_I386 -#endif - -#ifdef _MSC_VER -typedef unsigned __int64 uint64; -typedef signed __int64 int64; - -#pragma warning (3 :4505) // unreferenced local function -#pragma warning (disable :4018) // signed/unsigned mismatch -#pragma warning (disable :4761) // integral size mismatch in argument; conversion supplied -#pragma warning (disable :4305) // truncation from 'const int' to 'short' -#pragma warning (disable :4244) // conversion from 'unsigned short' to 'unsigned char' -#pragma warning (disable :4267) // truncation of 'size_t' -#pragma warning (disable :4146) // unary minus operator applied to unsigned type, result still unsigned -#pragma warning (disable :4142) // benign redefinition of type - -#elif __GNUC__ -/* The Xserver source compiles with -ansi -pendantic */ -#ifndef __STRICT_ANSI__ -#if defined(VM_X86_64) -typedef unsigned long uint64; -typedef long int64; -#else -typedef unsigned long long uint64; -typedef long long int64; -#endif -#elif defined(__FreeBSD__) -typedef unsigned long long uint64; -typedef long long int64; -#endif -#else -#error - Need compiler define for int64/uint64 -#endif - -typedef unsigned int uint32; -typedef unsigned short uint16; -typedef unsigned char uint8; - -typedef int int32; -typedef short int16; -typedef char int8; - -/* - * FreeBSD (for the tools build) unconditionally defines these in - * sys/inttypes.h so don't redefine them if this file has already - * been included. [greg] - * - * This applies to Solaris as well. - */ - -/* - * Before trying to do the includes based on OS defines, see if we can use - * feature-based defines to get as much functionality as possible - */ - -#ifdef HAVE_INTTYPES_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_INTTYPES_H -#include -#endif -#ifdef HAVE_STDINT_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif - -#if !defined(USING_AUTOCONF) -# if defined(__FreeBSD__) || defined(sun) -# ifdef KLD_MODULE -# include -# else -# if (BSD_VERSION >= 50) -# include -# include -# else -# include -# endif -# endif -# elif defined __APPLE__ -# if KERNEL -# include -# include /* mostly for size_t */ -# include -# else -# include -# include -# include -# include -# endif -# else -# if !defined(__intptr_t_defined) && !defined(intptr_t) -# define __intptr_t_defined -# define intptr_t intptr_t -# ifdef VM_I386 -# ifdef VM_X86_64 -typedef int64 intptr_t; -# else -typedef int32 intptr_t; -# endif -# endif -# endif - -# ifndef _STDINT_H -# ifdef VM_I386 -# ifdef VM_X86_64 -typedef uint64 uintptr_t; -# else -typedef uint32 uintptr_t; -# endif -# endif -# endif -# endif -#endif - - -/* - * Time - * XXX These should be cleaned up. -- edward - */ - -typedef int64 VmTimeType; /* Time in microseconds */ -typedef int64 VmTimeRealClock; /* Real clock kept in microseconds */ -typedef int64 VmTimeVirtualClock; /* Virtual Clock kept in CPU cycles */ - -/* - * Printf format specifiers for size_t and 64-bit number. - * Use them like this: - * printf("%"FMT64"d\n", big); - * - * FMTH is for handles/fds. - */ - -#ifdef _MSC_VER - #define FMT64 "I64" - #ifdef VM_X86_64 - #define FMTSZ "I64" - #define FMTPD "I64" - #define FMTH "I64" - #else - #define FMTSZ "I" - #define FMTPD "I" - #define FMTH "I" - #endif -#elif __GNUC__ - #define FMTH "" - #if defined(N_PLAT_NLM) || defined(sun) || \ - (defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) < 5)) - /* - * Why (__FreeBSD__ + 0)? See bug 141008. - * Yes, we really need to test both (__FreeBSD__ + 0) and - * ((__FreeBSD__ + 0) < 5). No, we can't remove "+ 0" from - * ((__FreeBSD__ + 0) < 5). - */ - #ifdef VM_X86_64 - #define FMTSZ "l" - #define FMTPD "l" - #else - #define FMTSZ "" - #define FMTPD "" - #endif - #elif defined(__linux__) \ - || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \ - || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \ - || (defined(_POSIX2_VERSION) && _POSIX2_VERSION >= 200112L) - /* BSD/Darwin, Linux */ - #define FMTSZ "z" - #define FMTPD "t" - #else - /* Systems with a pre-C99 libc */ - #define FMTSZ "Z" - #ifdef VM_X86_64 - #define FMTPD "l" - #else - #define FMTPD "" - #endif - #endif - #ifdef VM_X86_64 - #define FMT64 "l" - #elif defined(sun) || defined(__APPLE__) || defined(__FreeBSD__) - #define FMT64 "ll" - #else - #define FMT64 "L" - #endif -#else - #error - Need compiler define for FMT64 and FMTSZ -#endif - -/* - * Suffix for 64-bit constants. Use it like this: - * CONST64(0x7fffffffffffffff) for signed or - * CONST64U(0x7fffffffffffffff) for unsigned. - * - * 2004.08.30(thutt): - * The vmcore/asm64/gen* programs are compiled as 32-bit - * applications, but must handle 64 bit constants. If the - * 64-bit-constant defining macros are already defined, the - * definition will not be overwritten. - */ - -#if !defined(CONST64) || !defined(CONST64U) -#ifdef _MSC_VER -#define CONST64(c) c##I64 -#define CONST64U(c) c##uI64 -#elif __GNUC__ -#ifdef VM_X86_64 -#define CONST64(c) c##L -#define CONST64U(c) c##uL -#else -#define CONST64(c) c##LL -#define CONST64U(c) c##uLL -#endif -#else -#error - Need compiler define for CONST64 -#endif -#endif - -/* - * Use CONST3264/CONST3264U if you want a constant to be - * treated as a 32-bit number on 32-bit compiles and - * a 64-bit number on 64-bit compiles. Useful in the case - * of shifts, like (CONST3264U(1) << x), where x could be - * more than 31 on a 64-bit compile. - */ - -#ifdef VM_X86_64 - #define CONST3264(a) CONST64(a) - #define CONST3264U(a) CONST64U(a) -#else - #define CONST3264(a) (a) - #define CONST3264U(a) (a) -#endif - -#define MIN_INT32 ((int32)0x80000000) -#define MAX_INT32 ((int32)0x7fffffff) - -#define MIN_UINT32 ((uint32)0) -#define MAX_UINT32 ((uint32)0xffffffff) - -#define MIN_INT64 (CONST64(0x8000000000000000)) -#define MAX_INT64 (CONST64(0x7fffffffffffffff)) - -#define MIN_UINT64 (CONST64U(0)) -#define MAX_UINT64 (CONST64U(0xffffffffffffffff)) - -typedef uint8 *TCA; /* Pointer into TC (usually). */ - -/* - * Type big enough to hold an integer between 0..100 - */ -typedef uint8 Percent; -#define AsPercent(v) ((Percent)(v)) -#define CHOOSE_PERCENT AsPercent(101) - - -typedef uintptr_t VA; -typedef uintptr_t VPN; - -typedef uint64 PA; -typedef uint32 PPN; - -typedef uint64 PhysMemOff; -typedef uint64 PhysMemSize; - -/* The Xserver source compiles with -ansi -pendantic */ -#ifndef __STRICT_ANSI__ -typedef uint64 BA; -#endif -typedef uint32 BPN; -typedef uint32 PageNum; -typedef unsigned MemHandle; -typedef int32 World_ID; - -#define INVALID_WORLD_ID ((World_ID)0) - -typedef World_ID User_CartelID; -#define INVALID_CARTEL_ID INVALID_WORLD_ID - -typedef User_CartelID User_SessionID; -#define INVALID_SESSION_ID INVALID_CARTEL_ID - -typedef User_CartelID User_CartelGroupID; -#define INVALID_CARTELGROUP_ID INVALID_CARTEL_ID - -/* world page number */ -typedef uint32 WPN; - -/* The Xserver source compiles with -ansi -pendantic */ -#ifndef __STRICT_ANSI__ -typedef uint64 MA; -typedef uint32 MPN; -#endif - -/* - * This type should be used for variables that contain sector - * position/quantity. - */ -typedef uint64 SectorType; - -/* - * Linear address - */ - -typedef uintptr_t LA; -typedef uintptr_t LPN; -#define LA_2_LPN(_la) ((_la) >> PAGE_SHIFT) -#define LPN_2_LA(_lpn) ((_lpn) << PAGE_SHIFT) - -#define LAST_LPN ((((LA) 1) << (8 * sizeof(LA) - PAGE_SHIFT)) - 1) -#define LAST_LPN32 ((((LA32)1) << (8 * sizeof(LA32) - PAGE_SHIFT)) - 1) -#define LAST_LPN64 ((((LA64)1) << (8 * sizeof(LA64) - PAGE_SHIFT)) - 1) - -/* Valid bits in a LPN. */ -#define LPN_MASK LAST_LPN -#define LPN_MASK32 LAST_LPN32 -#define LPN_MASK64 LAST_LPN64 - -/* - * On 64 bit platform, address and page number types default - * to 64 bit. When we need to represent a 32 bit address, we use - * types defined below. - * - * On 32 bit platform, the following types are the same as the - * default types. - */ -typedef uint32 VA32; -typedef uint32 VPN32; -typedef uint32 LA32; -typedef uint32 LPN32; -typedef uint32 PA32; -typedef uint32 PPN32; -typedef uint32 MA32; -typedef uint32 MPN32; - -/* - * On 64 bit platform, the following types are the same as the - * default types. - */ -typedef uint64 VA64; -typedef uint64 VPN64; -typedef uint64 LA64; -typedef uint64 LPN64; -typedef uint64 PA64; -typedef uint64 PPN64; -typedef uint64 MA64; -typedef uint64 MPN64; - -/* - * VA typedefs for user world apps. - */ -typedef VA32 UserVA32; -typedef VA64 UserVA64; -typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */ -typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */ -#ifdef VMKERNEL -typedef UserVA32 UserVA; -#else -typedef void * UserVA; -#endif - - -/* - * Maximal possible PPN value (errors too) that PhysMem can handle. - * Must be at least as large as MAX_PPN which is the maximum PPN - * for any region other than buserror. - */ -#define PHYSMEM_MAX_PPN ((PPN)0xffffffff) -#define MAX_PPN ((PPN)0x1fffffff) /* Maximal observable PPN value. */ -#define INVALID_PPN ((PPN)0xffffffff) - -#define INVALID_BPN ((BPN) 0x1fffffff) - -#define INVALID_MPN ((MPN)-1) -#define MEMREF_MPN ((MPN)-2) -#define RESERVED_MPN ((MPN) 0) -/* Support 39 bits of address space, minus one page. */ -#define MAX_MPN ((MPN) 0x07ffffff) - -#define INVALID_LPN ((LPN)-1) -#define INVALID_VPN ((VPN)-1) -#define INVALID_LPN64 ((LPN64)-1) -#define INVALID_PAGENUM ((PageNum)-1) -#define INVALID_WPN ((WPN) -1) - - -/* - * Format modifier for printing VA, LA, and VPN. - * Use them like this: Log("%#"FMTLA"x\n", laddr) - */ - -#if defined(VMM64) || defined(FROBOS64) || vm_x86_64 || defined __APPLE__ -# define FMTLA "l" -# define FMTVA "l" -# define FMTVPN "l" -#else -# define FMTLA "" -# define FMTVA "" -# define FMTVPN "" -#endif - - -#define EXTERN extern -#define CONST const - - -#ifndef INLINE -# ifdef _MSC_VER -# define INLINE __inline -# else -# define INLINE inline -# endif -#endif - - -/* - * Annotation for data that may be exported into a DLL and used by other - * apps that load that DLL and import the data. - */ -#if defined(_WIN32) && defined(VMX86_IMPORT_DLLDATA) -# define VMX86_EXTERN_DATA extern __declspec(dllimport) -#else // !_WIN32 -# define VMX86_EXTERN_DATA extern -#endif - -#if defined(_WIN32) && !defined(VMX86_NO_THREADS) -#define THREADSPECIFIC __declspec(thread) -#else -#define THREADSPECIFIC -#endif - -/* - * Due to the wonderful "registry redirection" feature introduced in - * 64-bit Windows, if you access any key under HKLM\Software in 64-bit - * code, you need to open/create/delete that key with - * VMKEY_WOW64_32KEY if you want a consistent view with 32-bit code. - */ - -#ifdef _WIN32 -#ifdef _WIN64 -#define VMW_KEY_WOW64_32KEY KEY_WOW64_32KEY -#else -#define VMW_KEY_WOW64_32KEY 0x0 -#endif -#endif - - -/* - * Consider the following reasons functions are inlined: - * - * 1) inlined for performance reasons - * 2) inlined because it's a single-use function - * - * Functions which meet only condition 2 should be marked with this - * inline macro; It is not critical to be inlined (but there is a - * code-space & runtime savings by doing so), so when other callers - * are added the inline-ness should be removed. - */ - -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) -/* - * Starting at version 3.3, gcc does not always inline functions marked - * 'inline' (it depends on their size). To force gcc to do so, one must use the - * extra __always_inline__ attribute. - */ -# define INLINE_SINGLE_CALLER INLINE __attribute__((__always_inline__)) -# if defined(VMM) \ - && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1)) -# warning Verify INLINE_SINGLE_CALLER '__always_inline__' attribute (did \ - monitor size change?) -# endif -#else -# define INLINE_SINGLE_CALLER INLINE -#endif - -/* - * Used when a hard guaranteed of no inlining is needed. Very few - * instances need this since the absence of INLINE is a good hint - * that gcc will not do inlining. - */ - -#if defined(__GNUC__) && defined(VMM) -#define ABSOLUTELY_NOINLINE __attribute__((__noinline__)) -#endif - -/* - * Attributes placed on function declarations to tell the compiler - * that the function never returns. - */ - -#ifdef _MSC_VER -#define NORETURN __declspec(noreturn) -#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 9) -#define NORETURN __attribute__((__noreturn__)) -#else -#define NORETURN -#endif - -/* - * GCC 3.2 inline asm needs the + constraint for input/ouput memory operands. - * Older GCCs don't know about it --hpreg - */ - -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2) -# define VM_ASM_PLUS 1 -#else -# define VM_ASM_PLUS 0 -#endif - -/* - * Branch prediction hints: - * LIKELY(exp) - Expression exp is likely TRUE. - * UNLIKELY(exp) - Expression exp is likely FALSE. - * Usage example: - * if (LIKELY(excCode == EXC_NONE)) { - * or - * if (UNLIKELY(REAL_MODE(vc))) { - * - * We know how to predict branches on gcc3 and later (hopefully), - * all others we don't so we do nothing. - */ - -#if (__GNUC__ >= 3) -/* - * gcc3 uses __builtin_expect() to inform the compiler of an expected value. - * We use this to inform the static branch predictor. The '!!' in LIKELY - * will convert any !=0 to a 1. - */ -#define LIKELY(_exp) __builtin_expect(!!(_exp), 1) -#define UNLIKELY(_exp) __builtin_expect((_exp), 0) -#else -#define LIKELY(_exp) (_exp) -#define UNLIKELY(_exp) (_exp) -#endif - -/* - * GCC's argument checking for printf-like functions - * This is conditional until we have replaced all `"%x", void *' - * with `"0x%08x", (uint32) void *'. Note that %p prints different things - * on different platforms. Argument checking is enabled for the - * vmkernel, which has already been cleansed. - * - * fmtPos is the position of the format string argument, beginning at 1 - * varPos is the position of the variable argument, beginning at 1 - */ - -#if defined(__GNUC__) -# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos))) -#else -# define PRINTF_DECL(fmtPos, varPos) -#endif - -/* - * UNUSED_PARAM should surround the parameter name and type declaration, - * e.g. "int MyFunction(int var1, UNUSED_PARAM(int var2))" - * - */ - -#ifndef UNUSED_PARAM -# if defined(__GNUC__) -# define UNUSED_PARAM(_parm) _parm __attribute__((__unused__)) -# else -# define UNUSED_PARAM(_parm) _parm -# endif -#endif - -/* - * REGPARM defaults to REGPARM3, i.e., a requent that gcc - * puts the first three arguments in registers. (It is fine - * if the function has fewer than three args.) Gcc only. - * Syntactically, put REGPARM where you'd put INLINE or NORETURN. - */ - -#if defined(__GNUC__) -# define REGPARM0 __attribute__((regparm(0))) -# define REGPARM1 __attribute__((regparm(1))) -# define REGPARM2 __attribute__((regparm(2))) -# define REGPARM3 __attribute__((regparm(3))) -# define REGPARM REGPARM3 -#else -# define REGPARM0 -# define REGPARM1 -# define REGPARM2 -# define REGPARM3 -# define REGPARM -#endif - -/* - * ALIGNED specifies minimum alignment in "n" bytes. - */ - -#ifdef __GNUC__ -#define ALIGNED(n) __attribute__((__aligned__(n))) -#else -#define ALIGNED(n) -#endif - -/* - * __func__ is a stringified function name that is part of the C99 standard. The block - * below defines __func__ on older systems where the compiler does not support that - * macro. - */ -#if defined(__GNUC__) \ - && ((__GNUC__ == 2 && __GNUC_MINOR < 96) \ - || (__GNUC__ < 2)) -# define __func__ __FUNCTION__ -#endif - -/* - * Once upon a time, this was used to silence compiler warnings that - * get generated when the compiler thinks that a function returns - * when it is marked noreturn. Don't do it. Use NOT_REACHED(). - */ - -#define INFINITE_LOOP() do { } while (1) - -/* - * On FreeBSD (for the tools build), size_t is typedef'd if _BSD_SIZE_T_ - * is defined. Use the same logic here so we don't define it twice. [greg] - */ -#ifdef __FreeBSD__ -# ifdef _BSD_SIZE_T_ -# undef _BSD_SIZE_T_ -# ifdef VM_I386 -# ifdef VM_X86_64 - typedef uint64 size_t; -# else - typedef uint32 size_t; -# endif -# endif /* VM_I386 */ -# endif - -# ifdef _BSD_SSIZE_T_ -# undef _BSD_SSIZE_T_ -# define _SSIZE_T -# define __ssize_t_defined -# define _SSIZE_T_DECLARED -# ifdef VM_I386 -# ifdef VM_X86_64 - typedef int64 ssize_t; -# else - typedef int32 ssize_t; -# endif -# endif /* VM_I386 */ -# endif - -#else -# ifndef _SIZE_T -# define _SIZE_T -# ifdef VM_I386 -# ifdef VM_X86_64 - typedef uint64 size_t; -# else - typedef uint32 size_t; -# endif -# endif /* VM_I386 */ -# endif - -# if !defined(FROBOS) && !defined(_SSIZE_T) && !defined(ssize_t) && \ - !defined(__ssize_t_defined) && !defined(_SSIZE_T_DECLARED) -# define _SSIZE_T -# define __ssize_t_defined -# define _SSIZE_T_DECLARED -# ifdef VM_I386 -# ifdef VM_X86_64 - typedef int64 ssize_t; -# else - typedef int32 ssize_t; -# endif -# endif /* VM_I386 */ -# endif - -#endif - -/* - * Format modifier for printing pid_t. On sun the pid_t is a ulong, but on - * Linux it's an int. - * Use this like this: printf("The pid is %"FMTPID".\n", pid); - */ -#ifdef sun -# ifdef VM_X86_64 -# define FMTPID "d" -# else -# define FMTPID "lu" -# endif -#else -# define FMTPID "d" -#endif - -/* - * Format modifier for printing uid_t. On sun the uid_t is a ulong, but on - * Linux it's an int. - * Use this like this: printf("The uid is %"FMTUID".\n", uid); - */ -#ifdef sun -# ifdef VM_X86_64 -# define FMTUID "u" -# else -# define FMTUID "lu" -# endif -#else -# define FMTUID "u" -#endif - -/* - * Format modifier for printing mode_t. On sun the mode_t is a ulong, but on - * Linux it's an int. - * Use this like this: printf("The mode is %"FMTMODE".\n", mode); - */ -#ifdef sun -# ifdef VM_X86_64 -# define FMTMODE "o" -# else -# define FMTMODE "lo" -# endif -#else -# define FMTMODE "o" -#endif - -/* - * Format modifier for printing time_t. Most platforms define a time_t to be - * a long int, but on FreeBSD (as of 5.0, it seems), the time_t is a signed - * size quantity. Refer to the definition of FMTSZ to see why we need silly - * preprocessor arithmetic. - * Use this like this: printf("The mode is %"FMTTIME".\n", time); - */ -#if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5) -# define FMTTIME FMTSZ"d" -#else -# define FMTTIME "ld" -#endif - -/* - * Define MXSemaHandle here so both vmmon and vmx see this definition. - */ - -#ifdef _WIN32 -typedef uintptr_t MXSemaHandle; -#else -typedef int MXSemaHandle; -#endif - -/* - * Define type for poll device handles. - */ - -#ifdef _WIN32 -typedef uintptr_t PollDevHandle; -#else -typedef int PollDevHandle; -#endif - -/* - * Define the utf16_t type. - */ - -#if defined(_WIN32) && defined(_NATIVE_WCHAR_T_DEFINED) -typedef wchar_t utf16_t; -#else -typedef uint16 utf16_t; -#endif - -#endif /* _VM_BASIC_TYPES_H_ */ diff -Nrup source/vmnet-only/vm_device_version.h source.edited/vmnet-only/vm_device_version.h --- source/vmnet-only/vm_device_version.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vm_device_version.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,186 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -#ifndef VM_DEVICE_VERSION_H -#define VM_DEVICE_VERSION_H - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_VMMEXT -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_VMCORE -#include "includeCheck.h" - -#ifdef _WIN32 -#include "guiddef.h" -#endif - -/* Our own PCI IDs - * VMware SVGA II (Unified VGA) - * VMware SVGA (PCI Accelerator) - * VMware vmxnet (Idealized NIC) - * VMware vmxscsi (Abortive idealized SCSI controller) - * VMware chipset (Subsystem ID for our motherboards) - * VMware e1000 (Subsystem ID) - * VMware vmxnet3 (Uniform Pass Through NIC) - */ -#define PCI_VENDOR_ID_VMWARE 0x15AD -#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 -#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 -#define PCI_DEVICE_ID_VMWARE_NET 0x0720 -#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 -#define PCI_DEVICE_ID_VMWARE_VMCI 0x0740 -#define PCI_DEVICE_ID_VMWARE_CHIPSET 0x1976 -#define PCI_DEVICE_ID_VMWARE_82545EM 0x0750 /* single port */ -#define PCI_DEVICE_ID_VMWARE_82546EB 0x0760 /* dual port */ -#define PCI_DEVICE_ID_VMWARE_EHCI 0x0770 -#define PCI_DEVICE_ID_VMWARE_1394 0x0780 -#define PCI_DEVICE_ID_VMWARE_BRIDGE 0x0790 -#define PCI_DEVICE_ID_VMWARE_ROOTPORT 0x07A0 -#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0 -#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0 - -/* The hypervisor device might grow. Please leave room - * for 7 more subfunctions. - */ -#define PCI_DEVICE_ID_VMWARE_HYPER 0x0800 -#define PCI_DEVICE_ID_VMWARE_VMI 0x0801 - -#define PCI_DEVICE_VMI_CLASS 0x05 -#define PCI_DEVICE_VMI_SUBCLASS 0x80 -#define PCI_DEVICE_VMI_INTERFACE 0x00 -#define PCI_DEVICE_VMI_REVISION 0x01 - -/* From linux/pci_ids.h: - * AMD Lance Ethernet controller - * BusLogic SCSI controller - * Ensoniq ES1371 sound controller - */ -#define PCI_VENDOR_ID_AMD 0x1022 -#define PCI_DEVICE_ID_AMD_VLANCE 0x2000 -#define PCI_VENDOR_ID_BUSLOGIC 0x104B -#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140 -#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040 -#define PCI_VENDOR_ID_ENSONIQ 0x1274 -#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 - -/* From linux/pci_ids.h: - * Intel 82439TX (430 HX North Bridge) - * Intel 82371AB (PIIX4 South Bridge) - * Intel 82443BX (440 BX North Bridge and AGP Bridge) - * Intel 82545EM (e1000, server adapter, single port) - * Intel 82546EB (e1000, server adapter, dual port) - */ -#define PCI_VENDOR_ID_INTEL 0x8086 -#define PCI_DEVICE_ID_INTEL_82439TX 0x7100 -#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 -#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 -#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 -#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 -#define PCI_DEVICE_ID_INTEL_82443BX 0x7190 -#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191 -#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 /* Used when no AGP support */ -#define PCI_DEVICE_ID_INTEL_82545EM 0x100f -#define PCI_DEVICE_ID_INTEL_82546EB 0x1010 - - -/************* Strings for IDE Identity Fields **************************/ -#define VIDE_ID_SERIAL_STR "00000000000000000001" /* Must be 20 Bytes */ -#define VIDE_ID_FIRMWARE_STR "00000001" /* Must be 8 Bytes */ - -/* No longer than 40 Bytes */ -#define VIDE_ATA_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE Hard Drive" -#define VIDE_ATAPI_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE CDROM Drive" - -#define ATAPI_VENDOR_ID "NECVMWar" /* Must be 8 Bytes */ -#define ATAPI_PRODUCT_ID PRODUCT_GENERIC_NAME " IDE CDROM" /* Must be 16 Bytes */ -#define ATAPI_REV_LEVEL "1.00" /* Must be 4 Bytes */ - -#define IDE_NUM_INTERFACES 2 /* support for two interfaces */ -#define IDE_DRIVES_PER_IF 2 - -/************* Strings for SCSI Identity Fields **************************/ -#define SCSI_DISK_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI Hard Drive" -#define SCSI_DISK_VENDOR_NAME COMPANY_NAME -#define SCSI_DISK_REV_LEVEL "1.0" -#define SCSI_CDROM_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI CDROM Drive" -#define SCSI_CDROM_VENDOR_NAME COMPANY_NAME -#define SCSI_CDROM_REV_LEVEL "1.0" - -/************* SCSI implementation limits ********************************/ -#define SCSI_MAX_CONTROLLERS 4 // Need more than 1 for MSCS clustering -#define SCSI_MAX_DEVICES 16 // BT-958 emulates only 16 -#define SCSI_IDE_CHANNEL SCSI_MAX_CONTROLLERS -#define SCSI_IDE_HOSTED_CHANNEL (SCSI_MAX_CONTROLLERS + 1) -#define SCSI_MAX_CHANNELS (SCSI_MAX_CONTROLLERS + 2) - -/************* Strings for the VESA BIOS Identity Fields *****************/ -#define VBE_OEM_STRING COMPANY_NAME " SVGA" -#define VBE_VENDOR_NAME COMPANY_NAME -#define VBE_PRODUCT_NAME PRODUCT_GENERIC_NAME - -/************* PCI implementation limits ********************************/ -#define PCI_MAX_BRIDGES 15 - -/************* Ethernet implementation limits ***************************/ -#define MAX_ETHERNET_CARDS 10 - -/************* PCI Passthrough implementation limits ********************/ -#define MAX_PCI_PASSTHRU_DEVICES 2 - -/************* USB implementation limits ********************************/ -#define MAX_USB_DEVICES_PER_HOST_CONTROLLER 127 - -/************* Strings for Host USB Driver *******************************/ - -#ifdef _WIN32 - -/* - * Globally unique ID for the VMware device interface. Define INITGUID before including - * this header file to instantiate the variable. - */ -DEFINE_GUID(GUID_DEVICE_INTERFACE_VMWARE_USB_DEVICES, -0x2da1fe75, 0xaab3, 0x4d2c, 0xac, 0xdf, 0x39, 0x8, 0x8c, 0xad, 0xa6, 0x65); - -/* - * Globally unique ID for the VMware device setup class. - */ -DEFINE_GUID(GUID_CLASS_VMWARE_USB_DEVICES, -0x3b3e62a5, 0x3556, 0x4d7e, 0xad, 0xad, 0xf5, 0xfa, 0x3a, 0x71, 0x2b, 0x56); - -/* - * This string defines the device ID string of a VMware USB device. - * The format is USB\Vid_XXXX&Pid_YYYY, where XXXX and YYYY are the - * hexadecimal representations of the vendor and product ids, respectively. - * - * The official vendor ID for VMware, Inc. is 0x0E0F. - * The product id for USB generic devices is 0x0001. - */ -#define USB_VMWARE_DEVICE_ID_WIDE L"USB\\Vid_0E0F&Pid_0001" -#define USB_DEVICE_ID_LENGTH (sizeof(USB_VMWARE_DEVICE_ID_WIDE) / sizeof(WCHAR)) - -#ifdef UNICODE -#define USB_PNP_SETUP_CLASS_NAME L"VMwareUSBDevices" -#define USB_PNP_DRIVER_NAME L"vmusb" -#else -#define USB_PNP_SETUP_CLASS_NAME "VMwareUSBDevices" -#define USB_PNP_DRIVER_NAME "vmusb" -#endif -#endif - -#endif /* VM_DEVICE_VERSION_H */ diff -Nrup source/vmnet-only/vmnetInt.h source.edited/vmnet-only/vmnetInt.h --- source/vmnet-only/vmnetInt.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vmnetInt.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,169 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -#ifndef __VMNETINT_H__ -#define __VMNETINT_H__ - - -#define INCLUDE_ALLOW_MODULE -#include "includeCheck.h" -#include "driver-config.h" - - -/* - * Hide all kernel compatibility stuff in those macros. This part of code - * is used only when building prebuilt modules, when autoconf code is disabled. - */ - -/* All kernels above 2.6.23 have net namespaces. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && !defined(VMW_NETDEV_HAS_NET) -# define VMW_NETDEV_HAS_NET -#endif - -/* All kernels above 2.6.23 have skb argument in nf_hookfn. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && !defined(VMW_NFHOOK_USES_SKB) -# define VMW_NFHOOK_USES_SKB -#endif - -/* All kernels above 2.6.25 have dev_net & friends. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) && !defined(VMW_NETDEV_HAS_DEV_NET) -# define VMW_NETDEV_HAS_DEV_NET -#endif - - -#ifdef KERNEL_2_4_0 -# define compat_fop_set_owner(_pFop) do { \ - (_pFop)->owner = THIS_MODULE; \ -} while (0) -# define compat_mod_inc_refcount -# define compat_mod_dec_refcount -#else -# define compat_fop_set_owner(_pFop) -# define compat_mod_inc_refcount do { \ - MOD_INC_USE_COUNT; \ -} while (0) -# define compat_mod_dec_refcount do { \ - MOD_DEC_USE_COUNT; \ -} while (0) -#endif - - -#ifdef skb_shinfo -# define SKB_IS_CLONE_OF(clone, skb) ( \ - skb_shinfo(clone) == skb_shinfo(skb) \ - ) -#else -# define SKB_IS_CLONE_OF(clone, skb) ( \ - skb_datarefp(clone) == skb_datarefp(skb) \ - ) -#endif -#define DEV_QUEUE_XMIT(skb, dev, pri) ( \ - (skb)->dev = (dev), \ - (skb)->priority = (pri), \ - compat_skb_reset_mac_header(skb), \ - compat_skb_set_network_header(skb, sizeof (struct ethhdr)), \ - dev_queue_xmit(skb) \ - ) -#ifdef KERNEL_2_3_15 -# define dev_lock_list() read_lock(&dev_base_lock) -# define dev_unlock_list() read_unlock(&dev_base_lock) -# ifdef VMW_NETDEV_HAS_NET -# define DEV_GET(x) __dev_get_by_name(&init_net, (x)->name) -# ifdef VMW_NETDEV_HAS_DEV_NET -# define compat_dev_net(x) dev_net(x) -# else -# define compat_dev_net(x) (x)->nd_net -# endif -# else -# define DEV_GET(x) __dev_get_by_name((x)->name) -# endif -#else -# define DEV_GET(x) dev_get((x)->name) -#endif - - -/* - * Various fields (including 'dead') of struct sock are replaced with the - * 'flags' bitfield in 2.5.65, with sock_valbool_flag() to set flag's - * value. Since 2.5.71 there is sock_set_flag() to set bit to 1, and - * since 2.6.25-rc1 sock_valbool_flag() is gone. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65) -# define SET_SK_DEAD(_sk) (_sk)->dead = 1 -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 71) -# define SET_SK_DEAD(_sk) sock_valbool_flag(_sk, SOCK_DEAD, 1) -#else -# define SET_SK_DEAD(_sk) sock_set_flag(_sk, SOCK_DEAD) -#endif - - -#ifdef VMW_NETDEV_HAS_NET -extern struct proto vmnet_proto; -# define compat_sk_alloc(_bri, _pri) sk_alloc(&init_net, \ - PF_NETLINK, _pri, &vmnet_proto) -#elif defined(VMW_HAVE_SK_ALLOC_WITH_PROTO) -extern struct proto vmnet_proto; -# define compat_sk_alloc(_bri, _pri) sk_alloc(PF_NETLINK, _pri, &vmnet_proto, 1) -#elif defined(KERNEL_2_5_5) -# define compat_sk_alloc(_bri, _pri) sk_alloc(PF_NETLINK, _pri, 1, NULL) -#else -# define compat_sk_alloc(_bri, _pri) sk_alloc(0, _pri, 1) -#endif - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -# define fileTraversalLock(lock) spin_lock(lock) -# define fileTraversalUnLock(lock) spin_unlock(lock) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -# define fileTraversalLock(lock) read_lock(lock) -# define fileTraversalUnLock(lock) read_unlock(lock) -#else //2.2 kernels -# define fileTraversalLock(lock) lock_kernel() -# define fileTraversalUnLock(lock) unlock_kernel() -#endif - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -# define taskLock(lock) task_lock(lock) -# define taskUnLock(lock) task_unlock(lock) -#else //2.2 kernels -# define taskLock(lock) lock_kernel() -# define taskUnLock(lock) unlock_kernel() -#endif - - -/* - * The "owner" field in nf_hook_ops got added in 2.5.69 - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69) -# define compat_nf_hook_owner .owner = THIS_MODULE, -#else -# define compat_nf_hook_owner -#endif - - -#ifdef NF_IP_LOCAL_IN -#define VMW_NF_INET_LOCAL_IN NF_IP_LOCAL_IN -#define VMW_NF_INET_POST_ROUTING NF_IP_POST_ROUTING -#else -#define VMW_NF_INET_LOCAL_IN NF_INET_LOCAL_IN -#define VMW_NF_INET_POST_ROUTING NF_INET_POST_ROUTING -#endif - - -#endif /* __VMNETINT_H__ */ diff -Nrup source/vmnet-only/vm_oui.h source.edited/vmnet-only/vm_oui.h --- source/vmnet-only/vm_oui.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vm_oui.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,177 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -#ifndef _VM_OUI_H_ -#define _VM_OUI_H_ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMNIXMOD -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vm_basic_asm.h" - -/* - * Our own OUIs given by IEEE. - */ - -/* - * This OUI was previously used for generated macs on ESX. - * Don't use it for anything anymore or I'll slab you. --gustav - */ -#define VMX86_LEGACY_OUI 0x000569 - -/* This OUI is used for static MAC addresses. */ -#define VMX86_STATIC_OUI 0x005056 - -/* This OUI is used for generated MAC addresses. */ -#define VMX86_GENERATED_OUI 0x000C29 - -/* Entire OUI is reserved and should not be used for any purpose. */ -#define VMX86_FUTURE_OUI 0x001C14 - -#define VMX86_OUI_SIZE 3 - -#define VMX86_LEGACY_OUI0 ((uint8) (VMX86_LEGACY_OUI >> (VMX86_OUI_SIZE - 1) * 8)) -#define VMX86_LEGACY_OUI1 ((uint8) (VMX86_LEGACY_OUI >> (VMX86_OUI_SIZE - 2) * 8)) -#define VMX86_LEGACY_OUI2 ((uint8) (VMX86_LEGACY_OUI >> (VMX86_OUI_SIZE - 3) * 8)) - -#define VMX86_STATIC_OUI0 ((uint8) (VMX86_STATIC_OUI >> (VMX86_OUI_SIZE - 1) * 8)) -#define VMX86_STATIC_OUI1 ((uint8) (VMX86_STATIC_OUI >> (VMX86_OUI_SIZE - 2) * 8)) -#define VMX86_STATIC_OUI2 ((uint8) (VMX86_STATIC_OUI >> (VMX86_OUI_SIZE - 3) * 8)) - -#define VMX86_GEN_OUI0 ((uint8) (VMX86_GENERATED_OUI >> (VMX86_OUI_SIZE - 1) * 8)) -#define VMX86_GEN_OUI1 ((uint8) (VMX86_GENERATED_OUI >> (VMX86_OUI_SIZE - 2) * 8)) -#define VMX86_GEN_OUI2 ((uint8) (VMX86_GENERATED_OUI >> (VMX86_OUI_SIZE - 3) * 8)) - -#define VMX86_FUTURE_OUI0 ((uint8) (VMX86_FUTURE_OUI >> (VMX86_OUI_SIZE - 1) * 8)) -#define VMX86_FUTURE_OUI1 ((uint8) (VMX86_FUTURE_OUI >> (VMX86_OUI_SIZE - 2) * 8)) -#define VMX86_FUTURE_OUI2 ((uint8) (VMX86_FUTURE_OUI >> (VMX86_OUI_SIZE - 3) * 8)) - -/* This OUI is used for generated WWN addresses. */ -/* What exactly is a WWN address, anyway? */ -#define VMX86_STATIC_WWN_OUI 0x000C29 - -#define VMX86_WWN_OUI_SIZE 3 - -#define VMX86_STATIC_WWN_OUI0 ((uint8) (VMX86_STATIC_WWN_OUI >> (VMX86_WWN_OUI_SIZE - 1) * 8)) -#define VMX86_STATIC_WWN_OUI1 ((uint8) (VMX86_STATIC_WWN_OUI >> (VMX86_WWN_OUI_SIZE - 2) * 8)) -#define VMX86_STATIC_WWN_OUI2 ((uint8) (VMX86_STATIC_WWN_OUI >> (VMX86_WWN_OUI_SIZE - 3) * 8)) - -/* - * Top 2 bits of byte 3 of MAC address - */ - -#define VMX86_MAC_PREFIX 0xc0 -#define VMX86_MAC_RESERVED 0xc0 // reserved private MAC range. -#define VMX86_MAC_VPX 0x80 // VPX MAC range (old IP-based) -#define VMX86_MAC_STATIC 0x00 // reserved static MAC range. -#define VMX86_MAC_ESX 0x40 // standalone ESX VNIC MAC range. - -/* - * Bits left for MAC address assignment - * - * The explicit casts shut the compiler up. -- edward - */ - -#define VMX86_MAC_BITS 22 - -#define VMX86_IS_STATIC_OUI(addr) \ - ((addr)[0] == VMX86_STATIC_OUI0 && \ - (addr)[1] == VMX86_STATIC_OUI1 && \ - (addr)[2] == VMX86_STATIC_OUI2) - -#define VMX86_IS_GENERATED_OUI(addr) \ - ((addr)[0] == VMX86_GEN_OUI0 && \ - (addr)[1] == VMX86_GEN_OUI1 && \ - (addr)[2] == VMX86_GEN_OUI2) - -#define VMX86_IS_FUTURE_OUI(addr) \ - ((addr)[0] == VMX86_FUTURE_OUI0 && \ - (addr)[1] == VMX86_FUTURE_OUI1 && \ - (addr)[2] == VMX86_FUTURE_OUI2) - -#define VMX86_IS_RESERVED_MAC(addr) \ - (VMX86_IS_STATIC_OUI(addr) && \ - ((addr)[3] & VMX86_MAC_PREFIX) == VMX86_MAC_RESERVED) - -#define VMX86_IS_STATIC_MAC(addr) \ - (VMX86_IS_STATIC_OUI(addr) && \ - ((addr)[3] & VMX86_MAC_PREFIX) == VMX86_MAC_STATIC) - -#define VMX86_IS_VPX_MAC(addr) \ - (VMX86_IS_STATIC_OUI(addr) && \ - ((addr)[3] & VMX86_MAC_PREFIX) == VMX86_MAC_VPX) - -/* - * MAC addresses reserved for hostonly adapters. - */ -#define VMX86_IS_VIRT_ADAPTER_MAC(addr) \ - (VMX86_IS_RESERVED_MAC(addr) && \ - ((addr)[3] & ~VMX86_MAC_PREFIX) == 0x00 && \ - (addr)[4] == 0x00) - -#define VMX86_BUILD_MAC(addr, suffix) do { \ - (addr)[0] = VMX86_STATIC_OUI0; \ - (addr)[1] = VMX86_STATIC_OUI1; \ - (addr)[2] = VMX86_STATIC_OUI2; \ - (addr)[3] = (uint8) (VMX86_MAC_RESERVED \ - | (((suffix) >> 16) & ~VMX86_MAC_PREFIX)); \ - (addr)[4] = (uint8) ((suffix) >> 8); \ - (addr)[5] = (uint8) (suffix); \ -} while (0) - - -/* - * Generate a random static MAC usable by devices that are not - * virtual host adapters. - */ - -static INLINE void -VMX86_GENERATE_RANDOM_MAC(uint8 mac[6]) -{ - uint32 offset, r; - - /* - * We use the offset to only generate addresses in the range - * 0xe0:00:00-0xff:ff:ff instead of 0xc0:00:00-0xff:ff:ff. - * We reserve the lower range for other purposes that may come - * later. - * E.g. virtual host adapters use the range c0:00:00-c0:00:ff. - */ - offset = 0x200000; - /* Randomize bits 20-0 and make them unique on this machine. */ - r = (uint32)RDTSC(); - VMX86_BUILD_MAC(mac, r | offset); -} - - -static INLINE void -VMX86_GENERATE_LEGACY_MAC(uint8 mac[6], //OUT: - uint32 suffix) //IN: Only 3 lower bytes are used. -{ - mac[0] = VMX86_LEGACY_OUI0; - mac[1] = VMX86_LEGACY_OUI1; - mac[2] = VMX86_LEGACY_OUI2; - mac[3] = (suffix >> 16) & 0xff; - mac[4] = (suffix >> 8) & 0xff; - mac[5] = (suffix) & 0xff; -} - -#endif diff -Nrup source/vmnet-only/vmware_pack_begin.h source.edited/vmnet-only/vmware_pack_begin.h --- source/vmnet-only/vmware_pack_begin.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vmware_pack_begin.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,43 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -/* - * vmware_pack_begin.h -- - * - * Begin of structure packing. See vmware_pack_init.h for details. - * - * Note that we do not use the following construct in this include file, - * because we want to emit the code every time the file is included --hpreg - * - * #ifndef foo - * # define foo - * ... - * #endif - * - */ - - -#include "vmware_pack_init.h" - - -#ifdef _MSC_VER -# pragma pack(push, 1) -#elif __GNUC__ -#else -# error Compiler packing... -#endif diff -Nrup source/vmnet-only/vmware_pack_end.h source.edited/vmnet-only/vmware_pack_end.h --- source/vmnet-only/vmware_pack_end.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vmware_pack_end.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,44 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -/* - * vmware_pack_end.h -- - * - * End of structure packing. See vmware_pack_init.h for details. - * - * Note that we do not use the following construct in this include file, - * because we want to emit the code every time the file is included --hpreg - * - * #ifndef foo - * # define foo - * ... - * #endif - * - */ - - -#include "vmware_pack_init.h" - - -#ifdef _MSC_VER -# pragma pack(pop) -#elif __GNUC__ -__attribute__((__packed__)) -#else -# error Compiler packing... -#endif diff -Nrup source/vmnet-only/vmware_pack_init.h source.edited/vmnet-only/vmware_pack_init.h --- source/vmnet-only/vmware_pack_init.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vmware_pack_init.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,65 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __VMWARE_PACK_INIT_H__ -# define __VMWARE_PACK_INIT_H__ - - -/* - * vmware_pack_init.h -- - * - * Platform-independent code to make the compiler pack (i.e. have them - * occupy the smallest possible space) structure definitions. The following - * constructs are known to work --hpreg - * - * #include "vmware_pack_begin.h" - * struct foo { - * ... - * } - * #include "vmware_pack_end.h" - * ; - * - * typedef - * #include "vmware_pack_begin.h" - * struct foo { - * ... - * } - * #include "vmware_pack_end.h" - * foo; - */ - - -#ifdef _MSC_VER -/* - * MSVC 6.0 emits warning 4103 when the pack push and pop pragma pairing is - * not balanced within 1 included file. That is annoying because our scheme - * is based on the pairing being balanced between 2 included files. - * - * So we disable this warning, but this is safe because the compiler will also - * emit warning 4161 when there is more pops than pushes within 1 main - * file --hpreg - */ - -# pragma warning(disable:4103) -#elif __GNUC__ -#else -# error Compiler packing... -#endif - - -#endif /* __VMWARE_PACK_INIT_H__ */ diff -Nrup source/vmnet-only/vnetEvent.c source.edited/vmnet-only/vnetEvent.c --- source/vmnet-only/vnetEvent.c 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vnetEvent.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,549 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 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 - * - *********************************************************/ - -/* - * vnetEvent.c -- - * - * The event notification mechanism for the vmnet module. It consists of - * mechanisms, senders, listeners, and events. A mechanism is the scope of - * a single notification mechanism. Within this scope, senders send events - * to listeners and listeners handle events by means of their registered - * event handler. - * - * Mechanisms, senders, and listeners can be created and destroyed in any - * order. The implementation ensures proper destruction independent of the - * destruction order. - * - * The event handlers registered by the listeners are not allowed to - * recursively enter the mechanism. The implementation enforces this rule. - * The event handlers are not allowed to block. - * - * Mechanisms, senders, and listeners are thread-safe, i.e. they can be - * accessed concurrently by multiple threads. Event handlers must be thread- - * safe. - * - * Callers into the event notification mechanism can assume that they are - * not called recursively by event handlers. Furthermore, they can assume - * that they do not block. - * - * Implementation Notes - * - * The mechanism, including senders, listeners, ands event lists are - * guarded by the mechanism's 'lock' spinlock. The listener's event - * handlers are called holding this lock. - * - * To avoid deadlock from event handlers recursively calling the - * notification mechanism, the mechanism's 'currentHandler' field stores the - * calling task during invocation of an event handler. - * - */ - -#include "vnetKernel.h" -#include "vnetEvent.h" - -typedef struct VNetEvent_EventNode VNetEvent_EventNode; - -struct VNetEvent_EventNode { - VNetEvent_EventNode *nextEvent; - VNet_EventHeader event; -}; - -#define EVENT_NODE_HEADER_SIZE offsetof(struct VNetEvent_EventNode, event) - -struct VNetEvent_Mechanism { - VNetKernel_SpinLock lock; /* mechanism lock */ - void *handlerTask; /* task calling an event handler */ - uint32 refCount; /* ref count */ - uint32 senderId; /* next sender id */ - VNetEvent_Sender *firstSender; /* first sender */ - VNetEvent_Listener *firstListener; /* first listener */ -}; - -struct VNetEvent_Sender { - VNetEvent_Mechanism *m; /* mechanism */ - uint32 senderId; /* sender id */ - VNetEvent_Sender *nextSender; /* next sender */ - VNetEvent_EventNode *firstEvent; /* first event */ -}; - -struct VNetEvent_Listener { - VNetEvent_Mechanism *m; /* mechanism */ - VNetEvent_Listener *nextListener; /* next listener */ - VNetEvent_Handler handler; /* event handler */ - void *data; /* event handler data */ - uint32 classMask; /* event handler class mask */ -}; - - -/* - *----------------------------------------------------------------------------- - * VNetEvent_Mechanism - *----------------------------------------------------------------------------- - */ - -/* - *----------------------------------------------------------------------------- - * - * VNetEvent_CreateMechanism -- - * - * Creates a mechanism. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VNetEvent_CreateMechanism(VNetEvent_Mechanism **m) // OUT: the new mechanism -{ - VNetEvent_Mechanism *t; - - /* allocate mechanism */ - t = VNetKernel_MemoryAllocate(sizeof *t); - if (t == NULL) { - return VNetKernel_ENOMEM; - } - - /* initialize mechanism */ - VNetKernel_SpinLockInit(&t->lock); - t->handlerTask = NULL; - t->refCount = 1; - t->senderId = 0; - t->firstSender = NULL; - t->firstListener = NULL; - - /* return mechanism */ - *m = t; - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VNetEvent_DestroyMechanism -- - * - * Destroys a mechanism. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VNetEvent_DestroyMechanism(VNetEvent_Mechanism *m) // IN: a mechanism -{ - uint32 refCount; - - /* check handler recursion */ - if (m->handlerTask == VNetKernel_ThreadCurrent()) { - return VNetKernel_EBUSY; - } - - /* decrement ref count */ - VNetKernel_SpinLockAcquire(&m->lock); - refCount = --m->refCount; - VNetKernel_SpinLockRelease(&m->lock); - - /* free mechanism */ - if (refCount == 0) { - VNetKernel_SpinLockFree(&m->lock); - VNetKernel_MemoryFree(m); - } - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * VNetEvent_Sender - *----------------------------------------------------------------------------- - */ - -/* - *----------------------------------------------------------------------------- - * - * VNetEvent_CreateSender -- - * - * Creates a sender. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VNetEvent_CreateSender(VNetEvent_Mechanism *m, // IN: a mechanism - VNetEvent_Sender **s) // OUT: the new sender -{ - VNetEvent_Sender *t; - - /* check handler recursion */ - if (m->handlerTask == VNetKernel_ThreadCurrent()) { - return VNetKernel_EBUSY; - } - - /* allocate sender */ - t = VNetKernel_MemoryAllocate(sizeof *t); - if (t == NULL) { - return VNetKernel_ENOMEM; - } - - /* initialize sender and insert it into sender list */ - VNetKernel_SpinLockAcquire(&m->lock); - t->m = m; - m->refCount++; - t->senderId = m->senderId; - m->senderId++; - t->nextSender = m->firstSender; - m->firstSender = t; - t->firstEvent = NULL; - VNetKernel_SpinLockRelease(&m->lock); - - /* return sender */ - *s = t; - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VNetEvent_DestroySender -- - * - * Destroys a sender. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VNetEvent_DestroySender(VNetEvent_Sender *s) // IN: a sender -{ - VNetEvent_Mechanism *m; - VNetEvent_Sender *p; - VNetEvent_Sender **q; - VNetEvent_EventNode *n; - - /* check handler recursion */ - m = s->m; - if (m->handlerTask == VNetKernel_ThreadCurrent()) { - return VNetKernel_EBUSY; - } - - /* remove sender from sender list */ - VNetKernel_SpinLockAcquire(&m->lock); - q = &m->firstSender; - while (TRUE) { - p = *q; - if (p == NULL) { - /* not found */ - VNetKernel_SpinLockRelease(&m->lock); - return VNetKernel_EINVAL; - } else if (p == s) { - /* found */ - break; - } - q = &p->nextSender; - } - *q = p->nextSender; - VNetKernel_SpinLockRelease(&m->lock); - VNetEvent_DestroyMechanism(m); - - /* free sender and events */ - n = s->firstEvent; - while (n != NULL) { - VNetEvent_EventNode *t = n; - n = n->nextEvent; - VNetKernel_MemoryFree(t); - } - VNetKernel_MemoryFree(s); - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VNetEvent_GetSenderId -- - * - * Returns the sender id of a sender. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VNetEvent_GetSenderId(const VNetEvent_Sender *s, // IN: a sender - uint32 *senderId) // OUT: the sender id -{ - - /* we don't check handler recursion */ - - /* return senderId */ - *senderId = s->senderId; - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VNetEvent_Send -- - * - * Sends an event to all listeners registered with a sender. The - * precondition 's->senderId == e->senderId' must hold. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VNetEvent_Send(VNetEvent_Sender *s, // IN: a sender - VNet_EventHeader *e) // IN: an event -{ - VNetEvent_Mechanism *m; - VNetEvent_EventNode *p; - VNetEvent_EventNode **q; - VNetEvent_Listener *l; - uint32 classSet; - - /* check handler recursion */ - m = s->m; - if (m->handlerTask == VNetKernel_ThreadCurrent()) { - return VNetKernel_EBUSY; - } - - /* precondition */ - if (s->senderId != e->senderId) { - return VNetKernel_EINVAL; - } - - /* lock */ - VNetKernel_SpinLockAcquire(&m->lock); - m->handlerTask = VNetKernel_ThreadCurrent(); - - /* find previously sent event */ - q = &s->firstEvent; - while (TRUE) { - p = *q; - if (p == NULL || - (p->event.eventId == e->eventId && p->event.type == e->type)) { - break; - } - q = &p->nextEvent; - } - - /* remove previously sent event */ - if (p != NULL && p->event.size != e->size) { - *q = p->nextEvent; - VNetKernel_MemoryFree(p); - p = NULL; - } - - /* insert new event into event list*/ - if (p == NULL) { - p = VNetKernel_MemoryAllocate(EVENT_NODE_HEADER_SIZE + e->size); - if (p == NULL) { - m->handlerTask = NULL; - VNetKernel_SpinLockRelease(&m->lock); - return VNetKernel_ENOMEM; - } - p->nextEvent = s->firstEvent; - s->firstEvent = p; - } - memcpy(&p->event, e, e->size); - - /* send event */ - classSet = e->classSet; - l = m->firstListener; - while (l != NULL) { - if ((classSet & l->classMask) != 0) { - l->handler(l->data, e); - } - l = l->nextListener; - } - - /* unlock */ - m->handlerTask = NULL; - VNetKernel_SpinLockRelease(&m->lock); - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * VNetEvent_Listener - *----------------------------------------------------------------------------- - */ - -/* - *----------------------------------------------------------------------------- - * - * VNetEvent_CreateListener -- - * - * Creates a listener and re-sends all existing events to the listener's - * event handler. The listener will receive events that satisfy - * 'event.class & classMask != 0'. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VNetEvent_CreateListener(VNetEvent_Mechanism *m, // IN: a mechanism - VNetEvent_Handler h, // IN: a handler - void *data, // IN: the handler's data - uint32 classMask, // IN: a class mask - VNetEvent_Listener **l) // OUT: the new listener -{ - VNetEvent_Listener *t; - VNetEvent_Sender *s; - VNetEvent_EventNode *e; - - /* check handler recursion */ - if (m->handlerTask == VNetKernel_ThreadCurrent()) { - return VNetKernel_EBUSY; - } - - /* allocate listener */ - t = VNetKernel_MemoryAllocate(sizeof *t); - if (t == NULL) { - return VNetKernel_ENOMEM; - } - - /* lock */ - VNetKernel_SpinLockAcquire(&m->lock); - m->handlerTask = VNetKernel_ThreadCurrent(); - - /* initialize listener and insert it into listener list */ - t->m = m; - m->refCount++; - t->nextListener = m->firstListener; - m->firstListener = t; - t->handler = h; - t->data = data; - t->classMask = classMask; - - /* creation done, so send all events */ - s = m->firstSender; - while (s != NULL) { - e = s->firstEvent; - while (e != NULL) { - if ((e->event.classSet & classMask) != 0) { - h(data, &e->event); - } - e = e->nextEvent; - } - s = s->nextSender; - } - - /* unlock */ - m->handlerTask = NULL; - VNetKernel_SpinLockRelease(&m->lock); - - /* return listener */ - *l = t; - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VNetEvent_DestroyListener -- - * - * Destroys a listener. - * - * Results: - * Returns 0 if successful, or a negative value if an error occurs. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VNetEvent_DestroyListener(VNetEvent_Listener *l) // IN: a listener -{ - VNetEvent_Mechanism *m; - VNetEvent_Listener *p; - VNetEvent_Listener **q; - - /* check handler recursion */ - m = l->m; - if (m->handlerTask == VNetKernel_ThreadCurrent()) { - return VNetKernel_EBUSY; - } - - /* remove listener from listener list */ - VNetKernel_SpinLockAcquire(&m->lock); - q = &m->firstListener; - while (TRUE) { - p = *q; - if (p == NULL) { - /* not found */ - VNetKernel_SpinLockRelease(&m->lock); - return VNetKernel_EINVAL; - } else if (p == l) { - /* found */ - break; - } - q = &p->nextListener; - } - *q = p->nextListener; - VNetKernel_SpinLockRelease(&m->lock); - VNetEvent_DestroyMechanism(m); - - /* free listener */ - VNetKernel_MemoryFree(l); - return 0; -} diff -Nrup source/vmnet-only/vnetEvent.h source.edited/vmnet-only/vnetEvent.h --- source/vmnet-only/vnetEvent.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vnetEvent.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,50 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 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 - * - *********************************************************/ - -/* - * vnetEvent.h -- - */ - -#ifndef _VNETEVENT_H_ -#define _VNETEVENT_H_ - -#include "vm_basic_types.h" -#include "vnet.h" - -typedef struct VNetEvent_Mechanism VNetEvent_Mechanism; - -typedef struct VNetEvent_Sender VNetEvent_Sender; - -typedef struct VNetEvent_Listener VNetEvent_Listener; - -typedef void (*VNetEvent_Handler)(void *data, VNet_EventHeader *e); - -int VNetEvent_CreateMechanism(VNetEvent_Mechanism **m); -int VNetEvent_DestroyMechanism(VNetEvent_Mechanism *m); - -int VNetEvent_CreateSender(VNetEvent_Mechanism *m, VNetEvent_Sender **s); -int VNetEvent_DestroySender(VNetEvent_Sender *s); -int VNetEvent_Send(VNetEvent_Sender *s, VNet_EventHeader *e); -int VNetEvent_GetSenderId(const VNetEvent_Sender *s, uint32 *senderId); - -int VNetEvent_CreateListener(VNetEvent_Mechanism *m, VNetEvent_Handler h, - void *data, uint32 classMask, - VNetEvent_Listener **l); -int VNetEvent_DestroyListener(VNetEvent_Listener *l); - -#endif // _VNETEVENT_H_ diff -Nrup source/vmnet-only/vnetFilter.h source.edited/vmnet-only/vnetFilter.h --- source/vmnet-only/vnetFilter.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vnetFilter.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,207 +0,0 @@ -/********************************************************* - * 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 - * - *********************************************************/ - -/* - * vnetFilter.h -- - * - * This file defines the external interface provided - * by the vmnet driver for host packet filter - * functionality. This functionality is likely to - * be eventually moved to a separate driver. - * - */ - -#ifndef _VNETFILTER_H_ -#define _VNETFILTER_H_ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_MODULE -#include "includeCheck.h" - -#include "vm_basic_types.h" - -/* - * Call: - * Windows vmnet driver using IOCTL_VNET_FILTERHOST2. - * Linux vmnet driver using SIOCSFILTERRULES. - */ - - -/* list of subcommands for the host filter ioctl() call */ -#define VNET_FILTER_CMD_MIN 0x1000 /* equal to smallest sub-command */ -#define VNET_FILTER_CMD_CREATE_RULE_SET 0x1000 -#define VNET_FILTER_CMD_DELETE_RULE_SET 0x1001 -#define VNET_FILTER_CMD_ADD_IPV4_RULE 0x1002 -#define VNET_FILTER_CMD_ADD_IPV6_RULE 0x1003 /* not implemented */ -#define VNET_FILTER_CMD_CHANGE_RULE_SET 0x1004 -#define VNET_FILTER_CMD_SET_LOG_LEVEL 0x1005 -#define VNET_FILTER_CMD_MAX 0x1005 /* equal to largest sub-command */ - -/* action for a rule or rule set */ -/* VNet_CreateRuleSet.defaultAction */ -/* VNet_AddIPv4Rule.action */ -/* VNet_ChangeRuleSet.defaultAction */ -#define VNET_FILTER_RULE_NO_CHANGE 0x2000 -#define VNET_FILTER_RULE_BLOCK 0x2001 -#define VNET_FILTER_RULE_ALLOW 0x2002 - -/* direction that should apply to a rule */ -/* VNet_AddIPv4Rule.direction */ -#define VNET_FILTER_DIRECTION_IN 0x3001 -#define VNET_FILTER_DIRECTION_OUT 0x3002 -#define VNET_FILTER_DIRECTION_BOTH 0x3003 - -/* used to change which rule set is used for host filtering */ -/* VNet_ChangeRuleSet.activate */ -#define VNET_FILTER_STATE_NO_CHANGE 0x4000 -#define VNET_FILTER_STATE_ENABLE 0x4001 -#define VNET_FILTER_STATE_DISABLE 0x4002 - -/* log Levels, cut and paste from bora/lib/public/policy.h */ -#define VNET_FILTER_LOGLEVEL_NONE (0) -#define VNET_FILTER_LOGLEVEL_TERSE (1) -#define VNET_FILTER_LOGLEVEL_NORMAL (2) -#define VNET_FILTER_LOGLEVEL_VERBOSE (3) -#define VNET_FILTER_LOGLEVEL_MAXIMUM (4) - -/* header that's common for all command structs */ -typedef -#include "vmware_pack_begin.h" -struct VNet_RuleHeader { - uint32 type; /* type of struct */ - uint32 ver; /* version of struct */ - uint32 len; /* length of struct */ -} -#include "vmware_pack_end.h" -VNet_RuleHeader; - -typedef -#include "vmware_pack_begin.h" -struct VNet_CreateRuleSet { - VNet_RuleHeader header; /* type = VNET_FILTER_CMD_CREATE_RULE_SET, ver = 1, - len = sizeof(VNet_CreateRuleSet) */ - - uint32 ruleSetId; /* id of rule to delete (must be non-0) */ - uint32 defaultAction; /* VNET_FILTER_RULE_DROP or VNET_FILTER_RULE_PERMIT */ -} -#include "vmware_pack_end.h" -VNet_CreateRuleSet; - -typedef -#include "vmware_pack_begin.h" -struct VNet_DeleteRuleSet { - VNet_RuleHeader header; /* type = VNET_FILTER_CMD_DELETE_RULE_SET, ver = 1, - len = sizeof(VNet_DeleteRuleSet) */ - - uint32 ruleSetId; /* rule set to delete (from VNet_CreateRuleSet.ruleSetId) */ -} -#include "vmware_pack_end.h" -VNet_DeleteRuleSet; - -typedef -#include "vmware_pack_begin.h" -struct VNet_AddIPv4Rule { - VNet_RuleHeader header; /* type = VNET_FILTER_CMD_ADD_IPV4_RULE, ver = 1, - len = sizeof(VNet_AddIPv4Rule) + - addrListLen * sizeof(VNet_IPv4Address) + - protoListLen * sizeof(VNet_IPv4Protocol) */ - - uint32 ruleSetId; /* rule set (from VNet_CreateRuleSet.ruleSetId) */ - uint32 action; /* VNET_FILTER_RULE_DROP or VNET_FILTER_RULE_PERMIT */ - uint32 direction; /* VNET_FILTER_DIRECTION_IN, VNET_FILTER_DIRECTION_OUT, or - VNET_FILTER_DIRECTION_BOTH */ - - uint32 addressListLen; /* Number of VNet_IPv4Address's that follow. - Must be at least one. Must equal 1 if addr==mask==0. - expected but not required: (addr & ~mask) == 0 */ - - uint32 proto; /* ~0 is don't care, otherwise protocol in IP header*/ - - uint32 portListLen; /* Number of VNet_IPv4Port's that follow the - VNet_IPv4Address's. Ports currently only apply for - TCP and UDP. Must be at least one, even if non-TCP or - non-UDP protocol is specified in 'proto' (use 0 or ~0 for - all elements in VNet_IPv4Port). Must equal 1 if all - elements in a VNet_IPv4Port are ~0. */ - /* add flags for tracking in which direction the connection is established? */ -} -#include "vmware_pack_end.h" -VNet_AddIPv4Rule; - -/* - * VNet_AddIPv4Rule is immediately followed by 1 or more VNet_IPv4Address. - * The last VNet_IPv4Address is immediately followed by 1 or more VNet_IPv4Port. - */ - -typedef -#include "vmware_pack_begin.h" -struct VNet_IPv4Address { - /* currently no fields for local address/mask (add them?) */ - - /* can specify don't care on IP address via addr==mask==0, - but only for a list with 1 item */ - uint32 ipv4RemoteAddr; /* remote entity's address (dst on outbound, src on inbound) */ - uint32 ipv4RemoteMask; /* remote entity's mask (dst on outbound, src on inbound) */ -} -#include "vmware_pack_end.h" -VNet_IPv4Address; - -typedef -#include "vmware_pack_begin.h" -struct VNet_IPv4Port { - /* can specify ~0 for all 4 only if one item in the list */ - - uint32 localPortLow; /* ~0 is don't care, otherwise low local range (inclusive) */ - uint32 localPortHigh; /* ~0 is don't care, otherwise high local range (inclusive) */ - uint32 remotePortLow; /* ~0 is don't care, otherwise low remote range (inclusive) */ - uint32 remotePortHigh; /* ~0 is don't care, otherwise high remote range (inclusive) */ -} -#include "vmware_pack_end.h" -VNet_IPv4Port; - -// typedef struct VNet_IPv4Port VNet_IPv6Port; - -typedef -#include "vmware_pack_begin.h" -struct VNet_ChangeRuleSet { - VNet_RuleHeader header; /* type = VNET_FILTER_CMD_CHANGE_RULE_SET, ver = 1, - len = sizeof(VNet_ChangeRuleSet) */ - - uint32 ruleSetId; /* rule set (from VNet_CreateRuleSet.ruleSetId) */ - uint32 defaultAction; /* usually VNET_FILTER_RULE_NO_CHANGE, but can change default - rule via VNET_FILTER_RULE_DROP or VNET_FILTER_RULE_PERMIT */ - uint32 activate; /* specify rule to use for filtering via - VNET_FILTER_STATE_ENABLE or VNET_FILTER_STATE_DISABLE. - Can use VNET_FILTER_STATE_NO_CHANGE to change only the - default rule of the rule set */ -} -#include "vmware_pack_end.h" -VNet_ChangeRuleSet; - -typedef -#include "vmware_pack_begin.h" -struct VNet_SetLogLevel { - VNet_RuleHeader header; /* type = VNET_FILTER_CMD_SET_LOG_LEVEL, */ - /* ver = 1, */ - /* len = sizeof(VNet_SetLogLevel) */ - uint32 logLevel; /* the log level to set */ -} -#include "vmware_pack_end.h" -VNet_SetLogLevel; - -#endif // ifndef _VNETFILTER_H_ diff -Nrup source/vmnet-only/vnetFilterInt.h source.edited/vmnet-only/vnetFilterInt.h --- source/vmnet-only/vnetFilterInt.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vnetFilterInt.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,75 +0,0 @@ -/********************************************************* - * 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 - * - *********************************************************/ - -/* - * vnetFilterInt.h - * This file defines platform-independent structures and limits that are - * internally used in the vmnet driver for packet filtering. - */ - -#ifndef _VNETFILTERINT_H_ -#define _VNETFILTERINT_H_ - -#define MAX_RULE_SETS 32 /* maximum rule sets to allow */ -#define MAX_RULES_PER_SET 64 /* maximum rules for each rule set */ -#define MAX_ADDR_PER_RULE 64 /* maximum IP addresses for one rule */ -#define MAX_PORT_PER_RULE 64 /* maximum ports for one rule */ - -typedef struct RuleAddr { - uint32 ipv4Addr; /* remote entity's address (dst on outbound, src on inbound) */ - uint32 ipv4Mask; /* remote entity's mask (dst on outbound, src on inbound) */ -} RuleAddr; - -typedef struct RulePort { - uint32 localPortLow; /* ~0 is don't care, otherwise low local range (inclusive) */ - uint32 localPortHigh; /* ~0 is don't care, otherwise high local range (inclusive) */ - uint32 remotePortLow; /* ~0 is don't care, otherwise low remote range (inclusive) */ - uint32 remotePortHigh; /* ~0 is don't care, otherwise low remote range (inclusive) */ -} RulePort; - -typedef struct Rule { - struct Rule *next; /* used for linked list */ - - uint16 action; /* VNET_FILTER_RULE_BLOCK, or VNET_FILTER_RULE_ALLOW */ - uint16 direction; /* VNET_FILTER_DIRECTION_IN, - VNET_FILTER_DIRECTION_OUT, - VNET_FILTER_DIRECTION_BOTH */ - - uint8 addressListLen; /* items in addressList (0 means don't care about address) */ - uint8 portListLen; /* items in portList (0 means don't care about port) */ - - uint16 proto; /* IP protocol that rule applies to (e.g., TCP or UDP) */ - /* ~0 mean don't care, in which case "portList" is ignored */ - - RuleAddr *addressList; /* list of IP addresses for rule */ - - RulePort *portList; /* list of port ranges for rule (if proto is TCP or UDP) */ -} Rule; - -typedef struct RuleSet { - struct RuleSet *next; /* next item in linked list */ - uint32 id; /* id provided to user-mode application */ - uint16 enabled; /* bool: tracks if used enabled to take effect for filtering */ - uint16 action; /* default action to use for rule */ - /* VNET_FILTER_RULE_BLOCK, or VNET_FILTER_RULE_ALLOW */ - struct Rule *list; /* first rule in rule set */ - struct Rule **tail; /* used to quickly add element to end of list */ - uint32 numRules; /* number of rules in 'list' */ -} RuleSet; - -#endif // _VNETFILTERINT_H_ diff -Nrup source/vmnet-only/vnet.h source.edited/vmnet-only/vnet.h --- source/vmnet-only/vnet.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/vnet.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,415 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -#ifndef _VNET_H -#define _VNET_H - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMMEXT -#include "includeCheck.h" -#include "vm_basic_types.h" -#include "vm_atomic.h" - -#define VNET_PVN_ABI_ID_LEN (256 / 8) // bytes used on ioctl() -#define VNET_PVN_ID_LEN (160 / 8) // actual length used - -#define VNET_BIND_VERSION 0x1 -#define VNET_BIND_TO_VNET 0x1 -#define VNET_BIND_TO_PVN 0x2 - -typedef struct VNet_Bind { - uint32 version; // VNET_BIND_VERSION - uint32 bindType; // VNET_BIND_TO_xxx - int32 number; // used for VNET_BIND_TO_VNET - uint8 id[VNET_PVN_ABI_ID_LEN]; // used for VNET_BIND_TO_PVN -} VNet_Bind; - -/* - * We define customized ioctl commands by adding 0x1000 - * to the standard Linux definitions. - * - * See comments in iocontrols.h - */ - -#define VNET_FIRST_CMD 0x99F2 - -// #define SIOCSKEEP 0x99F0 // not used -// #define SIOCGKEEP 0x99F1 // not used -#define SIOCSLADRF 0x99F2 -#define SIOCPORT 0x99F3 -#define SIOCBRIDGE 0x99F4 -#define SIOCNETIF 0x99F5 - -#define SIOCSETMACADDR 0x99F6 -#define SIOCSSWITCHMAP 0x99F7 -#define SIOCSETNOTIFY 0x99F8 -#define SIOCUNSETNOTIFY 0x99F9 -// #define SIOCSETCLUSTERSIZE 0x99FA // obsolete -#define SIOCSETNOTIFY2 0x99FB -#define SIOCGETAPIVERSION 0x99FC - -#define VNET_LAST_CMD 0x99FC - -#if defined __linux__ || defined __APPLE__ -#define SIOCGETAPIVERSION2 _IOWR(0x99, 0xE0, uint32) -#define SIOCGBRSTATUS _IOR(0x99, 0xFD, uint32) -#define SIOCSPEER _IOW(0x99, 0xFE, char[8]) -#define SIOCSPEER2 _IOW(0x99, 0xFE, char[32]) -#define SIOCSBIND _IOW(0x99, 0xFF, VNet_Bind) -#define SIOCSFILTERRULES _IOW(0x99, 0xE1, VNet_RuleHeader) -#define SIOCSUSERLISTENER _IOW(0x99, 0xE2, VNet_SetUserListener) -#endif - -#ifdef __APPLE__ - -#define VMNET_KEXT_NAME_BASE "com.vmware.kext.vmnet" - -#ifdef VMX86_DEVEL -#define VMNET_KEXT_NAME VMNET_KEXT_NAME_BASE ".devel" -#else -#define VMNET_KEXT_NAME VMNET_KEXT_NAME_BASE -#endif - -/* - * We use [gs]etsockopt on Mac OS instead of ioctls for operations on vmnet - */ -enum VMNetSockOpt { - VMNET_SO_APIVERSION = 0, // Must come first, should never change - VMNET_SO_BRSTATUS, - VMNET_SO_PEER, - VMNET_SO_BINDTOHUB, - VMNET_SO_IFADDR, - VMNET_SO_NETIFCREATE, - VMNET_SO_IFFLAGS, - VMNET_SO_LADRF, - VMNET_SO_BRCREATE, - VMNET_SO_SETNOTIFY, - VMNET_SO_READDATA, - VMNET_SO_UNSETNOTIFY, - VMNET_SO_SETUSERLISTENER -}; - -/* - * This magic value is populated in VNet_Notify.actMask and VNet_Notify.pollMask - * to request the driver to clear the Notify pollPtr if the receive queue is empty. - */ -#define VNET_NOTIFY_CLR_MAGIC 0xDECAFBAD - -typedef struct VNet_NetIf { - char name[16]; // The BSD name of the interface - uint8 instance; // The "unit number" of the interface -} VNet_NetIf; - -typedef struct VNet_Read { - VA uAddr; // Buffer to read into - size_t len; // Max number of bytes to read -} VNet_Read; - -#endif - -/* - * VMnet driver version. - * - * Increment major version when you make an incompatible change. - * Compatibility goes both ways (old driver with new executable - * as well as new driver with old executable). - * - * Features under the VNET_API_DEPRECATED define are deprecated (so don't use - * them), but are not important enough to justify an increase of major version. - * However, if for some other reason you need to bump the major version, please - * also remove all code under the VNET_API_DEPRECATED define. --hpreg - */ - -#ifdef linux -#define VNET_API_VERSION (3 << 16 | 0) -#elif defined __APPLE__ -#define VNET_API_VERSION (5 << 16 | 0) -#else -#define VNET_API_VERSION (5 << 16 | 0) -#endif -#define VNET_API_VERSION_MAJOR(v) ((uint32) (v) >> 16) -#define VNET_API_VERSION_MINOR(v) ((uint16) (v)) - -/* - * Make sure the deprecated code will not be compiled anymore starting with the - * next major version. --hpreg - */ -#ifdef linux -# if VNET_API_VERSION < (3 << 16 | 0) -# define VNET_API_DEPRECATED 1 -# endif -#else -# if VNET_API_VERSION < (4 << 16 | 0) -# define VNET_API_DEPRECATED 1 -# endif -#endif - -/* version 1 structure */ - -typedef struct VNet_SetMacAddrIOCTL { - int version; - unsigned char addr[6]; - unsigned flags; -} VNet_SetMacAddrIOCTL; - -typedef struct VNet_Notify { - uint32 version; - uint32 padding; /* Make gcc 64bit abi padding explicit */ - uint64 actPtr; /* (Atomic_uint32 *) */ - uint64 pollPtr; /* (uint32 volatile *) */ - uint64 recvClusterPtr; /* (uint32 volatile *) */ - uint32 actMask; - uint32 pollMask; -} VNet_Notify; - -#define VNET_SETMACADDRF_UNIQUE 0x01 -/* - * The latest 802.3 standard sort of says that the length field ought to - * be less than 1536 (for VLAN tagging support). I am choosing 1532 - * as our max VNET_MTU size, as I'd rather keep it a multiple of 4 and - * VLAN tagging uses only upto 1518 bytes. - */ -#define VNET_MTU 1532 - - -#define VNET_BUF_TOO_SMALL -1 - -/* - * vlan switch stuff - */ - - -#define VNET_MAX_VLANS 255 - -struct VNetSwitchMap { - int trunk; - int vlan; - int connect; - int vnet; -}; - -/* - *---------------------------------------------------------------------------- - * VNetEvent - *---------------------------------------------------------------------------- - */ - -/* the current version */ -#define VNET_EVENT_VERSION 1 - -/* event classes */ -#define VNET_EVENT_CLASS_BRIDGE 1 - -/* event types */ -#define VNET_EVENT_TYPE_LINK_STATE 0 - -/* parameter for SIOCSUSERLISTENER */ -typedef -#include "vmware_pack_begin.h" -struct VNet_SetUserListener { - uint32 version; - uint32 classMask; -} -#include "vmware_pack_end.h" -VNet_SetUserListener; - -/* the event header */ -typedef -#include "vmware_pack_begin.h" -struct VNet_EventHeader { - uint32 size; - uint32 senderId; - uint32 eventId; - uint32 classSet; - uint32 type; -} -#include "vmware_pack_end.h" -VNet_EventHeader; - -/* - * the link state event - * header = { sizeof(VNet_LinkStateEvent), ?, ?, VNET_EVENT_CLASS_BRIDGE, - * VNET_EVENT_TYPE_LINK_STATE } - */ -typedef -#include "vmware_pack_begin.h" -struct VNet_LinkStateEvent { - VNet_EventHeader header; - uint32 adapter; - Bool up; - char _pad[3]; -} -#include "vmware_pack_end.h" -VNet_LinkStateEvent; - -/* - *---------------------------------------------------------------------------- - */ - -#if defined __APPLE__ && !defined KERNEL - -#include -#include -#include "str.h" - -/* - *---------------------------------------------------------------------------- - * - * VMNetOpen -- - * - * Create a socket connected to the vmnet kernel control extension, bind - * it to a vmnet hub. Optionally make the socket non-blocking. Optionally - * set the interface MAC address. Optionally set interface flags. - * - * Results: - * Connected and bound socket on success. - * -1 on failure, returns error message in the "error" parameter. - * - * Side Effects: - * Allocates memory for returning "error" message to caller. Caller should - * remember to free(error). - * - *---------------------------------------------------------------------------- - */ - -static INLINE int -VMNetOpen(int hubNum, // IN: hub number to bind to - Bool nonBlocking, // IN: make socket non-blocking - VNet_SetMacAddrIOCTL *ifAddr, // IN: optional MAC address - uint32 flags, // IN: optional interface flags - char **error) // OUT: error message on failures -{ - int fd; - struct sockaddr_ctl addr; - struct ctl_info info; - socklen_t optlen; - uint32 apiVersion; - - fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); - if (fd == -1) { - if (error) { - *error = Str_Asprintf(NULL, "Failed to create control socket: " - "errno %d\n", errno); - } - return -1; - } - - bzero(&addr, sizeof addr); - addr.sc_len = sizeof addr; - addr.sc_family = AF_SYSTEM; - addr.ss_sysaddr = AF_SYS_CONTROL; - - memset(&info, 0, sizeof info); - strncpy(info.ctl_name, VMNET_KEXT_NAME, sizeof info.ctl_name); - if (ioctl(fd, CTLIOCGINFO, &info)) { - if (error) { - *error = Str_Asprintf(NULL, "ioctl(CTLIOCGINFO) failed: errno %d\n", - errno); - } - goto exit_failure; - } - - addr.sc_id = info.ctl_id; - - if (connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0) { - if (error) { - *error = Str_Asprintf(NULL, "Connect to vmnet kext failed: errno %d\n", - errno); - } - goto exit_failure; - } - - /* Optionally make socket non-blocking */ - if (nonBlocking) { - int fFlags; - fFlags = fcntl(fd, F_GETFL); - if (fFlags == -1 || fcntl(fd, F_SETFL, fFlags | O_NONBLOCK) < 0) { - if (error) { - *error = Str_Asprintf(NULL, "Couldn't make socket non-blocking: " - "errno %d\n", errno); - } - goto exit_failure; - } - } - - optlen = sizeof apiVersion; - if (getsockopt(fd, SYSPROTO_CONTROL, VMNET_SO_APIVERSION, &apiVersion, - &optlen) < 0) { - if (error) { - *error = Str_Asprintf(NULL, "getsockopt(VMNET_SO_APIVERSION) failed: " - "errno %d\n", errno); - } - goto exit_failure; - } - - if (VNET_API_VERSION_MAJOR(apiVersion) != - VNET_API_VERSION_MAJOR(VNET_API_VERSION)) { - if (error) { - *error = Str_Asprintf(NULL, "Module version mismatch. Please update " - "host.\n"); - } - goto exit_failure; - } - - if (setsockopt(fd, SYSPROTO_CONTROL, VMNET_SO_BINDTOHUB, &hubNum, - sizeof hubNum) < 0) { - if (error) { - *error = Str_Asprintf(NULL, "Could not bind to hub %d: errno %d\n", - hubNum, errno); - } - goto exit_failure; - } - - /* Optionally set MAC address */ - if (ifAddr) { - if (setsockopt(fd, SYSPROTO_CONTROL, VMNET_SO_IFADDR, ifAddr, - sizeof (*ifAddr)) < 0) { - if (error) { - *error = Str_Asprintf(NULL, "Could not set MAC address: errno %d\n", - errno); - } - goto exit_failure; - } - } - - /* Optionally set interface flags */ - if (flags) { - if (setsockopt(fd, SYSPROTO_CONTROL, VMNET_SO_IFFLAGS, &flags, - sizeof flags) < 0) { - if (error) { - *error = Str_Asprintf(NULL, "Could not set interface flags to 0x%x: " - "errno %d\n", flags, errno); - } - goto exit_failure; - } - } - - /* Return success */ - return fd; - -exit_failure: - /* Return failure */ - close(fd); - return -1; -} - -#endif // __APPLE__ && ! KERNEL - -#endif diff -Nrup source/vmnet-only/vnetInt.h source.edited/vmnet-only/vnetInt.h --- source/vmnet-only/vnetInt.h 2009-10-20 17:31:32.000000000 -0700 +++ source.edited/vmnet-only/vnetInt.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,351 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -#ifndef _VNETINT_H -#define _VNETINT_H - -#define INCLUDE_ALLOW_MODULE -#include "includeCheck.h" -#include "vnet.h" -#include "vm_oui.h" -#include "net.h" -#include "vnetEvent.h" - -#include - -#define INLINE inline - - -/* - * Logging - */ - -#ifdef notdef -#ifdef VMX86_RELEASE -#define LOGLEVEL 0 -#else -#define LOGLEVEL 1 -#endif -#endif - -#define LOGLEVEL 1 - -#if LOGLEVEL >= 0 -#define LOG(level, args) ((void) (LOGLEVEL >= (level) ? (printk args) : 0)) -#else -#define LOG(level, args) -#endif - -#define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) - -/* - * Ethernet - */ - -#define MAC_EQ(_a, _b) !memcmp((_a), (_b), ETH_ALEN) -#define SKB_2_DESTMAC(_skb) (((struct ethhdr *)(_skb)->data)->h_dest) -#define SKB_2_SRCMAC(_skb) (((struct ethhdr *)(_skb)->data)->h_source) -#define UP_AND_RUNNING(_flags) (((_flags) & (IFF_RUNNING|IFF_UP)) == \ - (IFF_RUNNING|IFF_UP)) -#ifdef KERNEL_2_3_47 -#define NETDEV_UP_AND_RUNNING(dev) ((((dev)->flags) & IFF_UP) && netif_running(dev)) -#else -#ifdef KERNEL_2_3_43 -#define NETDEV_UP_AND_RUNNING(dev) ((((dev)->flags) & IFF_UP) && test_bit(LINK_STATE_START, &(dev)->state)) -#else -#define NETDEV_UP_AND_RUNNING(dev) UP_AND_RUNNING((dev)->flags) -#endif -#endif - -/* - * Misc defines - */ - -#define NULL_TERMINATE_STRING(a) (a)[sizeof (a) - 1] = '\0' - -/* - * Fundamental sizes - */ - -#define VNET_NUM_VNETS 256 -#define VNET_MAJOR_NUMBER 119 - -#define NUM_JACKS_PER_HUB 32 -#define VNET_MAX_QLEN 128 - -#define VNET_NUM_IPBASED_MACS 64 -#define VNET_MAX_JACK_NAME_LEN 16 - -#define VNET_LADRF_LEN 8 - -#if ( defined(IFNAMSIZ) && (IFNAMSIZ >= 16) ) -#define VNET_NAME_LEN IFNAMSIZ -#else -#define VNET_NAME_LEN 16 -#endif - -/* - * Data structures - */ - -typedef struct proc_dir_entry VNetProcEntry; - -typedef struct VNetJack VNetJack; -typedef struct VNetPort VNetPort; - -/* - * The jack is the basic mechanism for connecting to objects - * that send packet between them. - */ - -extern struct semaphore vnetStructureSemaphore; - -struct VNetJack { - VNetJack *peer; - int numPorts; - char name[VNET_MAX_JACK_NAME_LEN]; - void *private; // private field for containing object - int index; // private field for containing object - VNetProcEntry *procEntry; // private field for containing object - - void (*free)(VNetJack *this); - void (*rcv)(VNetJack *this, struct sk_buff *skb); - Bool (*cycleDetect)(VNetJack *this, int generation); - void (*portsChanged)(VNetJack *this); - int (*isBridged)(VNetJack *this); -}; - - -/* - * The port is an extension of the jack. It has a user level - * interface and an ethernet address. There are 3 types of ports: - * userif, netif, and bridge. - */ - -struct VNetPort { - VNetJack jack; // must be first - unsigned id; - uint32 flags; - uint8 paddr[ETH_ALEN]; - uint8 ladrf[VNET_LADRF_LEN]; - - VNetPort *next; - - int (*fileOpRead)(VNetPort *this, struct file *filp, - char *buf, size_t count); - int (*fileOpWrite)(VNetPort *this, struct file *filp, - const char *buf, size_t count); - int (*fileOpIoctl)(VNetPort *this, struct file *filp, - unsigned int iocmd, unsigned long ioarg); - int (*fileOpPoll)(VNetPort *this, struct file *filp, - poll_table *wait); -}; - - - -/* - * Functions exported from vnet module - */ - -VNetJack *VNetHub_AllocVnet(int hubNum); -VNetJack *VNetHub_AllocPvn(uint8 id[VNET_PVN_ID_LEN]); -int VNetHub_CreateSender(VNetJack *jack, VNetEvent_Sender **s); -int VNetHub_CreateListener(VNetJack *jack, VNetEvent_Handler h, void* data, - uint32 classMask, VNetEvent_Listener **l); - -int VNetConnect(VNetJack *jack1, VNetJack *jack2); - -VNetJack *VNetDisconnect(VNetJack *jack); - -void VNetSend(const VNetJack *jack, struct sk_buff *skb); - -int VNetProc_MakeEntry(char *name, int mode, - VNetProcEntry **ret); - -void VNetProc_RemoveEntry(VNetProcEntry *node); - -int VNetPrintJack(const VNetJack *jack, char *buf); - -int VNet_MakeMACAddress(VNetPort *port); - -int VNetSetMACUnique(VNetPort *port, const uint8 mac[ETH_ALEN]); - - -/* - * Utility functions - */ - -extern const uint8 allMultiFilter[VNET_LADRF_LEN]; -extern const uint8 broadcast[ETH_ALEN]; - -Bool VNetPacketMatch(const uint8 *destAddr, const uint8 *ifAddr, - const uint8 *ladrf, uint32 flags); - -Bool VNetCycleDetectIf(const char *name, int generation); - -void VNetIncrModCount(int delta); - -int VNetPrintPort(const VNetPort *port, char *buf); - -int VNetSnprintf(char *str, size_t size, const char *format, ...); - -/* - * Procfs file system - */ - -extern int VNetProc_Init(void); - -extern void VNetProc_Cleanup(void); - - -/* - *---------------------------------------------------------------------- - * - * VNetCycleDetect -- - * - * Perform the cycle detect alogorithm for this generation. - * - * Results: - * TRUE if a cycle was detected, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE Bool -VNetCycleDetect(VNetJack *jack, // IN: jack - int generation) // IN: -{ - if (jack && jack->cycleDetect) { - return jack->cycleDetect(jack, generation); - } - - return FALSE; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetPortsChanged -- - * - * Notify a jack that the number of connected ports has changed. - * vnetStructureSemaphore must be held. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE void -VNetPortsChanged(VNetJack *jack) // IN: -{ - if (jack && jack->portsChanged) { - jack->portsChanged(jack); - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetIsBridged -- - * - * Check whether we are bridged. - * vnetPeerLock must be held. - * - * Results: - * 0 - not bridged - * 1 - we are bridged but the interface is down - * 2 - we are bridged and the interface is up - * 3 - some bridges are down - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE int -VNetIsBridged(VNetJack *jack) // IN: jack -{ - if (jack && jack->peer && jack->peer->isBridged) { - return jack->peer->isBridged(jack->peer); - } - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetFree -- - * - * Free the resources owned by the jack. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE void -VNetFree(VNetJack *jack) // IN: jack -{ - if (jack && jack->free) { - jack->free(jack); - } -} - - -/* - *---------------------------------------------------------------------- - * - * VNetGetAttachedPorts -- - * - * Get the number of ports attached to this jack through its peer. - * - * Results: - * The number of attached ports to this jack through its peer. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE int -VNetGetAttachedPorts(VNetJack *jack) // IN: jack -{ - if (jack && jack->peer) { - return jack->peer->numPorts; - } - return 0; -} - -#endif diff -Nrup source/vmnet-only/vnetKernel.h source.edited/vmnet-only/vnetKernel.h --- source/vmnet-only/vnetKernel.h 2009-10-20 17:31:32.000000000 -0700 +++ source.edited/vmnet-only/vnetKernel.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,85 +0,0 @@ -/********************************************************* - * Copyright (C) 2008 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 - * - *********************************************************/ - -/* - * vnetKernel.h -- - * This file defines platform-independent functions for accessing basic - * kernel functions. This is the Linux implementation. - */ - -#ifndef _VNETKERNEL_H_ -#define _VNETKERNEL_H_ - -#include "driver-config.h" /* must be first */ -#include -#include "compat_sched.h" -#include "compat_slab.h" -#include "compat_semaphore.h" -#include "vm_basic_types.h" - -#define VNetKernel_EBUSY (-EBUSY) -#define VNetKernel_EINVAL (-EINVAL) -#define VNetKernel_ENOMEM (-ENOMEM) - -typedef struct VNetKernel_SpinLock { - spinlock_t lock; -} VNetKernel_SpinLock; - -static INLINE void * -VNetKernel_MemoryAllocate(size_t size) -{ - return kmalloc(size, GFP_ATOMIC); -} - -static INLINE void -VNetKernel_MemoryFree(void *ptr) -{ - kfree(ptr); -} - -static INLINE void -VNetKernel_SpinLockInit(VNetKernel_SpinLock *lock) -{ - spin_lock_init(&lock->lock); -} - -static INLINE void -VNetKernel_SpinLockFree(VNetKernel_SpinLock *lock) -{ - /* nothing to do */ -} - -static INLINE void -VNetKernel_SpinLockAcquire(VNetKernel_SpinLock *lock) -{ - spin_lock(&lock->lock); -} - -static INLINE void -VNetKernel_SpinLockRelease(VNetKernel_SpinLock *lock) -{ - spin_unlock(&lock->lock); -} - -static INLINE void * -VNetKernel_ThreadCurrent(void) -{ - return current; -} - -#endif // _VNETKERNEL_H_ diff -Nrup source/vmnet-only/vnetUserListener.c source.edited/vmnet-only/vnetUserListener.c --- source/vmnet-only/vnetUserListener.c 2010-05-09 20:06:53.000000000 -0700 +++ source.edited/vmnet-only/vnetUserListener.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,334 +0,0 @@ -/********************************************************* - * Copyright (C) 2008 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 - * - *********************************************************/ - -/* - * vnetUserListener.c -- - * - * The user listener module implements an event queue that can be accessed - * by the vmx process. - * - * It registers an event listener with a given classMask. The listener - * enqueues events and the vmx process dequeues them. The vmx process can - * use blocking or non-blocking reads to consume the events. The user - * listener is thread safe. - */ - -#include "driver-config.h" /* must be first */ -#include -#include -#include "compat_skbuff.h" -#include "compat_wait.h" -#include "compat_sched.h" -#include "vnetInt.h" - -typedef struct VNetUserListener_EventNode VNetUserListener_EventNode; - -struct VNetUserListener_EventNode { - VNetUserListener_EventNode *nextEvent; - VNet_EventHeader event; -}; - -#define EVENT_NODE_HEADER_SIZE offsetof(struct VNetUserListener_EventNode, event) - -typedef struct VNetUserListener { - VNetPort port; /* base port/jack */ - VNetEvent_Listener *eventListener; /* event listener */ - struct semaphore lock; /* listener lock */ - wait_queue_head_t readerQueue; /* reader queue */ - VNetUserListener_EventNode *firstEvent; /* first event to be read */ - VNetUserListener_EventNode *lastEvent; /* last event to be read*/ -} VNetUserListener; - -static void VNetUserListenerFree(VNetJack *jack); -static void VNetUserListenerEventHandler(void *context, VNet_EventHeader *e); -static int VNetUserListenerRead(VNetPort *port, struct file *filp, char *buf, - size_t count); -static int VNetUserListenerPoll(VNetPort *port, struct file *filp, - poll_table *wait); - - -/* - *---------------------------------------------------------------------- - * - * VNetUserListener_Create -- - * - * Creates a user listener. Initializes the jack, the port, and itself. - * Finally, registers the event listener. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VNetUserListener_Create(uint32 classMask, // IN: the listener's class mask - VNetJack *hubJack, // IN: the future hub jack - VNetPort **port) // OUT: port to virtual hub -{ - static unsigned id = 0; - VNetUserListener *userListener; - int res; - - /* allocate user listener */ - userListener = kmalloc(sizeof *userListener, GFP_USER); - if (userListener == NULL) { - return -ENOMEM; - } - - /* initialize jack */ - userListener->port.jack.peer = NULL; - userListener->port.jack.numPorts = 1; - VNetSnprintf(userListener->port.jack.name, - sizeof userListener->port.jack.name, "userListener%u", id); - userListener->port.jack.private = userListener; - userListener->port.jack.index = 0; - userListener->port.jack.procEntry = NULL; - userListener->port.jack.free = VNetUserListenerFree; - userListener->port.jack.rcv = NULL; - userListener->port.jack.cycleDetect = NULL; - userListener->port.jack.portsChanged = NULL; - userListener->port.jack.isBridged = NULL; - - /* initialize port */ - userListener->port.id = id++; - userListener->port.flags = 0; - memset(userListener->port.paddr, 0, sizeof userListener->port.paddr); - memset(userListener->port.ladrf, 0, sizeof userListener->port.ladrf); - userListener->port.next = NULL; - userListener->port.fileOpRead = VNetUserListenerRead; - userListener->port.fileOpWrite = NULL; - userListener->port.fileOpIoctl = NULL; - userListener->port.fileOpPoll = VNetUserListenerPoll; - - /* initialize user listener */ - userListener->eventListener = NULL; - sema_init(&userListener->lock, 1); - init_waitqueue_head(&userListener->readerQueue); - userListener->firstEvent = NULL; - userListener->lastEvent = NULL; - - /* - * create listener, must be after initialization because it fires right away - * and populates the event queue, i.e. the event handler callback is called - * before create listener returns - */ - res = VNetHub_CreateListener(hubJack, VNetUserListenerEventHandler, - userListener, classMask, - &userListener->eventListener); - if (res != 0) { - LOG(0, (KERN_DEBUG "VNetUserListener_Create, can't create listener " - "(%d)\n", res)); - kfree(userListener); - return res; - } - - /* return listener */ - *port = (VNetPort*)userListener; - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetUserListenerFree -- - * - * Frees a user listenere. Unregisters the event listener and drains the - * event queue. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -VNetUserListenerFree(VNetJack *jack) // IN: jack to free -{ - VNetUserListener *userListener; - int res; - VNetUserListener_EventNode *p; - - /* destroy event listener */ - userListener = (VNetUserListener*)jack; - res = VNetEvent_DestroyListener(userListener->eventListener); - if (res != 0) { - LOG(0, (KERN_DEBUG "VNetUserListenerFree, can't destroy listener" - "(%d)\n", res)); - } - - /* clear event queue */ - down(&userListener->lock); - p = userListener->firstEvent; - while (p != NULL) { - VNetUserListener_EventNode *t = p; - p = p->nextEvent; - kfree(t); - } - up(&userListener->lock); - - /* free user listener */ - kfree(userListener); -} - - -/* - *---------------------------------------------------------------------- - * - * VNetUserListenerEventHandler -- - * - * Enqueues an event. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -VNetUserListenerEventHandler(void *context, // IN: the user listener - VNet_EventHeader *e) // IN: an event -{ - VNetUserListener *userListener; - VNetUserListener_EventNode *t; - - /* allocate and initialize event node */ - t = kmalloc(EVENT_NODE_HEADER_SIZE + e->size, GFP_USER); - if (t == NULL) { - LOG(0, (KERN_DEBUG "VNetUserListenerEventHandler, out of memory\n")); - return; - } - t->nextEvent = NULL; - memcpy(&t->event, e, e->size); - - /* append event to event list */ - userListener = (VNetUserListener*)context; - down(&userListener->lock); - if (userListener->lastEvent != NULL) { - userListener->lastEvent->nextEvent = t; - } else { - userListener->firstEvent = t; - } - userListener->lastEvent = t; - up(&userListener->lock); - - /* wake up readers */ - wake_up_interruptible(&userListener->readerQueue); -} - -/* - *---------------------------------------------------------------------- - * - * VNetUserListenerRead -- - * - * Dequeues an event. May or may not block depending of the filp flags. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VNetUserListenerRead(VNetPort *port, // IN: the user listener - struct file *filp, // IN: the filp - char *buf, // OUT: the buffer - size_t count) // IN: the buffer size -{ - VNetUserListener *userListener; - VNetUserListener_EventNode *t; - size_t n; - int res; - - /* wait until there is data */ - userListener = (VNetUserListener*)port->jack.private; - down(&userListener->lock); - while (userListener->firstEvent == NULL) { - up(&userListener->lock); - - /* can we block? */ - if (filp->f_flags & O_NONBLOCK) { - return -EAGAIN; - } - - /* wait until there is data or we get interrupted */ - if (wait_event_interruptible(userListener->readerQueue, - userListener->firstEvent != NULL)) { - return -ERESTARTSYS; - } - - down(&userListener->lock); - } - - /* remove event from event list */ - t = userListener->firstEvent; - userListener->firstEvent = t->nextEvent; - if (userListener->firstEvent == NULL) { - userListener->lastEvent = NULL; - } - up(&userListener->lock); - - /* return data and free event */ - n = t->event.size; - if (count < n) { - n = count; - } - res = copy_to_user(buf, &t->event, n); - kfree(t); - return res ? -EFAULT : n; -} - - -/* - *---------------------------------------------------------------------- - * - * VNetUserListenerPoll -- - * - * Polls an event. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VNetUserListenerPoll(VNetPort *port, // IN: the user listener - struct file *filp, // IN: the filp - poll_table *wait) // IN: the poll table -{ - VNetUserListener *userListener = (VNetUserListener*)port->jack.private; - poll_wait(filp, &userListener->readerQueue, wait); - return userListener->firstEvent != NULL ? POLLIN | POLLRDNORM : 0; -} diff -Nrup source/vmnet-only/x86cpuid.h source.edited/vmnet-only/x86cpuid.h --- source/vmnet-only/x86cpuid.h 2009-10-20 17:31:33.000000000 -0700 +++ source.edited/vmnet-only/x86cpuid.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,903 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -#ifndef _X86CPUID_H_ -#define _X86CPUID_H_ - -/* http://www.sandpile.org/ia32/cpuid.htm */ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_VMMEXT -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMNIXMOD -#define INCLUDE_ALLOW_DISTRIBUTE -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMMON -#include "includeCheck.h" - -#include "vm_basic_types.h" - -/* - * The linux kernel's ptrace.h stupidly defines the bare - * EAX/EBX/ECX/EDX, which wrecks havoc with our preprocessor tricks. - */ -#undef EAX -#undef EBX -#undef ECX -#undef EDX - -typedef struct CPUIDRegs { - uint32 eax, ebx, ecx, edx; -} CPUIDRegs; - -typedef union CPUIDRegsUnion { - uint32 array[4]; - CPUIDRegs regs; -} CPUIDRegsUnion; - -/* - * Results of calling cpuid(eax, ecx) on all host logical CPU. - */ -#ifdef _MSC_VER -#pragma warning (disable :4200) // non-std extension: zero-sized array in struct -#endif - -typedef -#include "vmware_pack_begin.h" -struct CPUIDReply { - /* - * Unique host logical CPU identifier. It does not change across queries, so - * we use it to correlate the replies of multiple queries. - */ - uint64 tag; // OUT - - CPUIDRegs regs; // OUT -} -#include "vmware_pack_end.h" -CPUIDReply; - -typedef -#include "vmware_pack_begin.h" -struct CPUIDQuery { - uint32 eax; // IN - uint32 ecx; // IN - uint32 numLogicalCPUs; // IN/OUT - CPUIDReply logicalCPUs[0]; // OUT -} -#include "vmware_pack_end.h" -CPUIDQuery; - -/* - * CPUID levels the monitor caches and ones that are not cached, but - * have fields defined below (short name and actual value). - * - * The first parameter defines whether the level is masked/tested - * during power-on/migration. Any level which is marked as FALSE here - * *must* have all field masks defined as IGNORE in CPUID_FIELD_DATA. - * A static assert in lib/cpuidcompat/cpuidcompat.c will check this. - * - * IMPORTANT: WHEN ADDING A NEW FIELD TO THE CACHED LEVELS, make sure - * you update vmcore/vmm/cpu/priv.c:Priv_CPUID() and vmcore/vmm64/bt/ - * cpuid_shared.S (and geninfo) to include the new level. - */ - -#define CPUID_CACHED_LEVELS \ - CPUIDLEVEL(TRUE, 0, 0) \ - CPUIDLEVEL(TRUE, 1, 1) \ - CPUIDLEVEL(FALSE,400, 0x40000000) \ - CPUIDLEVEL(FALSE,410, 0x40000010) \ - CPUIDLEVEL(FALSE, 80, 0x80000000) \ - CPUIDLEVEL(TRUE, 81, 0x80000001) \ - CPUIDLEVEL(FALSE, 88, 0x80000008) \ - CPUIDLEVEL(TRUE, 8A, 0x8000000A) - -#define CPUID_UNCACHED_LEVELS \ - CPUIDLEVEL(FALSE, 4, 4) \ - CPUIDLEVEL(FALSE, 5, 5) \ - CPUIDLEVEL(FALSE, 6, 6) \ - CPUIDLEVEL(FALSE, A, 0xA) \ - CPUIDLEVEL(FALSE, 86, 0x80000006) \ - CPUIDLEVEL(FALSE, 87, 0x80000007) \ - -#define CPUID_ALL_LEVELS \ - CPUID_CACHED_LEVELS \ - CPUID_UNCACHED_LEVELS - -/* Define cached CPUID levels in the form: CPUID_LEVEL_ */ -typedef enum { -#define CPUIDLEVEL(t, s, v) CPUID_LEVEL_##s, - CPUID_CACHED_LEVELS -#undef CPUIDLEVEL - CPUID_NUM_LEVELS -} CpuidLevels; - -/* - * CPUID result registers - */ - -#define CPUID_REGS \ - CPUIDREG(EAX, eax) \ - CPUIDREG(EBX, ebx) \ - CPUIDREG(ECX, ecx) \ - CPUIDREG(EDX, edx) - -typedef enum { -#define CPUIDREG(uc, lc) CPUID_REG_##uc, - CPUID_REGS -#undef CPUIDREG - CPUID_NUM_REGS -} CpuidRegs; - -/* - * CPU vendors - */ - -typedef enum { - CPUID_VENDOR_UNKNOWN, - CPUID_VENDOR_COMMON, - CPUID_VENDOR_INTEL, - CPUID_VENDOR_AMD, - CPUID_VENDOR_CYRIX, - CPUID_NUM_VENDORS -} CpuidVendors; - -#define CPUID_INTEL_VENDOR_STRING "GenuntelineI" -#define CPUID_AMD_VENDOR_STRING "AuthcAMDenti" -#define CPUID_CYRIX_VENDOR_STRING "CyriteadxIns" -#define CPUID_INTEL_VENDOR_STRING_FIXED "GenuineIntel" -#define CPUID_AMD_VENDOR_STRING_FIXED "AuthenticAMD" -#define CPUID_CYRIX_VENDOR_STRING_FIXED "CyrixInstead" - -#define CPUID_HYPERV_HYPERVISOR_VENDOR_STRING "Microsoft Hv" - -/* - * FIELDDEF can be defined to process the CPUID information provided - * in the following CPUID_FIELD_DATA macro. The first parameter is - * the CPUID level of the feature (must be defined in CPUID_*_LEVELS. - * The second parameter is the register the field is contained in - * (defined in CPUID_REGS). The third field is the vendor this - * feature applies to. "COMMON" means all vendors apply. UNKNOWN may - * not be used here. The fourth and fifth parameters are the bit - * position of the field and the width, respectively. The sixth is - * the text name of the field. - * - * The seventh and eighth parameters specify the default CPUID - * behavior for power-on, guest view, and migration tests (cpt/rsm & - * vmotion). The eighth parameter is ignored for types other than - * MASK & TEST, and must be zero in this case. - * - * When adding a new field, be sure to consider its purpose. The - * following list of types is provided in order of likely use. - * - * NOTE: this form of representation is separate from the masking - * system specified via the config file. That is because this - * representation must take into account multi-bit fields. - * - * HOST - Passthrough host value and cannot change during migration. - * MASK, 0 - Hide from the guest, because we don't support it or we - * don't want the guest to know that it exists. - * IGNORE - Ignore this field for all tests - * - * (Think twice before using the below mask types/combinations) - * - * MASK, x - Force the guest to always see x, and don't compare for - * migration -- only APIC as of today; it is controlled by - * software and we know how to toggle it - * TEST, x - Require host CPUID field to be x for power-on - * RSVD - Hidden from the guest, but compared during migration - * - * - * Table to explain mask type meanings: - * - * IGNR MASK TEST HOST RSVD - * -------------------------------------------------------- - * Req'd val for power-on - - x - - - * Value guest sees * x * * 0 - * Checked on migration? N N Y Y Y - * - * * - initial host's power-on CPUID value - * - * FIELDDEFA takes a ninth parameter, the name used when creating - * accessor functions in lib/public/cpuidInfoFuncs.h. - * - * FLAGDEF/FLAGDEFA is defined identically to fields, but their - * accessors are more appropriate for 1-bit flags. - */ - -typedef enum { - CPUID_FIELD_MASK_IGNORE, - CPUID_FIELD_MASK_MASK, - CPUID_FIELD_MASK_TEST, - CPUID_FIELD_MASK_HOST, - CPUID_FIELD_MASK_RSVD, - CPUID_NUM_FIELD_MASKS -} CpuidFieldMasks; - -/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ -#define CPUID_FIELD_DATA_LEVEL_0 \ -FIELDDEF( 0, EAX, COMMON, 0, 32, NUMLEVELS, IGNORE, 0, FALSE) \ -FIELDDEF( 0, EBX, COMMON, 0, 32, VENDOR1, HOST, 0, TRUE) \ -FIELDDEF( 0, ECX, COMMON, 0, 32, VENDOR3, HOST, 0, TRUE) \ -FIELDDEF( 0, EDX, COMMON, 0, 32, VENDOR2, HOST, 0, TRUE) - -/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ -#define CPUID_FIELD_DATA_LEVEL_1 \ -FIELDDEFA( 1, EAX, COMMON, 0, 4, STEPPING, IGNORE, 0, FALSE, STEPPING) \ -FIELDDEFA( 1, EAX, COMMON, 4, 4, MODEL, IGNORE, 0, FALSE, MODEL) \ -FIELDDEFA( 1, EAX, COMMON, 8, 4, FAMILY, HOST, 0, FALSE, FAMILY) \ -FIELDDEF( 1, EAX, COMMON, 12, 2, TYPE, IGNORE, 0, FALSE) \ -FIELDDEFA( 1, EAX, COMMON, 16, 4, EXTMODEL, IGNORE, 0, FALSE, EXT_MODEL) \ -FIELDDEFA( 1, EAX, COMMON, 20, 8, EXTFAMILY, HOST, 0, FALSE, EXT_FAMILY) \ -FIELDDEF( 1, EBX, COMMON, 0, 8, BRAND_ID, IGNORE, 0, FALSE) \ -FIELDDEF( 1, EBX, COMMON, 8, 8, CLFL_SIZE, IGNORE, 0, FALSE) \ -FIELDDEFA( 1, EBX, COMMON, 16, 8, LCPU_COUNT, IGNORE, 0, FALSE, LCPU_COUNT) \ -FIELDDEFA( 1, EBX, COMMON, 24, 8, APICID, IGNORE, 0, FALSE, APICID) \ -FLAGDEFA( 1, ECX, COMMON, 0, 1, SSE3, HOST, 0, TRUE, SSE3) \ -FLAGDEF( 1, ECX, INTEL, 2, 1, NDA2, MASK, 0, FALSE) \ -FLAGDEFA( 1, ECX, COMMON, 3, 1, MWAIT, MASK, 0, FALSE, MWAIT) \ -FLAGDEFA( 1, ECX, INTEL, 4, 1, DSCPL, MASK, 0, FALSE, DSCPL) \ -FLAGDEFA( 1, ECX, INTEL, 5, 1, VMX, MASK, 0, FALSE, VMX) \ -FLAGDEF( 1, ECX, INTEL, 6, 1, SMX, MASK, 0, FALSE) \ -FLAGDEF( 1, ECX, INTEL, 7, 1, EST, MASK, 0, FALSE) \ -FLAGDEF( 1, ECX, INTEL, 8, 1, TM2, MASK, 0, FALSE) \ -FLAGDEFA( 1, ECX, COMMON, 9, 1, SSSE3, HOST, 0, TRUE, SSSE3) \ -FLAGDEF( 1, ECX, INTEL, 10, 1, HTCACHE, MASK, 0, FALSE) \ -FLAGDEFA( 1, ECX, COMMON, 13, 1, CMPX16, HOST, 0, TRUE, CMPX16) \ -FLAGDEF( 1, ECX, INTEL, 14, 1, xPPR, MASK, 0, FALSE) \ -FLAGDEF( 1, ECX, INTEL, 15, 1, PERF_MSR, MASK, 0, FALSE) \ -FLAGDEF( 1, ECX, INTEL, 18, 1, DCA, MASK, 0, FALSE) \ -FLAGDEFA( 1, ECX, INTEL, 19, 1, SSE41, HOST, 0, TRUE, SSE41) \ -FLAGDEFA( 1, ECX, INTEL, 20, 1, SSE42, HOST, 0, TRUE, SSE42) \ -FLAGDEF( 1, ECX, INTEL, 21, 1, X2APIC, MASK, 0, FALSE) \ -FLAGDEF( 1, ECX, INTEL, 22, 1, MOVBE, RSVD, 0, TRUE) \ -FLAGDEFA( 1, ECX, COMMON, 23, 1, POPCNT, HOST, 0, TRUE, POPCNT) \ -FLAGDEF( 1, ECX, INTEL, 24, 1, ULE, RSVD, 0, TRUE) \ -FLAGDEF( 1, ECX, INTEL, 26, 1, XSAVE, MASK, 0, FALSE) \ -FLAGDEF( 1, ECX, INTEL, 27, 1, OSXSAVE, RSVD, 0, TRUE) \ -FLAGDEFA( 1, ECX, COMMON, 31, 1, HYPERVISOR, IGNORE, 0, FALSE, HYPERVISOR)\ -FLAGDEFA( 1, EDX, COMMON, 0, 1, FPU, HOST, 0, TRUE, FPU) \ -FLAGDEFA( 1, EDX, COMMON, 1, 1, VME, HOST, 0, FALSE, VME) \ -FLAGDEF( 1, EDX, COMMON, 2, 1, DBGE, HOST, 0, FALSE) \ -FLAGDEF( 1, EDX, COMMON, 3, 1, PGSZE, HOST, 0, FALSE) \ -FLAGDEFA( 1, EDX, COMMON, 4, 1, TSC, HOST, 0, TRUE, TSC) \ -FLAGDEF( 1, EDX, COMMON, 5, 1, MSR, HOST, 0, FALSE) \ -FLAGDEFA( 1, EDX, COMMON, 6, 1, PAE, HOST, 0, FALSE, PAE) \ -FLAGDEF( 1, EDX, COMMON, 7, 1, MCK, HOST, 0, FALSE) \ -FLAGDEF( 1, EDX, COMMON, 8, 1, CPMX, HOST, 0, TRUE) \ -FLAGDEFA( 1, EDX, COMMON, 9, 1, APIC, MASK, 1, FALSE, APIC) \ -FLAGDEFA( 1, EDX, COMMON, 11, 1, SEP, HOST, 0, TRUE, SEP) \ -FLAGDEFA( 1, EDX, COMMON, 12, 1, MTRR, HOST, 0, FALSE, MTRR) \ -FLAGDEFA( 1, EDX, COMMON, 13, 1, PGE, HOST, 0, FALSE, PGE) \ -FLAGDEFA( 1, EDX, COMMON, 14, 1, MCA, HOST, 0, FALSE, MCA) \ -FLAGDEFA( 1, EDX, COMMON, 15, 1, CMOV, HOST, 0, TRUE, CMOV) \ -FLAGDEFA( 1, EDX, COMMON, 16, 1, PAT, HOST, 0, FALSE, PAT) \ -FLAGDEF( 1, EDX, COMMON, 17, 1, 36PG, HOST, 0, FALSE) \ -FLAGDEF( 1, EDX, INTEL, 18, 1, PSN, HOST, 0, FALSE) \ -FLAGDEFA( 1, EDX, COMMON, 19, 1, CLFL, HOST, 0, TRUE, CLFL) \ -FLAGDEF( 1, EDX, INTEL, 21, 1, DTES, HOST, 0, FALSE) \ -FLAGDEF( 1, EDX, INTEL, 22, 1, ACPI, HOST, 0, FALSE) \ -FLAGDEFA( 1, EDX, COMMON, 23, 1, MMX, HOST, 0, TRUE, MMX) \ -FLAGDEFA( 1, EDX, COMMON, 24, 1, FXSAVE, HOST, 0, TRUE, FXSAVE) \ -FLAGDEFA( 1, EDX, COMMON, 25, 1, SSE, HOST, 0, TRUE, SSE) \ -FLAGDEFA( 1, EDX, COMMON, 26, 1, SSE2, HOST, 0, TRUE, SSE2) \ -FLAGDEF( 1, EDX, INTEL, 27, 1, SS, HOST, 0, FALSE) \ -FLAGDEFA( 1, EDX, COMMON, 28, 1, HT, MASK, 0, FALSE, HT) \ -FLAGDEF( 1, EDX, INTEL, 29, 1, TM, MASK, 0, FALSE) \ -FLAGDEF( 1, EDX, INTEL, 30, 1, IA64, MASK, 0, FALSE) \ -FLAGDEF( 1, EDX, INTEL, 31, 1, PBE, MASK, 0, FALSE) - -/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ -#define CPUID_FIELD_DATA_LEVEL_4 \ -FIELDDEF( 4, EAX, INTEL, 0, 5, CACHE_TYPE, IGNORE, 0, FALSE) \ -FIELDDEF( 4, EAX, INTEL, 5, 3, CACHE_LEVEL, IGNORE, 0, FALSE) \ -FIELDDEF( 4, EAX, INTEL, 14, 12, CACHE_NUMHT_SHARING, IGNORE, 0, FALSE) \ -FIELDDEFA( 4, EAX, INTEL, 26, 6, CORE_COUNT, IGNORE, 0, FALSE, INTEL_CORE_COUNT) \ -FIELDDEF( 4, EBX, INTEL, 0, 12, CACHE_LINE, IGNORE, 0, FALSE) \ -FIELDDEF( 4, EBX, INTEL, 12, 10, CACHE_PART, IGNORE, 0, FALSE) \ -FIELDDEF( 4, EBX, INTEL, 22, 10, CACHE_WAYS, IGNORE, 0, FALSE) - -/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ -#define CPUID_FIELD_DATA_LEVEL_5 \ -FIELDDEF( 5, EAX, COMMON, 0, 16, MWAIT_MIN_SIZE, IGNORE, 0, FALSE) \ -FIELDDEF( 5, EBX, COMMON, 0, 16, MWAIT_MAX_SIZE, IGNORE, 0, FALSE) \ -FLAGDEF( 5, ECX, COMMON, 0, 1, MWAIT_EXTENSIONS, IGNORE, 0, FALSE) \ -FLAGDEF( 5, ECX, COMMON, 1, 1, MWAIT_INTR_BREAK, IGNORE, 0, FALSE) \ -FIELDDEF( 5, EDX, INTEL, 0, 4, MWAIT_C0_SUBSTATE, IGNORE, 0, FALSE) \ -FIELDDEF( 5, EDX, INTEL, 4, 4, MWAIT_C1_SUBSTATE, IGNORE, 0, FALSE) \ -FIELDDEF( 5, EDX, INTEL, 8, 4, MWAIT_C2_SUBSTATE, IGNORE, 0, FALSE) \ -FIELDDEF( 5, EDX, INTEL, 12, 4, MWAIT_C3_SUBSTATE, IGNORE, 0, FALSE) \ -FIELDDEF( 5, EDX, INTEL, 16, 4, MWAIT_C4_SUBSTATE, IGNORE, 0, FALSE) - -/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ -#define CPUID_FIELD_DATA_LEVEL_6 \ -FLAGDEF( 6, EAX, INTEL, 0, 1, THERMAL_SENSOR, IGNORE, 0, FALSE) \ -FLAGDEF( 6, EAX, INTEL, 1, 1, TURBO_MODE, IGNORE, 0, FALSE) \ -FIELDDEF( 6, EBX, INTEL, 0, 4, NUM_INTR_THRESHOLDS, IGNORE, 0, FALSE) \ -FLAGDEF( 6, ECX, INTEL, 0, 1, HW_COORD_FEEDBACK, IGNORE, 0, FALSE) - -/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ -#define CPUID_FIELD_DATA_LEVEL_A \ -FIELDDEFA( A, EAX, INTEL, 0, 8, PMC_VERSION, IGNORE, 0, FALSE, PMC_VERSION) \ -FIELDDEFA( A, EAX, INTEL, 8, 8, NUM_PMCS, IGNORE, 0, FALSE, NUM_PMCS) \ -FIELDDEF( A, EAX, INTEL, 16, 8, PMC_BIT_WIDTH, IGNORE, 0, FALSE) \ -FIELDDEFA( A, EAX, INTEL, 24, 8, PMC_EBX_LENGTH, IGNORE, 0, FALSE, PMC_EBX_LENGTH) \ -FLAGDEF( A, EBX, INTEL, 0, 1, PMC_CORE_CYCLE, IGNORE, 0, FALSE) \ -FLAGDEF( A, EBX, INTEL, 1, 1, PMC_INSTR_RETIRED, IGNORE, 0, FALSE) \ -FLAGDEF( A, EBX, INTEL, 2, 1, PMC_REF_CYCLES, IGNORE, 0, FALSE) \ -FLAGDEF( A, EBX, INTEL, 3, 1, PMC_LAST_LVL_CREF, IGNORE, 0, FALSE) \ -FLAGDEF( A, EBX, INTEL, 4, 1, PMC_LAST_LVL_CMISS, IGNORE, 0, FALSE) \ -FLAGDEF( A, EBX, INTEL, 5, 1, PMC_BR_INST_RETIRED, IGNORE, 0, FALSE) \ -FLAGDEF( A, EBX, INTEL, 6, 1, PMC_BR_MISS_RETIRED, IGNORE, 0, FALSE) - -/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ -#define CPUID_FIELD_DATA_LEVEL_80 \ -FIELDDEF( 80, EAX, COMMON, 0, 32, NUM_EXT_LEVELS, IGNORE, 0, FALSE) \ -FIELDDEF( 80, EBX, AMD, 0, 32, AMD_VENDOR1, IGNORE, 0, FALSE) \ -FIELDDEF( 80, ECX, AMD, 0, 32, AMD_VENDOR3, IGNORE, 0, FALSE) \ -FIELDDEF( 80, EDX, AMD, 0, 32, AMD_VENDOR2, IGNORE, 0, FALSE) - -/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ -#define CPUID_FIELD_DATA_LEVEL_81 \ -FIELDDEF( 81, EAX, INTEL, 0, 32, UNKNOWN81EAX, IGNORE, 0, FALSE) \ -FIELDDEF( 81, EAX, AMD, 0, 4, STEPPING, IGNORE, 0, FALSE) \ -FIELDDEF( 81, EAX, AMD, 4, 4, MODEL, IGNORE, 0, FALSE) \ -FIELDDEF( 81, EAX, AMD, 8, 4, FAMILY, IGNORE, 0, FALSE) \ -FIELDDEF( 81, EAX, AMD, 12, 2, TYPE, IGNORE, 0, FALSE) \ -FIELDDEF( 81, EAX, AMD, 16, 4, EXTMODEL, IGNORE, 0, FALSE) \ -FIELDDEF( 81, EAX, AMD, 20, 8, EXTFAMILY, IGNORE, 0, FALSE) \ -FIELDDEF( 81, EBX, INTEL, 0, 32, UNKNOWN81EBX, IGNORE, 0, FALSE) \ -FIELDDEF( 81, EBX, AMD, 0, 16, BRAND_ID, IGNORE, 0, FALSE) \ -FIELDDEF( 81, EBX, AMD, 16, 16, UNDEF, IGNORE, 0, FALSE) \ -FLAGDEFA( 81, ECX, COMMON, 0, 1, LAHF, HOST, 0, TRUE, LAHF64) \ -FLAGDEFA( 81, ECX, AMD, 1, 1, CMPLEGACY, MASK, 0, FALSE, CMPLEGACY) \ -FLAGDEFA( 81, ECX, AMD, 2, 1, SVM, MASK, 0, FALSE, SVM) \ -FLAGDEFA( 81, ECX, AMD, 3, 1, EXTAPICSPC, HOST, 0, FALSE, EXTAPICSPC) \ -FLAGDEFA( 81, ECX, AMD, 4, 1, CR8AVAIL, MASK, 0, FALSE, CR8AVAIL) \ -FLAGDEFA( 81, ECX, AMD, 5, 1, ABM, HOST, 0, TRUE, ABM) \ -FLAGDEFA( 81, ECX, AMD, 6, 1, SSE4A, HOST, 0, TRUE, SSE4A) \ -FLAGDEF( 81, ECX, AMD, 7, 1, MISALIGNED_SSE, HOST, 0, TRUE) \ -FLAGDEFA( 81, ECX, AMD, 8, 1, 3DNPREFETCH, HOST, 0, TRUE, 3DNPREFETCH) \ -FLAGDEF( 81, ECX, AMD, 9, 1, OSVW, MASK, 0, FALSE) \ -FLAGDEF( 81, ECX, AMD, 10, 1, IBS, MASK, 0, FALSE) \ -FLAGDEF( 81, ECX, AMD, 11, 1, SSE5, RSVD, 0, TRUE) \ -FLAGDEF( 81, ECX, AMD, 12, 1, SKINIT, MASK, 0, FALSE) \ -FLAGDEF( 81, ECX, AMD, 13, 1, WATCHDOG, MASK, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 0, 1, FPU, HOST, 0, TRUE) \ -FLAGDEF( 81, EDX, AMD, 1, 1, VME, HOST, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 2, 1, DBGE, HOST, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 3, 1, PGSZE, HOST, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 4, 1, TSC, HOST, 0, TRUE) \ -FLAGDEF( 81, EDX, AMD, 5, 1, MSR, HOST, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 6, 1, PAE, HOST, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 7, 1, MCK, HOST, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 8, 1, CPMX, HOST, 0, TRUE) \ -FLAGDEF( 81, EDX, AMD, 9, 1, APIC, MASK, 1, FALSE) \ -FLAGDEFA( 81, EDX, COMMON, 11, 1, SYSC, IGNORE, 0, TRUE, SYSC) \ -FLAGDEF( 81, EDX, AMD, 12, 1, MTRR, HOST, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 13, 1, PGE, HOST, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 14, 1, MCA, HOST, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 15, 1, CMOV, HOST, 0, TRUE) \ -FLAGDEF( 81, EDX, AMD, 16, 1, PAT, HOST, 0, FALSE) \ -FLAGDEF( 81, EDX, AMD, 17, 1, 36PG, HOST, 0, FALSE) \ -FLAGDEFA( 81, EDX, COMMON, 20, 1, NX, HOST, 0, FALSE, NX) \ -FLAGDEFA( 81, EDX, AMD, 22, 1, MMXEXT, HOST, 0, TRUE, MMXEXT) \ -FLAGDEF( 81, EDX, AMD, 23, 1, MMX, HOST, 0, TRUE) \ -FLAGDEF( 81, EDX, AMD, 24, 1, FXSAVE, HOST, 0, TRUE) \ -FLAGDEFA( 81, EDX, AMD, 25, 1, FFXSR, HOST, 0, FALSE, FFXSR) \ -FLAGDEF( 81, EDX, AMD, 26, 1, PDPE1GB, MASK, 0, FALSE) \ -FLAGDEFA( 81, EDX, COMMON, 27, 1, RDTSCP, HOST, 0, TRUE, RDTSCP) \ -FLAGDEFA( 81, EDX, COMMON, 29, 1, LM, TEST, 1, FALSE, LM) \ -FLAGDEFA( 81, EDX, AMD, 30, 1, 3DNOWPLUS, HOST, 0, TRUE, 3DNOWPLUS) \ -FLAGDEFA( 81, EDX, AMD, 31, 1, 3DNOW, HOST, 0, TRUE, 3DNOW) - -/* LEVEL, REG, VENDOR, POS, SIZE, NAME, MASK TYPE, SET TO, CPL3, [FUNC] */ -#define CPUID_FIELD_DATA_LEVEL_8x \ -FIELDDEF( 86, ECX, AMD, 0, 8, CACHE_LINE, IGNORE, 0, FALSE) \ -FIELDDEF( 86, ECX, AMD, 8, 4, CACHE_LINE_PER_TAG, IGNORE, 0, FALSE) \ -FIELDDEF( 86, ECX, AMD, 12, 4, CACHE_WAYS, IGNORE, 0, FALSE) \ -FIELDDEF( 86, ECX, AMD, 16, 16, CACHE_SIZE, IGNORE, 0, FALSE) \ -FLAGDEF( 87, EDX, AMD, 0, 1, TS, IGNORE, 0, FALSE) \ -FLAGDEF( 87, EDX, AMD, 1, 1, FID, IGNORE, 0, FALSE) \ -FLAGDEF( 87, EDX, AMD, 2, 1, VID, IGNORE, 0, FALSE) \ -FLAGDEF( 87, EDX, AMD, 3, 1, TTP, IGNORE, 0, FALSE) \ -FLAGDEF( 87, EDX, AMD, 4, 1, TM, IGNORE, 0, FALSE) \ -FLAGDEF( 87, EDX, AMD, 5, 1, STC, IGNORE, 0, FALSE) \ -FLAGDEF( 87, EDX, AMD, 6, 1, 100MHZSTEPS, IGNORE, 0, FALSE) \ -FLAGDEF( 87, EDX, AMD, 7, 1, HWPSTATE, IGNORE, 0, FALSE) \ -FLAGDEF( 87, EDX, AMD, 8, 1, TSC_INVARIANT, IGNORE, 0, FALSE) \ -FIELDDEFA(88, EAX, COMMON, 0, 8, PHYSBITS, IGNORE, 0, FALSE, PHYS_BITS) \ -FIELDDEFA(88, EAX, COMMON, 8, 8, VIRTBITS, IGNORE, 0, FALSE, VIRT_BITS) \ -FIELDDEFA(88, ECX, AMD, 0, 8, CORE_COUNT, IGNORE, 0, FALSE, AMD_CORE_COUNT) \ -FIELDDEF( 88, ECX, AMD, 12, 4, APICID_COREID_SIZE, IGNORE, 0, FALSE) \ -FIELDDEFA(8A, EAX, AMD, 0, 8, SVM_REVISION, MASK, 0, FALSE, SVM_REVISION) \ -FLAGDEF( 8A, EAX, AMD, 8, 1, SVM_HYPERVISOR, MASK, 0, FALSE) \ -FIELDDEF( 8A, EAX, AMD, 9, 23, SVMEAX_RSVD, MASK, 0, FALSE) \ -FIELDDEF( 8A, EBX, AMD, 0, 32, SVM_N_ASIDS, MASK, 0, FALSE) \ -FIELDDEF( 8A, ECX, AMD, 0, 32, SVMECX_RSVD, MASK, 0, FALSE) \ -FLAGDEFA( 8A, EDX, AMD, 0, 1, SVM_NP, MASK, 0, FALSE, NPT) \ -FLAGDEF( 8A, EDX, AMD, 1, 1, SVM_LBR, MASK, 0, FALSE) \ -FLAGDEF( 8A, EDX, AMD, 2, 1, SVM_LOCK, MASK, 0, FALSE) \ -FLAGDEF( 8A, EDX, AMD, 3, 1, SVM_NRIP, MASK, 0, FALSE) \ -FIELDDEF( 8A, EDX, AMD, 4, 28, SVMEDX_RSVD, MASK, 0, FALSE) - -#define CPUID_FIELD_DATA \ - CPUID_FIELD_DATA_LEVEL_0 \ - CPUID_FIELD_DATA_LEVEL_1 \ - CPUID_FIELD_DATA_LEVEL_4 \ - CPUID_FIELD_DATA_LEVEL_5 \ - CPUID_FIELD_DATA_LEVEL_6 \ - CPUID_FIELD_DATA_LEVEL_A \ - CPUID_FIELD_DATA_LEVEL_80 \ - CPUID_FIELD_DATA_LEVEL_81 \ - CPUID_FIELD_DATA_LEVEL_8x - -/* - * Define all field and flag values as an enum. The result is a full - * set of values taken from the table above in the form: - * - * CPUID_FEATURE__ID_ == mask for feature - * CPUID__ID__MASK == mask for field - * CPUID__ID__SHIFT == offset of field - * - * e.g. - CPUID_FEATURE_COMMON_ID1EDX_FPU = 0x1 - * - CPUID_COMMON_ID88EAX_VIRTBITS_MASK = 0xff00 - * - CPUID_COMMON_ID88EAX_VIRTBITS_SHIFT = 8 - * - * Note: The FEATURE/MASK definitions must use some gymnastics to get - * around a warning when shifting left by 32. - */ -#define VMW_BIT_MASK(shift) (((1 << (shift - 1)) << 1) - 1) - -#define FIELDDEF(lvl, reg, vend, bitpos, size, name, m, v, c3) \ - CPUID_##vend##_ID##lvl##reg##_##name##_SHIFT = bitpos, \ - CPUID_##vend##_ID##lvl##reg##_##name##_MASK = \ - VMW_BIT_MASK(size) << bitpos, \ - CPUID_FEATURE_##vend##_ID##lvl##reg##_##name = \ - CPUID_##vend##_ID##lvl##reg##_##name##_MASK, - -#define FIELDDEFA(lvl, reg, vend, bitpos, size, name, m, v, c3, f) \ - CPUID_##vend##_ID##lvl##reg##_##name##_SHIFT = bitpos, \ - CPUID_##vend##_ID##lvl##reg##_##name##_MASK = \ - VMW_BIT_MASK(size) << bitpos, \ - CPUID_FEATURE_##vend##_ID##lvl##reg##_##name = \ - CPUID_##vend##_ID##lvl##reg##_##name##_MASK, - -#define FLAGDEFA FIELDDEFA -#define FLAGDEF FIELDDEF - -enum { - /* Define data for every CPUID field we have */ - CPUID_FIELD_DATA -}; -#undef VMW_BIT_MASK -#undef FIELDDEF -#undef FLAGDEF -#undef FIELDDEFA -#undef FLAGDEFA - -/* - * Legal CPUID config file mask characters. For a description of the - * cpuid masking system, please see: - * - * http://vmweb.vmware.com/~mts/cgi-bin/view.cgi/Apps/CpuMigrationChecks - */ - -#define CPUID_MASK_HIDE_CHR '0' -#define CPUID_MASK_HIDE_STR "0" -#define CPUID_MASK_FORCE_CHR '1' -#define CPUID_MASK_FORCE_STR "1" -#define CPUID_MASK_PASS_CHR '-' -#define CPUID_MASK_PASS_STR "-" -#define CPUID_MASK_TRUE_CHR 'T' -#define CPUID_MASK_TRUE_STR "T" -#define CPUID_MASK_FALSE_CHR 'F' -#define CPUID_MASK_FALSE_STR "F" -#define CPUID_MASK_IGNORE_CHR 'X' -#define CPUID_MASK_IGNORE_STR "X" -#define CPUID_MASK_HOST_CHR 'H' -#define CPUID_MASK_HOST_STR "H" -#define CPUID_MASK_RSVD_CHR 'R' -#define CPUID_MASK_RSVD_STR "R" -#define CPUID_MASK_INSTALL_CHR 'I' -#define CPUID_MASK_INSTALL_STR "I" - -/* - * If a level is listed as not masked/tested in CPUID_LEVELS above, - * use all "don't care" values for its mask. - */ - -#define CPT_DFLT_UNDEFINED_MASK "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX" - -/* - * When LM is disabled, we overlay the following masks onto the - * guest's default masks. Any level that is not defined below should - * be treated as all "-"s - */ - -#define CPT_ID1ECX_LM_DISABLED "----:----:----:----:--0-:----:----:----" -#define CPT_ID81EDX_LM_DISABLED "--0-:----:----:----:----:----:----:----" -#define CPT_ID81ECX_LM_DISABLED "----:----:----:----:----:----:----:---0" - -#define CPT_GET_LM_DISABLED_MASK(lvl, reg) \ - ((lvl == 1 && reg == CPUID_REG_ECX) ? CPT_ID1ECX_LM_DISABLED : \ - (lvl == 0x80000001 && reg == CPUID_REG_ECX) ? CPT_ID81ECX_LM_DISABLED : \ - (lvl == 0x80000001 && reg == CPUID_REG_EDX) ? CPT_ID81EDX_LM_DISABLED : \ - NULL) - -/* - * Macro to define GET and SET functions for various common CPUID - * fields. To create function for a new field, simply name it (CPUID_ - * and CPUID_SET_ are automatically prepended), and list the field - * name that it needs to use. - */ - -#define FIELD_FUNC(name, field) \ - static INLINE uint32 CPUID_##name(uint32 reg) \ - { \ - return (reg & field##_MASK) >> field##_SHIFT; \ - } \ - static INLINE void CPUID_SET_##name(uint32 *reg, uint32 val) \ - { \ - *reg = (*reg & ~field##_MASK) | (val << field##_SHIFT); \ - } - -FIELD_FUNC(STEPPING, CPUID_COMMON_ID1EAX_STEPPING) -FIELD_FUNC(MODEL, CPUID_COMMON_ID1EAX_MODEL) -FIELD_FUNC(FAMILY, CPUID_COMMON_ID1EAX_FAMILY) -FIELD_FUNC(TYPE, CPUID_COMMON_ID1EAX_TYPE) -FIELD_FUNC(EXTENDED_MODEL, CPUID_COMMON_ID1EAX_EXTMODEL) -FIELD_FUNC(EXTENDED_FAMILY, CPUID_COMMON_ID1EAX_EXTFAMILY) -FIELD_FUNC(LCPU_COUNT, CPUID_COMMON_ID1EBX_LCPU_COUNT) -FIELD_FUNC(APICID, CPUID_COMMON_ID1EBX_APICID) -FIELD_FUNC(PA_BITS, CPUID_COMMON_ID88EAX_PHYSBITS) -FIELD_FUNC(VIRT_BITS, CPUID_COMMON_ID88EAX_VIRTBITS) -FIELD_FUNC(SVM_REVISION, CPUID_AMD_ID8AEAX_SVM_REVISION) -FIELD_FUNC(SVM_N_ASIDS, CPUID_AMD_ID8AEBX_SVM_N_ASIDS) -FIELD_FUNC(INTEL_CORE_COUNT, CPUID_INTEL_ID4EAX_CORE_COUNT) -FIELD_FUNC(AMD_CORE_COUNT, CPUID_AMD_ID88ECX_CORE_COUNT) -FIELD_FUNC(AMD_APICID_COREID_SIZE, CPUID_AMD_ID88ECX_APICID_COREID_SIZE) -FIELD_FUNC(AMD_EXTAPICSPC, CPUID_AMD_ID81ECX_EXTAPICSPC) -FIELD_FUNC(NUM_PMCS, CPUID_INTEL_IDAEAX_NUM_PMCS) -FIELD_FUNC(MWAIT_MIN_SIZE, CPUID_COMMON_ID5EAX_MWAIT_MIN_SIZE) -FIELD_FUNC(MWAIT_MAX_SIZE, CPUID_COMMON_ID5EBX_MWAIT_MAX_SIZE) -FIELD_FUNC(MWAIT_C0_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C0_SUBSTATE) -FIELD_FUNC(MWAIT_C1_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C1_SUBSTATE) -FIELD_FUNC(MWAIT_C2_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C2_SUBSTATE) -FIELD_FUNC(MWAIT_C3_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C3_SUBSTATE) -FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE) -#undef FIELD_FUNC - - -/* - * Definitions of various fields' values and more complicated - * macros/functions for reading cpuid fields. - */ - -/* Effective Intel CPU Families */ -#define CPUID_FAMILY_486 4 -#define CPUID_FAMILY_P5 5 -#define CPUID_FAMILY_P6 6 -#define CPUID_FAMILY_P4 15 - -/* Effective AMD CPU Families */ -#define CPUID_FAMILY_5x86 4 -#define CPUID_FAMILY_K5 5 -#define CPUID_FAMILY_K6 5 -#define CPUID_FAMILY_K7 6 -#define CPUID_FAMILY_K8 15 -#define CPUID_FAMILY_K8L 16 -#define CPUID_FAMILY_K8MOBILE 17 -#define CPUID_FAMILY_EXTENDED 15 - -/* Intel model information */ -#define CPUID_MODEL_PPRO 1 -#define CPUID_MODEL_PII_03 3 -#define CPUID_MODEL_PII_05 5 -#define CPUID_MODEL_CELERON_06 6 -#define CPUID_MODEL_PM_09 9 -#define CPUID_MODEL_PM_0E 14 // Yonah / Sossaman -#define CPUID_MODEL_CORE_0F 15 // Conroe / Merom -#define CPUID_MODEL_CORE_17 0x17 // Penryn -#define CPUID_MODEL_NEHALEM_1A 0x1a // Nehalem / Gainestown -#define CPUID_MODEL_CORE_1D 0x1d // Dunnington - -#define CPUID_MODEL_PIII_07 7 -#define CPUID_MODEL_PIII_08 8 -#define CPUID_MODEL_PIII_0A 10 - -static INLINE uint32 -CPUID_EFFECTIVE_FAMILY(uint32 v) /* %eax from CPUID with %eax=1. */ -{ - return CPUID_FAMILY(v) + - (CPUID_FAMILY(v) == CPUID_FAMILY_EXTENDED ? CPUID_EXTENDED_FAMILY(v) : 0); -} - -/* Normally only used when FAMILY==CPUID_FAMILY_EXTENDED, but Intel is - * now using the extended model field for FAMILY==CPUID_FAMILY_P6 to - * refer to the newer Core2 CPUs - */ -static INLINE uint32 -CPUID_EFFECTIVE_MODEL(uint32 v) /* %eax from CPUID with %eax=1. */ -{ - return CPUID_MODEL(v) + (CPUID_EXTENDED_MODEL(v) << 4); -} - -/* - * Notice that CPUID families for Intel and AMD overlap. The following macros - * should only be used AFTER the manufacturer has been established (through - * the use of CPUID standard function 0). - */ -static INLINE Bool -CPUID_FAMILY_IS_486(uint32 _eax) -{ - return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_486; -} - -static INLINE Bool -CPUID_FAMILY_IS_P5(uint32 _eax) -{ - return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_P5; -} - -static INLINE Bool -CPUID_FAMILY_IS_P6(uint32 _eax) -{ - return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_P6; -} - -static INLINE Bool -CPUID_FAMILY_IS_PENTIUM4(uint32 _eax) -{ - return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_P4; -} - -/* - * Intel Pentium M processors are Yonah/Sossaman or an older P-M - */ -static INLINE Bool -CPUID_UARCH_IS_PENTIUM_M(uint32 v) // IN: %eax from CPUID with %eax=1. -{ - /* Assumes the CPU manufacturer is Intel. */ - return CPUID_FAMILY_IS_P6(v) && - (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_09 || - CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_0E); -} - -/* - * Intel Core processors are Merom, Conroe, Woodcrest, Clovertown, - * Penryn, Dunnington, Kentsfield, Yorktown, Harpertown, ........ - */ -static INLINE Bool -CPUID_UARCH_IS_CORE(uint32 v) // IN: %eax from CPUID with %eax=1. -{ - uint32 model = CPUID_EFFECTIVE_MODEL(v); - /* Assumes the CPU manufacturer is Intel. */ - return CPUID_FAMILY_IS_P6(v) && - model >= CPUID_MODEL_CORE_0F && - (model < CPUID_MODEL_NEHALEM_1A || - model == CPUID_MODEL_CORE_1D); -} - - -/* - * Intel Nehalem processors are: Nehalem, Gainestown. - */ -static INLINE Bool -CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1. -{ - /* Assumes the CPU manufacturer is Intel. */ - return CPUID_FAMILY_IS_P6(v) && - CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A; -} - - -static INLINE Bool -CPUID_FAMILY_IS_K7(uint32 _eax) -{ - return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K7; -} - -static INLINE Bool -CPUID_FAMILY_IS_K8(uint32 _eax) -{ - return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K8; -} - -static INLINE Bool -CPUID_FAMILY_IS_K8EXT(uint32 _eax) -{ - /* - * We check for this pattern often enough that it's - * worth a separate function, for syntactic sugar. - */ - return CPUID_FAMILY_IS_K8(_eax) && - CPUID_EXTENDED_MODEL(_eax) != 0; -} - -static INLINE Bool -CPUID_FAMILY_IS_K8L(uint32 _eax) -{ - return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K8L; -} - -static INLINE Bool -CPUID_FAMILY_IS_K8MOBILE(uint32 _eax) -{ - /* Essentially a K8 (not K8L) part, but with mobile features. */ - return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K8MOBILE; -} - -static INLINE Bool -CPUID_FAMILY_IS_K8STAR(uint32 _eax) -{ - /* - * Read function name as "K8*", as in wildcard. - * Matches K8 or K8L or K8MOBILE - */ - return CPUID_FAMILY_IS_K8(_eax) || CPUID_FAMILY_IS_K8L(_eax) || - CPUID_FAMILY_IS_K8MOBILE(_eax); -} - - -#define CPUID_TYPE_PRIMARY 0 -#define CPUID_TYPE_OVERDRIVE 1 -#define CPUID_TYPE_SECONDARY 2 - -#define CPUID_INTEL_ID4EAX_CACHE_TYPE_NULL 0 -#define CPUID_INTEL_ID4EAX_CACHE_TYPE_DATA 1 -#define CPUID_INTEL_ID4EAX_CACHE_TYPE_INST 2 -#define CPUID_INTEL_ID4EAX_CACHE_TYPE_UNIF 3 - -#define CPUID_INTEL_ID4EAX_CACHE_SELF_INIT 0x00000100 -#define CPUID_INTEL_ID4EAX_CACHE_FULLY_ASSOC 0x00000200 - - -/* - * On AMD chips before Opteron and Intel chips before P4 model 3, - * WRMSR(TSC) clears the upper half of the TSC instead of using %edx. - */ -static INLINE Bool -CPUID_FullyWritableTSC(Bool isIntel, // IN - uint32 v) // IN: %eax from CPUID with %eax=1. -{ - /* - * Returns FALSE if: - * - Intel && P6 (pre-core) or - * - Intel && P4 (model < 3) or - * - !Intel && pre-K8 Opteron - * Otherwise, returns TRUE. - */ - return !((isIntel && - ((CPUID_FAMILY_IS_P6(v) && - CPUID_EFFECTIVE_MODEL(v) < CPUID_MODEL_PM_0E) || - (CPUID_FAMILY_IS_PENTIUM4(v) && - CPUID_EFFECTIVE_MODEL(v) < 3))) || - (!isIntel && - CPUID_FAMILY(v) < CPUID_FAMILY_K8)); -} - - -/* - * For certain AMD processors, an lfence instruction is necessary at various - * places to ensure ordering. - */ - -static INLINE Bool -CPUID_VendorRequiresFence(CpuidVendors vendor) -{ - return vendor == CPUID_VENDOR_AMD; -} - -static INLINE Bool -CPUID_VersionRequiresFence(uint32 version) -{ - return CPUID_EFFECTIVE_FAMILY(version) == CPUID_FAMILY_K8 && - CPUID_EFFECTIVE_MODEL(version) < 0x40; -} - -static INLINE Bool -CPUID_ID0RequiresFence(CPUIDRegs *id0) -{ - if (id0->eax == 0) { - return FALSE; - } - // hard to get strcmp() in some environments, so do it in the raw - return (id0->ebx == *(uint32 *) (CPUID_AMD_VENDOR_STRING + 0) && - id0->ecx == *(uint32 *) (CPUID_AMD_VENDOR_STRING + 4) && - id0->edx == *(uint32 *) (CPUID_AMD_VENDOR_STRING + 8)); -} - -static INLINE Bool -CPUID_ID1RequiresFence(CPUIDRegs *id1) -{ - return CPUID_VersionRequiresFence(id1->eax); -} - -static INLINE Bool -CPUID_RequiresFence(CpuidVendors vendor, // IN - uint32 version) // IN: %eax from CPUID with %eax=1. -{ - return CPUID_VendorRequiresFence(vendor) && - CPUID_VersionRequiresFence(version); -} - - -/* - *---------------------------------------------------------------------- - * - * CPUID_CountsCPUIDAsBranch -- - * - * Returns TRUE iff the cpuid given counts CPUID as a branch - * (i.e. is a pre-Merom E CPU). - * - *---------------------------------------------------------------------- - */ - -static INLINE Bool -CPUID_CountsCPUIDAsBranch(uint32 v) /* %eax from CPUID with %eax=1 */ -{ - /* - * CPUID no longer a branch starting with Merom E. Bug 148411. - * Penryn (Extended Model: 1) also has this fixed. - * - * Merom E is: CPUID.1.eax & 0xfff = 0x6f9 - */ - return !(CPUID_FAMILY_IS_P6(v) && - (CPUID_EFFECTIVE_MODEL(v) > CPUID_MODEL_CORE_0F || - (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_CORE_0F && - CPUID_STEPPING(v) >= 9))); -} - - -/* - * The following low-level functions compute the number of - * cores per cpu. They should be used cautiously because - * they do not necessarily work on all types of CPUs. - * High-level functions that are correct for all CPUs are - * available elsewhere: see lib/cpuidInfo/cpuidInfo.c. - */ - -static INLINE uint32 -CPUID_IntelCoresPerPackage(uint32 v) /* %eax from CPUID with %eax=4 and %ecx=0. */ -{ - // Note: This is not guaranteed to work on older Intel CPUs. - return 1 + CPUID_INTEL_CORE_COUNT(v); -} - -static INLINE uint32 -CPUID_AMDCoresPerPackage(uint32 v) /* %ecx from CPUID with %eax=0x80000008. */ -{ - // Note: This is not guaranteed to work on older AMD CPUs. - return 1 + CPUID_AMD_CORE_COUNT(v); -} - -/* - * Hypervisor CPUID space is 0x400000XX. - */ -static INLINE Bool -CPUID_IsHypervisorLevel(uint32 level, uint32 *offset) -{ - *offset = level & 0xff; - return (level & 0xffffff00) == 0x40000000; -} - - -#endif