VOID StSendDatagramCompletion( IN PTP_ADDRESS Address, IN PNDIS_PACKET NdisPacket, IN NDIS_STATUS NdisStatus ) /*++ Routine Description: This routine is called as an I/O completion handler at the time a StSendUIMdlFrame send request is completed. Because this handler is only associated with StSendUIMdlFrame, and because StSendUIMdlFrame is only used with datagrams and broadcast datagrams, we know that the I/O being completed is a datagram. Here we complete the in-progress datagram, and start-up the next one if there is one. Arguments: Address - Pointer to a transport address on which the datagram is queued. NdisPacket - pointer to the NDIS packet describing this request. Return Value: none. --*/ { PTP_REQUEST Request; PLIST_ENTRY p; KIRQL oldirql; PNDIS_BUFFER HeaderBuffer; UNREFERENCED_PARAMETER(NdisPacket); StReferenceAddress ("Complete datagram", Address); // // Dequeue the current request and return it to the client. Release // our hold on the send datagram queue. // // *** There may be no current request, if the one that was queued // was aborted or timed out. // ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); p = RemoveHeadList (&Address->SendDatagramQueue); if (p != &Address->SendDatagramQueue) { RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage); // // Strip off and unmap the buffers describing data and header. // NdisUnchainBufferAtFront (Address->Packet->NdisPacket, &HeaderBuffer); // drop the rest of the packet NdisReinitializePacket (Address->Packet->NdisPacket); NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL; NdisChainBufferAtFront (Address->Packet->NdisPacket, HeaderBuffer); // // Ignore NdisStatus; datagrams always "succeed". // StCompleteRequest (Request, STATUS_SUCCESS, Request->Buffer2Length); ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS; RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); // // Send more datagrams on the Address if possible. // StSendDatagramsOnAddress (Address); // do more datagrams. } else { Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS; RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); } StDereferenceAddress ("Complete datagram", Address); } /* StSendDatagramCompletion */
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) {