VBoxNetFlt-solaris.c revision aa9a868e21818a9c4691bfd51afd99c728e0a6ae
/* $Id$ */
/** @file
* VBoxNetFlt - Network Filter Driver (Host), Solaris Specific Code.
*/
/*
* Copyright (C) 2008 Oracle Corporation
*
* 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
#include <VBox/intnetinline.h>
#include <iprt/initterm.h>
#include <iprt/spinlock.h>
#define VBOXNETFLT_SOLARIS_IPV6_POLLING
#endif
#include <sys/pathname.h>
#include <sys/ethernet.h>
/*
* Experimental: Using netinfo interfaces and queuing out packets.
* This is for playing better with IPFilter.
*/
#endif
// #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"
/** The module descriptions as seen in 'modinfo'. */
#define DEVICE_DESC_DRV "VirtualBox NetDrv"
#define DEVICE_DESC_MOD "VirtualBox NetMod"
#if defined(DEBUG_ramshankar)
# define LogFlowFunc LogRel
#endif
/** Driver properties */
# define VBOXNETFLT_IP6POLLINTERVAL "ipv6-pollinterval"
#endif
/** Maximum loopback packet queue size per interface */
#define VBOXNETFLT_LOOPBACK_SIZE 32
/** VLAN tag masking, should probably be in IPRT? */
typedef struct VLANHEADER
{
} VLANHEADER;
typedef struct VLANHEADER *PVLANHEADER;
/*******************************************************************************
* 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);
/*******************************************************************************
* 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 mark */
0 /* lo-water mark */
};
/**
* 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, /* service */
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,
kIp4Stream = 0x1b,
kIp6Stream = 0xcc,
kArpStream = 0xab,
kPromiscStream = 0xdf
/**
* loopback packet identifier
*/
typedef struct VBOXNETFLTPACKETID
{
struct VBOXNETFLTPACKETID *pNext;
typedef struct VBOXNETFLTPACKETID *PVBOXNETFLTPACKETID;
/**
* vboxnetflt_stream_t: per-stream data (multiple streams per interface)
*/
typedef struct vboxnetflt_stream_t
{
int DevMinor; /* minor device no. (for clone) */
/**
* vboxnetflt_promisc_stream_t: per-interface dedicated stream data
*/
typedef struct vboxnetflt_promisc_stream_t
{
bool fPromisc; /* cached promiscous value */
bool fRawMode; /* whether raw mode request was successful */
#endif
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/* static int vboxNetFltSolarisSetFastMode(queue_t *pQueue); */
/* static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg); */
static int vboxNetFltSolarisQueueLoopback(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg);
static bool vboxNetFltSolarisIsOurMBlk(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg);
static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc);
static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pMsg);
/* static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg); */
/* static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg); */
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Global device info handle. */
/** The (common) global data. */
/** The list of all opened streams. */
/**
* g_VBoxNetFltInstance is the current PVBOXNETFLTINS to be associated with the stream being created
* in ModOpen. This is just shared global data between the dynamic attach and the ModOpen procedure.
*/
/** Global IPv6 polling interval */
static int g_VBoxNetFltSolarisPollInterval = -1;
#endif
/**
* Kernel entry points
*/
int _init(void)
{
/*
* Prevent module autounloading.
*/
if (pModCtl)
else
/*
* Initialize IPRT.
*/
if (RT_SUCCESS(rc))
{
/*
* Initialize Solaris specific globals here.
*/
{
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))
{
if (!rc)
return rc;
}
else
}
}
else
{
rc = VERR_NO_MEMORY;
}
RTR0Term();
}
else
return RTErrConvertToErrno(rc);
}
int _fini(void)
{
int rc;
/*
* Undo the work done during start (in reverse order).
*/
if (RT_FAILURE(rc))
{
return EBUSY;
}
if (!rc)
{
{
}
{
}
RTR0Term();
}
return rc;
}
{
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 (rc == DDI_SUCCESS)
{
/*
* Get the user prop. for polling interval.
*/
int Interval = ddi_getprop(DDI_DEV_T_ANY, pDip, DDI_PROP_DONTPASS, VBOXNETFLT_IP6POLLINTERVAL, -1 /* default */);
if (Interval == -1)
LogFlow((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: no poll interval property specified. Skipping Ipv6 polling.\n"));
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Invalid polling interval %d. Expected between 1 and 120 secs.\n",
Interval));
Interval = -1;
}
#endif
return DDI_SUCCESS;
}
else
return DDI_FAILURE;
}
case DDI_RESUME:
{
/* Nothing to do here... */
return DDI_SUCCESS;
}
/* case DDI_PM_RESUME: */
default:
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;
}
/* case DDI_PM_SUSPEND: */
/* case DDI_HOT_PLUG_DETACH: */
default:
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)
{
LogFlowFunc((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd,
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 read 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)
{
LogFlowFunc((DEVICE_NAME ":VBoxNetFltSolarisModOpen pQueue=%p pDev=%p fOpenMode=%d fStreamMode=%d\n", pQueue, pDev,
fOpenMode, fStreamMode));
/*
* Already open?
*/
{
return ENOENT;
}
/*
* Check that the request was initiated by our code.
*
* This ASSUMES that crdup() will return a copy with a unique address and
* not do any kind of clever pooling. This check will when combined with
* g_VBoxNetFltSolarisMtx prevent races and that the instance gets
* associated with the wrong streams.
*/
if (pCred != g_pVBoxNetFltSolarisCred)
{
return EACCES;
}
/*
* Check for the VirtualBox instance.
*/
if (!pThis)
{
return ENOENT;
}
/*
* Check VirtualBox stream type.
*/
{
LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed due to undefined VirtualBox open mode. Type=%d\n", g_VBoxNetFltSolarisStreamType));
return ENOENT;
}
/*
* Get minor number. For clone opens provide a new dev_t.
*/
if (fStreamMode == CLONEOPEN)
{
{
break;
DevMinor++;
}
}
else
{
if (RT_UNLIKELY(!pPromiscStream))
{
return ENOMEM;
}
pPromiscStream->fPromisc = false;
pPromiscStream->fRawMode = false;
pPromiscStream->ModeReqId = 0;
pPromiscStream->cLoopback = 0;
#endif
}
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.
*/
{
case kPromiscStream: ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pvPromiscStream, pStream); break;
default: /* Heh. */
{
return EINVAL;
}
}
/*
* Link it to the list of streams.
*/
*ppPrevStream = pStream;
/*
* Increment IntNet reference count for this stream.
*/
/*
* Don't hold the spinlocks across putnext calls as it could
* (and does mostly) re-enter the put procedure on the same thread.
*/
{
/*
* Bind to SAP 0 (DL_ETHER).
* Note: We don't support DL_TPR (token passing ring) SAP as that is unnecessary asynchronous
* work to get DL_INFO_REQ acknowledgements and determine SAP based on the Mac Type etc.
* Besides TPR doesn't really exist anymore practically as far as I know.
*/
{
/*
* Request the physical address (we cache the acknowledgement).
*/
{
/*
* Ask for DLPI link notifications, don't bother check for errors here.
*/
/*
* Enable raw mode.
*/
if (RT_FAILURE(rc))
}
else
}
else
}
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 read 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.
*/
{
LogFlowFunc((DEVICE_NAME ":VBoxNetFltSolarisModClose pQueue=%p fOpenMode=%d\n", pQueue, fOpenMode));
/*
* Get instance data.
*/
if (RT_UNLIKELY(!pStream))
{
return ENXIO;
}
{
}
{
/*
* Free-up loopback buffers.
*/
while (pCur)
{
}
pPromiscStream->cLoopback = 0;
/*
* Sheer paranoia.
*/
{
}
#endif
}
/*
* Unlink it from the list of streams.
*/
for (ppPrevStream = &g_VBoxNetFltSolarisStreams; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
break;
/*
* Delete the stream.
*/
{
default: /* Heh. */
{
break;
}
}
/*
* Decrement IntNet reference count for this stream.
*/
return 0;
}
/**
* Read side put procedure for processing messages in the read queue.
* All streams, bound and unbound share this read procedure.
*
* @param pQueue Pointer to the read queue.
* @param pMsg Pointer to the message.
*
* @returns corresponding solaris error code.
*/
{
if (!pMsg)
return 0;
bool fSendUpstream = true;
/*
* In the unlikely case where VirtualBox crashed and this filter
* is somehow still in the host stream we must try not to panic the host.
*/
if ( pStream
{
fSendUpstream = false;
{
/*
* Retain the instance if we're filtering regardless of we are active or not
* The reason being even when we are inactive we reference the instance (e.g
* the promiscuous OFF acknowledgement case).
*/
{
case M_DATA:
{
if ( fActive
&& pPromiscStream->fRawMode)
{
}
break;
}
case M_PROTO:
case M_PCPROTO:
{
switch (Prim)
{
case DL_NOTIFY_IND:
{
{
LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Invalid notification size; expected>=%d got=%d\n",
break;
}
switch (pNotifyInd->dl_notification)
{
case DL_NOTE_PHYS_ADDR:
{
break;
{
fSendUpstream = false;
break;
}
break;
}
case DL_NOTE_LINK_UP:
{
break;
}
case DL_NOTE_LINK_DOWN:
{
break;
}
}
break;
}
case DL_BIND_ACK:
{
/*
* Swallow our bind request acknowledgement.
*/
break;
}
case DL_PHYS_ADDR_ACK:
{
/*
* Swallow our physical address request acknowledgement.
*/
break;
}
case DL_OK_ACK:
{
/*
* Swallow our fake promiscous request acknowledgement.
*/
{
pPromiscStream->fPromisc = true;
}
{
pPromiscStream->fPromisc = false;
}
break;
}
}
break;
}
case M_IOCACK:
{
/*
*/
{
pPromiscStream->fRawMode = true;
}
break;
}
case M_IOCNAK:
{
/*
*/
{
pPromiscStream->fRawMode = false;
LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: WARNING! Mode not acknowledged. RawMode is %s\n",
}
break;
}
case M_FLUSH:
{
/*
* We must support flushing queues.
*/
break;
}
}
}
else
}
if (fSendUpstream)
{
/*
* Don't queue up things here, can cause bad things to happen when the system
* is under heavy loads and we need to jam across high priority messages which
* if it's not done properly will end up in an infinite loop.
*/
}
else
{
/*
* We need to free up the message if we don't pass it through.
*/
}
return 0;
}
/**
* Write side put procedure for processing messages in the write queue.
* All streams, bound and unbound share this write procedure.
*
* @param pQueue Pointer to the write queue.
* @param pMsg Pointer to the message.
*
* @returns corresponding solaris error code.
*/
{
return 0;
}
/**
* Put the stream in raw mode.
*
* @returns VBox status code.
* @param pQueue Pointer to the read queue.
*/
{
if (RT_UNLIKELY(!pRawMsg))
return VERR_NO_MEMORY;
if (!pQueue)
return VERR_INVALID_POINTER;
return VINF_SUCCESS;
}
#if 0
/**
* Put the stream back in fast path mode.
*
* @returns VBox status code.
* @param pQueue Pointer to the read 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;
}
#endif
/**
* Send fake promiscous mode requests downstream.
*
* @param pQueue Pointer to the read queue.
* @param fPromisc Whether to enable promiscous mode or not.
* @param PromiscLevel Promiscous level; DL_PROMISC_PHYS/SAP/MULTI.
*
* @returns VBox status code.
*/
{
LogFlowFunc((DEVICE_NAME ":vboxNetFltSolarisPromiscReq pQueue=%p fPromisc=%d\n", pQueue, fPromisc));
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 read queue.
*/
{
if (RT_UNLIKELY(!pPhysAddrMsg))
return VERR_NO_MEMORY;
return VINF_SUCCESS;
}
/**
* 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.
*/
{
{
bcopy(pMsg->b_rptr + pPhysAddrAck->dl_addr_offset, &pThis->u.s.MacAddr, sizeof(pThis->u.s.MacAddr));
{
if (pThis->pSwitchPort)
}
}
else
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr: Invalid address size. expected=%d got=%d\n", ETHERADDRL,
}
}
/**
* Prepare DLPI bind request to a SAP.
*
* @returns VBox status code.
* @param pQueue Pointer to the read queue.
* @param SAP The SAP to bind the stream to.
*/
{
if (RT_UNLIKELY(!pBindMsg))
return VERR_NO_MEMORY;
pBindReq->dl_max_conind = 0;
pBindReq->dl_conn_mgmt = 0;
pBindReq->dl_xidtest_flg = 0;
return VINF_SUCCESS;
}
/**
* Prepare DLPI notifications request.
*
* @returns VBox status code.
* @param pQueue Pointer to the read queue.
*/
{
if (RT_UNLIKELY(!pNotifyMsg))
return VERR_NO_MEMORY;
return VINF_SUCCESS;
}
/**
* 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
&& pVNodeHeld)
{
if (!rc)
{
if ( pUser
{
return VINF_SUCCESS;
}
else
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenDev failed. pUser=%p fp=%p f_vnode=%p\n", pUser, pUser ? pUser->fp : NULL,
}
if (pUser)
}
else
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenDev lookupname failed. rc=%d pVNodeHeld=%p\n", rc, pVNodeHeld));
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.
*/
{
}
/**
* Set the DLPI style-2 PPA via an attach request, Synchronous.
* Waits for request acknowledgement and verifies the result.
*
* @returns VBox status code.
* @param hDevice Layered device handle.
* @param PPA Physical Point of Attachment (PPA) number.
*/
{
int rc;
if (RT_UNLIKELY(!pAttachMsg))
return VERR_NO_MEMORY;
if (!rc)
{
if (!rc)
{
/*
* Verify if the attach succeeded.
*/
if (cbMsg >= sizeof(t_uscalar_t))
{
&& cbMsg == DL_OK_ACK_SIZE)
{
rc = VINF_SUCCESS;
}
&& cbMsg == DL_ERROR_ACK_SIZE)
{
}
else /* Garbled reply */
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachReq ldi_getmsg succeeded, but invalid op. expected %d recvd %d\n",
}
}
else
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachReq ldi_getmsg succeeded, but invalid size %d expected %d\n", cbMsg,
}
}
else
{
}
}
else
{
}
return rc;
}
/**
* 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 IPv4 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 vboxNetFltSolarisRelinkIp4(vnode_t *pVNode, struct lifreq *pInterface, int IpMuxFd, int ArpMuxFd)
{
LogFlowFunc((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: pVNode=%p pInterface=%p IpMuxFd=%d ArpMuxFd=%d\n", pVNode,
int NewIpMuxId;
int NewArpMuxId;
if ( !rc
&& !rc2)
{
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
}
else
return VERR_GENERAL_FAILURE;
}
/**
* Relinks the lower and the upper IPv6 stream.
*
* @returns VBox status code.
* @param pVNode Pointer to the device vnode.
* @param pInterface Pointer to the interface.
* @param Ip6MuxFd The IPv6 multiplexor ID.
*/
{
LogFlowFunc((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: pVNode=%p pInterface=%p Ip6MuxFd=%d\n", pVNode, pInterface, Ip6MuxFd));
int NewIp6MuxId;
if (!rc)
{
if (RT_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.
*/
{
LogFlowFunc((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;
}
}
LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to find %s in the host stack.\n", DEVICE_NAME));
}
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;
}
/**
* Opens up the DLPI style 2 link that requires explicit PPA attach
* phase.
*
* @returns VBox status code.
* @param pThis The instance.
* @param pDevId Where to store the opened LDI device id.
*/
{
/*
* Strip out PPA from the device name, eg: "ce3".
*/
if (!pszDev)
return VERR_NO_MEMORY;
if (!RT_C_IS_DIGIT(*pszEnd))
break;
pszEnd++;
int rc = VERR_GENERAL_FAILURE;
long PPA = -1;
if ( pszEnd
{
*pszEnd = '\0';
char szDev[128];
/*
* Try open the device as DPLI style 2.
*/
if (!rc)
{
/*
* Attach the PPA explictly.
*/
if (RT_SUCCESS(rc))
{
return rc;
}
LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStyle2 dl_attach failed. rc=%d szDev=%s PPA=%d rc=%d\n", rc, szDev, PPA));
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStyle2 Failed to open. rc=%d szDev=%s PPA=%d\n", rc, szDev, PPA));
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStyle2 Failed to construct PPA. pszDev=%s pszEnd=%s.\n", pszDev, pszEnd));
return VERR_INTNET_FLT_IF_FAILED;
}
/**
* Opens up dedicated stream on top of the interface.
* As a side-effect, the stream gets opened during
* the I_PUSH phase.
*
* @param pThis The instance.
*/
{
DevId = ldi_ident_from_anon();
int ret;
/*
* Figure out if this is a VLAN interface or not based on the interface name.
* Only works for the VLAN PPA-hack based names. See #4854 for details.
*/
if (!RT_C_IS_DIGIT(*pszEnd))
break;
pszEnd++;
if (PPA > 1000)
{
}
/*
* Try style-1 open first.
*/
char szDev[128];
if ( rc
{
/*
* Fallback to non-ClearView style-1 open.
*/
}
if (rc)
{
/*
* Try DLPI style 2.
*/
if (RT_FAILURE(rc))
LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream vboxNetFltSolarisOpenStyle2 failed. rc=%d\n", rc));
else
rc = 0;
}
if (rc)
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to open '%s' rc=%d pszName='%s'\n", szDev, rc, pThis->szName));
return VERR_INTNET_FLT_IF_FAILED;
}
if (!rc)
{
if (!ret)
{
{
rc = ldi_ioctl(pThis->u.s.hIface, I_PUSH, (intptr_t)DEVICE_NAME, FKIOCTL, g_pVBoxNetFltSolarisCred, &ret);
}
else
{
}
if (!rc)
return VINF_SUCCESS;
LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to push filter onto host interface '%s'\n", pThis->szName));
}
else
return VINF_SUCCESS;
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to search for filter in interface '%s'.\n", pThis->szName));
return VERR_INTNET_FLT_IF_FAILED;
}
/**
* Closes the interface, thereby closing the dedicated stream.
*
* @param pThis The instance.
*/
{
{
}
}
/**
* Dynamically attach under IPv4 and ARP streams on the host stack.
*
* @returns VBox status code.
* @param pThis The instance.
* @param fAttach Is this an attach or detach.
*/
{
/*
* Statuatory Warning: Hackish code ahead.
*/
char *pszModName = DEVICE_NAME;
struct lifreq Ip4Interface;
struct strmodconf StrMod;
struct strmodconf ArpStrMod;
int rc;
int rc2;
int ret;
/*
* Open the IP and ARP streams as layered devices.
*/
if (rc)
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open the IP stream on '%s'.\n", pThis->szName));
return VERR_INTNET_FLT_IF_FAILED;
}
if (rc)
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open the ARP stream on '%s'.\n", pThis->szName));
return VERR_INTNET_FLT_IF_FAILED;
}
/*
* Obtain the interface flags from IPv4.
*/
if (RT_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 (RT_SUCCESS(rc))
{
/*
* Get the multiplexor IDs.
*/
if (!rc)
{
/*
* Get the multiplex file descriptor to the lower streams. Generally this is lost
*/
int Ip4MuxFd;
int ArpMuxFd;
if ( RT_SUCCESS(rc)
&& RT_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.
*/
rc2 = strioctl(pUdp4VNode, I_PUNLINK, (intptr_t)Ip4Interface.lifr_arp_muxid, 0, K_TO_K, kcred, &ret);
if ( !rc
&& !rc2)
{
/*
* Obtain the vnode from the useless userland file descriptor.
*/
if ( pIpFile
&& pArpFile
{
/*
*/
if ( RT_SUCCESS(rc)
&& RT_SUCCESS(rc2))
{
/*
*/
/*
* Set global data which will be grabbed by ModOpen.
* There is a known (though very unlikely) race here because
* of the inability to pass user data while inserting.
*/
if (fAttach)
{
}
if (fAttach)
{
}
if (!rc)
{
/*
*/
if (fAttach)
{
}
if (fAttach)
{
}
if (!rc)
{
/*
* 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 (RT_SUCCESS(rc))
{
/*
* 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
{
}
/*
* Try failing gracefully during attach.
*/
if (fAttach)
}
else
{
}
if (fAttach)
}
else
{
}
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to find position. rc=%d rc2=%d\n", rc, rc2));
}
else
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to unlink upper stream rc=%d rc2=%d.\n", rc, rc2));
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get MuxFd from MuxId. rc=%d rc2=%d\n", rc, rc2));
}
else
}
else
}
else
{
/*
* This would happen for interfaces that are not plumbed.
*/
LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Warning: seems '%s' is unplumbed.\n", pThis->szName));
rc = VINF_SUCCESS;
}
return rc;
}
/**
* Dynamically attach under IPv6 on the host stack.
*
* @returns VBox status code.
* @param pThis The instance.
* @param fAttach Is this an attach or detach.
*/
{
/*
* Statuatory Warning: Hackish code ahead.
*/
char *pszModName = DEVICE_NAME;
struct lifreq Ip6Interface;
struct strmodconf StrMod;
int rc;
int ret;
/*
* Open the IPv6 stream as a layered devices.
*/
if (rc)
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to open the IPv6 stream on '%s'.\n", pThis->szName));
return VERR_INTNET_FLT_IF_FAILED;
}
/*
* Obtain the interface flags from IPv6.
*/
if (RT_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 (RT_SUCCESS(rc))
{
/*
* Get the multiplexor IDs.
*/
if (!rc)
{
/*
* Get the multiplex file descriptor to the lower streams. Generally this is lost
*/
int Ip6MuxFd;
if (RT_SUCCESS(rc))
{
/*
* 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.
*/
if (!rc)
{
/*
* Obtain the vnode from the useless userland file descriptor.
*/
if ( pIpFile
{
/*
*/
if (RT_SUCCESS(rc))
{
/*
* Set global data which will be grabbed by ModOpen.
* There is a known (though very unlikely) race here because
* of the inability to pass user data while inserting.
*/
if (fAttach)
{
}
/*
*/
if (fAttach)
{
}
if (!rc)
{
/*
* 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 (RT_SUCCESS(rc))
{
/*
* 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
{
}
if (fAttach)
}
else
{
}
}
else
}
else
}
else
}
else
}
else
}
else
}
else
{
}
return rc;
}
/**
* Ipv6 dynamic attachment timer callback to attach to the Ipv6 stream if needed.
*
* @param pThis Pointer to the timer.
* @param pvData Opaque pointer to the instance.
* @param iTick Timer tick (unused).
*/
{
{
if ( !pIp6Stream
&& !fIp6Attaching)
{
if (RT_SUCCESS(rc))
{
}
else
}
}
}
/**
* Setups up a kernel timer based on the driver property for attaching to IPv6 stream
* whenever the stream gets plumbed for the interface.
*
* @returns VBox status code.
* @param pThis The instance.
*/
{
int rc = VERR_GENERAL_FAILURE;
vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
if (RT_LIKELY(pPromiscStream))
{
{
/*
* Validate IPv6 polling interval.
*/
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Invalid polling interval %d. Expected between 1 and 120 secs.\n",
Interval));
return VERR_INVALID_PARAMETER;
}
/*
* Setup kernel poll timer.
*/
rc = RTTimerCreateEx(&pPromiscStream->pIp6Timer, Interval * (uint64_t)1000000000, RTTIMER_FLAGS_CPU_ANY,
vboxNetFltSolarispIp6Timer, (void *)pThis);
if (RT_SUCCESS(rc))
{
rc = RTTimerStart(pPromiscStream->pIp6Timer, 10 * (uint64_t)1000000000 /* 10 seconds to blastoff */);
LogFlow((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Ipv6 %d second timer begins firing in 10 seconds.\n", Interval));
}
else
}
else
{
rc = VINF_SUCCESS;
}
}
return rc;
}
#endif
/**
* 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).
*/
{
int rc = VINF_SUCCESS;
if (pThis->u.s.pvIp4Stream)
if (pThis->u.s.pvIp6Stream)
vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
if ( pPromiscStream
{
}
#endif
return rc;
}
/**
* Wrapper for attaching ourselves to the interface.
*
* @returns VBox status code.
* @param pThis The instance.
*/
{
/*
* Since this is asynchronous streams injection, let the attach succeed before we can start
* processing the stream.
*/
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/*
* Ipv6 attaching is optional and can fail. We don't bother to bring down the whole
* attach process just if Ipv6 interface is unavailable.
*/
/*
* If Ip6 interface is not plumbed and an Ip6 polling interval is specified, we need
* to begin polling to attach on the Ip6 interface whenver it comes up.
*/
if ( rc2 == VERR_INTNET_FLT_IF_NOT_FOUND
&& g_VBoxNetFltSolarisPollInterval != -1)
{
if (RT_FAILURE(rc3))
{
/*
* If we failed to setup Ip6 polling, warn in the release log and continue.
*/
}
}
#endif
/*
* Report promiscuousness and capabilities.
*/
{
/** @todo There is no easy way of obtaining the global host side promiscuous
* counter. Currently we just return false. */
pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
}
/*
* Ipv4 is successful, and maybe Ipv6, we're ready for transfers.
*/
return VINF_SUCCESS;
}
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface vboxNetFltSolarisOpenStream failed rc=%Rrc\n", rc));
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)
{
LogFlowFunc((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
/*
* Convert the message block to segments. Work INTNETSG::cbTotal.
*/
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;
}
#if 0
/**
* 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;
/*
* Change the chained blocks to type M_DATA.
*/
return VINF_SUCCESS;
}
#endif
/**
* Initializes a packet identifier.
*
* @param pTag Pointer to the packed identifier.
* @param pMsg Pointer to the message to be identified.
*
* @remarks Warning!!! This function assumes 'pMsg' is an unchained message.
*/
{
}
/**
* Queues a packet for loopback elimination.
*
* @returns VBox status code.
* @param pThis The instance.
* @param pPromiscStream Pointer to the promiscuous stream.
* @param pMsg Pointer to the message.
*/
static int vboxNetFltSolarisQueueLoopback(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg)
{
LogFlowFunc((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback pThis=%p pPromiscStream=%p pMsg=%p\n", pThis, pPromiscStream, pMsg));
{
/*
* We don't currently make chained messages in on Xmit
* so this only needs to be supported when we do that.
*/
return VERR_NOT_SUPPORTED;
}
return VERR_NET_MSG_SIZE;
|| ( pPromiscStream->pHead
{
do
{
if (!pPromiscStream->pHead)
{
if (RT_UNLIKELY(!pCur))
{
rc = VERR_NO_MEMORY;
break;
}
break;
}
else if ( pPromiscStream->pHead
{
break;
}
else
{
if (RT_UNLIKELY(!pCur))
{
rc = VERR_NO_MEMORY;
break;
}
LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback added head checksum=%u cLoopback=%d.\n", pCur->Checksum,
break;
}
} while (0);
}
else
{
/*
* Maximum loopback queue size reached. Re-use tail as head.
*/
/*
* Find tail's previous item.
*/
/** @todo consider if this is worth switching to a double linked list... */
{
}
LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback recycled tail!! checksum=%u cLoopback=%d\n", pCur->Checksum,
}
return rc;
}
/**
* Checks if the packet is enqueued for loopback as our own packet.
*
* @returns If it's our packet, returns true after dequeuing it, otherwise false.
* @param pThis The instance.
* @param pPromiscStream Pointer to the promiscuous stream.
* @param pMsg Pointer to the message.
*/
static bool vboxNetFltSolarisIsOurMBlk(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg)
{
{
/** Handle this when Xmit makes chained messages */
return false;
}
if (cbMsg < sizeof(RTNETETHERHDR))
return false;
bool fIsOurPacket = false;
while (pCur)
{
{
continue;
}
{
continue;
}
/*
* Yes, it really is our own packet, mark it as handled
* and move it as a "free slot" to the head and return success.
*/
if (pPrev)
{
}
fIsOurPacket = true;
LogFlow((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk found packet %p Checksum=%u cLoopback=%d\n", pMsg, Checksum,
break;
}
return fIsOurPacket;
}
/**
* Helper.
*/
{
/*
* MAC address change acknowledgements are intercepted on the read side
* hence theoritically we are always update to date with any changes.
*/
}
/**
* Worker for routing messages from the wire or from the host.
*
* @returns VBox status code.
* @param pThis The instance.
* @param pStream Pointer to the stream.
* @param pQueue Pointer to the read queue.
* @param pOrigMsg Pointer to the message.
*/
static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pMsg)
{
vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
if (RT_UNLIKELY(!pPromiscStream))
{
return VERR_INVALID_POINTER;
}
/*
* Paranoia...
*/
{
if (cbMsg < sizeof(RTNETETHERHDR))
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv %s: packet too small. Dropping packet.\n", pThis->szName));
return VINF_SUCCESS;
}
if (pFullMsg)
{
}
else
{
return VERR_NO_MEMORY;
}
}
/*
* Don't loopback packets we transmit to the wire.
*/
{
return VINF_SUCCESS;
}
/*
* Figure out the source of the packet based on the source Mac address.
*/
/*
* Afaik; we no longer need to worry about incorrect checksums because we now use
* checksum offloading.
*/
#if 0
if (fSrc & INTNETTRUNKDIR_HOST)
{
if (pCorrectedMsg)
}
#endif
/*
* Solaris raw mode streams for priority-tagged VLAN does not strip the VLAN tag.
* It zero's the VLAN-Id but keeps the tag intact as part of the Ethernet header.
* We need to manually strip these tags out or the guests might get confused.
*/
bool fCopied = false;
bool fTagged = false;
&& pPromiscStream->fRawMode)
{
{
{
{
if (pFullMsg)
{
/* Original pMsg will be freed by the caller */
fCopied = true;
}
else
{
return VERR_NO_MEMORY;
}
}
PVLANHEADER pVlanHdr = (PVLANHEADER)(pMsg->b_rptr + sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType));
{
/*
* Create new Ethernet header with stripped VLAN tag.
*/
if (RT_LIKELY(pStrippedMsg))
{
fTagged = true;
/*
* Copy ethernet header excluding the ethertype.
*/
/*
* Link the rest of the message (ethertype + data, skipping VLAN header).
*/
pMsg = pStrippedMsg;
}
else
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv insufficient memory for creating VLAN stripped packet cbMsg=%u.\n",
cbEthPrefix));
if (fCopied)
return VERR_NO_MEMORY;
}
}
}
}
}
/*
* Route all received packets into the internal network.
*/
if (RT_SUCCESS(rc))
else
/*
* If we've allocated the prefix before the VLAN tag in a new message, free that.
*/
if (fTagged)
{
}
/*
* If we made an extra copy for VLAN stripping, we need to free that ourselves.
*/
if (fCopied)
return VINF_SUCCESS;
}
#if 0
/**
* Finalize the message to be fed into the internal network.
* Verifies and tries to fix checksums for TCP, UDP and IP.
*
* @returns Corrected message or NULL if no change was required.
* @param pMsg Pointer to the message block.
* This must not be DLPI linked messages, must be M_DATA.
*
* @remarks If this function returns a checksum adjusted message, the
* passed in input message has been freed and should not be
* referenced anymore by the caller.
*/
{
{
return NULL;
}
{
/*
* Check if we have a complete packet or being fed a chain.
*/
size_t cbIpPacket = 0;
{
/*
* Handle chain by making a packet copy to verify if the IP checksum is correct.
* Contributions to calculating IP checksums from a chained message block with
* odd/non-pulled up sizes are welcome.
*/
if (RT_UNLIKELY(!pFullMsg))
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums failed to alloc new message of %d bytes.\n", cbFullMsg));
return NULL;
}
{
{
}
}
}
else
/*
* Check if the IP checksum is valid.
*/
bool fChecksumAdjusted = false;
{
/*
* Fix up TCP/UDP and IP checksums if they're incomplete/invalid.
*/
{
{
fChecksumAdjusted = true;
}
}
{
{
fChecksumAdjusted = true;
}
}
}
if (fChecksumAdjusted)
{
/*
* If we made a copy and the checksum is corrected on the copy,
* free the original, return the checksum fixed copy.
*/
if (pFullMsg)
{
return pFullMsg;
}
return pMsg;
}
/*
* If we made a copy and the checksum is NOT corrected, free the copy,
* and return NULL.
*/
if (pFullMsg)
return NULL;
}
return NULL;
}
/**
* Simple packet dump, used for internal debugging.
*
* @param pMsg Pointer to the message to analyze and dump.
*/
{
{
{
LogRel((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
{
{
LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
}
}
}
else
{
}
}
{
PVLANHEADER pVlanHdr = (PVLANHEADER)(pMsg->b_rptr + sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType));
LogRel((DEVICE_NAME ":VLAN Pcp=%u Cfi=%u Id=%u\n", VLAN_PRI(RT_BE2H_U16(pVlanHdr->Data)), VLAN_CFI(RT_BE2H_U16(pVlanHdr->Data)), VLAN_ID(RT_BE2H_U16(pVlanHdr->Data))));
}
{
}
{
}
{
}
else
{
LogRel((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
/* LogFlow((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
}
}
#endif
/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
{
/*
*/
if (pStream)
{
if (pStream->pReadQueue)
{
if (RT_FAILURE(rc))
}
else
}
else
}
{
{
}
{
}
#endif
return VINF_SUCCESS;
}
{
/* Nothing to do here. */
return VINF_SUCCESS;
}
{
/* Nothing to do here. */
}
{
/*
* Mutex used for loopback lockouts.
*/
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
#endif
if (RT_SUCCESS(rc))
return rc;
}
else
#endif
}
else
return rc;
}
{
/*
* Init. the solaris specific data.
*/
pThis->u.s.fAttaching = false;
#endif
return VINF_SUCCESS;
}
{
/*
* We don't support interface rediscovery on Solaris hosts because the
* filter is very tightly bound to the stream.
*/
return false;
}
{
int rc = VINF_SUCCESS;
if (fDst & INTNETTRUNKDIR_WIRE)
{
/*
* @todo try find a way for IPFilter to accept ethernet frames (currently silently drops them).
*/
{
unsigned uProtocol;
/*
* Queue out using netinfo.
*/
if (pNetStack)
{
if (pNetData)
{
if (pInterface)
{
/*
* Queue out rather than direct out transmission.
*/
if (!rc)
rc = VINF_SUCCESS;
else
{
}
}
else
{
}
}
else
{
}
}
else
{
}
}
else
{
rc = VERR_NO_MEMORY;
}
#else
vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
if (RT_LIKELY(pPromiscStream))
{
{
}
else
{
return VERR_NO_MEMORY;
}
}
#endif
}
if (fDst & INTNETTRUNKDIR_HOST)
{
/*
* For unplumbed interfaces we would not be bound to IP or ARP.
* We either bind to both or neither; so atomic reading one should be sufficient.
*/
if (!pIp4Stream)
return rc;
/*
* Create a message block and send it up the host stack (upstream).
*/
{
/*
* Send message up ARP stream.
*/
{
if (pArpStream)
{
/*
* Construct a DL_UNITDATA_IND style message for ARP as it doesn't understand fast path.
*/
if (RT_SUCCESS(rc))
{
}
else
{
rc = VERR_NO_MEMORY;
}
}
else
}
else
{
&& pIp6Stream)
{
/*
* Send messages up IPv6 stream.
*/
}
else
{
/*
* Send messages up IPv4 stream.
*/
}
}
}
else
{
rc = VERR_NO_MEMORY;
}
}
return rc;
}