From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/nw/rdr/ipx.c | 1749 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1749 insertions(+) create mode 100644 private/nw/rdr/ipx.c (limited to 'private/nw/rdr/ipx.c') diff --git a/private/nw/rdr/ipx.c b/private/nw/rdr/ipx.c new file mode 100644 index 000000000..2341d1cd3 --- /dev/null +++ b/private/nw/rdr/ipx.c @@ -0,0 +1,1749 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + Ipx.c + +Abstract: + + This module implements the low level Ipx support routines for the NetWare + redirector. + +Author: + + Colin Watson [ColinW] 28-Dec-1992 + +Revision History: + +--*/ + +#include "Procs.h" +#include "wsnwlink.h" + +// +// Define IPX interfaces that should be in a public header file but aren't +// (at least for NT 1.0). For Daytona, include isnkrnl.h. +// + +#define IPX_ID 'M'<<24 | 'I'<<16 | 'P'<<8 | 'X' + +#define I_MIPX (('I' << 24) | ('D' << 16) | ('P' << 8)) +#define MIPX_SENDPTYPE I_MIPX | 118 /* Send ptype in options on recv*/ +#define MIPX_RERIPNETNUM I_MIPX | 144 /* ReRip a network */ +#define MIPX_GETNETINFO I_MIPX | 135 /* Get info on a network num */ +#define MIPX_LINECHANGE I_MIPX | 310 /* queued until WAN line goes up/down */ + +#define Dbg (DEBUG_TRACE_IPX) + +extern BOOLEAN WorkerRunning; // From timer.c + +extern POBJECT_TYPE *IoFileObjectType; + +typedef TA_IPX_ADDRESS UNALIGNED *PUTA_IPX_ADDRESS; + +typedef struct _ADDRESS_INFORMATION { + ULONG ActivityCount; + TA_IPX_ADDRESS NetworkName; + ULONG Unused; // Junk needed to work around streams NWLINK bug. +} ADDRESS_INFORMATION, *PADDRESS_INFORMATION; + +// +// Handle difference between NT1.0 and use of ntifs.h +// +#ifdef IFS + #define ATTACHPROCESS(_X) KeAttachProcess(_X); +#else + #define ATTACHPROCESS(_X) KeAttachProcess(&(_X)->Pcb); +#endif + +NTSTATUS +SubmitTdiRequest ( + IN PDEVICE_OBJECT pDeviceObject, + IN PIRP pIrp + ); + +NTSTATUS +CompletionEvent( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context + ); + +NTSTATUS +QueryAddressInformation( + IN PIRP_CONTEXT pIrpContext, + IN PNW_TDI_STRUCT pTdiStruct, + OUT PADDRESS_INFORMATION AddressInformation + ); + +NTSTATUS +QueryProviderInformation( + IN PIRP_CONTEXT pIrpContext, + IN PNW_TDI_STRUCT pTdiStruct, + OUT PTDI_PROVIDER_INFO ProviderInfo + ); + +USHORT +GetSocketNumber( + IN PIRP_CONTEXT pIrpC, + IN PNW_TDI_STRUCT pTdiStruc + ); + +NTSTATUS +SetTransportOption( + IN PIRP_CONTEXT pIrpC, + IN PNW_TDI_STRUCT pTdiStruc, + IN ULONG Option + ); + +#ifndef QFE_BUILD + +NTSTATUS +CompletionLineChange( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context + ); + +#endif +#ifdef ALLOC_PRAGMA +#pragma alloc_text( PAGE, IPX_Get_Local_Target ) +#pragma alloc_text( PAGE, IPX_Get_Internetwork_Address ) +#pragma alloc_text( PAGE, IPX_Get_Interval_Marker ) +#pragma alloc_text( PAGE, IPX_Open_Socket ) +#pragma alloc_text( PAGE, IPX_Close_Socket ) +#pragma alloc_text( PAGE, IpxOpen ) +#pragma alloc_text( PAGE, IpxOpenHandle ) +#pragma alloc_text( PAGE, BuildIpxAddressEa ) +#pragma alloc_text( PAGE, IpxClose ) +#pragma alloc_text( PAGE, SetEventHandler ) +#pragma alloc_text( PAGE, SubmitTdiRequest ) +#pragma alloc_text( PAGE, GetSocketNumber ) +#pragma alloc_text( PAGE, GetMaximumPacketSize ) +#pragma alloc_text( PAGE, QueryAddressInformation ) +#pragma alloc_text( PAGE, QueryProviderInformation ) +#pragma alloc_text( PAGE, SetTransportOption ) +#pragma alloc_text( PAGE, GetNewRoute ) +#ifndef QFE_BUILD +#pragma alloc_text( PAGE, SubmitLineChangeRequest ) +#pragma alloc_text( PAGE, FspProcessLineChange ) +#endif + +#ifndef QFE_BUILD +#pragma alloc_text( PAGE1, CompletionEvent ) +#endif + +#endif + +#if 0 // Not pageable +BuildIpxAddress +CompletionLineChange + +// see ifndef QFE_BUILD above + +#endif + + +NTSTATUS +IPX_Get_Local_Target( + IN IPXaddress* RemoteAddress, + OUT NodeAddress* LocalTarget, + OUT word* Ticks + ) +/*++ + +Routine Description: + + Determine the address in the caller's own network to which to transmit + in order to reach the specified machine. + + This is not required for NT since the IPX transport handles the + issue of determining routing between this machine and the remote + address. + +Arguments: + + RemoteAddress - Supplies the remote computers address + NodeAddress - Where to store the intermediate machine address + Ticks - Returns the expected number of ticks to reach the remote address + +Return Value: + + status of the operation + +--*/ +{ + PAGED_CODE(); + + DebugTrace(0, Dbg, "IPX_Get_Local_Target\n", 0); + return STATUS_NOT_IMPLEMENTED; +} + + +VOID +IPX_Get_Internetwork_Address( + OUT IPXaddress* LocalAddress + ) +/*++ + +Routine Description: + + Determine the callers full address in a set of interconnected networks. + in order to reach the specified machine. + + This is not required for NT since the IPX transport handles the + issue of determining routing between this machine and the remote + address. + +Arguments: + + LocalAddress - Where to store the local address + +Return Value: + + none + +--*/ +{ + PAGED_CODE(); + + DebugTrace(0, Dbg, "IPX_Get_Internetwork_Address\n", 0); + RtlFillMemory(LocalAddress, sizeof(IPXaddress), 0xff); +} + + +word +IPX_Get_Interval_Marker( + VOID + ) +/*++ + +Routine Description: + + Determine the interval marker in clock ticks. + +Arguments: + +Return Value: + + interval marker + +--*/ +{ + PAGED_CODE(); + + DebugTrace(0, Dbg, "IPX_Get_Interval_Marker\n", 0); + return 0xff; +} + + +NTSTATUS +IPX_Open_Socket( + IN PIRP_CONTEXT pIrpC, + IN PNW_TDI_STRUCT pTdiStruc + ) +/*++ + +Routine Description: + + Open a local socket to be used for a conection to a remote server. + +Arguments: + + pIrpC - supplies the irp context for the request creating the socket. + + pTdiStruc - supplies where to record the handle and both device and file + object pointers + +Return Value: + + 0 success + +--*/ +{ + NTSTATUS Status; + UCHAR NetworkName[ sizeof( FILE_FULL_EA_INFORMATION )-1 + + TDI_TRANSPORT_ADDRESS_LENGTH + 1 + + sizeof(TA_IPX_ADDRESS)]; + + static UCHAR LocalNodeAddress[6] = {0,0,0,0,0,0}; + + PAGED_CODE(); + + DebugTrace(+1, Dbg, "IPX_Open_Socket %X\n", pTdiStruc->Socket); + + // + // Let the transport decide the network number and node address + // if the caller specified socket 0. This will allow the transport + // to use whatever local adapters are available to get to the + // remote server. + // + + BuildIpxAddressEa( (ULONG)0, + LocalNodeAddress, + (USHORT)pTdiStruc->Socket, + &NetworkName ); + + Status = IpxOpenHandle( &pTdiStruc->Handle, + &pTdiStruc->pDeviceObject, + &pTdiStruc->pFileObject, + &NetworkName, + FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) + + TDI_TRANSPORT_ADDRESS_LENGTH + 1 + + sizeof(TA_IPX_ADDRESS)); + + if ( !NT_SUCCESS(Status) ) { + return( Status ); + } + + if ( pTdiStruc->Socket == 0 ) { + + // + // Find out the socket number assigned by the transport + // + + pTdiStruc->Socket = GetSocketNumber( pIrpC, pTdiStruc ); + DebugTrace(0, Dbg, "Assigned socket number %X\n", pTdiStruc->Socket ); + } + + // + // Tell transport to accept packet type being set in the connection + // information provided with the send datagram. Transport reports + // the packet type similarly on receive datagram. + // BUGBUG we should get the ioctl codes for ipx into a standard place + // + + Status = SetTransportOption( + pIrpC, + pTdiStruc, + MIPX_SENDPTYPE ); + + DebugTrace(-1, Dbg, " %X\n", Status ); + return Status; +} + + + +VOID +IPX_Close_Socket( + IN PNW_TDI_STRUCT pTdiStruc + ) +/*++ + +Routine Description: + + Terminate a connection over the network. + +Arguments: + + pTdiStruc - supplies where to record the handle and both device and file + object pointers + +Return Value: + + none + +--*/ +{ + BOOLEAN ProcessAttached = FALSE; + + PAGED_CODE(); + + DebugTrace(+1, Dbg, "IPX_Close_Socket %x\n", pTdiStruc->Socket); + + if ( pTdiStruc->Handle == NULL ) { + return; + } + + ObDereferenceObject( pTdiStruc->pFileObject ); + + // + // Attach to the redirector's FSP to allow the handle for the + // connection to hang around. + // + + if (PsGetCurrentProcess() != FspProcess) { + ATTACHPROCESS(FspProcess); + ProcessAttached = TRUE; + } + + ZwClose( pTdiStruc->Handle ); + + if (ProcessAttached) { + // + // Now re-attach back to our original process + // + + KeDetachProcess(); + } + + pTdiStruc->Handle = NULL; + + pTdiStruc->pFileObject = NULL; + + DebugTrace(-1, Dbg, "IPX_Close_Socket\n", 0); + return; +} + + +NTSTATUS +IpxOpen( + VOID + ) +/*++ + +Routine Description: + + Open handle to the Ipx transport. + +Arguments: + + none. + +Return Value: + + none + +--*/ +{ + NTSTATUS Status; + + Status = IpxOpenHandle( &IpxHandle, + &pIpxDeviceObject, + &pIpxFileObject, + NULL, + 0 ); + + DebugTrace(-1, Dbg, "IpxOpen of local node address %X\n", Status); + return Status; +} + + +NTSTATUS +IpxOpenHandle( + OUT PHANDLE pHandle, + OUT PDEVICE_OBJECT* ppDeviceObject, + OUT PFILE_OBJECT* ppFileObject, + IN PVOID EaBuffer OPTIONAL, + IN ULONG EaLength + ) +/*++ + +Routine Description: + + Open handle to the Ipx transport. + +Arguments: + + OUT Handle - The handle to the transport if return value is NT_SUCCESS + +Return Value: + + none + +--*/ +{ + OBJECT_ATTRIBUTES AddressAttributes; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + BOOLEAN ProcessAttached = FALSE; + + PAGED_CODE(); + + DebugTrace(+1, Dbg, "IpxOpenHandle\n", 0); + + *pHandle = NULL; + + InitializeObjectAttributes (&AddressAttributes, + &IpxTransportName, + OBJ_CASE_INSENSITIVE,// Attributes + NULL, // RootDirectory + NULL); // SecurityDescriptor + + // + // Attach to the redirector's FSP to allow the handle for the + // connection to hang around. Normally we create 3 handles at once + // so the outer code already has done this to avoid the expensive + // attach procedure. + // + + if (PsGetCurrentProcess() != FspProcess) { + ATTACHPROCESS(FspProcess); + ProcessAttached = TRUE; + } + + Status = ZwCreateFile(pHandle, + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, + &AddressAttributes, // Object Attributes + &IoStatusBlock, // Final I/O status block + NULL, // Allocation Size + FILE_ATTRIBUTE_NORMAL, // Normal attributes + FILE_SHARE_READ,// Sharing attributes + FILE_OPEN_IF, // Create disposition + 0, // CreateOptions + EaBuffer,EaLength); + + if (!NT_SUCCESS(Status) || + !NT_SUCCESS(Status = IoStatusBlock.Status)) { + + goto error_cleanup2; + + } + + // + // Obtain a referenced pointer to the file object. + // + Status = ObReferenceObjectByHandle ( + *pHandle, + 0, + NULL, + KernelMode, + ppFileObject, + NULL + ); + + if (!NT_SUCCESS(Status)) { + + goto error_cleanup; + + } + + if (ProcessAttached) { + + // + // Now re-attach back to our original process + // + + KeDetachProcess(); + } + + *ppDeviceObject = IoGetRelatedDeviceObject( *ppFileObject ); + + DebugTrace(-1, Dbg, "IpxOpenHandle %X\n", Status); + return Status; + +error_cleanup2: + + ASSERT( *pHandle != NULL ); + ZwClose( *pHandle ); + *pHandle = NULL; + +error_cleanup: + if (ProcessAttached) { + + // + // Now re-attach back to our original process + // + + KeDetachProcess(); + } + + DebugTrace(-1, Dbg, "IpxOpenHandle %X\n", Status); + return Status; +} + + +VOID +BuildIpxAddress( + IN ULONG NetworkAddress, + IN PUCHAR NodeAddress, + IN USHORT Socket, + OUT PTA_IPX_ADDRESS NetworkName + ) + +/*++ + +Routine Description: + + This routine builds a TA_NETBIOS_ADDRESS structure in the locations pointed + to by NetworkName. All fields are filled out. + +Arguments: + NetworkAddress - Supplies the network number + NodeAddress - Supplies the node number + Socket - The socket number (in Hi-Lo order) + NetworkName - Supplies the structure to place the address + +Return Value: + + none. + +--*/ + +{ + // Warn compiler that TAAddressCount may be mis-aligned. + PUTA_IPX_ADDRESS UNetworkName = (PUTA_IPX_ADDRESS)NetworkName; + + DebugTrace(+0, Dbg, "BuildIpxAddress\n", 0); + + UNetworkName->TAAddressCount = 1; + UNetworkName->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX; + UNetworkName->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IPX; + + RtlMoveMemory ( + UNetworkName->Address[0].Address[0].NodeAddress, + NodeAddress, + 6); + UNetworkName->Address[0].Address[0].NetworkAddress = NetworkAddress; + UNetworkName->Address[0].Address[0].Socket = Socket; + +} /* TdiBuildIpxAddress */ + + +VOID +BuildIpxAddressEa ( + IN ULONG NetworkAddress, + IN PUCHAR NodeAddress, + IN USHORT Socket, + OUT PVOID NetworkName + ) + +/*++ + +Routine Description: + + Builds an EA describing a Netbios address in the buffer supplied by the + user. + +Arguments: + + NetworkAddress - Supplies the network number + NodeAddress - Supplies the node number + Socket - + NetworkName - The Ea structure that describes the input parameters. + +Return Value: + + An informative error code if something goes wrong. STATUS_SUCCESS if the + ea is built properly. + +--*/ + +{ + PFILE_FULL_EA_INFORMATION EaBuffer; + PTA_IPX_ADDRESS TAAddress; + ULONG Length; + + DebugTrace(+0, Dbg, "BuildIpxAddressEa\n", 0); + + Length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) + + TDI_TRANSPORT_ADDRESS_LENGTH + 1 + + sizeof (TA_IPX_ADDRESS); + EaBuffer = (PFILE_FULL_EA_INFORMATION)NetworkName; + + EaBuffer->NextEntryOffset = 0; + EaBuffer->Flags = 0; + EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH; + EaBuffer->EaValueLength = sizeof (TA_IPX_ADDRESS); + + RtlCopyMemory ( + EaBuffer->EaName, + TdiTransportAddress, + EaBuffer->EaNameLength + 1); + + TAAddress = (PTA_IPX_ADDRESS)&EaBuffer->EaName[EaBuffer->EaNameLength+1]; + + BuildIpxAddress( + NetworkAddress, + NodeAddress, + Socket, + TAAddress); + + + return; + +} + + +VOID +IpxClose( + VOID + ) +/*++ + +Routine Description: + + Open handle to the Ipx transport. + +Arguments: + + none + +Return Value: + + none + +--*/ +{ + PAGED_CODE(); + + DebugTrace(+1, Dbg, "IpxClose...\n", 0); + if ( pIpxFileObject ) { + ObDereferenceObject( pIpxFileObject ); + pIpxFileObject = NULL; + } + + if (IpxHandle) { + // + // Attach to the redirector's FSP to allow the handle for the + // connection to hang around. + // + + if (PsGetCurrentProcess() != FspProcess) { + ATTACHPROCESS(FspProcess); + ZwClose( IpxHandle ); + KeDetachProcess(); + } else { + ZwClose( IpxHandle ); + } + + IpxHandle = NULL; + } + DebugTrace(-1, Dbg, "IpxClose\n", 0); + +} + + +NTSTATUS +SetEventHandler ( + IN PIRP_CONTEXT pIrpC, + IN PNW_TDI_STRUCT pTdiStruc, + IN ULONG EventType, + IN PVOID pEventHandler, + IN PVOID pContext + ) + +/*++ + +Routine Description: + + This routine registers an event handler with a TDI transport provider. + +Arguments: + + pIrpC - supplies an Irp among other things. + + pTdiStruc - supplies the handle and both device and file object pointers + to the transport. + + IN ULONG EventType, - Supplies the type of event. + + IN PVOID pEventHandler - Supplies the event handler. + + IN PVOID pContext - Supplies the context to be supplied to the event + handler. + +Return Value: + + NTSTATUS - Final status of the set event operation + +--*/ + +{ + NTSTATUS Status; + + PAGED_CODE(); + + TdiBuildSetEventHandler(pIrpC->pOriginalIrp, + pTdiStruc->pDeviceObject, + pTdiStruc->pFileObject, + NULL, + NULL, + EventType, + pEventHandler, + pContext); + + Status = SubmitTdiRequest(pTdiStruc->pDeviceObject, + pIrpC->pOriginalIrp); + + return Status; +} + + +NTSTATUS +SubmitTdiRequest ( + IN PDEVICE_OBJECT pDeviceObject, + IN PIRP pIrp + ) + +/*++ + +Routine Description: + + This routine submits a request to TDI and waits for it to complete. + +Arguments: + + IN PDevice_OBJECT DeviceObject - Connection or Address handle for TDI request + IN PIRP Irp - TDI request to submit. + +Return Value: + + NTSTATUS - Final status of request. + +--*/ + +{ + NTSTATUS Status; + KEVENT Event; + + PAGED_CODE(); + + DebugTrace(+1, Dbg, "SubmitTdiRequest\n", 0); + + KeInitializeEvent (&Event, NotificationEvent, FALSE); + + IoSetCompletionRoutine(pIrp, CompletionEvent, &Event, TRUE, TRUE, TRUE); + + // + // Submit the request + // + + Status = IoCallDriver(pDeviceObject, pIrp); + + // + // If it failed immediately, return now, otherwise wait. + // + + if (!NT_SUCCESS(Status)) { + DebugTrace(-1, Dbg, "SubmitTdiRequest %X\n", Status); + return Status; + } + + if (Status == STATUS_PENDING) { + + DebugTrace(+0, Dbg, "Waiting....\n", 0); + + Status = KeWaitForSingleObject(&Event, // Object to wait on. + Executive, // Reason for waiting + KernelMode, // Processor mode + FALSE, // Alertable + NULL); // Timeout + + if (!NT_SUCCESS(Status)) { + DebugTrace(-1, Dbg, "SubmitTdiRequest could not wait %X\n", Status); + return Status; + } + + Status = pIrp->IoStatus.Status; + } + + DebugTrace(-1, Dbg, "SubmitTdiRequest %X\n", Status); + + return(Status); +} + + +NTSTATUS +CompletionEvent( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context + ) +/*++ + +Routine Description: + + This routine does not complete the Irp. It is used to signal to a + synchronous part of the driver that it can proceed. + +Arguments: + + DeviceObject - unused. + + Irp - Supplies Irp that the transport has finished processing. + + Context - Supplies the event associated with the Irp. + +Return Value: + + The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops + processing Irp stack locations at this point. + +--*/ +{ + DebugTrace( 0, Dbg, "CompletionEvent\n", 0 ); + + KeSetEvent((PKEVENT )Context, 0, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; + + UNREFERENCED_PARAMETER( DeviceObject ); + UNREFERENCED_PARAMETER( Irp ); +} + + +USHORT +GetSocketNumber( + IN PIRP_CONTEXT pIrpC, + IN PNW_TDI_STRUCT pTdiStruc + ) +/*++ + +Routine Description: + + Use a TDI_ACTION to set the Option. + +Arguments: + + pIrpC - supplies an Irp among other things. + + pTdiStruc - supplies the handle and both device and file object pointers + to the transport. + + Option - supplies the option to set. + +Return Value: + + 0 failed otherwise the socket number. + +--*/ +{ + ADDRESS_INFORMATION AddressInfo; + NTSTATUS Status; + USHORT SocketNumber; + + PAGED_CODE(); + + Status = QueryAddressInformation( pIrpC, pTdiStruc, &AddressInfo ); + + if ( !NT_SUCCESS( Status ) ) { + SocketNumber = 0; + } else { + SocketNumber = AddressInfo.NetworkName.Address[0].Address[0].Socket; + + RtlCopyMemory( &OurAddress, + &AddressInfo.NetworkName.Address[0].Address[0], + sizeof(TDI_ADDRESS_IPX)); + + } + + return( SocketNumber ); +} + + +NTSTATUS +GetMaximumPacketSize( + IN PIRP_CONTEXT pIrpContext, + IN PNW_TDI_STRUCT pTdiStruct, + OUT PULONG pMaximumPacketSize + ) +/*++ + +Routine Description: + + Query the maximum packet size for this network. + +Arguments: + + pIrpContext - supplies an Irp among other things. + + pTdiStruct - supplies the handle and both device and file object pointers + to the transport. + + pMaximumPacketSize - Returns the maximum packet size for the network. + +Return Value: + + The status of the query. + +--*/ +{ + TDI_PROVIDER_INFO ProviderInfo; + + NTSTATUS Status; + + PAGED_CODE(); + + Status = QueryProviderInformation( pIrpContext, pTdiStruct, &ProviderInfo ); + + if ( NT_SUCCESS( Status ) ) { + *pMaximumPacketSize = ProviderInfo.MaximumLookaheadData; + } + + return( Status ); +} + +NTSTATUS +QueryAddressInformation( + PIRP_CONTEXT pIrpContext, + IN PNW_TDI_STRUCT pTdiStruct, + PADDRESS_INFORMATION AddressInformation + ) +{ + NTSTATUS Status; + + PMDL MdlSave = pIrpContext->pOriginalIrp->MdlAddress; + PMDL Mdl; + + PAGED_CODE(); + + Mdl = ALLOCATE_MDL( + AddressInformation, + sizeof( *AddressInformation ), + FALSE, // Secondary Buffer + FALSE, // Charge Quota + NULL); + + if ( Mdl == NULL ) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + try { + MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess ); + } except( EXCEPTION_EXECUTE_HANDLER ) { + FREE_MDL( Mdl ); + return GetExceptionCode(); + } + + TdiBuildQueryInformation( + pIrpContext->pOriginalIrp, + pTdiStruct->pDeviceObject, + pTdiStruct->pFileObject, + CompletionEvent, + NULL, + TDI_QUERY_ADDRESS_INFO, + Mdl); + + Status = SubmitTdiRequest( pTdiStruct->pDeviceObject, pIrpContext->pOriginalIrp); + + pIrpContext->pOriginalIrp->MdlAddress = MdlSave; + MmUnlockPages( Mdl ); + FREE_MDL( Mdl ); + + return( Status ); +} + + +NTSTATUS +QueryProviderInformation( + IN PIRP_CONTEXT pIrpContext, + IN PNW_TDI_STRUCT pTdiStruct, + PTDI_PROVIDER_INFO ProviderInfo + ) +{ + NTSTATUS Status; + + PMDL MdlSave = pIrpContext->pOriginalIrp->MdlAddress; + PMDL Mdl; + + PAGED_CODE(); + + Mdl = ALLOCATE_MDL( + ProviderInfo, + sizeof( *ProviderInfo ), + FALSE, // Secondary Buffer + FALSE, // Charge Quota + NULL); + + if ( Mdl == NULL ) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + try { + MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess ); + } except( EXCEPTION_EXECUTE_HANDLER ) { + FREE_MDL( Mdl ); + return GetExceptionCode(); + } + + TdiBuildQueryInformation( + pIrpContext->pOriginalIrp, + pTdiStruct->pDeviceObject, + pTdiStruct->pFileObject, + CompletionEvent, + NULL, + TDI_QUERY_PROVIDER_INFO, + Mdl); + + Status = SubmitTdiRequest(pTdiStruct->pDeviceObject, pIrpContext->pOriginalIrp); + + pIrpContext->pOriginalIrp->MdlAddress = MdlSave; + MmUnlockPages( Mdl ); + FREE_MDL( Mdl ); + + return( Status ); +} + + + +NTSTATUS +SetTransportOption( + IN PIRP_CONTEXT pIrpC, + IN PNW_TDI_STRUCT pTdiStruc, + IN ULONG Option + ) +/*++ + +Routine Description: + + Use a TDI_ACTION to set the Option. + +Arguments: + + pIrpC - supplies an Irp among other things. + + pTdiStruc - supplies the handle and both device and file object pointers + to the transport. + + Option - supplies the option to set. + +Return Value: + + 0 success + +--*/ +{ + static struct { + TDI_ACTION_HEADER Header; + BOOLEAN DatagramOption; + ULONG BufferLength; + ULONG Option; + } SetPacketType = { + IPX_ID, + 0, // ActionCode + 0, // Reserved + TRUE, // DatagramOption + sizeof(ULONG) // BufferLength + }; + + KEVENT Event; + NTSTATUS Status; + + PIRP pIrp = pIrpC->pOriginalIrp; + + // + // Save the original MDL and System buffer address, to restore + // after the IRP completes. + // + // We use both the MDL and SystemBuffer because NWLINK assumes that + // we are using SystemBuffer even though we are supposed to use the + // MDL to pass a pointer to the action buffer. + // + + PMDL MdlSave = pIrp->MdlAddress; + PCHAR SystemBufferSave = pIrp->AssociatedIrp.SystemBuffer; + + PMDL Mdl; + + PAGED_CODE(); + + Mdl = ALLOCATE_MDL( + &SetPacketType, + sizeof( SetPacketType ), + FALSE, // Secondary Buffer + FALSE, // Charge Quota + NULL ); + + if ( Mdl == NULL ) { + IPX_Close_Socket( pTdiStruc ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + SetPacketType.Option = Option; + + try { + MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess ); + } except( EXCEPTION_EXECUTE_HANDLER ) { + FREE_MDL( Mdl ); + return GetExceptionCode(); + } + + KeInitializeEvent ( + &Event, + SynchronizationEvent, + FALSE); + + TdiBuildAction( + pIrp, + pTdiStruc->pDeviceObject, + pTdiStruc->pFileObject, + CompletionEvent, + &Event, + Mdl ); + + // + // Set up the system buffer for NWLINK. + // + + pIrp->AssociatedIrp.SystemBuffer = &SetPacketType; + + Status = IoCallDriver (pTdiStruc->pDeviceObject, pIrp); + + if ( Status == STATUS_PENDING ) { + Status = KeWaitForSingleObject ( + &Event, + Executive, + KernelMode, + FALSE, + NULL ); + + if ( NT_SUCCESS( Status ) ) { + Status = pIrp->IoStatus.Status; + } + } + + // + // Now restore the system buffer and MDL address in the IRP + // + + pIrp->AssociatedIrp.SystemBuffer = SystemBufferSave; + pIrp->MdlAddress = MdlSave; + + MmUnlockPages( Mdl ); + FREE_MDL( Mdl ); + + return Status; +} + + +NTSTATUS +GetNewRoute( + IN PIRP_CONTEXT pIrpContext + ) +/*++ + +Routine Description: + + Use a TDI_ACTION to get a new route. + +Arguments: + + pIrpContext - Supplies IRP context information. + +Return Value: + + The status of the operation. + +--*/ +{ + struct { + TDI_ACTION_HEADER Header; + BOOLEAN DatagramOption; + ULONG BufferLength; + ULONG Option; + ULONG info_netnum; + USHORT info_hopcount; + USHORT info_netdelay; + int info_cardnum; + UCHAR info_router[6]; + } ReRipRequest = { + IPX_ID, + 0, // ActionCode + 0, // Reserved + TRUE, // DatagramOption + 24 // Buffer length (not including header) + }; + + KEVENT Event; + NTSTATUS Status; + + PIRP pIrp = pIrpContext->pOriginalIrp; + + // + // Save the original MDL and System buffer address, to restore + // after the IRP completes. + // + // We use both the MDL and SystemBuffer because NWLINK assumes that + // we are using SystemBuffer even though we are supposed to use the + // MDL to pass a pointer to the action buffer. + // + + PMDL MdlSave = pIrp->MdlAddress; + PCHAR SystemBufferSave = pIrp->AssociatedIrp.SystemBuffer; + + PMDL Mdl; + + PAGED_CODE(); + + Mdl = ALLOCATE_MDL( + &ReRipRequest, + sizeof( ReRipRequest ), + FALSE, // Secondary Buffer + FALSE, // Charge Quota + NULL ); + + if ( Mdl == NULL ) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + ReRipRequest.Option = MIPX_RERIPNETNUM; + ReRipRequest.info_netnum = pIrpContext->pNpScb->ServerAddress.Net; + + try { + MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess ); + } except( EXCEPTION_EXECUTE_HANDLER ) { + FREE_MDL( Mdl ); + return GetExceptionCode(); + } + + KeInitializeEvent ( + &Event, + SynchronizationEvent, + FALSE); + + TdiBuildAction( + pIrp, + pIrpContext->pNpScb->Server.pDeviceObject, + pIrpContext->pNpScb->Server.pFileObject, + CompletionEvent, + &Event, + Mdl ); + + // + // Set up the system buffer for NWLINK. + // + + pIrp->AssociatedIrp.SystemBuffer = &ReRipRequest; + + Status = IoCallDriver ( pIrpContext->pNpScb->Server.pDeviceObject, pIrp); + + if ( Status == STATUS_PENDING ) { + Status = KeWaitForSingleObject ( + &Event, + Executive, + KernelMode, + FALSE, + NULL ); + + if ( NT_SUCCESS( Status ) ) { + Status = pIrp->IoStatus.Status; + } + } + + // + // Now restore the system buffer and MDL address in the IRP + // + + pIrp->AssociatedIrp.SystemBuffer = SystemBufferSave; + pIrp->MdlAddress = MdlSave; + + MmUnlockPages( Mdl ); + FREE_MDL( Mdl ); + + return Status; +} + + +NTSTATUS +GetTickCount( + IN PIRP_CONTEXT pIrpContext, + OUT PUSHORT TickCount + ) +/*++ + +Routine Description: + + Use a TDI_ACTION to get a new route. + +Arguments: + + pIrpContext - Supplies IRP context information. + +Return Value: + + The status of the operation. + +--*/ +{ + struct { + TDI_ACTION_HEADER Header; + BOOLEAN DatagramOption; + ULONG BufferLength; + ULONG Option; + IPX_NETNUM_DATA NetNumData; + } GetTickCountInput = { + IPX_ID, + 0, // ActionCode + 0, // Reserved + TRUE, // DatagramOption + sizeof( IPX_NETNUM_DATA) + 2 * sizeof( ULONG ) + }; + + struct _GET_TICK_COUNT_OUTPUT { + ULONG Option; + IPX_NETNUM_DATA NetNumData; + }; + + struct _GET_TICK_COUNT_OUTPUT *GetTickCountOutput; + + KEVENT Event; + NTSTATUS Status; + + PIRP pIrp = pIrpContext->pOriginalIrp; + + // + // Save the original MDL and System buffer address, to restore + // after the IRP completes. + // + // We use both the MDL and SystemBuffer because NWLINK assumes that + // we are using SystemBuffer even though we are supposed to use the + // MDL to pass a pointer to the action buffer. + // + + PMDL MdlSave = pIrp->MdlAddress; + PCHAR SystemBufferSave = pIrp->AssociatedIrp.SystemBuffer; + + PMDL Mdl; + + PAGED_CODE(); + + Mdl = ALLOCATE_MDL( + &GetTickCountInput, + sizeof( GetTickCountInput ), + FALSE, // Secondary Buffer + FALSE, // Charge Quota + NULL ); + + if ( Mdl == NULL ) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + GetTickCountInput.Option = MIPX_GETNETINFO; + *(PULONG)GetTickCountInput.NetNumData.netnum = pIrpContext->pNpScb->ServerAddress.Net; + + try { + MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess ); + } except( EXCEPTION_EXECUTE_HANDLER ) { + FREE_MDL( Mdl ); + return GetExceptionCode(); + } + + KeInitializeEvent ( + &Event, + SynchronizationEvent, + FALSE); + + TdiBuildAction( + pIrp, + pIrpContext->pNpScb->Server.pDeviceObject, + pIrpContext->pNpScb->Server.pFileObject, + CompletionEvent, + &Event, + Mdl ); + + // + // Set up the system buffer for NWLINK. + // + + pIrp->AssociatedIrp.SystemBuffer = &GetTickCountInput; + + Status = IoCallDriver ( pIrpContext->pNpScb->Server.pDeviceObject, pIrp); + + if ( Status == STATUS_PENDING ) { + Status = KeWaitForSingleObject ( + &Event, + Executive, + KernelMode, + FALSE, + NULL ); + + if ( NT_SUCCESS( Status ) ) { + Status = pIrp->IoStatus.Status; + } + } + + DebugTrace( +0, Dbg, "Get Tick Count, net= %x\n", pIrpContext->pNpScb->ServerAddress.Net ); + + if ( NT_SUCCESS( Status ) ) { + + // + // HACK-o-rama. Streams and non-streams IPX have different output + // buffer formats. For now accept both. + // + + if ( IpxTransportName.Length == 32 ) { + + // ISNIPX format + + *TickCount = GetTickCountInput.NetNumData.netdelay; + } else { + + // NWLINK format + + GetTickCountOutput = (struct _GET_TICK_COUNT_OUTPUT *)&GetTickCountInput; + *TickCount = GetTickCountOutput->NetNumData.netdelay; + } + + DebugTrace( +0, Dbg, "Tick Count = %d\n", *TickCount ); + } else { + DebugTrace( +0, Dbg, "GetTickCount failed, status = %X\n", Status ); + } + + // + // Now restore the system buffer and MDL address in the IRP + // + + pIrp->AssociatedIrp.SystemBuffer = SystemBufferSave; + pIrp->MdlAddress = MdlSave; + + MmUnlockPages( Mdl ); + FREE_MDL( Mdl ); + + return Status; +} + +#ifndef QFE_BUILD + +static PIRP LineChangeIrp = NULL; + + +NTSTATUS +SubmitLineChangeRequest( + VOID + ) +/*++ + +Routine Description: + + Use a TDI_ACTION to get a new route. + +Arguments: + + pIrpContext - Supplies IRP context information. + +Return Value: + + The status of the operation. + +--*/ +{ + struct _LINE_CHANGE { + TDI_ACTION_HEADER Header; + BOOLEAN DatagramOption; + ULONG BufferLength; + ULONG Option; + } *LineChangeInput; + + PIRP pIrp; + PMDL Mdl; + + PAGED_CODE(); + + LineChangeInput = ALLOCATE_POOL( NonPagedPool, sizeof( struct _LINE_CHANGE ) ); + + // + // Complete initialization of the request, and allocate and build an + // MDL for the request input buffer. + // + + LineChangeInput->Header.TransportId = IPX_ID; + LineChangeInput->Header.ActionCode = 0; + LineChangeInput->Header.Reserved = 0; + LineChangeInput->DatagramOption = 2; + LineChangeInput->BufferLength = 2 * sizeof( ULONG ); + LineChangeInput->Option = MIPX_LINECHANGE; + + Mdl = ALLOCATE_MDL( + LineChangeInput, + sizeof( *LineChangeInput ), + FALSE, // Secondary Buffer + FALSE, // Charge Quota + NULL ); + + if ( Mdl == NULL ) { + FREE_POOL( LineChangeInput ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + pIrp = ALLOCATE_IRP( pIpxDeviceObject->StackSize, FALSE ); + + if ( pIrp == NULL ) { + FREE_POOL( LineChangeInput ); + FREE_MDL( Mdl ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Remember this IRP so that we can cancel it. + // + + LineChangeIrp = pIrp; + + MmBuildMdlForNonPagedPool( Mdl ); + + // + // Build and submit a TDI request packet. + // + + TdiBuildAction( + pIrp, + pIpxDeviceObject, + pIpxFileObject, + CompletionLineChange, + NULL, + Mdl ); + + IoCallDriver ( pIpxDeviceObject, pIrp ); +} + + + +NTSTATUS +CompletionLineChange( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context + ) +/*++ + +Routine Description: + + This routine is called when the transport completes a line change IRP. + This means that we have switched nets, and that we should mark + all of our servers disconnected. + +Arguments: + + DeviceObject - unused. + + Irp - Supplies Irp that the transport has finished processing. + + Context - unused. + +Return Value: + + The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops + processing Irp stack locations at this point. + +--*/ +{ + PMDL Mdl; + PWORK_QUEUE_ITEM WorkQueueItem; + + DebugTrace( 0, Dbg, "CompletionLineChange\n", 0 ); + + Mdl = Irp->MdlAddress; + + if ( !NT_SUCCESS( Irp->IoStatus.Status ) ) { + FREE_POOL( Mdl->MappedSystemVa ); + FREE_MDL( Mdl ); + FREE_IRP( Irp ); + return( STATUS_MORE_PROCESSING_REQUIRED ); + } + + // + // If the scavenger is running, simply make a note that + // we need to do this when it is finished. + // + + KeAcquireSpinLockAtDpcLevel( &NwScavengerSpinLock ); + + if ( WorkerRunning ) { + + if ( ( DelayedProcessLineChange != FALSE ) && + ( DelayedLineChangeIrp != NULL ) ) { + + // + // We've already got a line change. Dump this one. + // + + KeReleaseSpinLockFromDpcLevel( &NwScavengerSpinLock ); + + DebugTrace( 0, Dbg, "Dumping an additional line change request.\n", 0 ); + + FREE_POOL( Mdl->MappedSystemVa ); + FREE_MDL( Mdl ); + FREE_IRP( Irp ); + return( STATUS_MORE_PROCESSING_REQUIRED ); + + } else { + + DebugTrace( 0, Dbg, "Delaying a line change request.\n", 0 ); + + DelayedProcessLineChange = TRUE; + DelayedLineChangeIrp = Irp; + + KeReleaseSpinLockFromDpcLevel( &NwScavengerSpinLock ); + return STATUS_MORE_PROCESSING_REQUIRED; + + } + + } else { + + // + // Don't let the scavenger start up while we're running. + // + + WorkerRunning = TRUE; + KeReleaseSpinLockFromDpcLevel( &NwScavengerSpinLock ); + } + + WorkQueueItem = ALLOCATE_POOL( NonPagedPool, sizeof( *WorkQueueItem ) ); + if ( WorkQueueItem == NULL ) { + FREE_POOL( Mdl->MappedSystemVa ); + FREE_MDL( Mdl ); + FREE_IRP( Irp ); + return( STATUS_MORE_PROCESSING_REQUIRED ); + } + + // + // Use the user buffer field as a convenient place to remember where + // the address of the WorkQueueItem. We can get away with this since + // we don't let this IRP complete. + // + + Irp->UserBuffer = WorkQueueItem; + + // + // Process the line change in the FSP. + // + + ExInitializeWorkItem( WorkQueueItem, FspProcessLineChange, Irp ); + ExQueueWorkItem( WorkQueueItem, DelayedWorkQueue ); + + return( STATUS_MORE_PROCESSING_REQUIRED ); +} + +VOID +FspProcessLineChange( + IN PVOID Context + ) +{ + PIRP Irp; + ULONG ActiveHandles; + + NwReferenceUnlockableCodeSection(); + + Irp = (PIRP)Context; + + // + // Free the work queue item + // + + FREE_POOL( Irp->UserBuffer ); + Irp->UserBuffer = NULL; + + // + // Invalid all remote handles + // + + ActiveHandles = NwInvalidateAllHandles(NULL, NULL); + + // + // Now that we're done walking all the servers, it's safe + // to let the scavenger run again. + // + + WorkerRunning = FALSE; + + // + // Resubmit the IRP + // + + TdiBuildAction( + Irp, + pIpxDeviceObject, + pIpxFileObject, + CompletionLineChange, + NULL, + Irp->MdlAddress ); + + IoCallDriver ( pIpxDeviceObject, Irp ); + + NwDereferenceUnlockableCodeSection (); + return; +} +#endif + -- cgit v1.2.3