VBoxNetFlt-solaris.c revision de4157257515400c2c25373591135f110227b68c
/* $Id$ */
/** @file
* VBoxNetFlt - Network Filter Driver (Host), Solaris Specific Code.
*/
/*
* Copyright (C) 2008 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#if defined(DEBUG_ramshankar) && !defined(LOG_ENABLED)
# define LOG_ENABLED
#endif
#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
#include <iprt/initterm.h>
#include <sys/pathname.h>
#include <sys/ethernet.h>
// #define u (curproc->p_user) /* user is now part of proc structure */
#ifdef u
#undef u
#endif
#define VBOXNETFLT_OS_SPECFIC 1
#include "../VBoxNetFltInternal.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** The module name. */
#define DEVICE_NAME "vboxflt"
#define DEVICE_DESC_DRV "VirtualBox NetFilter Driver"
#define DEVICE_DESC_MOD "VirtualBox NetFilter Module"
/** @todo Remove the below hackery once done! */
#if defined(DEBUG_ramshankar) && defined(LOG_ENABLED)
#endif
/** Dynamic module binding specific oddities. */
#define VBOXNETFLT_MODE_REQ_MAGIC 0xacce55ed
/*******************************************************************************
* Global Functions *
*******************************************************************************/
/**
* Stream Driver hooks.
*/
static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
/**
* Stream Module hooks.
*/
static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fFile, int fStream, cred_t *pCred);
/**
* OS specific hooks invoked from common VBoxNetFlt ring-0.
*/
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Streams: module info.
*/
static struct module_info g_VBoxNetFltSolarisModInfo =
{
0xbad, /* module id */
0, /* min. packet size */
INFPSZ, /* max. packet size */
0, /* hi-water mask */
0 /* lo-water mask */
};
/**
* Streams: read queue hooks.
*/
static struct qinit g_VBoxNetFltSolarisReadQ =
{
NULL, /* service */
NULL, /* admin (reserved) */
NULL /* module stats */
};
/**
* Streams: write queue hooks.
*/
static struct qinit g_VBoxNetFltSolarisWriteQ =
{
NULL, /* open */
NULL, /* close */
NULL, /* admin (reserved) */
NULL /* module stats */
};
/**
* Streams: IO stream tab.
*/
static struct streamtab g_VBoxNetFltSolarisStreamTab =
{
NULL, /* muxread init */
NULL /* muxwrite init */
};
/**
*/
static struct cb_ops g_VBoxNetFltSolarisCbOps =
{
nulldev, /* cb open */
nulldev, /* cb close */
nodev, /* b strategy */
nodev, /* b dump */
nodev, /* b print */
nodev, /* cb read */
nodev, /* cb write */
nodev, /* cb ioctl */
nodev, /* c devmap */
nodev, /* c mmap */
nodev, /* c segmap */
nochpoll, /* c poll */
ddi_prop_op, /* property ops */
CB_REV /* revision */
};
/**
*/
static struct dev_ops g_VBoxNetFltSolarisDevOps =
{
DEVO_REV, /* driver build revision */
0, /* ref count */
nulldev, /* identify */
nulldev, /* probe */
nodev, /* reset */
(struct bus_ops *)0,
nodev /* power */
};
/**
* modldrv: export driver specifics to kernel
*/
static struct modldrv g_VBoxNetFltSolarisDriver =
{
&mod_driverops, /* extern from kernel */
};
/**
* fmodsw: streams module ops
*/
static struct fmodsw g_VBoxNetFltSolarisModOps =
{
};
/**
* modlstrmod: streams module specifics to kernel
*/
static struct modlstrmod g_VBoxNetFltSolarisModule =
{
&mod_strmodops, /* extern from kernel */
};
/**
*/
static struct modlinkage g_VBoxNetFltSolarisModLinkage =
{
MODREV_1, /* loadable module system revision */
&g_VBoxNetFltSolarisDriver, /* streams driver framework */
&g_VBoxNetFltSolarisModule, /* streams module framework */
NULL /* terminate array of linkage structures */
};
struct vboxnetflt_state_t;
/**
* vboxnetflt_dladdr_t: DL SAP address format
*/
typedef struct vboxnetflt_dladdr_t
{
#define VBOXNETFLT_DLADDRL sizeof(vboxnetflt_dladdr_t)
/**
* which stream is this?
*/
typedef enum VBOXNETFLTSTREAMTYPE
{
kUndefined = 0,
kIpStream = 0x1b,
kArpStream = 0xab
/**
* vboxnetflt_stream_t: per-stream data
*/
typedef struct vboxnetflt_stream_t
{
int DevMinor; /* minor device no. (for clone) */
bool fPromisc; /* cached promiscous value */
bool fRawMode; /* whether raw mode request was successful */
t_uscalar_t UnAckPrim; /* unacknowledged primitive sent by this stream, again fake DL request tracking stuff */
/**
* vboxnetflt_state_t: per-driver data
*/
typedef struct vboxnetflt_state_t
{
/** Global device info handle. */
/** The list of all opened streams. */
/**
* pCurInstance is the currently VBox instance to be associated with the stream being created
* in ModOpen. This is just shared global data between the dynamic attach and the ModOpen procedure.
*/
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc);
static int vboxNetFltSolarisIOWorker(PVBOXNETFLTINS pThis, queue_t *pQueue, vboxnetflt_stream_t *pStream, mblk_t *pMsg, uint32_t fSrc);
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** The (common) global data. */
/** Global state. */
/** GCC C++ hack. */
unsigned __gxx_personality_v0 = 0xdecea5ed;
/** Global Mutex protecting global state. */
/**
* Kernel entry points
*/
int _init(void)
{
/*
* Prevent module autounloading.
*/
if (pModCtl)
else
/*
* Initialize IPRT.
*/
if (RT_SUCCESS(rc))
{
/*
* Initialize the globals and connect to the support driver.
*
* This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
* for establishing the connect to the support driver.
*/
if (RT_SUCCESS(rc))
return mod_install(&g_VBoxNetFltSolarisModLinkage);
else
RTR0Term();
}
else
return -1;
}
int _fini(void)
{
int rc;
#if 0
/*
* First check if Detach has been called and thus unloaded the correct way.
* This fixes the boot-up auto-unload problem where Solaris silently unloads
* us without calling detach which would wrongly succeed.
*/
{
return EBUSY;
}
#endif
/*
* Undo the work done during start (in reverse order).
*/
if (RT_FAILURE(rc))
{
return EBUSY;
}
RTR0Term();
return mod_remove(&g_VBoxNetFltSolarisModLinkage);
}
{
return rc;
}
/**
* Attach entry point, to attach a device to the system or resume it.
*
* @param pDip The module structure instance.
*
* @returns corresponding solaris error code.
*/
{
switch (enmCmd)
{
case DDI_ATTACH:
{
if (RT_SUCCESS(rc))
{
if (rc == DDI_SUCCESS)
{
return DDI_SUCCESS;
}
else
}
else
return DDI_FAILURE;
}
case DDI_RESUME:
{
/* Nothing to do here... */
return DDI_SUCCESS;
}
}
return DDI_FAILURE;
}
/**
* Detach entry point, to detach a device to the system or suspend it.
*
* @param pDip The module structure instance.
*
* @returns corresponding solaris error code.
*/
{
switch (enmCmd)
{
case DDI_DETACH:
{
return DDI_SUCCESS;
}
case DDI_RESUME:
{
/* Nothing to do here... */
return DDI_SUCCESS;
}
}
return DDI_FAILURE;
}
/**
* Info entry point, called by solaris kernel for obtaining driver info.
*
* @param pDip The module structure instance (do not use).
* @param enmCmd Information request type.
* @param pvArg Type specific argument.
* @param ppvResult Where to store the requested info.
*
* @returns corresponding solaris error code.
*/
static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppResult)
{
LogFlow((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd, getminor((dev_t)pvArg)));
switch (enmCmd)
{
case DDI_INFO_DEVT2DEVINFO:
{
return DDI_SUCCESS;
}
case DDI_INFO_DEVT2INSTANCE:
{
return DDI_SUCCESS;
}
}
return DDI_FAILURE;
}
/**
* Stream module open entry point, initializes the queue and allows streams processing.
*
* @param pQueue Pointer to the queue (cannot be NULL).
* @param pDev Pointer to the dev_t associated with the driver at the end of the stream.
* @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
* @param fStreamMode Stream open mode.
* @param pCred Pointer to user credentials.
*
* @returns corresponding solaris error code.
*/
static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fOpenMode, int fStreamMode, cred_t *pCred)
{
LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModOpen pQueue=%p pDev=%p fOpenMode=%d fStreamMode=%d\n", pQueue, pDev, fOpenMode, fStreamMode));
/*
* Already open?
*/
{
return ENOENT;
}
/*
* Check for the VirtualBox instance.
*/
{
return ENOENT;
}
/*
* Check VirtualBox stream type.
*/
{
return ENOENT;
}
/*
* Get minor number. For clone opens provide a new dev_t.
*/
if (fStreamMode == CLONEOPEN)
{
{
break;
DevMinor++;
}
}
else
/*
* Allocate & initialize per-stream data. Hook it into the (read and write) queue's module specific data.
*/
if (RT_UNLIKELY(!pStream))
{
return ENOMEM;
}
/*
* Pick up the current global VBOXNETFLTINS instance as
* the one that we will associate this stream with.
*/
else
/*
* Link it to the list of streams.
*/
*ppPrevStream = pStream;
/*
* Request the physical address (we cache the acknowledgement).
*/
/*
* Enable raw mode.
*/
LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModOpen returns 0, DevMinor=%d pQueue=%p\n", DevMinor, pStream->pReadQueue));
return 0;
}
/**
* Stream module close entry point, undoes the work done on open and closes the stream.
*
* @param pQueue Pointer to the queue (cannot be NULL).
* @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
* @param pCred Pointer to user credentials.
*
* @returns corresponding solaris error code.
*/
{
/*
* Get instance data.
*/
if (RT_UNLIKELY(!pStream))
{
return ENXIO;
}
/*
* Enable native mode.
*/
/*
* Unlink it from the list of streams.
*/
for (ppPrevStream = &pState->pOpenedStreams; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
break;
/*
* Delete the stream.
*/
else
return 0;
}
/**
* Read side put procedure for processing messages in the read queue.
*
* @param pQueue Pointer to the queue.
* @param pMsg Pointer to the message.
*
* @returns corresponding solaris error code.
*/
{
bool fSendUpstream = true;
{
{
case M_DATA:
{
fSendUpstream = false; /* vboxNetFltSolarisIOWorker would send it if required, do nothing more here. */
break;
}
case M_PROTO:
case M_PCPROTO:
{
switch (Prim)
{
case DL_UNITDATA_IND:
{
/*
* I do not think control would come here... We convert all outgoing fast mode requests
* to raw mode; so I don't think we should really receive any fast mode replies.
*/
fSendUpstream = false; /* vboxNetFltSolarisIOWorker would send it if required, do nothing more here. */
break;
}
case DL_PHYS_ADDR_ACK:
{
/*
* Swallow our fake physical address request acknowledgement.
*/
{
fSendUpstream = false;
}
break;
}
case DL_OK_ACK:
{
{
}
{
}
/*
* Swallow our fake promiscous request acknowledgement.
*/
{
fSendUpstream = false;
}
break;
}
}
break;
}
case M_IOCACK:
{
/*
*/
{
/*
* Somehow raw mode is turned off??
*/
{
}
fSendUpstream = false;
}
break;
}
case M_FLUSH:
{
/*
* We must support flushing queues.
*/
break;
}
}
}
if ( fSendUpstream
&& pMsg)
{
/*
* Pass foward high priority messages or when there's no flow control
* on an empty queue, otherwise queue them.
*/
{
}
else
}
return 0;
}
/**
* Write side put procedure for processing messages in the write queue.
*
* @param pQueue Pointer to the queue.
* @param pMsg Pointer to the message.
*
* @returns corresponding solaris error code.
*/
{
/*
* Check for the VirtualBox connection.
*/
bool fSendDownstream = true;
int rc;
{
{
case M_DATA:
{
break;
}
case M_PROTO:
case M_PCPROTO:
{
/*
* Queue up other primitives to the service routine.
*/
switch (Prim)
{
case DL_UNITDATA_REQ:
{
if (VBOX_SUCCESS(rc))
else
fSendDownstream = false;
break;
}
default:
{
/*
* Enqueue other DLPI primitives and service them later.
*/
fSendDownstream = false;
break;
}
}
break;
}
case M_IOCTL:
{
{
{
/*
* Somebody is wanting fast path when we need raw mode.
* Since we are evil, let's acknowledge the request ourselves!
*/
fSendDownstream = false;
}
}
break;
}
case M_FLUSH:
{
/*
* Canonical flush courtesy man qreply(9F) while we have a service routine.
*/
{
/*
* Flush and mark as serviced.
*/
}
{
/*
* Send the request upstream.
*/
}
else
break;
}
}
}
if ( fSendDownstream
&& pMsg)
{
/*
* Pass foward high priority messages or when there's no flow control
* on an empty queue, otherwise queue them.
*/
{
}
else
}
return 0;
}
/**
* Write side service procedure for deferred message processing on the write queue.
*
* @param pQueue Pointer to the queue.
*
* @returns corresponding solaris error code.
*/
{
/*
* Drain the queue as we service the messages.
*/
{
{
case M_DATA:
case M_PROTO:
case M_PCPROTO:
{
LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWriteService M_DATA/M_PROTO/M_PCPROTO forwarding downstream\n"));
break;
}
case M_IOCTL:
case M_IOCDATA:
{
break;
}
default:
{
if (canputnext(pQueue))
else
break;
}
}
}
return 0;
}
/**
* Put the stream in raw mode.
*
* @returns VBox status code.
* @param pQueue Pointer to the queue.
*/
{
if (RT_UNLIKELY(!pRawMsg))
return VERR_NO_MEMORY;
return VINF_SUCCESS;
}
/**
* Put the stream back in fast path mode.
*
* @returns VBox status code.
* @param pQueue Pointer to the queue.
*/
{
if (RT_UNLIKELY(!pFastMsg))
return VERR_NO_MEMORY;
if (RT_UNLIKELY(!pDataReqMsg))
return VERR_NO_MEMORY;
/*
* Link the data format request message into the header ioctl message.
*/
return VINF_SUCCESS;
}
/**
* Send fake promiscous mode requests downstream.
*
* @param pQueue Pointer to the queue.
* @param fPromisc Whether to enable promiscous mode or not.
* @param PromiscLevel Promiscous level; DL_PROMISC_PHYS/SAP/MULTI.
*
* @returns VBox error code.
*/
{
if (fPromisc)
{
}
else
{
}
if (RT_UNLIKELY(!pPromiscPhysMsg))
return VERR_NO_MEMORY;
if (RT_UNLIKELY(!pPromiscSapMsg))
{
return VERR_NO_MEMORY;
}
if (fPromisc)
{
}
else
{
}
return VINF_SUCCESS;
}
/**
* Send a fake physical address request downstream.
*
* @returns VBox status code.
* @param pQueue Pointer to the queue.
* @param pMsg Pointer to the request message.
*/
{
if (RT_UNLIKELY(!pPhysAddrMsg))
return VERR_NO_MEMORY;
return VERR_GENERAL_FAILURE;
}
/**
* Cache the MAC address into the VirtualBox instance given a physical
* address acknowledgement message.
*
* @param pThis The instance.
* @param pMsg Pointer to the physical address acknowledgement message.
*/
{
{
LogFlow((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr: DL_PHYS_ADDR_ACK: Mac=%.*Rhxs\n", sizeof(pThis->u.s.Mac), &pThis->u.s.Mac));
}
}
/**
* Opens the required device and returns the vnode_t associated with it.
*
* @returns VBox status code.
* @param pszDev The device path.
* @param ppVNode Where to store the vnode_t pointer associated with the opened device.
* @param ppVNodeHeld Where to store the vnode_t required during closing of the device.
* @param ppUser Open handle required while closing the device.
*/
static int vboxNetFltSolarisOpenDev(char *pszDev, vnode_t **ppVNode, vnode_t **ppVNodeHeld, TIUSER **ppUser)
{
int rc;
if (!rc)
{
if (!rc)
{
return VINF_SUCCESS;
}
}
return VERR_PATH_NOT_FOUND;
}
/**
* Close the device opened using vboxNetFltSolarisOpenDev.
*
* @param pVNodeHeld Pointer to the held vnode of the device.
* @param pUser Pointer to the file handle.
*/
{
}
/**
* Get the logical interface flags from the stream.
*
* @returns VBox status code.
* @param hDevice Layered device handle.
* @param pInterface Pointer to the interface.
*/
{
int rc;
int ret;
if (!rc)
return VINF_SUCCESS;
return RTErrConvertFromErrno(rc);
}
/**
* Sets the multiplexor ID from the interface.
*
* @returns VBox status code.
* @param pVNode Pointer to the device vnode.
* @param pInterface Pointer to the interface.
*/
{
int rc;
int ret;
if (!rc)
return VINF_SUCCESS;
return RTErrConvertFromErrno(rc);
}
/**
* Get the multiplexor file descriptor of the lower stream.
*
* @returns VBox status code.
* @param MuxId The multiplexor ID.
* @param pFd Where to store the lower stream file descriptor.
*/
{
int ret;
if (!rc)
{
return VINF_SUCCESS;
}
return RTErrConvertFromErrno(rc);
}
/**
* Relinks the lower and the upper stream.
*
* @returns VBox status code.
* @param pVNode Pointer to the device vnode.
* @param pInterface Pointer to the interface.
* @param IpMuxFd The IP multiplexor ID.
* @param ArpMuxFd The ARP multiplexor ID.
*/
static int vboxNetFltSolarisRelink(vnode_t *pVNode, struct lifreq *pInterface, int IpMuxFd, int ArpMuxFd)
{
LogFlow((DEVICE_NAME ":vboxNetFltSolarisRelink: pVNode=%p pInterface=%p IpMuxFd=%d ArpMuxFd=%d\n", pVNode, pInterface, IpMuxFd, ArpMuxFd));
int NewIpMuxId;
int NewArpMuxId;
if ( !rc
&& !rc2)
{
if (VBOX_SUCCESS(rc))
return VINF_SUCCESS;
}
else
return VERR_GENERAL_FAILURE;
}
/**
*
* @returns VBox status code.
* @param pVNode Pointer to the lower stream vnode.
* @param pModPos Where to store the module position.
*/
{
LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: fAttach=%d pVNode=%p pModPos=%p\n", fAttach, pVNode, pModPos));
int cMod;
if (!rc)
{
if (cMod < 1)
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: too few modules on host interface. cMod=%d\n"));
return VERR_OUT_OF_RANGE;
}
/*
* While attaching we make sure we are at the bottom most of the stack, excepting
* the host driver.
*/
if (fAttach)
{
return VINF_SUCCESS;
}
/*
* Detaching is a bit more complicated; since user could have altered the stack positions
* we take the safe approach by finding our position.
*/
{
return VERR_NO_MEMORY;
}
/*
* Get the list of all modules on the stack.
*/
int ret;
if (!rc)
{
/*
* Find our filter.
*/
{
{
LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: Success! Found %s at %d.\n", DEVICE_NAME, i));
*pModPos = i;
return VINF_SUCCESS;
}
}
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get module information. rc=%d\n"));
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get list of modules on host interface. rc=%d\n", rc));
return VERR_GENERAL_FAILURE;
}
/**
* Dynamically attaches this streams module on to the host stack.
* As a side-effect, this streams also gets opened during the actual
* insertion phase.
*
* @returns VBox status code.
* @param pThis The instance.
* @param fRediscovery Rediscovery attempt, currently unused on solaris.
*/
{
LogFlow(("vboxNetFltSolarisModSetup: pThis=%p (%s) fAttach=%s\n", pThis, pThis->szName, fAttach ? "true" : "false"));
/*
* Statuatory Warning: Hackish code ahead.
*/
{
return VERR_INTNET_FLT_IF_NOT_FOUND;
}
const char *pszAtChar = "@";
char *pszModName = DEVICE_NAME;
struct strmodconf StrMod;
struct strmodconf ArpStrMod;
int rc;
int rc2;
int rc3;
int ret;
/*
* Open the IP stream as a layered device.
*/
if ( !rc
&& !rc2)
{
/*
* Obtain the interface flags from IP.
*/
if (VBOX_SUCCESS(rc))
{
/*
* Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
* things that are not possible from the layered interface.
*/
if (VBOX_SUCCESS(rc))
{
/*
* Get the multiplexor IDs.
*/
if (!rc)
{
/*
* Get the multiplex file descriptor to the lower streams. Generally this is lost
*/
int IpMuxFd;
int ArpMuxFd;
if ( VBOX_SUCCESS(rc)
&& VBOX_SUCCESS(rc2))
{
/*
* We need to I_PUNLINK on these multiplexor IDs before we can start
* operating on the lower stream as insertions are direct operations on the lower stream.
*/
int ret;
if ( !rc
&& !rc2)
{
/*
* Obtain the vnode from the useless userland file descriptor.
*/
if ( pIpFile
&& pArpFile
{
/*
*/
if ( VBOX_SUCCESS(rc)
&& VBOX_SUCCESS(rc2))
{
/*
* Set global data which will be grabbed by ModOpen.
*/
/*
*/
rc = strioctl(pVNodeIp, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
/*
*/
rc2 = strioctl(pVNodeArp, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&ArpStrMod, 0, K_TO_K, kcred, &ret);
/*
* Our job's not yet over; we need to relink the upper and lower streams
* otherwise we've pretty much screwed up the host interface.
*/
if ( !rc
&& !rc2
&& VBOX_SUCCESS(rc3))
{
if (fAttach)
{
/*
* Check if our raw mode request was successful (only in the IP stream).
*/
{
fRawModeOk = true;
}
else
fRawModeOk = false;
}
if (fRawModeOk)
{
/*
* Close the devices ONLY during the return from function case; otherwise
* we end up close twice which is an instant kernel panic.
*/
return VINF_SUCCESS;
}
else
}
else
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: module %s or relinking failed. rc=%d rc2=%d rc3=%d.\n",
}
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: vboxNetFltSolarisDetermineModPos failed. rc=%d rc2=%d\n", rc, rc2));
}
else
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to unlink upper stream rc=%d rc2=%d.\n", rc, rc2));
}
else
}
else
}
else
}
else
}
else
return VERR_INTNET_FLT_IF_FAILED;
}
/**
* Wrapper for attaching ourselves to the interface.
*
* @returns VBox status code.
* @param pThis The instance.
* @remarks Owns the globals mutex, so re-requesting it anytime during this phase
* would panic the system e.g. in vboxNetFltSolarisFindInstance).
*/
{
return rc;
}
/**
* Wrapper for detaching ourselves from the interface.
*
* @returns VBox status code.
* @param pThis The instance.
* @remarks Owns the globals mutex, so re-requesting it anytime during this phase
* would panic the system (e.g. in vboxNetFltSolarisFindInstance).
*/
{
return rc;
}
/**
* Create a solaris message block from the SG list.
*
* @returns Solaris message block.
* @param pThis The instance.
* @param pSG Pointer to the scatter-gather list.
*/
{
if (RT_UNLIKELY(!pMsg))
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
return NULL;
}
/*
* Single buffer copy. Maybe later explore the
* need/possibility for using a mblk_t chain rather.
*/
{
{
}
}
return pMsg;
}
/**
* Calculate the number of segments required for this message block.
*
* @returns Number of segments.
* @param pThis The instance
* @param pMsg Pointer to the data message.
*/
{
unsigned cSegs = 0;
cSegs++;
#ifdef PADD_RUNT_FRAMES_FROM_HOST
cSegs++;
#endif
}
/**
* Initializes an SG list from the given message block.
*
* @returns VBox status code.
* @param pThis The instance.
* @param pMsg Pointer to the data message.
The caller must ensure it's not a control message block.
* @param pSG Pointer to the SG.
* @param cSegs Number of segments in the SG.
* This should match the number in the message block exactly!
* @param fSrc The source of the message.
*/
static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
{
LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
/*
* Convert the message block to segments.
*/
unsigned iSeg = 0;
while (pCur)
{
if (cbSeg)
{
iSeg++;
}
}
#ifdef PADD_RUNT_FRAMES_FROM_HOST
{
}
#endif
LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
return VINF_SUCCESS;
}
/**
* Converts raw mode M_DATA messages to M_PROTO DL_UNITDATA_IND format.
*
* @returns VBox status code.
* @param pMsg Pointer to the raw message.
* @param pDlpiMsg Where to store the M_PROTO message.
*
* @remarks The original raw message would be no longer valid and will be
* linked as part of the new DLPI message. Callers must take care
* not to use the raw message if this routine is successful.
*/
{
return VERR_NO_MEMORY;
if (RT_UNLIKELY(!pDlpiMsg))
return VERR_NO_MEMORY;
vboxnetflt_dladdr_t *pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_dest_addr_offset);
/* Make the message point to the protocol header */
return VINF_SUCCESS;
}
/**
* Converts DLPI M_PROTO messages to the raw mode M_DATA format.
*
* @returns VBox status code.
* @param pMsg Pointer to the M_PROTO message.
* @param ppRawMsg Where to store the converted message.
*
* @remarks If successful, the original pMsg is no longer valid, it will be deleted.
* Callers must take care not to continue to use pMsg after a successful
* call to this conversion routine.
*/
{
{
return VERR_NET_PROTOCOL_ERROR;
}
/*
* We of course need to convert them into raw ethernet frames.
*/
switch (pPrim->dl_primitive)
{
case DL_UNITDATA_IND:
{
/*
* Receive side.
*/
vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
break;
}
case DL_UNITDATA_REQ:
{
/*
* Send side.
*/
vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
break;
}
default:
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw Unknown M_PROTO. This shouldn't be happening!!"));
return VERR_NET_PROTOCOL_ERROR;
}
}
/*
* Let us just link it as a mblk_t chain rather than re-copy the entire message.
* The vboxNetFltSolarisMBlkToSG function will handle chained mblk_t's.
*/
if (RT_UNLIKELY(!pEtherMsg))
return VERR_NO_MEMORY;
return VINF_SUCCESS;
}
/**
* Worker for routing messages from the wire or from the host.
*
* @returns VBox status code.
* @param pThis The instance.
* @param pQueue Pointer to the queue.
* @param pMsg Pointer to the message.
* @param fSrc The source of the frame.
*/
static int vboxNetFltSolarisIOWorker(PVBOXNETFLTINS pThis, queue_t *pQueue, vboxnetflt_stream_t *pStream, mblk_t *pMsg, uint32_t fSrc)
{
LogFlow((DEVICE_NAME ":vboxNetFltSolarisIOWorker pThis=%p pQueue=%p pMsg=%p fSrc=%d\n", pThis, pQueue, pMsg, fSrc));
/*
* Make a copy as we will alter pMsg.
*/
/*
* Sort out M_PROTO and M_DATA.
*/
bool fOriginalIsRaw = true;
{
fOriginalIsRaw = false;
if (VBOX_SUCCESS(rc))
else
{
return VERR_GENERAL_FAILURE;
}
}
/*
* Figure out the source of the frame based on the source Mac address.
*/
/*
* Don't route ARP stream packets from the wire up the internal network,
* because we already get them on the IP stream under full promiscous mode.
* This avoids sending 2 copies of packets into the internal network.
*/
bool fDropIt = false;
{
if (VBOX_FAILURE(rc))
{
return rc;
}
}
if (fDropIt)
{
}
else
{
/*
* Packets from the host must be send down as raw mode packets.
* Packets from the wire, we don't care; just push the original
* upstream in whatever way we go it.
*/
{
if (fSrc & INTNETTRUNKDIR_HOST)
{
if (fOriginalIsRaw)
else
{
}
}
else /* INTNETTRUNKDIR_WIRE */
{
if (fOriginalIsRaw)
}
}
else
}
return VINF_SUCCESS;
}
/**
* Find the PVBOXNETFLTINS associated with a stream.
*
* @returns PVBOXNETFLTINS instance, or NULL if there's none.
* @param pStream Pointer to the stream to search for.
*/
{
return NULL;
}
/**
* Finalize the message to be fed into the internal network.
*
* @param pMsg Pointer to the message block.
* This must not be DLPI linked messages, must be M_DATA.
*
* @remarks We don't compute ethernet CRC here.
*/
{
/*
* Concatenate chained mblks.
*/
{
if (!pFullMsg)
{
return;
}
{
{
}
else
{
return;
}
}
}
if (cbMsg > sizeof(RTNETETHERHDR))
{
{
cbMsg -= sizeof(RTNETETHERHDR);
else
{
return;
}
{
#if 0
/*
* Fix up TCP checksum.
*/
{
{
/*
* @todo -XXX- this will horribly fail for an mblk_t chain! Fix this later by allocating, copying temp buffer.
*/
}
}
/*
* Fix up UDP checksum.
*/
{
}
#endif
}
else
{
}
}
else
LogFlow((DEVICE_NAME ":EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac, &pEthHdr->SrcMac));
}
else
}
{
{
{
LogFlow((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
}
else
{
return;
}
}
{
}
else
{
LogFlow((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac, &pEthHdr->SrcMac));
/* LogFlow((DEVICE_NAME ":%.*Vhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
}
}
/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
{
}
{
{
/* Bummer, Mac address is not copied yet. */
return;
}
}
{
/* ASSUMES that the MAC address never changes. */
}
{
/*
* Enable promiscuous mode.
*/
if (VBOX_FAILURE(rc))
}
{
/* Nothing to do here. */
return VINF_SUCCESS;
}
{
/* Nothing to do here. */
return VINF_SUCCESS;
}
{
}
{
return vboxNetFltSolarisAttachToInterface(pThis);
}
{
/*
* Init. the solaris specific data.
*/
return VINF_SUCCESS;
}
{
return true;
}
{
/*
* Create a message block and send it down the wire (downstream).
*/
if (fDst & INTNETTRUNKDIR_WIRE)
{
if (RT_UNLIKELY(!pMsg))
{
return VERR_NO_MEMORY;
}
}
/*
* Create a message block and send it up the host stack (upstream).
*/
if (fDst & INTNETTRUNKDIR_HOST)
{
if (RT_UNLIKELY(!pMsg))
{
return VERR_NO_MEMORY;
}
/*
* Construct a DL_UNITDATA_IND style message.
*/
if (VBOX_FAILURE(rc))
{
return VERR_NO_MEMORY;
}
if (fArp)
{
/*
* Send message up ARP stream.
*/
}
else
{
/*
* Send messages up IP stream.
*/
}
}
return VINF_SUCCESS;
}