xbox-kernel/private/ntos/net/xnet.cpp
2020-09-30 17:17:25 +02:00

513 lines
14 KiB
C++

// ---------------------------------------------------------------------------------------
// xnet.cpp
//
// Copyright (C) Microsoft Corporation
// ---------------------------------------------------------------------------------------
#include "xnp.h"
#include "xnver.h"
// ---------------------------------------------------------------------------------------
// Trace Tags
// ---------------------------------------------------------------------------------------
DefineTag(Verbose, 0); // Trace verbose messages
DefineTag(Warning, TAG_ENABLE); // Trace warnings
DefineTag(pktRecv, 0); // Trace packet receives
DefineTag(pktBroadcast, 0); // Trace broadcast packet receives
DefineTag(pktXmit, 0); // Trace packet transmits
DefineTag(pktWarn, TAG_ENABLE); // Trace packet Recv/Xmit uncommon events
// ---------------------------------------------------------------------------------------
// Globals
// ---------------------------------------------------------------------------------------
LONG g_lXnLock = 0;
// ---------------------------------------------------------------------------------------
// XnInit
// ---------------------------------------------------------------------------------------
INT _WSAAPI_ XnInit(void ** ppXn, char * pszXbox, const XNetStartupParams * pxnsp, BOOL fWsa, WORD wVersionRequired, LPWSADATA lpWSAData)
{
while (InterlockedCompareExchange(&g_lXnLock, 1, 0))
{
Sleep(0);
}
CXn * pXn = (CXn *)(*ppXn);
int err = 0;
if (pXn == NULL)
{
pXn = new CXn;
if (pXn == NULL)
{
err = RtlNtStatusToDosError(NETERR_MEMORY);
goto err;
}
*ppXn = pXn;
// Set up XNetInitParams and XNetConfigParams
XNetInitParams xnip;
XNetConfigParams xncp;
xnip.pxnp = (XNetParams *)pxnsp;
xnip.pszXbox = pszXbox;
HalQueryTsc(&xnip.liTime);
memset(&xncp, 0, sizeof(xncp));
xncp.dwSigEnd = XNET_CONFIG_PARAMS_SIGEND;
HANDLE hVolume = XNetOpenConfigVolume();
if (hVolume != INVALID_HANDLE_VALUE)
{
if (XNetLoadConfigSector(hVolume, 0, (BYTE *)&xncp, sizeof(xncp)))
{
// Extract the rand seed from the config sector and move it into
// the init params. If we couldn't read the config sector, just
// leave the seed with whatever is on the stack.
Assert(sizeof(xnip.abSeed) == sizeof(xncp.abSeed));
memcpy(xnip.abSeed, xncp.abSeed, sizeof(xnip.abSeed));
}
}
if (xncp.dwSigEnd != XNET_CONFIG_PARAMS_SIGEND)
{
memset(&xncp, 0, sizeof(xncp));
xncp.dwSigEnd = XNET_CONFIG_PARAMS_SIGEND;
}
NTSTATUS status = pXn->SockInit(&xnip);
if (!NT_SUCCESS(status))
{
err = RtlNtStatusToDosError(status);
}
if (hVolume != INVALID_HANDLE_VALUE)
{
if (err == 0)
{
// Write the updated rand seed back to the config sector.
Assert(sizeof(xnip.abSeed) == sizeof(xncp.abSeed));
memcpy(xncp.abSeed, xnip.abSeed, sizeof(xncp.abSeed));
XNetSaveConfigSector(hVolume, 0, (BYTE *)&xncp, sizeof(xncp));
}
XNetCloseConfigVolume(hVolume);
}
if (err == 0 && (pxnsp == NULL || (pxnsp->cfgFlags & XNET_STARTUP_MANUAL_CONFIG) == 0))
{
#if defined(XNET_FEATURE_XBDM_SERVER) && defined(DEVKIT)
xncp.ina.s_addr = (ULONG)DmTell(DMTELL_GETDBGIP, NULL);
#endif
err = pXn->XNetConfig(&xncp, XNET_CONFIG_NORMAL);
}
if (err != 0)
{
pXn->SockTerm();
pXn = NULL;
*ppXn = NULL;
goto err;
}
pXn->SockStart();
}
if (fWsa)
{
pXn->SockAddRef();
lpWSAData->wVersion = wVersionRequired;
lpWSAData->wHighVersion = 0x0202;
lpWSAData->lpVendorInfo = NULL;
lpWSAData->iMaxSockets = 0;
lpWSAData->iMaxUdpDg = 0;
lpWSAData->szDescription[0] = 0;
lpWSAData->szSystemStatus[0] = 0;
}
else
{
pXn->XNetAddRef();
}
err:
g_lXnLock = 0;
if (err != 0)
{
TraceSz2(Warning, "%s failed: %d", fWsa ? "WSAStartup" : "XNetStartup", err);
if (fWsa)
{
SetLastError(err);
err = SOCKET_ERROR;
}
}
return(err);
}
// ---------------------------------------------------------------------------------------
// XnTerm
// ---------------------------------------------------------------------------------------
INT _WSAAPI_ XnTerm(void ** ppXn, BOOL fWsa)
{
int err = 0;
while (InterlockedCompareExchange(&g_lXnLock, 1, 0))
{
Sleep(0);
}
CXn * pXn = (CXn *)*ppXn;
if ( pXn == NULL
|| ( fWsa && pXn->SockGetRefs() == 0)
|| (!fWsa && pXn->XNetGetRefs() == 0))
{
err = WSANOTINITIALISED;
}
else
{
if (fWsa)
{
if (pXn->SockRelease() == 0)
pXn->SockShutdown();
}
else
{
pXn->XNetRelease();
}
if (pXn->XNetGetRefs() + pXn->SockGetRefs() == 0)
{
pXn->SockTerm();
delete pXn;
*ppXn = NULL;
}
}
g_lXnLock = 0;
if (err != 0)
{
TraceSz2(Warning, "%s failed: %d", fWsa ? "WSACleanup" : "XNetCleanup", err);
if (fWsa)
{
SetLastError(err);
err = SOCKET_ERROR;
}
}
return(err);
}
// ---------------------------------------------------------------------------------------
// Key API's
// ---------------------------------------------------------------------------------------
INT CXn::XNetCreateKey(XNKID * pxnkid, XNKEY * pxnkey)
{
XNetEnter(XNetCreateKey, pxnkid != NULL && pxnkey != NULL);
INT err = IpCreateKey(pxnkid, pxnkey);
XNetLeave(err);
return(err);
}
INT CXn::XNetRegisterKey(const XNKID * pxnkid, const XNKEY * pxnkey)
{
XNetEnter(XNetRegisterKey, pxnkid != NULL && pxnkey != NULL);
INT err = IpRegisterKey(pxnkid, pxnkey);
XNetLeave(err);
return(err);
}
INT CXn::XNetUnregisterKey(const XNKID * pxnkid)
{
XNetEnter(XNetUnregisterKey, pxnkid != NULL);
INT err = IpUnregisterKey(pxnkid);
XNetLeave(err);
return(err);
}
INT CXn::XNetRandom(BYTE * pb, UINT cb)
{
XNetEnter(XNetRandom, pb != NULL || cb == 0);
Rand(pb, cb);
XNetLeave(0);
return(0);
}
// ---------------------------------------------------------------------------------------
// XnAddr API's
// ---------------------------------------------------------------------------------------
INT CXn::XNetXnAddrToInAddr(const XNADDR * pxna, const XNKID * pxnkid, IN_ADDR * pina)
{
XNetEnter(XNetXnAddrToInAddr, pxna != NULL && pxnkid != NULL && pina != NULL);
INT err = IpXnAddrToInAddr(pxna, pxnkid, (CIpAddr *)pina);
XNetLeave(err);
return(err);
}
INT CXn::XNetServerToInAddr(const IN_ADDR ina, DWORD dwServiceId, IN_ADDR * pina)
{
XNetEnter(XNetServerToInAddr, ina.s_addr != 0 && pina != NULL);
#ifdef XNET_FEATURE_SG
INT err = IpServerToInAddr(CIpAddr(ina.s_addr), dwServiceId, (CIpAddr *)pina);
#else
INT err = WSAEACCES;
#endif
XNetLeave(err);
return(err);
}
INT CXn::XNetInAddrToXnAddr(const IN_ADDR ina, XNADDR * pxna, XNKID * pxnkid)
{
XNetEnter(XNetInAddrToXnAddr, ina.s_addr != 0);
INT err = IpInAddrToXnAddr(CIpAddr(ina.s_addr), pxna, pxnkid);
XNetLeave(err);
return(err);
}
INT CXn::XNetInAddrToString(const IN_ADDR ina, char * pchBuf, INT cchBuf)
{
XNetParamCheck(XNetInAddrToString, pchBuf != NULL && cchBuf > 0, WSAEFAULT);
XnInAddrToString(ina, pchBuf, cchBuf);
return(0);
}
INT CXn::XNetUnregisterInAddr(const IN_ADDR ina)
{
XNetEnter(XNetUnregisterInAddr, ina.s_addr != 0);
INT err = IpUnregisterInAddr(CIpAddr(ina.s_addr));
XNetLeave(err);
return(err);
}
DWORD CXn::XNetGetTitleXnAddr(XNADDR * pxna)
{
XNetInitCheck(XNetGetTitleXnAddr, XNET_GET_XNADDR_NONE);
XNetParamCheck(XNetGetTitleXnAddr, pxna != NULL, XNET_GET_XNADDR_NONE);
#ifdef XNET_FEATURE_XBDM_SERVER
return(NicGetOtherXnAddr(pxna));
#else
return(IpGetXnAddr(pxna));
#endif
}
DWORD CXn::XNetGetDebugXnAddr(XNADDR * pxna)
{
XNetInitCheck(XNetGetDebugXnAddr, XNET_GET_XNADDR_NONE);
XNetParamCheck(XNetGetDebugXnAddr, pxna != NULL, XNET_GET_XNADDR_NONE);
#ifdef XNET_FEATURE_XBDM_CLIENT
return(NicGetOtherXnAddr(pxna));
#elif defined(XNET_FEATURE_XBDM_SERVER)
return(IpGetXnAddr(pxna));
#else
return(XNET_GET_XNADDR_NONE);
#endif
}
// ---------------------------------------------------------------------------------------
// Domain Name Service APIs
// ---------------------------------------------------------------------------------------
INT CXn::XNetDnsLookup(const char * pszHost, WSAEVENT hEvent, XNDNS ** ppxndns)
{
XNetEnter(XNetDnsLookup, pszHost != NULL && ppxndns != NULL);
#ifdef XNET_FEATURE_DNS
INT err = IpDnsLookup(pszHost, hEvent, ppxndns);
#else
INT err = WSAEACCES;
#endif
XNetLeave(err);
return(err);
}
INT CXn::XNetDnsRelease(XNDNS * pxndns)
{
XNetEnter(XNetDnsRelease, pxndns != NULL);
#ifdef XNET_FEATURE_DNS
INT err = IpDnsRelease(pxndns);
#else
INT err = WSAEACCES;
#endif
XNetLeave(err);
return(err);
}
// ---------------------------------------------------------------------------------------
// Quality of Service APIs
// ---------------------------------------------------------------------------------------
INT CXn::XNetQosListen(const XNKID * pxnkid, const BYTE * pb, UINT cb, DWORD dwBitsPerSec, DWORD dwFlags)
{
XNetEnter(XNetQosListen, pxnkid != NULL && (!!pb == !!cb) && (dwFlags & ~(XNET_QOS_LISTEN_ENABLE|XNET_QOS_LISTEN_DISABLE|XNET_QOS_LISTEN_SET_DATA|XNET_QOS_LISTEN_SET_BITSPERSEC)) == 0);
#ifdef XNET_FEATURE_QOS
INT err = IpQosListen(pxnkid, pb, cb, dwBitsPerSec, dwFlags);
#else
INT err = WSAEACCES;
#endif
XNetLeave(err);
return(err);
}
INT CXn::XNetQosXnAddr(UINT cxnqos, const XNADDR * apxna[], const XNKID * apxnkid[], const XNKEY * apxnkey[], DWORD dwFlags, WSAEVENT hEvent, XNQOS ** ppxnqos)
{
XNetEnter(XNetQosXnAddr, cxnqos > 0 && apxna != NULL && apxnkid != NULL && apxnkey != NULL && dwFlags == 0 && ppxnqos != NULL);
#ifdef XNET_FEATURE_QOS
INT err = IpQosXnAddr(cxnqos, apxna, apxnkid, apxnkey, dwFlags, hEvent, ppxnqos);
#else
INT err = WSAEACCES;
#endif
XNetLeave(err);
return(err);
}
INT CXn::XNetQosServer(UINT cxnqos, const IN_ADDR aina[], const DWORD adwServiceId[], DWORD dwFlags, WSAEVENT hEvent, XNQOS ** ppxnqos)
{
XNetEnter(XNetQosServer, cxnqos > 0 && aina != NULL && adwServiceId != NULL && dwFlags == 0 && ppxnqos != NULL);
#if defined(XNET_FEATURE_QOS) && defined(XNET_FEATURE_SG)
INT err = IpQosServer(cxnqos, aina, adwServiceId, dwFlags, hEvent, ppxnqos);
#else
INT err = WSAEACCES;
#endif
XNetLeave(err);
return(err);
}
INT CXn::XNetQosRelease(XNQOS * pxnqos)
{
XNetEnter(XNetQosRelease, pxnqos != NULL);
#ifdef XNET_FEATURE_QOS
INT err = IpQosRelease(pxnqos);
#else
INT err = WSAEACCES;
#endif
XNetLeave(err);
return(err);
}
// ---------------------------------------------------------------------------------------
// Config
// ---------------------------------------------------------------------------------------
INT CXn::XNetConfig(const XNetConfigParams * pxncp, DWORD dwFlags)
{
XNetEnter(XNetConfig, pxncp != NULL);
INT err = IpConfig(pxncp, dwFlags);
XNetLeave(err);
return(err);
}
INT CXn::XNetGetConfigStatus(XNetConfigStatus * pxncs)
{
XNetEnter(XNetGetConfigStatus, pxncs != NULL);
INT err = IpGetConfigStatus(pxncs);
XNetLeave(err);
return(err);
}
// ---------------------------------------------------------------------------------------
// Main entrypoints for XNet/Winsock APIs
// ---------------------------------------------------------------------------------------
#ifdef XNET_FEATURE_XBOX
CXn * g_pXn = NULL;
#endif
#undef XNETAPI
#define XNETAPI(ret, fname, arglist, paramlist) ret _WSAAPI_ fname arglist { return(GetXn()->fname paramlist); }
#undef XNETAPI_
#define XNETAPI_(ret, fname, arglist, paramlist)
#undef XNETAPIV
#define XNETAPIV(ret, fname, arglist, paramlist)
XNETAPILIST()
SOCKAPILIST()
INT _WSAAPI_ XNetStartup(const XNetStartupParams * pxnsp)
{
XNetParamCheck(XNetStartup, pxnsp == NULL || pxnsp->cfgSizeOfStruct == sizeof(XNetStartupParams), WSAEFAULT);
return(XnInit((void **)GetXnRef(), GetAchXbox(), pxnsp, FALSE, 0, NULL));
}
int _WSAAPI_ WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData)
{
WinsockApiPrologTrivial_(WSAStartup);
WinsockApiParamCheck_(lpWSAData != NULL);
return(XnInit((void **)GetXnRef(), GetAchXbox(), NULL, TRUE, wVersionRequired, lpWSAData));
}
INT _WSAAPI_ XNetCleanup()
{
return(XnTerm((void **)GetXnRef(), FALSE));
}
int _WSAAPI_ WSACleanup()
{
return(XnTerm((void **)GetXnRef(), TRUE));
}
// ---------------------------------------------------------------------------------------
// XNetGetEthernetLinkStatus
//
// This function is placed in the default .text code section so that is can be called
// before the XNET code section is loaded.
// ---------------------------------------------------------------------------------------
#ifdef XNET_FEATURE_XBOX
#pragma code_seg(".text")
#endif
DWORD _WSAAPI_ XNetGetEthernetLinkStatus()
{
#ifdef XNET_FEATURE_XBOX
while (InterlockedCompareExchange(&g_lXnLock, 1, 0))
{
Sleep(0);
}
if (g_pXn == NULL)
{
PhyInitialize(FALSE, NULL);
}
g_lXnLock = 0;
return(PhyGetLinkState(FALSE));
#else
return(XNET_ETHERNET_LINK_ACTIVE|XNET_ETHERNET_LINK_100MBPS|XNET_ETHERNET_LINK_FULL_DUPLEX);
#endif
}