DevINIP.cpp revision f488d0d8bf5898bbee1c3944c6c4547ee34a0fe9
/* $Id$ */
/** @file
*/
/*
* Copyright (C) 2007-2013 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_DEV_INIP
#include <iprt/semaphore.h>
/* All lwip header files are not C++ safe. So hack around this. */
#ifndef VBOX_WITH_NEW_LWIP
#else
# include "lwip/tcp_impl.h"
#endif
#include "VBoxDD.h"
#ifdef VBOX_WITH_NEW_LWIP
# include "VBoxLwipCore.h"
#endif
/*******************************************************************************
* Macros and Defines *
*******************************************************************************/
/** Maximum frame size this device can handle. */
#define DEVINIP_MAX_FRAME 1514
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Internal Network IP stack device instance data.
*
* @implements PDMIBASE
* @implements PDMINETWORKDOWN
*/
typedef struct DEVINTNETIP
{
/** The base interface for LUN\#0. */
/** The network port this device provides (LUN\#0). */
/** The network configuration port this device provides (LUN\#0). */
/** The base interface of the network driver below us. */
/** The connector of the network driver below us. */
/** Pointer to the device instance. */
/** MAC address. */
/** Static IP address of the interface. */
char *pszIP;
/** Netmask of the interface. */
char *pszNetmask;
/** Gateway for the interface. */
char *pszGateway;
/** lwIP network interface description. */
/** lwIP ARP timer. */
/** lwIP TCP fast timer. */
/** lwIP TCP slow timer. */
/** hack: get linking right. remove this eventually, once the device
* provides a proper interface to all IP stack functions. */
const void *pLinkHack;
/** Flag whether the link is up. */
bool fLnkUp;
#ifndef VBOX_WITH_NEW_LWIP
/**
* This hack-flag for spliting initialization logic in devINIPTcpipInitDone,
* this is the only place when during initialization we can be called from TCPIP
* thread.
* This callback used for Initialization and Finalization with old lwip.
*/
bool fTermination;
#endif
/**
* In callback we're getting status of interface adding operation (TCPIP thread),
* but we need inform constructing routine whether it was success or not(EMT thread).
*/
bool rcInitialization;
} DEVINTNETIP, *PDEVINTNETIP;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/**
* Pointer to the (only) instance data in this device.
*/
/*
* really ugly hack to avoid linking problems on unix style platforms
* using .a libraries for now.
*/
static const PFNRT g_pDevINILinkHack[] =
{
};
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
#ifndef VBOX_WITH_NEW_LWIP
#endif
static DECLCALLBACK(err_t) devINIPOutput(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr);
#ifndef VBOX_WITH_NEW_LWIP
/**
* ARP cache timeout handling for lwIP.
*
* @param pDevIns Device instance.
* @param pTimer Pointer to timer.
*/
{
}
/**
* TCP fast timer handling for lwIP.
*
* @param pDevIns Device instance.
* @param pTimer Pointer to timer.
*/
{
}
/**
* TCP slow timer handling for lwIP.
*
* @param pDevIns Device instance.
* @param pTimer Pointer to timer.
*/
{
}
#endif /* VBOX_WITH_NEW_LWIP */
/**
* code to resolve the address and call the link-level packet function.
*
* @returns lwIP error code
* @param netif Interface on which to send IP packet.
* @param p Packet data.
* @param ipaddr Destination IP address.
*/
static DECLCALLBACK(err_t) devINIPOutput(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
{
#ifndef VBOX_WITH_NEW_LWIP
#else
#endif
return lrc;
}
/**
* Output a raw packet on the interface.
*
* @returns lwIP error code
* @param netif Interface on which to send frame.
* @param p Frame data.
*/
{
int rc = VINF_SUCCESS;
/* Silently ignore packets being sent while lwIP isn't set up. */
if (g_pDevINIPData)
{
if (RT_FAILURE(rc))
return ERR_IF;
rc = g_pDevINIPData->pDrv->pfnAllocBuf(g_pDevINIPData->pDrv, DEVINIP_MAX_FRAME, NULL /*pGso*/, &pSgBuf);
if (RT_SUCCESS(rc))
{
#if ETH_PAD_SIZE
#endif
{
{
{
}
}
else
{
LogRel(("INIP: exceeded frame size\n"));
break;
}
}
if (cbBuf)
{
}
else
#if ETH_PAD_SIZE
#endif
}
}
if (RT_FAILURE(rc))
return lrc;
}
/**
* Implements the ethernet interface backend initialization for lwIP.
*
* @returns lwIP error code
* @param netif Interface to configure.
*/
{
#ifdef VBOX_WITH_NEW_LWIP
/** @todo why explicit ARP routing required for 1.2.0 case? */
/* Note! We always assign link-local IPv6 address */
#else
#endif
return ERR_OK;
}
/**
* Parses CFGM parameters related to network connection
*/
static DECLCALLBACK(int) devINIPNetworkConfiguration(PPDMDEVINS pDevIns, PDEVINTNETIP pThis, PCFGMNODE pCfg)
{
int rc = VINF_SUCCESS;
if (RT_FAILURE(rc))
{
N_("Configuration error: Failed to get the \"IP\" value"));
/* @todo: perhaps we should panic if IPv4 address isn't specify, with assumtion that
* ISCSI target specified in IPv6 form.
*/
return rc;
}
if (RT_FAILURE(rc))
{
N_("Configuration error: Failed to get the \"Netmask\" value"));
return rc;
}
if ( RT_FAILURE(rc)
&& rc != VERR_CFGM_VALUE_NOT_FOUND)
{
N_("Configuration error: Failed to get the \"Gateway\" value"));
return rc;
}
return VINF_SUCCESS;
}
/**
* Wait until data can be received.
*
* @returns VBox status code. VINF_SUCCESS means there is at least one receive descriptor available.
* @param pInterface PDM network port interface pointer.
* @param cMillies Number of milliseconds to wait. 0 means return immediately.
*/
static DECLCALLBACK(int) devINIPNetworkDown_WaitInputAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
{
return VINF_SUCCESS;
}
/**
* Receive data and pass it to lwIP for processing.
*
* @returns VBox status code
* @param pInterface PDM network port interface pointer.
* @param pvBuf Pointer to frame data.
* @param cb Frame size.
*/
static DECLCALLBACK(int) devINIPNetworkDown_Input(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
{
struct pbuf *p, *q;
int rc = VINF_SUCCESS;
/* Silently ignore packets being received while lwIP isn't set up. */
if (!g_pDevINIPData)
{
return VINF_SUCCESS;
}
#if ETH_PAD_SIZE
#endif
/* We allocate a pbuf chain of pbufs from the pool. */
if (p != NULL)
{
#if ETH_PAD_SIZE
#endif
{
/* Fill the buffers, and clean out unused buffer space. */
}
#ifndef VBOX_WITH_NEW_LWIP
{
case ETHTYPE_IP: /* IP packet */
if (lrc)
break;
case ETHTYPE_ARP: /* ARP packet */
break;
default:
lwip_pbuf_free(p);
}
#else
/* We've setup flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET
so this should be thread-safe. */
tcpip_input(p,iface);
#endif
}
out:
return rc;
}
/**
* @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
*/
{
}
/**
* Signals the end of lwIP TCPIP initialization.
*
* @note: TCPIP thread, corresponding EMT waiting on semaphore.
* @param arg opaque argument, here the pointer to the PDEVINTNETIP.
*/
{
#ifndef VBOX_WITH_NEW_LWIP
/* see PDEVINTNETIP::fTermination */
if (!pThis->fTermination)
{
#endif
{
N_("Configuration error: Invalid \"IP\" value"));
goto done;
}
{
N_("Configuration error: Invalid \"Netmask\" value"));
goto done;
}
if (pThis->pszGateway)
{
{
N_("Configuration error: Invalid \"Gateway\" value"));
goto done;
}
}
else
{
}
if (!ret)
{
N_("netif_add failed"));
goto done;
}
#ifndef VBOX_WITH_NEW_LWIP
}
done:
#else
done:
return;
#endif
}
#ifdef VBOX_WITH_NEW_LWIP
/**
* This callback is for finitializing our activity on TCPIP thread.
* XXX: We do it only for new LWIP, old LWIP will stay broken for now.
*/
{
}
#endif
/**
* Gets the current Media Access Control (MAC) address.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param pMac Where to store the MAC address.
* @thread EMT
*/
{
return VINF_SUCCESS;
}
/**
* Gets the new link state.
*
* @returns The current link state.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @thread EMT
*/
{
return PDMNETWORKLINKSTATE_UP;
return PDMNETWORKLINKSTATE_DOWN;
}
/**
* Sets the new link state.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param enmState The new link state
*/
static DECLCALLBACK(int) devINIPSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
{
{
if (fNewUp)
{
LogFlowFunc(("Link is up\n"));
}
else
{
LogFlowFunc(("Link is down\n"));
}
}
return VINF_SUCCESS;
}
/* -=-=-=-=- PDMIBASE -=-=-=-=- */
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
const char *pszIID)
{
return NULL;
}
/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
/**
* Destruct a device instance.
*
* Most VM resources are freed by the VM. This callback is provided so that any non-VM
* resources can be freed correctly.
*
* @returns VBox status.
* @param pDevIns The device instance data.
*/
{
if (g_pDevINIPData != NULL)
{
#ifndef VBOX_WITH_NEW_LWIP
pThis->fTermination = true;
#else
#endif
}
return VINF_SUCCESS;
}
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
{
int rc = VINF_SUCCESS;
#ifdef VBOX_WITH_NEW_LWIP
#endif
/*
* Validate the config.
*/
#ifdef VBOX_WITH_NEW_LWIP
"IPv6\0"
#endif
"Netmask\0Gateway\0"))
N_("Unknown Internal Networking IP configuration option"));
/*
* Init the static parts.
*/
/* Pointer to device instance */
/* IBase */
/* INetworkDown */
/* INetworkConfig */
/*
* Get the configuration settings.
*/
if (rc == VERR_CFGM_NOT_BYTES)
{
char szMAC[64];
if (RT_SUCCESS(rc))
{
for (uint32_t i = 0; i < 6; i++)
{
return PDMDEV_SET_ERROR(pDevIns,
N_("Configuration error: Invalid \"MAC\" value"));
if (c1 > 9)
c1 -= 7;
if (c2 > 9)
c2 -= 7;
macStr++;
}
}
}
if (RT_FAILURE(rc))
N_("Configuration error: Failed to get the \"MAC\" value"));
/*
* Attach driver and query the network connector interface.
*/
if (RT_FAILURE(rc))
{
}
AssertMsgReturn(pThis->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"), VERR_PDM_MISSING_INTERFACE_BELOW);
/*
* Set up global pointer to interface data.
*/
/* link hack */
/*
* Initialize lwIP.
*/
#ifndef VBOX_WITH_NEW_LWIP
# if MEM_LIBC_MALLOC == 0
# endif
#else /* VBOX_WITH_NEW_LWIP */
#endif
/* this rc could be updated in devINIPTcpInitDone thread */
return rc;
}
/**
* Query whether lwIP is initialized or not. Since there is only a single
* instance of this device ever for a VM, it can be a global function.
*
* @returns True if lwIP is initialized.
*/
bool DevINIPConfigured(void)
{
return g_pDevINIPData != NULL;
}
/**
* Internal network IP stack device registration record.
*/
const PDMDEVREG g_DeviceINIP =
{
/* u32Version */
/* szName */
"IntNetIP",
"",
"",
/* pszDescription */
"Internal Network IP stack device",
/* fFlags */
/* fClass. As this is used by the storage devices, it must come earlier. */
/* cMaxInstances */
1,
/* cbInstance */
sizeof(DEVINTNETIP),
/* pfnConstruct */
/* pfnDestruct */
/* pfnRelocate */
NULL,
/* pfnMemSetup */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnQueryInterface */
NULL,
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
};