/*++ 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); }