--- /dev/null
+diff -Nur old/vmware-any-any-update117d/vmnet-only/bridge.c new/vmware-any-any-update117d/vmnet-only/bridge.c
+--- old/vmware-any-any-update117d/vmnet-only/bridge.c 2008-08-30 15:50:06.800648000 +0000
++++ new/vmware-any-any-update117d/vmnet-only/bridge.c 2008-08-30 16:10:34.153352750 +0000
+@@ -275,7 +275,7 @@
+ struct net_device *net) // IN: Network device
+ {
+ #ifdef VMW_NETDEV_HAS_NET
+- if (dev_net(net) != dev_net(bridge->internalDev)) {
++ if (net->nd_net != bridge->internalDev->nd_net) {
+ return 0;
+ }
+ #endif
+diff -Nur old/vmware-any-any-update117d/vmnet-only/bridge.c~ new/vmware-any-any-update117d/vmnet-only/bridge.c~
+--- old/vmware-any-any-update117d/vmnet-only/bridge.c~ 1970-01-01 00:00:00.000000000 +0000
++++ new/vmware-any-any-update117d/vmnet-only/bridge.c~ 2008-08-30 15:57:32.192483250 +0000
+@@ -0,0 +1,1550 @@
++/* **********************************************************
++ * Copyright 1998 VMware, Inc. All rights reserved. -- VMware Confidential
++ * **********************************************************/
++
++#include "driver-config.h"
++
++#define EXPORT_SYMTAB
++
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/sched.h>
++#ifdef KERNEL_2_2
++# include <linux/slab.h>
++#else
++# include <linux/malloc.h>
++#endif
++#include <linux/poll.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/mm.h>
++#include "compat_skbuff.h"
++#include <linux/sockios.h>
++#include "compat_sock.h"
++
++#define __KERNEL_SYSCALLS__
++#include <asm/io.h>
++
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <net/tcp.h>
++
++#ifdef CONFIG_NET_RADIO
++# include <linux/wireless.h>
++#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
++#ifdef VMW_NETDEV_HAS_NET
++ struct net_device *internalDev;
++#endif
++};
++
++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
++}
++
++
++#ifdef VMW_NETDEV_HAS_NET
++/*
++ *----------------------------------------------------------------------
++ *
++ * VNetBridgeInternalSetup --
++ *
++ * Setup callback for our bridge internal device. Nothing to do,
++ * generic code sets up everything we expect from device.
++ *
++ * Results:
++ * None.
++ *
++ * Side effects:
++ * None.
++ *
++ *----------------------------------------------------------------------
++ */
++
++static void
++VNetBridgeInternalSetup(struct net_device *net)
++{
++ /* Do nothing. */
++}
++#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 (net->nd_net != bridge->internalDev->nd_net)) {
++ return 0;
++ }
++#endif
++ return strcmp(net->name, bridge->name) == 0;
++}
++
++
++/*
++ *----------------------------------------------------------------------
++ *
++ * VNetBridge_Create --
++ *
++ * Create a bridge. Allocates/initializes struct, registers
++ * with kernel for device state changes, connects to virtual
++ * hub, initializes port/jack, and creates a proc entry.
++ *
++ * Results:
++ * Errno. Also returns an allocated jack to connect to,
++ * NULL on error.
++ *
++ * Side effects:
++ * None.
++ *
++ *----------------------------------------------------------------------
++ */
++
++int
++VNetBridge_Create(char *devName, // IN: name of device (e.g., "eth0")
++ 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);
++
++#ifdef VMW_NETDEV_HAS_NET
++ bridge->internalDev = compat_alloc_netdev(0, "vmnetX", VNetBridgeInternalSetup);
++ if (!bridge->internalDev) {
++ retval = -ENOMEM;
++ goto out;
++ }
++#endif
++
++ /*
++ * Set up notifier for network device state change
++ */
++
++ bridge->notifier.notifier_call = VNetBridgeNotify;
++ bridge->notifier.priority = 0;
++ register_netdevice_notifier(&bridge->notifier);
++
++ /*
++ * Try to bring it up
++ */
++
++ retval = VNetBridgeUp(bridge, TRUE);
++ if (retval == -ENODEV) {
++ LOG(1, (KERN_DEBUG "bridge-%s: peer interface %s not found, "
++ "will wait for it to come up\n",
++ bridge->name, devName));
++ retval = 0;
++ }
++ if (retval != 0) {
++ goto out;
++ }
++
++ /*
++ * 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(NULL, 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;
++
++ *ret = &bridge->port;
++
++ LOG(1, (KERN_DEBUG "bridge-%s: attached\n", bridge->name));
++ return 0;
++
++out:
++ if (bridge != NULL) {
++ if (bridge->notifier.notifier_call != NULL) {
++ unregister_netdevice_notifier(&bridge->notifier);
++ }
++#ifdef VMW_NETDEV_HAS_NET
++ if (bridge->internalDev) {
++ compat_free_netdev(bridge->internalDev);
++ }
++#endif
++ kfree(bridge);
++ }
++ return retval;
++}
++
++
++/*
++ *----------------------------------------------------------------------
++ *
++ * VNetBridgeFree --
++ *
++ * Disconnect the bridge, unregister from device state
++ * notifications, remove proc entry, and deallocate struct.
++ *
++ * Results:
++ * None.
++ *
++ * Side effects:
++ * None.
++ *
++ *----------------------------------------------------------------------
++ */
++
++void
++VNetBridgeFree(VNetJack *this) // IN: jack to free
++{
++ VNetBridge *bridge = (VNetBridge*)this->private;
++
++ if (bridge->dev != NULL) {
++ VNetBridgeDown(bridge, TRUE);
++ }
++
++ unregister_netdevice_notifier(&bridge->notifier);
++
++#ifdef VMW_NETDEV_HAS_NET
++ if (bridge->internalDev) {
++ compat_free_netdev(bridge->internalDev);
++ }
++#endif
++
++ if (this->procEntry) {
++ VNetProc_RemoveEntry(this->procEntry, NULL);
++ }
++
++ if (bridge->smac){
++ SMAC_CleanupState(&(bridge->smac));
++ }
++
++ 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 succesfull 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;
++ atomic_add(skb->truesize, &sk->sk_wmem_alloc);
++ 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, (uint8 *)&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
++{
++#if !defined(CONFIG_NET_RADIO)
++ return FALSE;
++#elif WIRELESS_EXT > 19
++ return dev->wireless_handlers != NULL;
++#elif WIRELESS_EXT > 12
++ return dev->wireless_handlers != NULL || dev->get_wireless_stats != NULL;
++#else
++ return dev->get_wireless_stats != NULL;
++#endif
++}
++
++/*
++ *----------------------------------------------------------------------
++ *
++ * 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.
++ *
++ *----------------------------------------------------------------------
++ */
++
++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);
++
++ /*
++ * Finish up
++ */
++
++ 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.
++ *
++ *----------------------------------------------------------------------
++ */
++
++void
++VNetBridgeDown(VNetBridge *bridge, // IN: bridge
++ Bool rtnlLock) // IN: acquire RTNL lock
++{
++ if (bridge->dev == NULL) {
++ LOG(0, (KERN_NOTICE "bridge-%s: already down\n", bridge->name));
++ return;
++ }
++
++ 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));
++}
++
++
++/*
++ *-----------------------------------------------------------------------------
++ *
++ * 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.
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++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_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);
++ switch (-errno) {
++ case 0:
++ break;
++
++ case ENODEV:
++ LOG(0, (KERN_WARNING "bridge-%s: interface %s not found or not "
++ "up\n", bridge->name, dev->name));
++ break;
++
++ case EINVAL:
++ LOG(0, (KERN_WARNING "bridge-%s: interface %s is not a valid "
++ "Ethernet interface\n", bridge->name, dev->name));
++ break;
++
++ case ENOMEM:
++ LOG(0, (KERN_WARNING "bridge-%s: failed to allocate memory\n",
++ bridge->name));
++ break;
++
++ default:
++ /* This should never happen --hpreg */
++ LOG(0, (KERN_WARNING "bridge-%s: failed to enable the bridge to "
++ "interface %s (error %d)\n", bridge->name, dev->name,
++ -errno));
++ break;
++ }
++ }
++ 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_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 -Nur old/vmware-any-any-update117d/vmnet-only/vmnetInt.h new/vmware-any-any-update117d/vmnet-only/vmnetInt.h
+--- old/vmware-any-any-update117d/vmnet-only/vmnetInt.h 2008-08-30 15:50:06.800648000 +0000
++++ new/vmware-any-any-update117d/vmnet-only/vmnetInt.h 2008-08-30 15:59:47.768956250 +0000
+@@ -63,7 +63,7 @@
+ # 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(dev_net((x)->internalDev), (x)->name)
++# define DEV_GET(x) __dev_get_by_name((x)->internalDev->nd_net, (x)->name)
+ # else
+ # define DEV_GET(x) __dev_get_by_name((x)->name)
+ # endif
+@@ -89,7 +89,7 @@
+
+ #ifdef VMW_NETDEV_HAS_NET
+ extern struct proto vmnet_proto;
+-# define compat_sk_alloc(_bri, _pri) sk_alloc(dev_net((_bri)->internalDev), \
++# define compat_sk_alloc(_bri, _pri) sk_alloc((_bri)->internalDev->nd_net, \
+ PF_NETLINK, _pri, &vmnet_proto)
+ #elif defined(VMW_HAVE_SK_ALLOC_WITH_PROTO)
+ extern struct proto vmnet_proto;
+diff -Nur old/vmware-any-any-update117d/vmnet-only/vmnetInt.h~ new/vmware-any-any-update117d/vmnet-only/vmnetInt.h~
+--- old/vmware-any-any-update117d/vmnet-only/vmnetInt.h~ 1970-01-01 00:00:00.000000000 +0000
++++ new/vmware-any-any-update117d/vmnet-only/vmnetInt.h~ 2008-08-30 15:49:59.016161500 +0000
+@@ -0,0 +1,157 @@
++/* **********************************************************
++ * Copyright 1998 VMware, Inc. All rights reserved. -- VMware Confidential
++ * **********************************************************/
++
++#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
++ */
++
++/* 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
++
++
++#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(dev_net((x)->internalDev), (x)->name)
++# 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(dev_net((_bri)->internalDev), \
++ 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
++
++
++/*
++ * Use CHECKSUM_HW for old kernels, if they have CHECKSUM_HW. Use CHECKSUM_PARTIAL for
++ * new ones even if CHECKSUM_HW is defined. We do not do decision based on kernel version
++ * only as CHECKSUM_PARTIAL was in mm tree for some time already, and we do not test
++ * for CHECKSUM_PARTIAL existence as it may get converted to enum in future.
++ */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW)
++# define VM_CHECKSUM_PARTIAL CHECKSUM_HW
++#else
++# define VM_CHECKSUM_PARTIAL CHECKSUM_PARTIAL
++#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__ */