Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1041 lines
25 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
nspatalk.c
Abstract:
Contains support for the winsock 1.x Name Space Provider for Appletalk.
Author:
Sue Adams (suea) 10-Mar-1995
Revision History:
--*/
#include "nspatalk.h"
#define ADSP_BIT 0x0001 // Bitmask used internally to store the
#define PAP_BIT 0x0002 // protocols requested by the caller
INT
APIENTRY
NPLoadNameSpaces(
IN OUT LPDWORD lpdwVersion,
IN OUT LPNS_ROUTINE nsrBuffer,
IN OUT LPDWORD lpdwBufferLength
)
/*++
Routine Description:
This routine returns name space info and functions supported in this
dll.
Arguments:
lpdwVersion - dll version
nsrBuffer - on return, this will be filled with an array of
NS_ROUTINE structures
lpdwBufferLength - on input, the number of bytes contained in the buffer
pointed to by nsrBuffer. On output, the minimum number of bytes
to pass for the nsrBuffer to retrieve all the requested info
Return Value:
The number of NS_ROUTINE structures returned, or SOCKET_ERROR (-1) if
the nsrBuffer is too small. Use GetLastError() to retrieve the
error code.
--*/
{
DWORD err;
DWORD dwLengthNeeded;
*lpdwVersion = DLL_VERSION;
//
// Check to see if the buffer is large enough
//
dwLengthNeeded = sizeof(NS_ROUTINE) + 4 * sizeof(LPFN_NSPAPI);
if ( ( *lpdwBufferLength < dwLengthNeeded )
|| ( nsrBuffer == NULL )
)
{
*lpdwBufferLength = dwLengthNeeded;
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return (DWORD) SOCKET_ERROR;
}
//
// We only support 1 name space, so fill in the NS_ROUTINE.
//
nsrBuffer->dwFunctionCount = 3;
nsrBuffer->alpfnFunctions = (LPFN_NSPAPI *)
((BYTE *) nsrBuffer + sizeof(NS_ROUTINE));
(nsrBuffer->alpfnFunctions)[NSPAPI_GET_ADDRESS_BY_NAME] =
(LPFN_NSPAPI) NbpGetAddressByName;
(nsrBuffer->alpfnFunctions)[NSPAPI_GET_SERVICE] = NULL;
(nsrBuffer->alpfnFunctions)[NSPAPI_SET_SERVICE] =
(LPFN_NSPAPI) NbpSetService;
(nsrBuffer->alpfnFunctions)[3] = NULL;
nsrBuffer->dwNameSpace = NS_NBP;
nsrBuffer->dwPriority = NS_STANDARD_PRIORITY;
return 1; // number of namespaces
}
INT
NbpGetAddressByName(
IN LPGUID lpServiceType,
IN LPWSTR lpServiceName,
IN LPDWORD lpdwProtocols,
IN DWORD dwResolution,
IN OUT LPVOID lpCsAddrBuffer,
IN OUT LPDWORD lpdwBufferLength,
IN OUT LPWSTR lpAliasBuffer,
IN OUT LPDWORD lpdwAliasBufferLength,
IN HANDLE hCancellationEvent
)
/*++
Routine Description:
This routine returns address information about a specific service.
Arguments:
lpServiceType - pointer to the GUID for the service type
lpServiceName - unique string representing the service name.
lpdwProtocols - a zero terminated array of protocol ids. This parameter
is optional; if lpdwProtocols is NULL, information on all available
Protocols is returned
dwResolution - can be one of the following values:RES_SERVICE
lpCsAddrBuffer - on return, will be filled with CSADDR_INFO structures
lpdwBufferLength - on input, the number of bytes contained in the buffer
pointed to by lpCsAddrBuffer. On output, the minimum number of bytes
to pass for the lpCsAddrBuffer to retrieve all the requested info
lpAliasBuffer - not used
lpdwAliasBufferLength - not used
hCancellationEvent - the event which signals us to cancel the request
Return Value:
The number of CSADDR_INFO structures returned, or SOCKET_ERROR (-1) if
the lpCsAddrBuffer is too small. Use GetLastError() to retrieve the
error code.
--*/
{
DWORD err;
WSH_NBP_NAME NbpLookupName;
DWORD cAddress = 0; // Count of the number of address returned
// in lpCsAddrBuffer
DWORD cProtocols = 0; // Count of the number of protocols contained
// in lpdwProtocols + 1 ( for zero terminate )
DWORD nProt = ADSP_BIT | PAP_BIT;
if ( ARGUMENT_PRESENT( lpdwAliasBufferLength )
&& ARGUMENT_PRESENT( lpAliasBuffer )
)
{
if ( *lpdwAliasBufferLength >= sizeof(WCHAR) )
*lpAliasBuffer = 0;
}
//DebugBreak();
//
// Check for invalid parameters
//
if ( ( lpServiceType == NULL )
|| ( (lpServiceName == NULL) && (dwResolution != RES_SERVICE) )
|| ( lpdwBufferLength == NULL )
)
{
SetLastError( ERROR_INVALID_PARAMETER );
return SOCKET_ERROR;
}
// The size of the user's buffer will dictate also how many
// tuples can be returned from the NBP lookup in case they
// are querying using wildcards.
if ( *lpdwBufferLength < (sizeof(WSH_LOOKUP_NAME) + sizeof(WSH_NBP_TUPLE)) )
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return SOCKET_ERROR;
}
//
// If an array of protocol ids is passed in, check to see if
// the ADSP or PAP protocol is requested. If not, return 0 since
// we only support these 2.
//
if ( lpdwProtocols != NULL )
{
INT i = -1;
nProt = 0;
while ( lpdwProtocols[++i] != 0 )
{
if ( lpdwProtocols[i] == ATPROTO_ADSP )
nProt |= ADSP_BIT;
if ( lpdwProtocols[i] == ATPROTO_PAP )
nProt |= PAP_BIT;
}
if ( nProt == 0 )
return 0; // No address found
}
//
// If this is a service asking what local address to use when
// bind()-ing its appletalk socket, return the generic Appletalk
// socket address.
//
if ((dwResolution & RES_SERVICE) != 0)
{
err = FillBufferWithCsAddr( NULL,
nProt,
lpCsAddrBuffer,
lpdwBufferLength,
&cAddress );
if ( err )
{
SetLastError( err );
return SOCKET_ERROR;
}
return cAddress;
}
//
// This is a client trying to do an NBP lookup on an Appletalk
// named entity to find out what remote address to connect() to.
//
err = GetNameInNbpFormat(lpServiceType,
lpServiceName,
&NbpLookupName);
if (err)
{
KdPrint(("GetNameInNbpFormat failed with error %d for name %ws\n", err, lpServiceName ));
SetLastError(err);
return SOCKET_ERROR;
}
err = NbpLookupAddress( &NbpLookupName,
nProt,
lpCsAddrBuffer,
lpdwBufferLength,
&cAddress );
#if DBG
if ( err == NO_ERROR )
{
KdPrint(("NbpGetAddrByName:Successfully got %d address for %ws from NBP.\n",
cAddress, lpServiceName ));
}
else
{
KdPrint(("NbpGetAddrByName:Failed with err %d when getting address for %ws from NBP.\n", err, lpServiceName ));
}
#endif
if ( err )
{
SetLastError( err );
return SOCKET_ERROR;
}
return cAddress;
}
NTSTATUS
GetNameInNbpFormat(
IN LPGUID pServiceType,
IN LPWSTR pServiceName,
IN OUT PWSH_NBP_NAME pNbpName
)
/*++
Routine description:
Convert pServiceType and pServiceName to system ANSI strings in
the pLookupName structure so they can be used to do NBP lookup.
Arguments:
Return value:
--*/
{
INT err;
WCHAR wtypeBuf[MAX_ENTITY + 1];
CHAR entityBuf[(MAX_ENTITY + 1) * 2]; // potentially all multibyte
PWCHAR pColon, pAtSign, pType = wtypeBuf, pObject = pServiceName, pZone = L"*";
// Parse the service name for "object:type@zone" form. If we find a
// ':' there must also be a '@' (and vice-versa).
// If there is a type in the servicename string, we will still convert
// the LPGUID to a string. If the types don't match return an error.
// So, we will accept the following forms for the service name:
// object OR object:type@zone. If just object is given, then the zone
// used will be the default zone "*". Wildcards are acceptible for
// NBP Lookup, but not for NBP (De)Register. No checking is done for that.
//
pColon = wcschr(pServiceName, L':');
pAtSign = wcschr(pServiceName, L'@');
if ( ((pColon != NULL) && (pAtSign == NULL)) ||
((pAtSign != NULL) && (pColon == NULL)) ||
(pColon > pAtSign) )
{
return(ERROR_INVALID_PARAMETER);
}
//
// By default we only use our own local zone
//
if (pAtSign != NULL)
{
pZone = pAtSign + 1;
if ((wcslen(pZone) == 0) ||
(wcslen(pZone) > MAX_ENTITY))
{
return ERROR_INVALID_PARAMETER;
}
}
if (WideCharToMultiByte(CP_ACP,
0,
pZone,
-1, // says that wchar string is null terminated
entityBuf,
sizeof(entityBuf),
NULL,
NULL) == 0)
{
DBGPRINT(("GetNameInNbpFormat FAILED wctomb %ws\n", pZone));
return GetLastError();
}
pNbpName->ZoneNameLen = strlen( entityBuf );
memcpy( pNbpName->ZoneName,
entityBuf,
pNbpName->ZoneNameLen );
if (pAtSign != NULL)
{
// change the @ to a null so the type will be null terminated
*pAtSign = 0;
}
//
// Convert the Type string
//
err = GetNameByType(pServiceType, wtypeBuf, sizeof(wtypeBuf));
if (err != NO_ERROR)
{
// Appletalk type can be 32 chars max, so if this
// fails with buffer too small error it couldn't be
// used on appletalk anyway
return err;
}
// If there was a type name in the ServiceName, then it better match
// what the LPGUID resolved to.
if (pColon != NULL)
{
pType = pColon + 1;
if ((wcslen(pType) == 0) ||
// (wcscmp(pType, wtypeBuf) != 0) ||
(wcslen(pType) > MAX_ENTITY))
{
return ERROR_INVALID_PARAMETER;
}
}
if (WideCharToMultiByte(CP_ACP,
0,
pType,
-1, // says that wchar string is null terminated
entityBuf,
sizeof(entityBuf),
NULL,
NULL) == 0)
{
DBGPRINT(("GetNameInNbpFormat FAILED wctomb %ws\n", pType));
return GetLastError();
}
pNbpName->TypeNameLen = strlen( entityBuf );
memcpy( pNbpName->TypeName,
entityBuf,
pNbpName->TypeNameLen );
if (pColon != NULL)
{
// change the colon to a null so the object will be null terminated
*pColon = 0;
}
//
// Convert the Object string
//
if ((wcslen(pObject) == 0) ||
(wcslen(pObject) > MAX_ENTITY))
{
return ERROR_INVALID_PARAMETER;
}
if (WideCharToMultiByte(CP_ACP,
0,
pServiceName,
-1, // says that wchar string is null terminated
entityBuf,
sizeof(entityBuf),
NULL,
NULL) == 0)
{
DBGPRINT(("GetNameInNbpFormat FAILED wctomb %ws\n", pServiceName));
return GetLastError();
}
pNbpName->ObjectNameLen = strlen( entityBuf );
memcpy( pNbpName->ObjectName,
entityBuf,
pNbpName->ObjectNameLen );
return STATUS_SUCCESS;
} // GetNameInNbpFormat
NTSTATUS
NbpLookupAddress(
IN PWSH_NBP_NAME pNbpLookupName,
IN DWORD nProt,
IN OUT LPVOID lpCsAddrBuffer,
IN OUT LPDWORD lpdwBufferLength,
OUT LPDWORD lpcAddress
)
/*++
Routine Description:
This routine uses NBP requests to find the address of the given service
name/type.
Arguments:
pNbpLookupName - NBP name to lookup
nProt - ADSP_BIT | PAP_BIT
lpCsAddrBuffer - on return, will be filled with CSADDR_INFO structures
lpdwBufferLength - on input, the number of bytes contained in the buffer
pointed to by lpCsAddrBuffer. On output, the minimum number of bytes
to pass for the lpCsAddrBuffer to retrieve all the requested info
hCancellationEvent - the event which signals us to cancel the request???
lpcAddress - on output, the number of CSADDR_INFO structures returned
Return Value:
Win32 error code.
--*/
{
DWORD err = NO_ERROR;
NTSTATUS ntstatus;
WSADATA wsaData;
SOCKET socketNbp;
SOCKADDR_AT socketAddr = {AF_APPLETALK, 0, 0, 0};
PWSH_LOOKUP_NAME pWshLookupName;
PWSH_ATALK_ADDRESS pWshATAddr;
PBYTE pTmp = lpCsAddrBuffer;
DWORD templen = *lpdwBufferLength;
DWORD bufsize;
PBYTE buf = NULL;
int i;
*lpcAddress = 0;
//
// Initialize the socket interface
//
err = WSAStartup( WSOCK_VER_REQD, &wsaData );
if ( err )
{
return err;
}
//
// Open an Appletalk datagram socket
// ISSUE: should we use DDPPROTO_NBP, or just a random
// dynamic DDP socket? Or an ADSP socket since we know
// that works and has been tested...Does it really matter
// since this only defines what devicename will be opened
// in the appletalk driver i.e. \\device\\atalkddp\2 .
//
socketNbp = socket( AF_APPLETALK, SOCK_DGRAM, DDPPROTO_NBP);
if ( socketNbp == INVALID_SOCKET )
{
err = WSAGetLastError();
(VOID) WSACleanup();
return err;
}
do
{
//
// Bind the socket (this does not actually go thru
// the WSHAtalk helper dll, it goes thru AFD which
// Ioctls appletalk directly. The node and net values
// are ignored, and socket 0 means give me a dynamic
// socket number)
//
if ( bind( socketNbp,
(PSOCKADDR) &socketAddr,
sizeof( SOCKADDR_AT)) == SOCKET_ERROR )
{
err = WSAGetLastError();
break;
}
//
// Determine how many CSADDR_INFO structures could fit
// into this buffer, then allocate a buffer to use for
// the NBP lookup that can hold this many returned tuples
//
bufsize = sizeof(WSH_LOOKUP_NAME) +
( (*lpdwBufferLength / (sizeof(CSADDR_INFO) + (2*sizeof(SOCKADDR_AT)))) *
sizeof(WSH_NBP_TUPLE) );
if ((buf = LocalAlloc(LMEM_ZEROINIT, bufsize)) == NULL)
{
err = GetLastError();
break;
}
// copy the NBP name to look for into the buffer
pWshLookupName = (PWSH_LOOKUP_NAME)buf;
pWshLookupName->LookupTuple.NbpName = *pNbpLookupName;
//
// Send the Nbp lookup request
//
if (getsockopt( socketNbp,
SOL_APPLETALK,
SO_LOOKUP_NAME,
buf,
&bufsize) != NO_ERROR)
{
err = WSAGetLastError();
if (err == WSAENOBUFS)
{
// this assumes that getsockopt will NOT
// put the required number of bytes into the
// bufsize parameter on error
*lpdwBufferLength = 2 * *lpdwBufferLength;
}
break;
}
if (pWshLookupName->NoTuples == 0)
{
// didn't find anything matching this NBP entity name
*lpdwBufferLength = 0;
break;
}
// point to the returned tuples
pWshATAddr = (PWSH_ATALK_ADDRESS)(pWshLookupName + 1);
for ( i = 0; i < (INT)pWshLookupName->NoTuples; i++ )
{
DWORD cAddr, bytesWritten;
socketAddr.sat_net = pWshATAddr->Network;
socketAddr.sat_node = pWshATAddr->Node;
socketAddr.sat_socket = pWshATAddr->Socket;
err = FillBufferWithCsAddr( &socketAddr,
nProt,
// USE LOCALS TO KEEP TRACK OF BUF POSITION AND COUNT LEFT
pTmp,
&templen,
&cAddr);
if (err != NO_ERROR)
{
// Fill in how many bytes the buffer should have been to
// hold all the returned addresses
*lpdwBufferLength = templen * pWshLookupName->NoTuples;
break; // from for and then from while
}
else
{
pTmp += sizeof(CSADDR_INFO) * cAddr;
templen -= (sizeof(CSADDR_INFO) + (2 * sizeof(SOCKADDR_AT))) * cAddr;
*lpcAddress += cAddr; // running count of CSADDR_INFOs in buffer
(PWSH_NBP_TUPLE)pWshATAddr ++; // get next NBP tuple
}
}
} while (FALSE);
//
// Clean up the socket interface
//
if (buf != NULL)
{
LocalFree(buf);
}
closesocket( socketNbp );
(VOID) WSACleanup();
return err;
}
DWORD
FillBufferWithCsAddr(
IN PSOCKADDR_AT pAddress, // if NULL, then return generic appletalk socket address for RemoteAddr
IN DWORD nProt,
IN OUT LPVOID lpCsAddrBuffer,
IN OUT LPDWORD lpdwBufferLength,
OUT LPDWORD pcAddress
)
{
DWORD nAddrCount = 0;
CSADDR_INFO *pCsAddr;
SOCKADDR_AT *pAddrLocal, *pAddrRemote;
DWORD i;
LPBYTE pBuffer;
if ( nProt & ADSP_BIT )
nAddrCount ++;
if ( nProt & PAP_BIT )
nAddrCount++;
if ( *lpdwBufferLength <
nAddrCount * ( sizeof( CSADDR_INFO) + 2*sizeof( SOCKADDR_AT)))
{
*lpdwBufferLength = nAddrCount *
( sizeof( CSADDR_INFO) + 2*sizeof( SOCKADDR_AT));
return ERROR_INSUFFICIENT_BUFFER;
}
pBuffer = ((LPBYTE) lpCsAddrBuffer) + *lpdwBufferLength -
(2*sizeof( SOCKADDR_AT) * nAddrCount);
for ( i = 0, pCsAddr = (CSADDR_INFO *)lpCsAddrBuffer;
(i < nAddrCount) && ( nProt != 0 );
i++, pCsAddr++ )
{
if ( nProt & ADSP_BIT )
{
pCsAddr->iSocketType = SOCK_RDM;
pCsAddr->iProtocol = ATPROTO_ADSP;
nProt &= ~ADSP_BIT;
}
else if ( nProt & PAP_BIT )
{
pCsAddr->iSocketType = SOCK_RDM;
pCsAddr->iProtocol = ATPROTO_PAP;
nProt &= ~PAP_BIT;
}
else
{
break;
}
pCsAddr->LocalAddr.iSockaddrLength = sizeof( SOCKADDR_AT );
pCsAddr->RemoteAddr.iSockaddrLength = sizeof( SOCKADDR_AT );
pCsAddr->LocalAddr.lpSockaddr = (LPSOCKADDR) pBuffer;
pCsAddr->RemoteAddr.lpSockaddr =
(LPSOCKADDR) ( pBuffer + sizeof(SOCKADDR_AT));
pBuffer += 2 * sizeof( SOCKADDR_AT );
pAddrLocal = (SOCKADDR_AT *) pCsAddr->LocalAddr.lpSockaddr;
pAddrRemote = (SOCKADDR_AT *) pCsAddr->RemoteAddr.lpSockaddr;
pAddrLocal->sat_family = AF_APPLETALK;
pAddrRemote->sat_family = AF_APPLETALK;
//
// The default local sockaddr for ADSP and PAP is
// sa_family = AF_APPLETALK and all other bytes = 0.
//
pAddrLocal->sat_net = 0;
pAddrLocal->sat_node = 0;
pAddrLocal->sat_socket = 0;
//
// If pAddress is NULL, i.e. we are doing RES_SERVICE,
// just make all bytes in remote address zero.
//
if ( pAddress == NULL )
{
pAddrRemote->sat_net = 0;
pAddrRemote->sat_node = 0;
pAddrRemote->sat_socket = 0;
}
else
{
pAddrRemote->sat_net = pAddress->sat_net;
pAddrRemote->sat_node = pAddress->sat_node;
pAddrRemote->sat_socket = pAddress->sat_socket;
}
}
*pcAddress = nAddrCount;
return NO_ERROR;
} // FillBufferWithCSAddr
NTSTATUS
NbpSetService (
IN DWORD dwOperation,
IN DWORD dwFlags,
IN BOOL fUnicodeBlob,
IN LPSERVICE_INFO lpServiceInfo
)
/*++
Routine Description:
This routine registers or deregisters the given service type/name on NBP.
Arguments:
dwOperation - Either SERVICE_REGISTER or SERVICE_DEREGISTER
dwFlags - ignored
fUnicodeBlob - ignored
lpServiceInfo - Pointer to a SERVICE_INFO structure containing all info
about the service.
Return Value:
Win32 error code.
--*/
{
NTSTATUS err = STATUS_SUCCESS;
SOCKADDR_AT sockAddr;
WSH_NBP_NAME nbpName;
DWORD i;
INT nNBP = -1;
UNREFERENCED_PARAMETER( dwFlags );
UNREFERENCED_PARAMETER( fUnicodeBlob );
DBGPRINT(("NbpSetService entered...\n"));
//
// Check for invalid parameters
//
if ( ( lpServiceInfo == NULL )
|| ( lpServiceInfo->lpServiceType == NULL )
|| ( lpServiceInfo->lpServiceName == NULL ) )
{
return ERROR_INVALID_PARAMETER;
}
if ( lpServiceInfo->lpServiceAddress == NULL )
return ERROR_INCORRECT_ADDRESS;
switch (dwOperation)
{
case SERVICE_REGISTER:
case SERVICE_DEREGISTER:
{
//
// Check to see if the service address array contains NBP address,
// we will only use the first NBP address contained in the array.
//
for ( i = 0; i < lpServiceInfo->lpServiceAddress->dwAddressCount; i++)
{
if ( lpServiceInfo->lpServiceAddress->Addresses[i].dwAddressType == AF_APPLETALK )
{
sockAddr = *(PSOCKADDR_AT)(lpServiceInfo->lpServiceAddress->Addresses[i].lpAddress);
nNBP = (INT) i;
break;
}
}
//
// If we cannot find a atalk address in the user's array, return error
//
if ( nNBP == -1 )
{
DBGPRINT(("NbpSetService: no Appletalk addresses in lpServiceInfo!\n"));
return ERROR_INCORRECT_ADDRESS;
}
//
// Convert the service type and name into NBP form
//
err = GetNameInNbpFormat(lpServiceInfo->lpServiceType,
lpServiceInfo->lpServiceName,
&nbpName);
if (err != NO_ERROR)
{
break;
}
err = NbpRegDeregService(dwOperation, &nbpName, &sockAddr);
break;
}
case SERVICE_FLUSH:
case SERVICE_ADD_TYPE:
case SERVICE_DELETE_TYPE:
//
// This is a no-op in our provider, so just return success
//
return NO_ERROR;
default:
//
// We can probably say all other operations which we have no
// knowledge of are ignored by us. So, just return success.
//
return NO_ERROR;
}
return err;
}
DWORD
NbpRegDeregService(
IN DWORD dwOperation,
IN PWSH_NBP_NAME pNbpName,
IN PSOCKADDR_AT pSockAddr
)
/*++
Routine Description:
This routine registers or deregisters the given service on NBP.
Arguments:
dwOperation - either SERVICE_REGISTER or SERVICE_DEREGISTER
pNbpName - points to NBP name to register (zone should be "*")
pSockAddr - socket address on which to register name
Return Value:
Win32 error.
--*/
{
int status;
BYTE EaBuffer[sizeof(FILE_FULL_EA_INFORMATION) +
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
sizeof(TA_APPLETALK_ADDRESS)];
PFILE_FULL_EA_INFORMATION pEaBuf = (PFILE_FULL_EA_INFORMATION)EaBuffer;
TA_APPLETALK_ADDRESS Ta;
OBJECT_ATTRIBUTES ObjAttr;
UNICODE_STRING DeviceName;
IO_STATUS_BLOCK IoStsBlk;
NBP_TUPLE nbpTuple;
SOCKET bogusSocket = 0;
HANDLE AtalkAddressHandle = NULL, eventHandle = NULL;
PTDI_ACTION_HEADER tdiAction;
ULONG tdiActionLength;
BOOLEAN freeTdiAction = FALSE, closeEventHandle = FALSE;
PNBP_REGDEREG_ACTION nbpAction;
PVOID completionApc = NULL;
PVOID apcContext = NULL;
DBGPRINT(("NbpRegDeregService entered...\n"));
DebugBreak();
// Dosn't matter what protocol or socket we open, we just want a
// device handle into the stack.
RtlInitUnicodeString(&DeviceName, WSH_ATALK_ADSPRDM);
InitializeObjectAttributes(&ObjAttr, &DeviceName, 0, NULL, NULL);
// Initialize the EA Buffer
pEaBuf->NextEntryOffset = 0;
pEaBuf->Flags = 0;
pEaBuf->EaValueLength = sizeof(TA_APPLETALK_ADDRESS);
pEaBuf->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
RtlCopyMemory(pEaBuf->EaName,TdiTransportAddress,
TDI_TRANSPORT_ADDRESS_LENGTH + 1);
Ta.TAAddressCount = 1;
Ta.Address[0].AddressType = TDI_ADDRESS_TYPE_APPLETALK;
Ta.Address[0].AddressLength = sizeof(TDI_ADDRESS_APPLETALK);
// Open dynamic socket - note we will be using up one extra socket for the
// duration we have the device handle open in this routine.
Ta.Address[0].Address[0].Socket = 0;
Ta.Address[0].Address[0].Network = 0;
Ta.Address[0].Address[0].Node = 0;
RtlCopyMemory(&pEaBuf->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1], &Ta, sizeof(Ta));
// Open a handle to appletalk stack DDP device
status = NtCreateFile(
&AtalkAddressHandle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjAttr,
&IoStsBlk,
NULL, // Don't Care
0, // Don't Care
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE,
0,
&EaBuffer,
sizeof(EaBuffer));
if (!NT_SUCCESS(status))
{
DBGPRINT(("NbpRegDeregService: NtCreateFile failed (0x%x)\n", status));
return WSHNtStatusToWinsockErr(status);
}
do
{
status = NtCreateEvent(
&eventHandle,
EVENT_ALL_ACCESS,
NULL,
SynchronizationEvent,
FALSE
);
if ( !NT_SUCCESS(status) )
{
DBGPRINT(("NbpRegDeregService: Create event failed (%d)\n", status));
break;
}
else
closeEventHandle = TRUE;
tdiActionLength = sizeof(NBP_REGDEREG_ACTION);
tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
if ( tdiAction == NULL )
{
status = STATUS_NO_MEMORY;
DBGPRINT(("NbpRegDeregService: Could not allocate tdiAction\n"));
break;
}
else
freeTdiAction = TRUE;
tdiAction->TransportId = MATK;
tdiAction->ActionCode = (dwOperation == SERVICE_REGISTER) ?
COMMON_ACTION_NBPREGISTER_BY_ADDR :
COMMON_ACTION_NBPREMOVE_BY_ADDR;
nbpAction = (PNBP_REGDEREG_ACTION)tdiAction;
//
// Copy the nbp tuple info to the proper place
//
nbpAction->Params.RegisterTuple.Address.Network = pSockAddr->sat_net;
nbpAction->Params.RegisterTuple.Address.Node = pSockAddr->sat_node;
nbpAction->Params.RegisterTuple.Address.Socket = pSockAddr->sat_socket;
nbpAction->Params.RegisterTuple.Enumerator = 0;
nbpAction->Params.RegisterTuple.NbpName = *((PNBP_NAME)pNbpName);
//
// Convert the tuple to MAC code page
//
if (!WshNbpNameToMacCodePage(
(PWSH_NBP_NAME)&nbpAction->Params.RegisterTuple.NbpName))
{
status = STATUS_INVALID_PARAMETER;
break;
}
status = NtDeviceIoControlFile(
AtalkAddressHandle,
eventHandle,
completionApc,
apcContext,
&IoStsBlk,
IOCTL_TDI_ACTION,
NULL, // Input buffer
0, // Length of input buffer
tdiAction,
tdiActionLength
);
if ( status == STATUS_PENDING )
{
status = NtWaitForSingleObject( eventHandle, FALSE, NULL );
ASSERT( NT_SUCCESS(status) );
status = IoStsBlk.Status;
}
if (status != NO_ERROR)
{
DBGPRINT(("NbpRegDeregService: DevIoctl SO_(DE)REGISTER_NAME failed (0x%x)\n", status));
}
} while (0);
if (closeEventHandle)
NtClose(eventHandle);
if (freeTdiAction)
RtlFreeHeap( RtlProcessHeap( ), 0, tdiAction );
NtClose(AtalkAddressHandle);
return WSHNtStatusToWinsockErr(status);
}