From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/tdi/isn/spx/spxbind.c | 602 +++++++++++++++++++++++++++++++++++++ 1 file changed, 602 insertions(+) create mode 100644 private/ntos/tdi/isn/spx/spxbind.c (limited to 'private/ntos/tdi/isn/spx/spxbind.c') diff --git a/private/ntos/tdi/isn/spx/spxbind.c b/private/ntos/tdi/isn/spx/spxbind.c new file mode 100644 index 000000000..ba46eb7a9 --- /dev/null +++ b/private/ntos/tdi/isn/spx/spxbind.c @@ -0,0 +1,602 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + spxbind.c + +Abstract: + + This module contains the code to bind to the IPX transport, as well as the + indication routines for the IPX transport not including the send/recv ones. + +Author: + + Stefan Solomon (stefans) Original Version + Nikhil Kamkolkar (nikhilk) 11-November-1993 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "precomp.h" +#pragma hdrstop + +// Define module number for event logging entries +#define FILENUM SPXBIND + +VOID +SpxStatus ( + IN USHORT NicId, + IN NDIS_STATUS GeneralStatus, + IN PVOID StatusBuffer, + IN UINT StatusBufferLength); + +VOID +SpxFindRouteComplete ( + IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest, + IN BOOLEAN FoundRoute); + +VOID +SpxScheduleRoute ( + IN PIPX_ROUTE_ENTRY RouteEntry); + +VOID +SpxLineDown ( + IN USHORT NicId, + IN ULONG FwdAdapterContext); + +VOID +SpxLineUp ( + IN USHORT NicId, + IN PIPX_LINE_INFO LineInfo, + IN NDIS_MEDIUM DeviceType, + IN PVOID ConfigurationData); + +VOID +SpxFindRouteComplete ( + IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest, + IN BOOLEAN FoundRoute); + +#if defined(_PNP_POWER) +VOID +SpxPnPNotification( + IN IPX_PNP_OPCODE OpCode, + IN PVOID PnPData + ); +#endif _PNP_POWER + +#if defined(_PNP_POWER) +// +// globals and externs +// +extern CTELock spxTimerLock; +extern LARGE_INTEGER spxTimerTick; +extern KTIMER spxTimer; +extern KDPC spxTimerDpc; +extern BOOLEAN spxTimerStopped; +#endif _PNP_POWER + +NTSTATUS +SpxInitBindToIpx( + VOID + ) + +{ + NTSTATUS status; + IO_STATUS_BLOCK ioStatusBlock; + OBJECT_ATTRIBUTES objectAttr; + PIPX_INTERNAL_BIND_INPUT pBindInput; + PIPX_INTERNAL_BIND_OUTPUT pBindOutput; + + InitializeObjectAttributes( + &objectAttr, + &IpxDeviceName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + status = NtCreateFile( + &IpxHandle, + SYNCHRONIZE | GENERIC_READ, + &objectAttr, + &ioStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0L); + + if (!NT_SUCCESS(status)) { + return status; + } + + if ((pBindInput = CTEAllocMem(sizeof(IPX_INTERNAL_BIND_INPUT))) == NULL) { + NtClose(IpxHandle); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + // Fill in our bind data +#if defined(_PNP_POWER) + pBindInput->Version = ISN_VERSION; +#else + pBindInput->Version = 1; +#endif _PNP_POWER + pBindInput->Identifier = IDENTIFIER_SPX; + pBindInput->BroadcastEnable = FALSE; + pBindInput->LookaheadRequired = IPX_HDRSIZE; + pBindInput->ProtocolOptions = 0; + pBindInput->ReceiveHandler = SpxReceive; + pBindInput->ReceiveCompleteHandler = SpxReceiveComplete; + pBindInput->StatusHandler = SpxStatus; + pBindInput->SendCompleteHandler = SpxSendComplete; + pBindInput->TransferDataCompleteHandler = SpxTransferDataComplete; + pBindInput->FindRouteCompleteHandler = SpxFindRouteComplete; + pBindInput->LineUpHandler = SpxLineUp; + pBindInput->LineDownHandler = SpxLineDown; + pBindInput->ScheduleRouteHandler = SpxScheduleRoute; +#if defined(_PNP_POWER) + pBindInput->PnPHandler = SpxPnPNotification; +#endif _PNP_POWER + + + // First get the length for the output buffer. + status = NtDeviceIoControlFile( + IpxHandle, // HANDLE to File + NULL, // HANDLE to Event + NULL, // ApcRoutine + NULL, // ApcContext + &ioStatusBlock, // IO_STATUS_BLOCK + IOCTL_IPX_INTERNAL_BIND, // IoControlCode + pBindInput, // Input Buffer + sizeof(IPX_INTERNAL_BIND_INPUT), // Input Buffer Length + NULL, // Output Buffer + 0); + + if (status == STATUS_PENDING) { + status = NtWaitForSingleObject( + IpxHandle, + (BOOLEAN)FALSE, + NULL); + } + + if (status != STATUS_BUFFER_TOO_SMALL) { + CTEFreeMem(pBindInput); + NtClose(IpxHandle); + return(STATUS_INVALID_PARAMETER); + } + + if ((pBindOutput = CTEAllocMem(ioStatusBlock.Information)) == NULL) { + CTEFreeMem(pBindInput); + NtClose(IpxHandle); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + status = NtDeviceIoControlFile( + IpxHandle, // HANDLE to File + NULL, // HANDLE to Event + NULL, // ApcRoutine + NULL, // ApcContext + &ioStatusBlock, // IO_STATUS_BLOCK + IOCTL_IPX_INTERNAL_BIND, // IoControlCode + pBindInput, // Input Buffer + sizeof(IPX_INTERNAL_BIND_INPUT), // Input Buffer Length + pBindOutput, // Output Buffer + ioStatusBlock.Information); + + if (status == STATUS_PENDING) { + status = NtWaitForSingleObject( + IpxHandle, + (BOOLEAN)FALSE, + NULL); + } + + if (status == STATUS_SUCCESS) { + + // Get all the info from the bind output buffer and save in + // appropriate places. + IpxLineInfo = pBindOutput->LineInfo; + IpxMacHdrNeeded = pBindOutput->MacHeaderNeeded; + IpxInclHdrOffset = pBindOutput->IncludedHeaderOffset; + + IpxSendPacket = pBindOutput->SendHandler; + IpxFindRoute = pBindOutput->FindRouteHandler; + IpxQuery = pBindOutput->QueryHandler; + IpxTransferData = pBindOutput->TransferDataHandler; + +#if !defined(_PNP_POWER) + // Copy over the network node info. + RtlCopyMemory( + SpxDevice->dev_Network, + pBindOutput->Network, + IPX_NET_LEN); + + RtlCopyMemory( + SpxDevice->dev_Node, + pBindOutput->Node, + IPX_NODE_LEN); + + + DBGPRINT(TDI, INFO, + ("SpxInitBindToIpx: Ipx Net %lx\n", + *(UNALIGNED ULONG *)SpxDevice->dev_Network)); + + // + // Find out how many adapters IPX has, if this fails + // just assume one. + // + + if ((*IpxQuery)( + IPX_QUERY_MAXIMUM_NIC_ID, + 0, + &SpxDevice->dev_Adapters, + sizeof(USHORT), + NULL) != STATUS_SUCCESS) { + + SpxDevice->dev_Adapters = 1; + + } +#endif !_PNP_POWER + } else { + + NtClose(IpxHandle); + status = STATUS_INVALID_PARAMETER; + } + CTEFreeMem(pBindInput); + CTEFreeMem(pBindOutput); + + return status; +} + + + + +VOID +SpxUnbindFromIpx( + VOID + ) + +{ + NtClose(IpxHandle); + return; +} + + + + +VOID +SpxStatus( + IN USHORT NicId, + IN NDIS_STATUS GeneralStatus, + IN PVOID StatusBuffer, + IN UINT StatusBufferLength + ) + +{ + DBGPRINT(RECEIVE, ERR, + ("SpxStatus: CALLED WITH %lx\n", + GeneralStatus)); + + return; +} + + + +VOID +SpxFindRouteComplete ( + IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest, + IN BOOLEAN FoundRoute + ) + +{ + CTELockHandle lockHandle; + PSPX_FIND_ROUTE_REQUEST pSpxFrReq = (PSPX_FIND_ROUTE_REQUEST)FindRouteRequest; + PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)pSpxFrReq->fr_Ctx; + + // This will be on a connection. Grab the lock, check the state and go from + // there. + if (pSpxConnFile == NULL) + { + // Should this ever happen? + KeBugCheck(0); + return; + } + + // Check the state. The called routines release the lock, remove the reference. + CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle); + if (SPX_CONN_CONNECTING(pSpxConnFile)) + { + // We are doing an active connect! + SpxConnConnectFindRouteComplete( + pSpxConnFile, + pSpxFrReq, + FoundRoute, + lockHandle); + } + else // For all others call active + { + SpxConnActiveFindRouteComplete( + pSpxConnFile, + pSpxFrReq, + FoundRoute, + lockHandle); + } + + // Free the find route request. + SpxFreeMemory(pSpxFrReq); + + return; +} + + + + +VOID +SpxLineUp ( + IN USHORT NicId, + IN PIPX_LINE_INFO LineInfo, + IN NDIS_MEDIUM DeviceType, + IN PVOID ConfigurationData + ) + +{ + // With PnP, our local address is changed when we get PnP + // notification. +#if !defined(_PNP_POWER) + + // + // If we get a line up for NicId 0, it means our local + // network number has changed, re-query from IPX. + // + + if (NicId == 0) { + + TDI_ADDRESS_IPX IpxAddress; + + if ((*IpxQuery)( + IPX_QUERY_IPX_ADDRESS, + 0, + &IpxAddress, + sizeof(TDI_ADDRESS_IPX), + NULL) == STATUS_SUCCESS) { + + RtlCopyMemory( + SpxDevice->dev_Network, + &IpxAddress.NetworkAddress, + IPX_NET_LEN); + + DBGPRINT(TDI, INFO, + ("SpxLineUp: Ipx Net %lx\n", + *(UNALIGNED ULONG *)SpxDevice->dev_Network)); + + // + // The node shouldn't change! + // + + if (!RtlEqualMemory( + SpxDevice->dev_Node, + IpxAddress.NodeAddress, + IPX_NODE_LEN)) { + + DBGPRINT(TDI, ERR, + ("SpxLineUp: Node address has changed\n")); + } + } + + } else { + + DBGPRINT(RECEIVE, ERR, + ("SpxLineUp: CALLED WITH %lx\n", + NicId)); + } + + return; +#endif !_PNP_POWER + +} + + + + +VOID +SpxLineDown ( + IN USHORT NicId, + IN ULONG FwdAdapterContext + ) + +{ + DBGPRINT(RECEIVE, ERR, + ("SpxLineDown: CALLED WITH %lx\n", + NicId)); + + return; +} + + + + +VOID +SpxScheduleRoute ( + IN PIPX_ROUTE_ENTRY RouteEntry + ) + +{ + DBGPRINT(RECEIVE, ERR, + ("SpxScheduleRoute: CALLED WITH %lx\n", + RouteEntry)); + + return; +} + +#if defined(_PNP_POWER) +VOID +SpxPnPNotification( + IN IPX_PNP_OPCODE OpCode, + IN PVOID PnPData + ) + +/*++ + +Routine Description: + + This function receives the notification about PnP events from IPX + +Arguments: + + OpCode - Type of the PnP event + + PnPData - Data associated with this event. + +Return Value: + + None. + +--*/ + +{ + + USHORT MaximumNicId = 0; + CTELockHandle LockHandle; + NTSTATUS Status; + PDEVICE Device = SpxDevice; + UNICODE_STRING UnicodeDeviceName; + + DBGPRINT(DEVICE, DBG,("Received a pnp notification, opcode %d\n",OpCode)); + + switch( OpCode ) { + case IPX_PNP_ADD_DEVICE : { + CTELockHandle TimerLockHandle; + IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData; + + + CTEGetLock (&Device->dev_Lock, &LockHandle); + + if ( PnPInfo->FirstORLastDevice ) { + CTEAssert( PnPInfo->NewReservedAddress ); + CTEAssert( Device->dev_State != DEVICE_STATE_OPEN ); + + *(UNALIGNED ULONG *)Device->dev_Network = PnPInfo->NetworkAddress; + RtlCopyMemory( Device->dev_Node, PnPInfo->NodeAddress, 6); + + // + // Start the timer. It is possible that the timer + // was still running or we are still in the timer dpc + // from the previous ADD_DEVICE - DELETE_DEVICE execution + // cycle. But it is ok simply restart this, because + // KeSetTimer implicitly cancels the previous Dpc. + // + + CTEGetLock(&spxTimerLock, &TimerLockHandle); + spxTimerStopped = FALSE; + CTEFreeLock(&spxTimerLock, TimerLockHandle); + KeSetTimer(&spxTimer, + spxTimerTick, + &spxTimerDpc); + + + Device->dev_State = DEVICE_STATE_OPEN; + + + CTEAssert( !Device->dev_Adapters ); + + IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize; + IpxLineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumPacketSize; + // set the provider info + SpxDevice->dev_ProviderInfo.MaximumLookaheadData = IpxLineInfo.MaximumPacketSize; + // Set the window size in statistics + SpxDevice->dev_Stat.MaximumSendWindow = + SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) * + IpxLineInfo.MaximumSendSize; + + }else { + IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize; + // Set the window size in statistics + SpxDevice->dev_Stat.MaximumSendWindow = + SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) * + IpxLineInfo.MaximumSendSize; + + } + + Device->dev_Adapters++; + CTEFreeLock ( &Device->dev_Lock, LockHandle ); + + // + // Notify the TDI clients about the device creation + // + if ( PnPInfo->FirstORLastDevice ) { + UnicodeDeviceName.Buffer = Device->dev_DeviceName; + UnicodeDeviceName.MaximumLength = Device->dev_DeviceNameLen; + UnicodeDeviceName.Length = Device->dev_DeviceNameLen - sizeof(WCHAR); + + if ( !NT_SUCCESS( TdiRegisterDeviceObject( + &UnicodeDeviceName, + &Device->dev_TdiRegistrationHandle ) )) { + DBGPRINT(TDI,ERR, ("Failed to register Spx Device with TDI\n")); + } + } + + break; + } + case IPX_PNP_DELETE_DEVICE : { + + IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData; + + CTEGetLock (&Device->dev_Lock, &LockHandle); + + CTEAssert( Device->dev_Adapters ); + Device->dev_Adapters--; + + if ( PnPInfo->FirstORLastDevice ) { + Device->dev_State = DEVICE_STATE_LOADED; + Device->dev_Adapters = 0; + } + + IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize; + CTEFreeLock ( &Device->dev_Lock, LockHandle ); + + if ( PnPInfo->FirstORLastDevice ) { + SpxTimerFlushAndStop(); + // + // inform tdi clients about the device deletion + // + if ( !NT_SUCCESS( TdiDeregisterDeviceObject( + Device->dev_TdiRegistrationHandle ) )) { + DBGPRINT(TDI,ERR, ("Failed to Deregister Spx Device with TDI\n")); + } + } + // + // TBD: call ExNotifyCallback + // + + break; + } + case IPX_PNP_ADDRESS_CHANGE: { + IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData; + + CTEGetLock (&Device->dev_Lock, &LockHandle); + CTEAssert( PnPInfo->NewReservedAddress ); + + *(UNALIGNED ULONG *)Device->dev_Network = PnPInfo->NetworkAddress; + RtlCopyMemory( Device->dev_Node, PnPInfo->NodeAddress, 6); + + CTEFreeLock ( &Device->dev_Lock, LockHandle ); + break; + } + case IPX_PNP_TRANSLATE_DEVICE: + break; + case IPX_PNP_TRANSLATE_ADDRESS: + break; + default: + CTEAssert( FALSE ); + } +} /* NbiPnPNotification */ + +#endif _PNP_POWER -- cgit v1.2.3