diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/isnp/nb/datagram.c | 1089 |
1 files changed, 1089 insertions, 0 deletions
diff --git a/private/ntos/tdi/isnp/nb/datagram.c b/private/ntos/tdi/isnp/nb/datagram.c new file mode 100644 index 000000000..e81579d1b --- /dev/null +++ b/private/ntos/tdi/isnp/nb/datagram.c @@ -0,0 +1,1089 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + datagram.c + +Abstract: + + This module contains the code to handle datagram reception + for the Netbios module of the ISN transport. + +Author: + + Adam Barr (adamba) 28-November-1993 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "precomp.h" +#pragma hdrstop + + + +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 + + NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle); + + + if (ReferencedAddressFile != NULL) { + NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION); + } + +} /* NbiIndicateDatagram */ + + +NTSTATUS +NbiTdiSendDatagram( + IN PDEVICE Device, + IN PREQUEST Request + ) + +/*++ + +Routine Description: + + This routine sends a datagram on an address. + +Arguments: + + Device - The netbios device. + + Request - The request describing the datagram send. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + PADDRESS_FILE AddressFile; + PNB_SEND_RESERVED Reserved; + PNDIS_PACKET Packet; + TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName; + PTDI_REQUEST_KERNEL_SENDDG Parameters; + PSINGLE_LIST_ENTRY s; + PNETBIOS_CACHE CacheName; + CTELockHandle LockHandle; + NTSTATUS Status; + + // + // Make sure that the address is valid. + // + + AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request); + +#if defined(_PNP_POWER) + Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK); +#else + Status = NbiVerifyAddressFile (AddressFile); +#endif _PNP_POWER + + if (Status == STATUS_SUCCESS) { + + Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request); + RemoteName = NbiParseTdiAddress((PTRANSPORT_ADDRESS)(Parameters->SendDatagramInformation->RemoteAddress), TRUE); + + + // + // Check that datagram size is less than the maximum allowable + // by the adapters. In the worst case this would be + // 576 - 64 = 512. + // + +#if defined(_PNP_POWER) + if ( ( Parameters->SendLength + sizeof(NB_DATAGRAM) ) > Device->Bind.LineInfo.MaximumSendSize ) { + NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY); + NB_DEBUG(DATAGRAM, ("Datagram too large %d, Max allowed %d\n", Parameters->SendLength + sizeof(NB_DATAGRAM), Device->Bind.LineInfo.MaximumSendSize )); + return STATUS_INVALID_PARAMETER; + } +#else + if ( ( Parameters->SendLength + sizeof(NB_DATAGRAM) ) > Device->Bind.LineInfo.MaximumPacketSize ) { + NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY); + NB_DEBUG(DATAGRAM, ("Datagram too large %d, Max allowed %d\n", Parameters->SendLength + sizeof(NB_DATAGRAM), Device->Bind.LineInfo.MaximumPacketSize )); + return STATUS_INVALID_PARAMETER; + } +#endif _PNP_POWER + + if (RemoteName != NULL) { + + // + // Get a packet to use in this send. + // + + s = NbiPopSendPacket (Device, FALSE); + + if (s != NULL) { + + Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage); + Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]); + + // + // Check on the cache status of this name. + // + + Reserved->u.SR_DG.DatagramRequest = Request; + Reserved->u.SR_DG.AddressFile = AddressFile; + Reserved->u.SR_DG.RemoteName = RemoteName; + + REQUEST_INFORMATION (Request) = Parameters->SendLength; + + ++Device->Statistics.DatagramsSent; + ADD_TO_LARGE_INTEGER( + &Device->Statistics.DatagramBytesSent, + Parameters->SendLength); + + if (Device->Internet) { + + NB_GET_LOCK (&Device->Lock, &LockHandle); + + Status = CacheFindName( + Device, + FindNameOther, + (RemoteName == (PVOID)-1) ? NULL : (PUCHAR)RemoteName->NetbiosName, + &CacheName); + + if (Status == STATUS_PENDING) { + + // + // A request for routes to this name has been + // sent out on the net, we queue up this datagram + // request and processing will be resumed when + // we get a response. + // + + NB_DEBUG2 (CONNECTION, ("Queueing up datagram %lx on %lx\n", + Request, AddressFile)); + + NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM); + + InsertTailList( + &Device->WaitingDatagrams, + &Reserved->WaitLinkage); + + NB_FREE_LOCK (&Device->Lock, LockHandle); + + } else if (Status == STATUS_SUCCESS) { + + NB_DEBUG2 (CONNECTION, ("Found datagram cached %lx on %lx\n", + Request, AddressFile)); + + // + // We reference the cache name entry so it won't + // go away while we are using it. + // + + Reserved->u.SR_DG.Cache = CacheName; + Reserved->u.SR_DG.CurrentNetwork = 0; + ++CacheName->ReferenceCount; + + NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM); + + NB_FREE_LOCK (&Device->Lock, LockHandle); + + Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]); + if ( REQUEST_NDIS_BUFFER(Request) ) { + NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Request)); + } + + NbiTransmitDatagram( + Reserved); + + Status = STATUS_PENDING; + + } else { + + // + // Only this failure gets passed back up to + // the caller, to avoid confusing the browser. + // + + if (Status != STATUS_DEVICE_DOES_NOT_EXIST) { + + Status = STATUS_SUCCESS; + + } else { + + REQUEST_INFORMATION (Request) = 0; + } + NB_FREE_LOCK (&Device->Lock, LockHandle); + + ExInterlockedPushEntrySList( + &Device->SendPacketList, + s, + &NbiGlobalPoolInterlock); + + + + } + + } else { + + // + // We are not in internet mode, so we do not + // need to do the name discovery. + // + + NB_DEBUG2 (CONNECTION, ("Sending datagram direct %lx on %lx\n", + Request, AddressFile)); + + Reserved->u.SR_DG.Cache = NULL; + + NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM); + + Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]); + + if ( REQUEST_NDIS_BUFFER(Request) ) { + NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Request)); + } + NbiTransmitDatagram( + Reserved); + + Status = STATUS_PENDING; + + } + + } else { + + // + // Could not allocate a packet for the datagram. + // + + NB_DEBUG (DATAGRAM, ("Couldn't get packet to send DG %lx\n", Request)); + + Status = STATUS_INSUFFICIENT_RESOURCES; + + } + + } else { + + // + // There is no netbios remote address specified. + // + + NB_DEBUG (DATAGRAM, ("No netbios address in DG %lx\n", Request)); + Status = STATUS_BAD_NETWORK_PATH; + + } + + NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY); + + } else { + + NB_DEBUG (DATAGRAM, ("Invalid address file for DG %lx\n", Request)); + + } + + return Status; + +} /* NbiTdiSendDatagram */ + + +VOID +NbiTransmitDatagram( + IN PNB_SEND_RESERVED Reserved + ) + +/*++ + +Routine Description: + + This routine sends a datagram to the next net in the + cache entry for the remote name. + +Arguments: + + Reserved - The reserved section of the packet that has + been allocated for this send. Reserved->u.SR_DG.Cache + will be NULL if Internet mode is off, otherwise it + will contain the cache entry to use when sending + this datagram. + +Return Value: + + None. + +--*/ + +{ + + PNDIS_PACKET Packet; + PNETBIOS_CACHE CacheName; + NB_CONNECTIONLESS UNALIGNED * Header; + ULONG HeaderLength; + ULONG PacketLength; + NDIS_STATUS NdisStatus; + IPX_LOCAL_TARGET TempLocalTarget; + PIPX_LOCAL_TARGET LocalTarget; + PDEVICE Device = NbiDevice; + + + Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]); + + + CTEAssert (Reserved->SendInProgress == FALSE); + Reserved->SendInProgress = TRUE; + Reserved->Type = SEND_TYPE_DATAGRAM; + + CacheName = Reserved->u.SR_DG.Cache; + + + // + // Fill in the IPX header -- the default header has the broadcast + // address on net 0 as the destination IPX address, so we modify + // that for the current netbios cache entry if needed. + // + + Header = (NB_CONNECTIONLESS UNALIGNED *) + (&Reserved->Header[Device->Bind.IncludedHeaderOffset]); + RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER)); + + if (CacheName == NULL) { + +#if defined(_PNP_POWER) + // + // IPX will send this on all the Nics. + // + TempLocalTarget.NicHandle.NicId = 0; +#else + TempLocalTarget.NicId = 1; +#endif _PNP_POWER + RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6); + LocalTarget = &TempLocalTarget; + + } else { + + if (CacheName->Unique) { + RtlCopyMemory (Header->IpxHeader.DestinationNetwork, &CacheName->FirstResponse, 12); + } else { + *(UNALIGNED ULONG *)Header->IpxHeader.DestinationNetwork = CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].Network; + RtlCopyMemory (&Header->IpxHeader.DestinationNode, BroadcastAddress, 6); + } + + LocalTarget = &CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].LocalTarget; + + } + + HeaderLength = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM); + + PacketLength = HeaderLength + REQUEST_INFORMATION(Reserved->u.SR_DG.DatagramRequest); + + Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256); + Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256); + Header->IpxHeader.PacketType = 0x04; + + + // + // Now fill in the Netbios header. + // + + Header->Datagram.ConnectionControlFlag = 0x00; + RtlCopyMemory( + Header->Datagram.SourceName, + Reserved->u.SR_DG.AddressFile->Address->NetbiosAddress.NetbiosName, + 16); + + if (Reserved->u.SR_DG.RemoteName != (PVOID)-1) { + + // + // This is a directed, as opposed to broadcast, datagram. + // + + Header->Datagram.DataStreamType = NB_CMD_DATAGRAM; + RtlCopyMemory( + Header->Datagram.DestinationName, + Reserved->u.SR_DG.RemoteName->NetbiosName, + 16); + + } else { + + Header->Datagram.DataStreamType = NB_CMD_BROADCAST_DATAGRAM; + RtlZeroMemory( + Header->Datagram.DestinationName, + 16); + + } + + + // + // Now send the frame (IPX will adjust the length of the + // first buffer and the whole frame correctly). + // + + NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), HeaderLength); + if ((NdisStatus = + (*Device->Bind.SendHandler)( + LocalTarget, + Packet, + PacketLength, + HeaderLength)) != STATUS_PENDING) { + + NbiSendComplete( + Packet, + NdisStatus); + + } + +} /* NbiTransmitDatagram */ + + +NTSTATUS +NbiTdiReceiveDatagram( + IN PDEVICE Device, + IN PREQUEST Request + ) + +/*++ + +Routine Description: + + This routine performs the TdiReceiveDatagram request for the transport + provider. Receive datagrams just get queued up to an address, and are + completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at + the address. + +Arguments: + + Request - Describes this request. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + + NTSTATUS Status; + PADDRESS Address; + PADDRESS_FILE AddressFile; + CTELockHandle LockHandle; + CTELockHandle CancelLH; + + + AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request); + +#if defined(_PNP_POWER) + Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK); +#else + Status = NbiVerifyAddressFile (AddressFile); +#endif _PNP_POWER + + if (Status != STATUS_SUCCESS) { + return Status; + } + + Address = AddressFile->Address; + + NB_GET_CANCEL_LOCK( &CancelLH ); + NB_GET_LOCK (&Address->Lock, &LockHandle); + + if (AddressFile->State != ADDRESSFILE_STATE_OPEN) { + + NB_FREE_LOCK (&Address->Lock, LockHandle); + NB_FREE_CANCEL_LOCK( CancelLH ); + NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY); + return STATUS_INVALID_HANDLE; + } + + + if (Request->Cancel) { + + NB_FREE_LOCK (&Address->Lock, LockHandle); + NB_FREE_CANCEL_LOCK( CancelLH ); + NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY); + return STATUS_CANCELLED; + } + + InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request)); + + IoSetCancelRoutine (Request, NbiCancelReceiveDatagram); + + NB_DEBUG2 (DATAGRAM, ("RDG posted on %lx\n", AddressFile)); + + NbiTransferReferenceAddressFile (AddressFile, AFREF_VERIFY, AFREF_RCV_DGRAM); + + NB_FREE_LOCK (&Address->Lock, LockHandle); + NB_FREE_CANCEL_LOCK( CancelLH ); + + return STATUS_PENDING; + +} /* NbiTdiReceiveDatagram */ + + +VOID +NbiCancelReceiveDatagram( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + This routine is called by the I/O system to cancel a receive + datagram. The datagram is found on the address file's receive + datagram queue. + + NOTE: This routine is called with the CancelSpinLock held and + is responsible for releasing it. + +Arguments: + + DeviceObject - Pointer to the device object for this driver. + + Irp - Pointer to the request packet representing the I/O request. + +Return Value: + + none. + +--*/ + +{ + + PLIST_ENTRY p; + PADDRESS_FILE AddressFile; + PADDRESS Address; + PREQUEST Request = (PREQUEST)Irp; + BOOLEAN Found; + NB_DEFINE_LOCK_HANDLE(LockHandle) + + + CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) && + (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM)); + + CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE); + + AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request); + Address = AddressFile->Address; + + Found = FALSE; + + NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); + + for (p = AddressFile->ReceiveDatagramQueue.Flink; + p != &AddressFile->ReceiveDatagramQueue; + p = p->Flink) { + + if (LIST_ENTRY_TO_REQUEST(p) == Request) { + + RemoveEntryList (p); + Found = TRUE; + break; + } + } + + NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle); + IoReleaseCancelSpinLock (Irp->CancelIrql); + + if (Found) { + + NB_DEBUG (DATAGRAM, ("Cancelled datagram on %lx\n", AddressFile)); + + REQUEST_INFORMATION(Request) = 0; + REQUEST_STATUS(Request) = STATUS_CANCELLED; + + NbiCompleteRequest (Request); + NbiFreeRequest((PDEVICE)DeviceObject, Request); + + NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM); + + } + +} /* NbiCancelReceiveDatagram */ + |