Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1109 lines
33 KiB

/*++
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 sl;
PSLIST_ENTRY s;
PNB_RECEIVE_RESERVED ReceiveReserved;
PNB_RECEIVE_BUFFER ReceiveBuffer;
ULONG DataOffset;
UINT BytesTransferred;
PNDIS_PACKET Packet;
CTELockHandle LockHandle;
ULONG MediaType = -1;
//
// 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
//
// Bug#s 219325, 221483
//
if (((Address->NetbiosAddress.NetbiosName[15] == 0x1c) &&
(Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ||
(Address->NetbiosAddress.NetbiosName[15] == 0x1b) )
{
//
// Cache this name only if it either came over a router or,
// it came over an NdisWan line (Bug# 38221)
//
NdisStatus = (*Device->Bind.QueryHandler) ( IPX_QUERY_MEDIA_TYPE,
&RemoteAddress->NicHandle,
&MediaType,
sizeof(MediaType),
NULL);
if (Connectionless->IpxHeader.TransportControl || (MediaType == (ULONG) NdisMediumWan)) {
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);
sl = NbiPopReceiveBuffer (Device);
if (sl == NULL) {
ExInterlockedPushEntrySList(
&Device->ReceivePacketList,
&ReceiveReserved->PoolLinkage,
&NbiGlobalPoolInterlock);
NbiDereferenceAddress (Address, AREF_FIND);
return;
}
ReceiveBuffer = CONTAINING_RECORD (sl, 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, ActualBytesCopied;
PREQUEST Request;
TA_NETBIOS_ADDRESS SourceName;
PTDI_CONNECTION_INFORMATION RemoteInformation;
PADDRESS_FILE AddressFile, ReferencedAddressFile;
PTDI_CONNECTION_INFORMATION DatagramInformation;
TDI_ADDRESS_NETBIOS * 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, DatagramInformation->RemoteAddressLength, 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,
&ActualBytesCopied);
REQUEST_INFORMATION (Request) = ActualBytesCopied;
} 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 * RemoteName;
PTDI_REQUEST_KERNEL_SENDDG Parameters;
PSLIST_ENTRY s;
PNETBIOS_CACHE CacheName;
CTELockHandle LockHandle;
NTSTATUS Status;
//
// Check that the file type is valid
//
if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE)
{
CTEAssert(FALSE);
return (STATUS_INVALID_ADDRESS_COMPONENT);
}
//
// 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), Parameters->SendDatagramInformation->RemoteAddressLength, 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 {
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 = (USHORT)ITERATIVE_NIC_ID;
#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 + (ULONG) 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;
//
// Check that the file type is valid
//
if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE)
{
CTEAssert(FALSE);
return (STATUS_INVALID_ADDRESS_COMPONENT);
}
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 */