VOID NbiProcessDatagram( IN NDIS_HANDLE MacBindingHandle, IN NDIS_HANDLE MacReceiveContext, IN PIPX_LOCAL_TARGET RemoteAddress, IN ULONG MacOptions, IN PUCHAR LookaheadBuffer, IN UINT LookaheadBufferSize, IN UINT LookaheadBufferOffset, IN UINT PacketSize, IN BOOLEAN Broadcast ) /*++ Routine Description: This routine handles datagram indications. Arguments: MacBindingHandle - A handle to use when calling NdisTransferData. MacReceiveContext - A context to use when calling NdisTransferData. RemoteAddress - The local target this packet was received from. MacOptions - The MAC options for the underlying NDIS binding. LookaheadBuffer - The lookahead buffer, starting at the IPX header. LookaheadBufferSize - The length of the lookahead data. LookaheadBufferOffset - The offset to add when calling NdisTransferData. PacketSize - The total length of the packet, starting at the IPX header. Broadcast - TRUE if the frame was a broadcast datagram. Return Value: None. --*/ { PADDRESS Address; NDIS_STATUS NdisStatus; PUCHAR NetbiosName; NB_CONNECTIONLESS UNALIGNED * Connectionless = (NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer; PDEVICE Device = NbiDevice; PSINGLE_LIST_ENTRY s; PNB_RECEIVE_RESERVED ReceiveReserved; PNB_RECEIVE_BUFFER ReceiveBuffer; ULONG DataOffset; UINT BytesTransferred; PNDIS_PACKET Packet; CTELockHandle LockHandle; // // See if there is an address that might want this. // if (Broadcast) { NetbiosName = (PVOID)-1; } else { NetbiosName = (PUCHAR)Connectionless->Datagram.DestinationName; if (Device->AddressCounts[NetbiosName[0]] == 0) { return; } } DataOffset = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM); #if defined(_PNP_POWER) if ((PacketSize < DataOffset) || (PacketSize > DataOffset + Device->CurMaxReceiveBufferSize)) { #else if ((PacketSize < DataOffset) || (PacketSize > DataOffset + Device->Bind.LineInfo.MaximumPacketSize)) { #endif _PNP_POWER NB_DEBUG (DATAGRAM, ("Datagram length %d discarded\n", PacketSize)); return; } Address = NbiFindAddress (Device, NetbiosName); if (Address == NULL) { return; } // // We need to cache the remote name if the packet came across the router. // This allows this machine to get back to the RAS client which might // have sent this datagram. We currently dont allow broadcasts to go out // on the dial-in line. // Dont cache some of the widely used group names, that would be too much // to store in cache. // #if 0 if ( Connectionless->IpxHeader.TransportControl && !( (Address->NetbiosAddress.NetbiosName[15] == 0x0 ) && (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) && !( (Address->NetbiosAddress.NetbiosName[15] == 0x01 ) && (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) && !( (Address->NetbiosAddress.NetbiosName[15] == 0x1E ) && (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) { #endif if ( Connectionless->IpxHeader.TransportControl && ( (Address->NetbiosAddress.NetbiosName[15] == 0x1c ) && (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) { PNETBIOS_CACHE CacheName; NB_GET_LOCK (&Device->Lock, &LockHandle); if ( FindInNetbiosCacheTable ( Device->NameCache, Connectionless->Datagram.SourceName, &CacheName ) != STATUS_SUCCESS ) { CacheName = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry"); if (CacheName ) { RtlCopyMemory (CacheName->NetbiosName, Connectionless->Datagram.SourceName, 16); CacheName->Unique = TRUE; CacheName->ReferenceCount = 1; RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12); CacheName->NetworksAllocated = 1; CacheName->NetworksUsed = 1; CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork); CacheName->Networks[0].LocalTarget = *RemoteAddress; NB_DEBUG2 (CACHE, ("Alloc new cache from Datagram %lx for <%.16s>\n", CacheName, CacheName->NetbiosName)); CacheName->TimeStamp = Device->CacheTimeStamp; InsertInNetbiosCacheTable( Device->NameCache, CacheName); } } else if ( CacheName->Unique ) { // // We already have an entry for this remote. We should update // the address. This is so that if the ras client dials-out // then dials-in again and gets a new address, we dont end up // caching the old address. // if ( !RtlEqualMemory( &CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12) ) { RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12); CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork); CacheName->Networks[0].LocalTarget = *RemoteAddress; } } NB_FREE_LOCK (&Device->Lock, LockHandle); } // // We need to allocate a packet and buffer for the transfer. // s = NbiPopReceivePacket (Device); if (s == NULL) { NbiDereferenceAddress (Address, AREF_FIND); return; } ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage); s = NbiPopReceiveBuffer (Device); if (s == NULL) { ExInterlockedPushEntrySList( &Device->ReceivePacketList, &ReceiveReserved->PoolLinkage, &NbiGlobalPoolInterlock); NbiDereferenceAddress (Address, AREF_FIND); return; } ReceiveBuffer = CONTAINING_RECORD (s, NB_RECEIVE_BUFFER, PoolLinkage); Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]); ReceiveReserved->u.RR_DG.ReceiveBuffer = ReceiveBuffer; // // Now that we have a packet and a buffer, set up the transfer. // The indication to the TDI clients will happen at receive // complete time. // NdisChainBufferAtFront (Packet, ReceiveBuffer->NdisBuffer); ReceiveBuffer->Address = Address; ReceiveReserved->Type = RECEIVE_TYPE_DATAGRAM; CTEAssert (!ReceiveReserved->TransferInProgress); ReceiveReserved->TransferInProgress = TRUE; TdiCopyLookaheadData( &ReceiveBuffer->RemoteName, Connectionless->Datagram.SourceName, 16, (MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) ? TDI_RECEIVE_COPY_LOOKAHEAD : 0); (*Device->Bind.TransferDataHandler) ( &NdisStatus, MacBindingHandle, MacReceiveContext, LookaheadBufferOffset + DataOffset, PacketSize - DataOffset, Packet, &BytesTransferred); if (NdisStatus != NDIS_STATUS_PENDING) { #if DBG if (NdisStatus == STATUS_SUCCESS) { CTEAssert (BytesTransferred == PacketSize - DataOffset); } #endif NbiTransferDataComplete( Packet, NdisStatus, BytesTransferred); } } /* NbiProcessDatagram */ VOID NbiIndicateDatagram( IN PADDRESS Address, IN PUCHAR RemoteName, IN PUCHAR Data, IN ULONG DataLength ) /*++ Routine Description: This routine indicates a datagram to clients on the specified address. It is called from NbiReceiveComplete. Arguments: Address - The address the datagram was sent to. RemoteName - The source netbios address of the datagram. Data - The data. DataLength - The length of the data. Return Value: None. --*/ { PLIST_ENTRY p, q; PIRP Irp; ULONG IndicateBytesCopied; PREQUEST Request; TA_NETBIOS_ADDRESS SourceName; PTDI_CONNECTION_INFORMATION RemoteInformation; PADDRESS_FILE AddressFile, ReferencedAddressFile; PTDI_CONNECTION_INFORMATION DatagramInformation; TDI_ADDRESS_NETBIOS UNALIGNED * DatagramAddress; PDEVICE Device = NbiDevice; NB_DEFINE_LOCK_HANDLE (LockHandle) CTELockHandle CancelLH; // // Update our statistics. // ++Device->Statistics.DatagramsReceived; ADD_TO_LARGE_INTEGER( &Device->Statistics.DatagramBytesReceived, DataLength); // // Call the client's ReceiveDatagram indication handler. He may // want to accept the datagram that way. // TdiBuildNetbiosAddress (RemoteName, FALSE, &SourceName); ReferencedAddressFile = NULL; NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); for (p = Address->AddressFileDatabase.Flink; p != &Address->AddressFileDatabase; p = p->Flink) { // // Find the next open address file in the list. // AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage); if (AddressFile->State != ADDRESSFILE_STATE_OPEN) { continue; } NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION); // // do we have a datagram receive request outstanding? If so, we will // satisfy it first. We run through the receive datagram queue // until we find a datagram with no remote address or with // this sender's address as its remote address. // for (q = AddressFile->ReceiveDatagramQueue.Flink; q != &AddressFile->ReceiveDatagramQueue; q = q->Flink) { Request = LIST_ENTRY_TO_REQUEST (q); DatagramInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG) REQUEST_PARAMETERS(Request))->ReceiveDatagramInformation; if (DatagramInformation && (DatagramInformation->RemoteAddress) && (DatagramAddress = NbiParseTdiAddress(DatagramInformation->RemoteAddress, FALSE)) && (!RtlEqualMemory( RemoteName, DatagramAddress->NetbiosName, 16))) { continue; } break; } if (q != &AddressFile->ReceiveDatagramQueue) { RemoveEntryList (q); NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle); if (ReferencedAddressFile != NULL) { NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION); } ReferencedAddressFile = AddressFile; // // Do this deref now, we hold another one so it // will stick around. // NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM); IndicateBytesCopied = 0; // // Fall past the else to copy the data. // } else { NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle); if (ReferencedAddressFile != NULL) { NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION); } ReferencedAddressFile = AddressFile; // // No receive datagram requests; is there a kernel client? // if (AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE_DATAGRAM]) { IndicateBytesCopied = 0; if ((*AddressFile->ReceiveDatagramHandler)( AddressFile->HandlerContexts[TDI_EVENT_RECEIVE_DATAGRAM], sizeof (TA_NETBIOS_ADDRESS), &SourceName, 0, NULL, TDI_RECEIVE_COPY_LOOKAHEAD, DataLength, // indicated DataLength, // available &IndicateBytesCopied, Data, &Irp) != STATUS_MORE_PROCESSING_REQUIRED) { // // The client did not return a request, go to the // next address file. // NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); continue; } Request = NbiAllocateRequest (Device, Irp); IF_NOT_ALLOCATED(Request) { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); continue; } } else { // // The client has nothing posted and no handler, // go on to the next address file. // NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); continue; } } // // We have a request; copy the actual user data. // if ( REQUEST_NDIS_BUFFER (Request) ) { REQUEST_STATUS(Request) = TdiCopyBufferToMdl ( Data, IndicateBytesCopied, DataLength - IndicateBytesCopied, REQUEST_NDIS_BUFFER (Request), 0, &REQUEST_INFORMATION (Request)); } else { // // No buffer specified in the request // REQUEST_INFORMATION (Request) = 0; // // If there was any data to be copied, return error o/w success // REQUEST_STATUS(Request) = ( (DataLength - IndicateBytesCopied) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS ); } // // Copy the addressing information. // RemoteInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG) REQUEST_PARAMETERS(Request))->ReturnDatagramInformation; if (RemoteInformation != NULL) { RtlCopyMemory( (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress, &SourceName, (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ? RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS)); } NB_GET_CANCEL_LOCK( &CancelLH ); IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); NB_FREE_CANCEL_LOCK( CancelLH ); NbiCompleteRequest (Request); NbiFreeRequest (Device, Request); NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); } // end of for loop through the address files
NTSTATUS StIndicateDatagram( IN PDEVICE_CONTEXT DeviceContext, IN PTP_ADDRESS Address, IN PUCHAR Header, IN ULONG Length ) /*++ Routine Description: This routine processes an incoming DATAGRAM or DATAGRAM_BROADCAST frame. BROADCAST and normal datagrams have the same receive logic, except for broadcast datagrams Address will be the broadcast address. When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of this routine will continue to call us for each address for the device context. When we return STATUS_SUCCESS, the caller will switch to the next address. When we return any other status code, including STATUS_ABANDONED, the caller will stop distributing the frame. Arguments: DeviceContext - Pointer to our device context. Address - Pointer to the transport address object. StHeader - Pointer to a buffer that contains the receive datagram. The first byte of information is the ST header. Length - The length of the MDL pointed to by StHeader. Return Value: NTSTATUS - status of operation. --*/ { NTSTATUS status; PLIST_ENTRY p, q; PIRP irp; PIO_STACK_LOCATION irpSp; PTP_REQUEST Request; ULONG IndicateBytesCopied, MdlBytesCopied; KIRQL oldirql; TA_NETBIOS_ADDRESS SourceName; TA_NETBIOS_ADDRESS DestinationName; PTDI_CONNECTION_INFORMATION remoteInformation; ULONG returnLength; PTP_ADDRESS_FILE addressFile, prevaddressFile; PST_HEADER StHeader; // // If this datagram wasn't big enough for a transport header, then don't // let the caller look at any data. // if (Length < sizeof(ST_HEADER)) { return STATUS_ABANDONED; } // // Update our statistics. // ++DeviceContext->DatagramsReceived; ADD_TO_LARGE_INTEGER( &DeviceContext->DatagramBytesReceived, Length - sizeof(ST_HEADER)); // // Call the client's ReceiveDatagram indication handler. He may // want to accept the datagram that way. // StHeader = (PST_HEADER)Header; TdiBuildNetbiosAddress (StHeader->Source, FALSE, &SourceName); TdiBuildNetbiosAddress (StHeader->Destination, FALSE, &DestinationName); ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); // // Find the first open address file in the list. // p = Address->AddressFileDatabase.Flink; while (p != &Address->AddressFileDatabase) { addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage); if (addressFile->State != ADDRESSFILE_STATE_OPEN) { p = p->Flink; continue; } StReferenceAddressFile(addressFile); break; } while (p != &Address->AddressFileDatabase) { // // do we have a datagram receive request outstanding? If so, we will // satisfy it first. // // NOTE: We should check if this receive dataframs is for // a specific address. // q = RemoveHeadList (&addressFile->ReceiveDatagramQueue); RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); if (q != &addressFile->ReceiveDatagramQueue) { Request = CONTAINING_RECORD (q, TP_REQUEST, Linkage); // // Copy the actual user data. // MdlBytesCopied = 0; status = TdiCopyBufferToMdl ( StHeader, sizeof(ST_HEADER), // offset Length - sizeof(ST_HEADER), // length Request->IoRequestPacket->MdlAddress, 0, &MdlBytesCopied); irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket); remoteInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))-> ReturnDatagramInformation; if (remoteInformation != NULL) { try { if (remoteInformation->RemoteAddressLength != 0) { if (remoteInformation->RemoteAddressLength >= sizeof (TA_NETBIOS_ADDRESS)) { RtlCopyMemory ( (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress, &SourceName, sizeof (TA_NETBIOS_ADDRESS)); returnLength = sizeof(TA_NETBIOS_ADDRESS); remoteInformation->RemoteAddressLength = returnLength; } else { RtlCopyMemory ( (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress, &SourceName, remoteInformation->RemoteAddressLength); returnLength = remoteInformation->RemoteAddressLength; remoteInformation->RemoteAddressLength = returnLength; } } else { returnLength = 0; } status = STATUS_SUCCESS; } except (EXCEPTION_EXECUTE_HANDLER) { returnLength = 0; status = GetExceptionCode (); } } StCompleteRequest (Request, STATUS_SUCCESS, MdlBytesCopied); } else { // // no receive datagram requests; is there a kernel client? // if (addressFile->RegisteredReceiveDatagramHandler) {
NTSTATUS LpxTdiQueryInformation( IN PDEVICE_CONTEXT DeviceContext, IN PIRP Irp ) /*++ Routine Description: This routine performs the TdiQueryInformation request for the transport provider. Arguments: Irp - the Irp for the requested operation. Return Value: NTSTATUS - status of operation. --*/ { NTSTATUS status; PIO_STACK_LOCATION irpSp; PTDI_REQUEST_KERNEL_QUERY_INFORMATION query; PTA_NETBIOS_ADDRESS broadcastAddress; PTDI_PROVIDER_STATISTICS ProviderStatistics; PTDI_CONNECTION_INFO ConnectionInfo; ULONG TargetBufferLength; LARGE_INTEGER timeout = {0,0}; PTP_CONNECTION Connection; PTP_ADDRESS_FILE AddressFile; PTP_ADDRESS Address; struct { ULONG ActivityCount; TA_NETBIOS_ADDRESS TaAddressBuffer; } AddressInfo; PTRANSPORT_ADDRESS TaAddress; TDI_DATAGRAM_INFO DatagramInfo; BOOLEAN UsedConnection; PLIST_ENTRY p; KIRQL oldirql; ULONG BytesCopied; // // what type of status do we want? // irpSp = IoGetCurrentIrpStackLocation (Irp); query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&irpSp->Parameters; switch (query->QueryType) { #if 0 case 0x12345678: { typedef struct _LPX_CONNECTION_STATUS { UCHAR LocalName[16]; UCHAR RemoteName[16]; BOOLEAN SendActive; BOOLEAN ReceiveQueued; BOOLEAN ReceiveActive; BOOLEAN ReceiveWakeUp; ULONG Flags; ULONG Flags2; } LPX_CONNECTION_STATUS, *PLPX_CONNECTION_STATUS; PLPX_CONNECTION_STATUS CurStatus; ULONG TotalStatus; ULONG AllowedStatus; PLIST_ENRY q; CurStatus = MmGetSystemAddressForMdl (Irp->MdlAddress); TotalStatus = 0; AllowedStatus = MmGetMdlByteCount (Irp->MdlAddress) / sizeof(LPX_CONNECTION_STATUS); for (p = DeviceContext->AddressDatabase.Flink; p != &DeviceContext->AddressDatabase; p = p->Flink) { Address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage); if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) { continue; } for (q = Address->ConnectionDatabase.Flink; q != &Address->ConnectionDatabase; q = q->Flink) { Connection = CONTAINING_RECORD (q, TP_CONNECTION, AddressList); if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) { continue; } if (TotalStatus >= AllowedStatus) { continue; } RtlMoveMemory (CurStatus->LocalName, Address->NetworkName->NetbiosName, 16); RtlMoveMemory (CurStatus->RemoteName, Connection->RemoteName, 16); CurStatus->Flags = Connection->Flags; CurStatus->Flags2 = Connection->Flags2; CurStatus->SendActive = (BOOLEAN)(!IsListEmpty(&Connection->SendQueue)); CurStatus->ReceiveQueued = (BOOLEAN)(!IsListEmpty(&Connection->ReceiveQueue)); CurStatus->ReceiveActive = (BOOLEAN)((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0); CurStatus->ReceiveWakeUp = (BOOLEAN)((Connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) != 0); ++CurStatus; ++TotalStatus; } } Irp->IoStatus.Information = TotalStatus * sizeof(LPX_CONNECTION_STATUS); status = STATUS_SUCCESS; } break; #endif case TDI_QUERY_CONNECTION_INFO: // // Connection info is queried on a connection, // verify this. // if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) { ASSERT( FALSE ); return STATUS_INVALID_CONNECTION; } Connection = irpSp->FileObject->FsContext; status = LpxVerifyConnectionObject (Connection); if (!NT_SUCCESS (status)) { ASSERT( FALSE ); #if DBG LpxPrint2 ("TdiQueryInfo: Invalid Connection %p Irp %p\n", Connection, Irp); #endif return status; } ConnectionInfo = ExAllocatePoolWithTag ( NonPagedPool, sizeof (TDI_CONNECTION_INFO), LPX_MEM_TAG_TDI_CONNECTION_INFO); if (ConnectionInfo == NULL) { PANIC ("LpxQueryInfo: Cannot allocate connection info!\n"); LpxWriteResourceErrorLog( DeviceContext, EVENT_TRANSPORT_RESOURCE_POOL, 6, sizeof(TDI_CONNECTION_INFO), 0); status = STATUS_INSUFFICIENT_RESOURCES; #if __LPX__ } else { LARGE_INTEGER delay; RtlZeroMemory ((PVOID)ConnectionInfo, sizeof(TDI_CONNECTION_INFO)); ConnectionInfo->Event; ConnectionInfo->TransmittedTsdus = Connection->LpxSmp.NumberOfSendPackets; ConnectionInfo->ReceivedTsdus = Connection->LpxSmp.NumberofRecvPackets; ConnectionInfo->TransmissionErrors = Connection->LpxSmp.NumberOfSendRetransmission; ConnectionInfo->ReceiveErrors = Connection->LpxSmp.DropOfReceivePacket; if (Connection->LpxSmp.ResponseTimeOfLargeSendRequests.QuadPart) { ConnectionInfo->Throughput.QuadPart = Connection->LpxSmp.BytesOfLargeSendRequests.QuadPart * 1000 * 1000 * 10 / Connection->LpxSmp.ResponseTimeOfLargeSendRequests.QuadPart; } else if (Connection->LpxSmp.ResponseTimeOfSmallSendRequests.QuadPart) { ConnectionInfo->Throughput.QuadPart = Connection->LpxSmp.BytesOfSmallSendRequests.QuadPart * 1000 * 1000 * 10 / Connection->LpxSmp.ResponseTimeOfSmallSendRequests.QuadPart; } if (Connection->LpxSmp.NumberofSmallSendRequests) { delay.QuadPart = Connection->LpxSmp.ResponseTimeOfSmallSendRequests.QuadPart / Connection->LpxSmp.NumberofSmallSendRequests; ConnectionInfo->Delay.HighPart = -1L; ConnectionInfo->Delay.LowPart = (ULONG) - ((LONG)(delay.LowPart)); // 100 ns } ConnectionInfo->SendBufferSize; ConnectionInfo->ReceiveBufferSize; ConnectionInfo->Unreliable; status = TdiCopyBufferToMdl ( (PVOID)ConnectionInfo, 0L, sizeof(TDI_CONNECTION_INFO), Irp->MdlAddress, 0, &BytesCopied); Irp->IoStatus.Information = BytesCopied; ExFreePool (ConnectionInfo); } #endif LpxDereferenceConnection ("query connection info", Connection, CREF_BY_ID); break; case LPXTDI_QUERY_CONNECTION_TRANSSTAT: { TRANS_STAT transStat; // // Connection info is queried on a connection, // verify this. // if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) { ASSERT( FALSE ); return STATUS_INVALID_CONNECTION; } Connection = irpSp->FileObject->FsContext; status = LpxVerifyConnectionObject (Connection); if (!NT_SUCCESS (status)) { ASSERT( FALSE ); #if DBG LpxPrint2 ("TdiTransStat: Invalid Connection %p Irp %p\n", Connection, Irp); #endif return status; } transStat.PacketLoss = InterlockedExchange(&Connection->LpxSmp.TransportStats.PacketLoss, 0); transStat.Retransmits = InterlockedExchange(&Connection->LpxSmp.TransportStats.Retransmits, 0); status = TdiCopyBufferToMdl ( &transStat, 0L, sizeof(TRANS_STAT), Irp->MdlAddress, 0, &BytesCopied); Irp->IoStatus.Information = BytesCopied; LpxDereferenceConnection ("query connection info", Connection, CREF_BY_ID); break; } case TDI_QUERY_ADDRESS_INFO: if (irpSp->FileObject->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) { AddressFile = irpSp->FileObject->FsContext; status = LpxVerifyAddressObject(AddressFile); if (!NT_SUCCESS (status)) { #if DBG LpxPrint2 ("TdiQueryInfo: Invalid AddressFile %p Irp %p\n", AddressFile, Irp); #endif return status; } UsedConnection = FALSE; } else if (irpSp->FileObject->FsContext2 == (PVOID)TDI_CONNECTION_FILE) { Connection = irpSp->FileObject->FsContext; status = LpxVerifyConnectionObject (Connection); if (!NT_SUCCESS (status)) { #if DBG LpxPrint2 ("TdiQueryInfo: Invalid Connection %p Irp %p\n", Connection, Irp); #endif return status; } AddressFile = Connection->AddressFile; UsedConnection = TRUE; } else { return STATUS_INVALID_ADDRESS; } Address = AddressFile->Address; #if 0 TdiBuildNetbiosAddress( Address->NetworkName->NetbiosName, (BOOLEAN)(Address->Flags & ADDRESS_FLAGS_GROUP ? TRUE : FALSE), &AddressInfo.TaAddressBuffer); #else TdiBuildNetbiosAddress( Address->NetworkName->Node, FALSE, &AddressInfo.TaAddressBuffer); #endif // // Count the active addresses. // AddressInfo.ActivityCount = 0; ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); for (p = Address->AddressFileDatabase.Flink; p != &Address->AddressFileDatabase; p = p->Flink) { ++AddressInfo.ActivityCount; } RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); status = TdiCopyBufferToMdl ( &AddressInfo, 0, sizeof(ULONG) + sizeof(TA_NETBIOS_ADDRESS), Irp->MdlAddress, 0, &BytesCopied); Irp->IoStatus.Information = BytesCopied; if (UsedConnection) { LpxDereferenceConnection ("query address info", Connection, CREF_BY_ID); } else { LpxDereferenceAddress ("query address info", Address, AREF_VERIFY); } break; case TDI_QUERY_BROADCAST_ADDRESS: // // for this provider, the broadcast address is a zero byte name, // contained in a Transport address structure. // broadcastAddress = ExAllocatePoolWithTag ( NonPagedPool, sizeof (TA_NETBIOS_ADDRESS), LPX_MEM_TAG_TDI_QUERY_BUFFER); if (broadcastAddress == NULL) { PANIC ("LpxQueryInfo: Cannot allocate broadcast address!\n"); LpxWriteResourceErrorLog( DeviceContext, EVENT_TRANSPORT_RESOURCE_POOL, 2, sizeof(TA_NETBIOS_ADDRESS), 0); status = STATUS_INSUFFICIENT_RESOURCES; } else { broadcastAddress->TAAddressCount = 1; broadcastAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS; broadcastAddress->Address[0].AddressLength = 0; Irp->IoStatus.Information = sizeof (broadcastAddress->TAAddressCount) + sizeof (broadcastAddress->Address[0].AddressType) + sizeof (broadcastAddress->Address[0].AddressLength); BytesCopied = (ULONG)Irp->IoStatus.Information; status = TdiCopyBufferToMdl ( (PVOID)broadcastAddress, 0L, BytesCopied, Irp->MdlAddress, 0, &BytesCopied); Irp->IoStatus.Information = BytesCopied; ExFreePool (broadcastAddress); } break; case TDI_QUERY_PROVIDER_INFO: status = TdiCopyBufferToMdl ( &(DeviceContext->Information), 0, sizeof (TDI_PROVIDER_INFO), Irp->MdlAddress, 0, &BytesCopied); Irp->IoStatus.Information = BytesCopied; break; case TDI_QUERY_PROVIDER_STATISTICS: // // This information is probablt available somewhere else. // LpxGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength); if (TargetBufferLength < sizeof(TDI_PROVIDER_STATISTICS) + ((LPX_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS))) { Irp->IoStatus.Information = 0; status = STATUS_BUFFER_OVERFLOW; } else { ProviderStatistics = ExAllocatePoolWithTag( NonPagedPool, sizeof(TDI_PROVIDER_STATISTICS) + ((LPX_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)), LPX_MEM_TAG_TDI_PROVIDER_STATS); if (ProviderStatistics == NULL) { PANIC ("LpxQueryInfo: Cannot allocate provider statistics!\n"); LpxWriteResourceErrorLog( DeviceContext, EVENT_TRANSPORT_RESOURCE_POOL, 7, sizeof(TDI_PROVIDER_STATISTICS), 0); status = STATUS_INSUFFICIENT_RESOURCES; } else { LpxStoreProviderStatistics (DeviceContext, ProviderStatistics); status = TdiCopyBufferToMdl ( (PVOID)ProviderStatistics, 0L, sizeof(TDI_PROVIDER_STATISTICS) + ((LPX_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)), Irp->MdlAddress, 0, &BytesCopied); Irp->IoStatus.Information = BytesCopied; ExFreePool (ProviderStatistics); } } break; case TDI_QUERY_SESSION_STATUS: status = STATUS_NOT_IMPLEMENTED; break; case TDI_QUERY_ADAPTER_STATUS: ASSERT( FALSE ); status = STATUS_NOT_IMPLEMENTED; break; case TDI_QUERY_FIND_NAME: ASSERT( FALSE ); status = STATUS_NOT_IMPLEMENTED; break; case TDI_QUERY_DATA_LINK_ADDRESS: case TDI_QUERY_NETWORK_ADDRESS: TaAddress = (PTRANSPORT_ADDRESS)&AddressInfo.TaAddressBuffer; TaAddress->TAAddressCount = 1; TaAddress->Address[0].AddressLength = 6; if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) { TaAddress->Address[0].AddressType = DeviceContext->MacInfo.MediumAsync ? NdisMediumWan : DeviceContext->MacInfo.MediumType; } else { TaAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_UNSPEC; } RtlCopyMemory (TaAddress->Address[0].Address, DeviceContext->LocalAddress.Address, 6); status = TdiCopyBufferToMdl ( &AddressInfo.TaAddressBuffer, 0, sizeof(TRANSPORT_ADDRESS)+5, Irp->MdlAddress, 0, &BytesCopied); Irp->IoStatus.Information = BytesCopied; break; case TDI_QUERY_DATAGRAM_INFO: DatagramInfo.MaximumDatagramBytes = 0; DatagramInfo.MaximumDatagramCount = 0; status = TdiCopyBufferToMdl ( &DatagramInfo, 0, sizeof(DatagramInfo), Irp->MdlAddress, 0, &BytesCopied); Irp->IoStatus.Information = BytesCopied; break; default: status = STATUS_INVALID_DEVICE_REQUEST; break; } return status; } /* LpxTdiQueryInformation */