Пример #1
0
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) {
Пример #2
0
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