/*++ Copyright (c) 1990-1995 Microsoft Corporation Module Name: sendm.c Abstract: Author: Kyle Brandon (KyleB) Environment: Kernel mode Revision History: --*/ #include #pragma hdrstop #include "sendm.h" // // Define the module number for debug code. // #define MODULE_NUMBER MODULE_SENDM VOID ndisMCopyFromPacketToBuffer( IN PNDIS_PACKET Packet, IN UINT Offset, IN UINT BytesToCopy, OUT PCHAR Buffer, OUT PUINT BytesCopied ) /*++ Routine Description: Copy from an ndis packet into a buffer. Arguments: Packet - The packet to copy from. Offset - The offset from which to start the copy. BytesToCopy - The number of bytes to copy from the packet. Buffer - The destination of the copy. BytesCopied - The number of bytes actually copied. Can be less then BytesToCopy if the packet is shorter than BytesToCopy. Return Value: None --*/ { // // Holds the number of ndis buffers comprising the packet. // UINT NdisBufferCount; // // Points to the buffer from which we are extracting data. // PNDIS_BUFFER CurrentBuffer; // // Holds the virtual address of the current buffer. // PVOID VirtualAddress; // // Holds the length of the current buffer of the packet. // UINT CurrentLength; // // Keep a local variable of BytesCopied so we aren't referencing // through a pointer. // UINT LocalBytesCopied = 0; // // Take care of boundary condition of zero length copy. // *BytesCopied = 0; if (!BytesToCopy) return; // // Get the first buffer. // NdisQueryPacket(Packet, NULL, &NdisBufferCount, &CurrentBuffer, NULL); // // Could have a null packet. // if (!NdisBufferCount) return; NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength); while (LocalBytesCopied < BytesToCopy) { if (CurrentLength == 0) { NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer); // // We've reached the end of the packet. We return // with what we've done so far. (Which must be shorter // than requested. // if (!CurrentBuffer) break; NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength); continue; } // // Try to get us up to the point to start the copy. // if (Offset) { if (Offset > CurrentLength) { // // What we want isn't in this buffer. // Offset -= CurrentLength; CurrentLength = 0; continue; } else { VirtualAddress = (PCHAR)VirtualAddress + Offset; CurrentLength -= Offset; Offset = 0; } } // // Copy the data. // { // // Holds the amount of data to move. // UINT AmountToMove; AmountToMove = ((CurrentLength <= (BytesToCopy - LocalBytesCopied)) ? (CurrentLength): (BytesToCopy - LocalBytesCopied)); MoveMemory(Buffer, VirtualAddress, AmountToMove); Buffer = (PCHAR)Buffer + AmountToMove; VirtualAddress = (PCHAR)VirtualAddress + AmountToMove; LocalBytesCopied += AmountToMove; CurrentLength -= AmountToMove; } } *BytesCopied = LocalBytesCopied; } BOOLEAN FASTCALL ndisMIsLoopbackPacket( IN PNDIS_MINIPORT_BLOCK Miniport, IN PNDIS_PACKET Packet ) /*++ Routine Description: This routine will determine if a packet needs to be looped back in software. if the packet is any kind of loopback packet then it will get placed on the loopback queue and a workitem will be queued to process it later. Arguments: Miniport- Pointer to the miniport block to send the packet on. Packet - Packet to check for loopback. Return Value: Returns TRUE if the packet is self-directed. --*/ { PNDIS_BUFFER FirstBuffer; UINT Length; UINT Offset; PUCHAR BufferAddress; BOOLEAN Loopback; BOOLEAN SelfDirected; PNDIS_PACKET pNewPacket; PUCHAR Buffer; NDIS_STATUS Status; PNDIS_BUFFER pNdisBuffer; UINT HdrLength; BOOLEAN ArcEncap = TRUE; // // We should not be here if the driver handles loopback. // ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK); ASSERT(MINIPORT_AT_DPC_LEVEL); FirstBuffer = Packet->Private.Head; BufferAddress = MDL_ADDRESS(FirstBuffer); // // If the card does not do loopback, then we check if // we need to send it to ourselves, then if that is the // case we also check for it being self-directed. // switch (Miniport->MediaType) { case NdisMedium802_3: if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) { if (ETH_IS_MULTICAST(BufferAddress)) { Loopback = FALSE; SelfDirected = FALSE; break; } // // Packet is of type directed, now make sure that it // is not self-directed. // ETH_COMPARE_NETWORK_ADDRESSES_EQ( BufferAddress, Miniport->EthDB->AdapterAddress, &Loopback); SelfDirected = FALSE; break; } // // Check for the miniports that don't do loopback. // EthShouldAddressLoopBackMacro(Miniport->EthDB, BufferAddress, &Loopback, &SelfDirected); break; case NdisMedium802_5: if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) { BOOLEAN IsNotDirected; TR_IS_NOT_DIRECTED(BufferAddress + 2, &IsNotDirected); if (IsNotDirected) { Loopback = FALSE; SelfDirected = FALSE; break; } // // Packet is of type directed, now make sure that it // is not self-directed. // TR_COMPARE_NETWORK_ADDRESSES_EQ( BufferAddress + 2, Miniport->TrDB->AdapterAddress, &Loopback); SelfDirected = FALSE; break; } TrShouldAddressLoopBackMacro(Miniport->TrDB, BufferAddress +2, BufferAddress +8, &Loopback, &SelfDirected); break; case NdisMediumFddi: if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) { BOOLEAN IsMulticast; FDDI_IS_MULTICAST( BufferAddress + 1, (BufferAddress[0] & 0x40) ? FDDI_LENGTH_OF_LONG_ADDRESS : FDDI_LENGTH_OF_SHORT_ADDRESS, &IsMulticast); if (IsMulticast) { Loopback = FALSE; SelfDirected = FALSE; break; } // // Packet is of type directed, now make sure that it // is not self-directed. // FDDI_COMPARE_NETWORK_ADDRESSES_EQ( BufferAddress + 1, (BufferAddress[0] & 0x40) ? Miniport->FddiDB->AdapterLongAddress : Miniport->FddiDB->AdapterShortAddress, (BufferAddress[0] & 0x40) ? FDDI_LENGTH_OF_LONG_ADDRESS : FDDI_LENGTH_OF_SHORT_ADDRESS, &Loopback); SelfDirected = FALSE; break; } FddiShouldAddressLoopBackMacro(Miniport->FddiDB, BufferAddress + 1, // Skip FC byte to dest address. (BufferAddress[0] & 0x40) ? FDDI_LENGTH_OF_LONG_ADDRESS : FDDI_LENGTH_OF_SHORT_ADDRESS, &Loopback, &SelfDirected); break; case NdisMediumArcnet878_2: // // We just handle arcnet packets (encapsulated or not) in // a totally different manner... // SelfDirected = ndisMArcnetSendLoopback(Miniport, Packet); // // Mark the packet as having been looped back. // MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK); return(SelfDirected); break; } // // If it is not a loopback packet then get out of here. // if (!Loopback) { ASSERT(!SelfDirected); return FALSE; } // // Get the buffer length. // NdisQueryPacket(Packet, NULL, NULL, NULL, &Length); Offset = 0; // // Allocate a buffer for the packet. // pNewPacket = (PNDIS_PACKET)ALLOC_FROM_POOL(Length + sizeof(NDIS_PACKET) + sizeof(NDIS_PACKET_OOB_DATA) + sizeof(NDIS_PACKET_PRIVATE_EXTENSION) + PROTOCOL_RESERVED_SIZE_IN_PACKET, NDIS_TAG_LOOP_PKT); if (pNewPacket != NULL) { // // Get a pointer to the destination buffer. // Buffer = (PUCHAR)pNewPacket + sizeof(NDIS_PACKET) + sizeof(NDIS_PACKET_OOB_DATA) + sizeof(NDIS_PACKET_PRIVATE_EXTENSION) + PROTOCOL_RESERVED_SIZE_IN_PACKET; ZeroMemory(pNewPacket, sizeof(NDIS_PACKET) + sizeof(NDIS_PACKET_OOB_DATA) + sizeof(NDIS_PACKET_PRIVATE_EXTENSION) + PROTOCOL_RESERVED_SIZE_IN_PACKET); // // Allocate an MDL for the packet. // NdisAllocateBuffer(&Status, &pNdisBuffer, NULL, Buffer, Length); if (NDIS_STATUS_SUCCESS == Status) { // // NdisChainBufferAtFront() // pNewPacket->Private.Head = pNdisBuffer; pNewPacket->Private.Tail = pNdisBuffer; pNewPacket->Private.NdisPacketOobOffset = (USHORT)sizeof(NDIS_PACKET) + PROTOCOL_RESERVED_SIZE_IN_PACKET; ndisMCopyFromPacketToBuffer(Packet, // Packet to copy from. Offset, // Offset from beginning of packet. Length, // Number of bytes to copy. Buffer, // The destination buffer. &HdrLength);// The number of bytes copied. } else { // // Clean up the memory allocated for the packet. // FREE_POOL(pNewPacket); pNewPacket = NULL; } } // // Do we have a packet built ? // if (NULL != pNewPacket) { // // Mark the packet as having been looped back. // MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK); NDISM_LOG_PACKET(Miniport, Packet, pNewPacket, 'pool'); // // Place the packet on the loopback queue. // if (NULL == Miniport->LoopbackHead) { Miniport->LoopbackHead = pNewPacket; // // If this is the first one on the loopback queue then we need // to make sure that we pick it up later. // NDISM_DEFER_PROCESS_DEFERRED(Miniport); } else { PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LoopbackTail)->Next = pNewPacket; } Miniport->LoopbackTail = pNewPacket; // // Packet needs to have a workitem queued. // NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL); } return(SelfDirected); } BOOLEAN FASTCALL ndisMIndicateLoopback( IN PNDIS_MINIPORT_BLOCK Miniport ) /*++ Routine Description: Checks if a packet needs to be loopbacked and does so if necessary. NOTE: Must be called at DPC_LEVEL with lock HELD! Arguments: Miniport - Miniport to send to. Packet - Packet to loopback. Return Value: FALSE if the packet should be sent on the net, TRUE if it is a self-directed packet. --*/ { UINT Length; PUCHAR BufferAddress; PNDIS_PACKET Packet, QueueHead; PNDIS_PACKET_OOB_DATA pOob; NDIS_STATUS Status; BOOLEAN fReturnStatus = FALSE; // We should not be here if the driver handles loopback ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK); ASSERT(MINIPORT_AT_DPC_LEVEL); if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX)) { NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport); } // // Get a local copy of the loopback queue. // QueueHead = Miniport->LoopbackHead; Miniport->LoopbackHead = NULL; Miniport->LoopbackTail = NULL; if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX)) { NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport); } // // Loop through any loopback packets that are queue'd. // while (QueueHead != NULL) { // // Grab the first loopback packet to indicate up. // Packet = QueueHead; pOob = NDIS_OOB_DATA_FROM_PACKET(Packet); pOob->Status = NDIS_STATUS_RESOURCES; QueueHead = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next; NDISM_LOG_PACKET(Miniport, Packet, NULL, 'i'); // // Setup the packet references and packet array. // Miniport->LoopbackPacket = Packet; BufferAddress = (PUCHAR)Packet + sizeof(NDIS_PACKET) + sizeof(NDIS_PACKET_OOB_DATA) + sizeof(NDIS_PACKET_PRIVATE_EXTENSION) + PROTOCOL_RESERVED_SIZE_IN_PACKET; // // For ethernet/token-ring/fddi/encapsulated arc-net, we want to // indicate the packet using the receivepacket way. // switch (Miniport->MediaType) { case NdisMedium802_3: pOob->HeaderSize = 14; EthFilterDprIndicateReceivePacket(Miniport, &Packet, 1); break; case NdisMedium802_5: pOob->HeaderSize = 14; if (BufferAddress[8] & 0x80) { pOob->HeaderSize += (BufferAddress[14] & 0x1F); } TrFilterDprIndicateReceivePacket(Miniport, &Packet, 1); break; case NdisMediumFddi: pOob->HeaderSize = (*BufferAddress & 0x40) ? 2 * FDDI_LENGTH_OF_LONG_ADDRESS + 1: 2 * FDDI_LENGTH_OF_SHORT_ADDRESS + 1; FddiFilterDprIndicateReceivePacket(Miniport, &Packet, 1); break; } ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_PENDING); NdisFreeBuffer(Packet->Private.Head); FREE_POOL(Packet); } Miniport->LoopbackPacket = NULL; if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX)) { NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport); } // // If there are more loopback packets on the loopback // queue then we need to let process deferred know not to // dequeue the loopback workitem. // if (Miniport->LoopbackHead != NULL) { fReturnStatus = TRUE; } if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX)) { NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport); } return(fReturnStatus); } BOOLEAN FASTCALL ndisMStartSendPacketsFullDuplex( PNDIS_MINIPORT_BLOCK Miniport ) { BOOLEAN fReturn = FALSE; #ifdef NDIS_NT PNDIS_PACKET Packet; PNDIS_PACKET PrevPacket; NDIS_STATUS Status; PNDIS_PACKET_RESERVED Reserved; PNDIS_M_OPEN_BLOCK Open; UINT Flags; PPNDIS_PACKET pPktArray; // // Acquire the send lock. // ASSERT(MINIPORT_AT_DPC_LEVEL); NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMStartSendPacketsFullDuplex\n")); MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED); // // Loop and process sends. // while ((Miniport->SendResourcesAvailable != 0) && (Miniport->FirstPendingPacket != NULL)) { UINT Count; UINT ResourcesCount; UINT NumberOfPackets; // // Initialize the packet array. // pPktArray = Miniport->PacketArray; // // Place as many packets as we can in the packet array to send // to the miniport. // for (NumberOfPackets = 0; (NumberOfPackets < Miniport->MaximumSendPackets) && (Miniport->FirstPendingPacket != NULL); ) { // // Grab the packet off of the pending queue. // Packet = Miniport->FirstPendingPacket; Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); // // Remove from pending queue // Miniport->FirstPendingPacket = Reserved->Next; // // Put on finish queue // PrevPacket = Miniport->LastMiniportPacket; Miniport->LastMiniportPacket = Packet; // // Indicate the packet loopback if necessary. // if (((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) || MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) && !MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK) && ndisMIsLoopbackPacket(Miniport, Packet)) { DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Packet 0x%x is self-directed.\n", Packet)); // // Get a pointer to the open block. // DO NOT USE "Reserved->Open" TO CALL INTO THE MACRO!!!!! // Open = Reserved->Open; // // Complete the packet back to the binding. // NDISM_COMPLETE_SEND_FULL_DUPLEX( Miniport, Open, Packet, PrevPacket, NDIS_STATUS_SUCCESS); // // No, we don't want to increment the counter for the // miniport's packet array. // } else { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'inim'); // // We have to re-initialize this. // *pPktArray = Packet; NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS); // // Increment the counter for the packet array index. // NumberOfPackets++; pPktArray++; } } // // Are there any packets to send? // if (NumberOfPackets != 0) { // // Get a temp pointer to our packet array. // pPktArray = Miniport->PacketArray; Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open; // // Pass the packet array down to the miniport. // (Open->SendPacketsHandler)( Miniport->MiniportAdapterContext, Miniport->PacketArray, NumberOfPackets); // // First check to see if the LastMiniportPacket is NULL. // If it is then the miniport called NdisMSendComplete() // in our send context and we don't need to do anything more. // if (NULL == Miniport->LastMiniportPacket) { // // We may still have packets pending to be sent down.... // continue; } // // Process the packet completion. // for (Count = 0; Count < NumberOfPackets; Count++, pPktArray++) { BOOLEAN fFoundPacket = FALSE; // // Try and find the packet on our miniport's packet queue. // Packet = Miniport->FirstPacket; PrevPacket = NULL; ASSERT(Packet != NULL); // // We are only going to travers the packet queue from the // FirstPacket to the LastMiniportPacket. // Why you ask? Well we need to make sure that the miniport // didn't complete the packet we are now trying to complete // with a call to NdisMSendComplete(). // while (Packet != PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastMiniportPacket)->Next) { if (Packet == *pPktArray) { fFoundPacket = TRUE; break; } PrevPacket = Packet; Packet = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next; } // // If we didn't find the packet on our queue then we need to // go on to the next one since it MUST have been completed // via NdisMSendComplete.... // if (!fFoundPacket) { continue; } Status = NDIS_GET_PACKET_STATUS(*pPktArray); // // Process the packet based on it's return status. // if (NDIS_STATUS_PENDING == Status) { NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'dnep'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Complete is pending\n")); } else if (NDIS_STATUS_RESOURCES != Status) { #if DBG if (Status != NDIS_STATUS_SUCCESS) { NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'liaf'); } else { NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'ccus'); } #endif ADD_RESOURCE(Miniport, 'F'); // // Remove from the finish queue. // DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Completed packet 0x%x with status 0x%x\n", *pPktArray, Status)); // // Fix up the packet queues. // if (Miniport->FirstPacket == *pPktArray) { Miniport->FirstPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next; if (Miniport->LastMiniportPacket == *pPktArray) { Miniport->LastMiniportPacket = NULL; } } else { // // If we just completed the last packet then // we need to update our last packet pointer. // PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next; if (*pPktArray == Miniport->LastPacket) { Miniport->LastPacket = PrevPacket; } // // If we just complete the last miniport packet then // the last miniport packet is the previous packet. // if (Miniport->LastMiniportPacket == *pPktArray) { Miniport->LastMiniportPacket = PrevPacket; } } // // We need to save a pointer to the open so that we // can dereference it after the completion. // Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open; NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport); (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( Open->ProtocolBindingContext, *pPktArray, Status); NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport); } else { // // Once we hit a return code of NDIS_STATUS_RESOURCES // for a packet then we must break out and re-queue. // CLEAR_RESOURCE(Miniport, 'S'); MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED); break; } } // // if there are any packets that returned NDIS_STATUS_RESOURCES // then re-queue them. // if (Count != NumberOfPackets) { PNDIS_PACKET FinalPrevPacket = PrevPacket; for (ResourcesCount = NumberOfPackets - 1, pPktArray = &Miniport->PacketArray[ResourcesCount]; ResourcesCount > Count; ResourcesCount--, pPktArray--) { DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Packet 0x%x returned resources\n", *pPktArray)); NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser'); // // Float the pointers. // Miniport->LastMiniportPacket = *(pPktArray - 1); Miniport->FirstPendingPacket = *pPktArray; } DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Packet 0x%x returned resources\n", *pPktArray)); NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser'); // // If this is the last packet on the miniport queue // then NULL the last miniport packet out so we know there // are no more. // if (Miniport->FirstPacket == *pPktArray) { Miniport->LastMiniportPacket = NULL; Miniport->FirstPendingPacket = *pPktArray; } else { // // There are other packets that are pending on // the miniport queue. // Miniport->LastMiniportPacket = PrevPacket; Miniport->FirstPendingPacket = *pPktArray; } } } } DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSendPacketsFullDuplex\n")); // // If there are no more resources available but // there are still packets to send then we need to // keep the workitem queue'd. // if ((0 == Miniport->SendResourcesAvailable) && (Miniport->FirstPendingPacket != NULL)) { fReturn = TRUE; } else { fReturn = FALSE; } NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED'); NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport); #endif return(fReturn); } BOOLEAN FASTCALL ndisMStartSendsFullDuplex( PNDIS_MINIPORT_BLOCK Miniport ) /*++ Routine Description: This routine will process any pending sends for full-duplex miniports. !!!!!!!NOTE!!!!!!!! This routine MUST be called with the Miniport Lock NOT held!!!! Arguments: Return Value: --*/ { BOOLEAN fReturn = FALSE; #ifdef NDIS_NT PNDIS_PACKET Packet; PNDIS_PACKET PrevPacket; NDIS_STATUS Status; PNDIS_PACKET_RESERVED Reserved; PNDIS_M_OPEN_BLOCK Open; UINT Flags; KIRQL OldIrql; // // Acquire the send lock. // NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMStartSendsFullDuplex\n")); MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED); // // Loop and process sends. // while ((Miniport->SendResourcesAvailable != 0) && (Miniport->FirstPendingPacket != NULL)) { // // Grab the packet off of the pending queue. // Packet = Miniport->FirstPendingPacket; Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); Open = Reserved->Open; // // Remove from pending queue // Miniport->FirstPendingPacket = Reserved->Next; // // Put on finish queue // PrevPacket = Miniport->LastMiniportPacket; Miniport->LastMiniportPacket = Packet; // // Send the packet // NDISM_SEND_PACKET(Miniport, Open, Packet, &Status); // // Process the completion status of the packet. // if (NDIS_STATUS_PENDING == Status) { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Complete is pending\n")); } else if (Status != NDIS_STATUS_RESOURCES) { NDISM_COMPLETE_SEND_FULL_DUPLEX( Miniport, Open, Packet, PrevPacket, Status); } else { NDISM_COMPLETE_SEND_RESOURCES(Miniport, Packet, PrevPacket); } } DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSendsFullDuplex\n")); // // If there are no more resources available but // there are still packets to send then we need to // keep the workitem queue'd. // if ((0 == Miniport->SendResourcesAvailable) && (Miniport->FirstPendingPacket != NULL)) { fReturn = TRUE; } else { fReturn = FALSE; } NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED'); NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport); #endif return(fReturn); } BOOLEAN FASTCALL ndisMStartSendPackets( PNDIS_MINIPORT_BLOCK Miniport ) { PNDIS_PACKET Packet; PNDIS_PACKET PrevPacket; NDIS_STATUS Status; PNDIS_PACKET_RESERVED Reserved; PNDIS_M_OPEN_BLOCK Open; UINT Flags; BOOLEAN fReturn; PPNDIS_PACKET pPktArray; ASSERT(MINIPORT_AT_DPC_LEVEL); ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMStartSendPackets\n")); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed'); MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED); // // Loop and process sends. // while ((Miniport->SendResourcesAvailable != 0) && (Miniport->FirstPendingPacket != NULL)) { UINT Count; UINT ResourcesCount; UINT NumberOfPackets; PNDIS_PACKET FirstPrevPacket = NULL; // // Initialize the packet array. // pPktArray = Miniport->PacketArray; // // Place as many packets as we can in the packet array to send // to the miniport. // for (NumberOfPackets = 0; (NumberOfPackets < Miniport->MaximumSendPackets) && (Miniport->FirstPendingPacket != NULL); ) { // // Grab the packet off of the pending queue. // Packet = Miniport->FirstPendingPacket; Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); // // Remove from pending queue // Miniport->FirstPendingPacket = Reserved->Next; // // Put on finish queue // PrevPacket = Miniport->LastMiniportPacket; Miniport->LastMiniportPacket = Packet; // // Indicate the packet loopback if necessary. // if (((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) || MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) && !MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK) && ndisMIsLoopbackPacket(Miniport, Packet)) { DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Packet 0x%x is self-directed.\n", Packet)); // // Get a pointer to our open block. // DO NOT USE "Reserved->Open" TO CALL INTO THE MACRO SINCE IT // WILL NOT BE VALID FOR THE LIFE OF THE MACRO!!!!! // Open = Reserved->Open; // // Complete the packet back to the binding. // NDISM_COMPLETE_SEND( Miniport, Open, Packet, PrevPacket, NDIS_STATUS_SUCCESS); // // No, we don't want to increment the counter for the // miniport's packet array. // } else { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'inim'); // // We have to re-initialize this. // *pPktArray = Packet; NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS); // // Increment the counter for the packet array index. // NumberOfPackets++; pPktArray++; } } // // Are there any packets to send? // if (NumberOfPackets != 0) { // // Get a temp pointer to our packet array. // pPktArray = Miniport->PacketArray; Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open; // // Pass the packet array down to the miniport. // (Open->SendPacketsHandler)( Miniport->MiniportAdapterContext, Miniport->PacketArray, NumberOfPackets); // // First check to see if the LastMiniportPacket is NULL. // If it is then the miniport called NdisMSendComplete() // in our send context and we don't need to do anything more. // if (NULL == Miniport->LastMiniportPacket) { // // We may still have packets pending to be sent down.... // continue; } // // Process the packet completion. // for (Count = 0; Count < NumberOfPackets; Count++, pPktArray++) { BOOLEAN fFoundPacket = FALSE; // // Try and find the packet on our miniport's packet queue. // Packet = Miniport->FirstPacket; PrevPacket = NULL; ASSERT(Packet != NULL); // // We are only going to travers the packet queue from the // FirstPacket to the LastMiniportPacket. // Why you ask? Well we need to make sure that the miniport // didn't complete the packet we are now trying to complete // with a call to NdisMSendComplete(). // while (Packet != PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastMiniportPacket)->Next) { if (Packet == *pPktArray) { fFoundPacket = TRUE; break; } PrevPacket = Packet; Packet = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next; } // // If we didn't find the packet on our queue then we need to // go on to the next one since it MUST have been completed // via NdisMSendComplete.... // if (!fFoundPacket) { continue; } Status = NDIS_GET_PACKET_STATUS(*pPktArray); // // Process the packet based on it's return status. // if (NDIS_STATUS_PENDING == Status) { NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'dnep'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Complete is pending\n")); } else if (Status != NDIS_STATUS_RESOURCES) { #if DBG if (Status != NDIS_STATUS_SUCCESS) { NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'liaf'); } else { NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'ccus'); } #endif ADD_RESOURCE(Miniport, 'F'); // // Remove from the finish queue. // DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Completed packet 0x%x with status 0x%x\n", *pPktArray, Status)); // // Fix up the packet queues. // if (Miniport->FirstPacket == *pPktArray) { Miniport->FirstPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next; if (Miniport->LastMiniportPacket == *pPktArray) { Miniport->LastMiniportPacket = NULL; } } else { // // If we just completed the last packet then // we need to update our last packet pointer. // PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next; if (*pPktArray == Miniport->LastPacket) { Miniport->LastPacket = PrevPacket; } // // If we just complete the last miniport packet then // the last miniport packet is the previous packet. // if (Miniport->LastMiniportPacket == *pPktArray) { Miniport->LastMiniportPacket = PrevPacket; } } // // We need to save a pointer to the open so that we // can dereference it after the completion. // Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open; NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport); (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( Open->ProtocolBindingContext, *pPktArray, Status); NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport); DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("- Open 0x%x Reference 0x%x\n", Open, Open->References)); Open->References--; DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("==0 Open 0x%x Reference 0x%x\n", PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open, PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open->References)); if (Open->References == 0) { ndisMFinishClose(Miniport, Open); } } else { // // Once we hit a return code of NDIS_STATUS_RESOURCES // for a packet then we must break out and re-queue. // CLEAR_RESOURCE(Miniport, 'S'); MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED); break; } } // // if there are any packets that returned NDIS_STATUS_RESOURCES // then re-queue them. // if (Count != NumberOfPackets) { PNDIS_PACKET FinalPrevPacket = PrevPacket; for (ResourcesCount = NumberOfPackets - 1, pPktArray = &Miniport->PacketArray[ResourcesCount]; ResourcesCount > Count; ResourcesCount--, pPktArray--) { DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Packet 0x%x returned resources\n", *pPktArray)); NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser'); // // Float the pointers. // Miniport->LastMiniportPacket = *(pPktArray - 1); Miniport->FirstPendingPacket = *pPktArray; } DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Packet 0x%x returned resources\n", *pPktArray)); NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser'); // // If this is the last packet on the miniport queue // then NULL the last miniport packet out so we know there // are no more. // if (Miniport->FirstPacket == *pPktArray) { Miniport->LastMiniportPacket = NULL; Miniport->FirstPendingPacket = *pPktArray; } else { // // There are other packets that are pending on // the miniport queue. // Miniport->LastMiniportPacket = PrevPacket; Miniport->FirstPendingPacket = *pPktArray; } } } } NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSendPackets\n")); return(FALSE); } BOOLEAN FASTCALL ndisMStartSends( PNDIS_MINIPORT_BLOCK Miniport ) /*++ Routine Description: Submits as many sends as possible to the mini-port. Arguments: Miniport - Miniport to send to. Return Value: If there are more packets to send but no resources to do it with the this is TRUE to keep a workitem queue'd. --*/ { PNDIS_PACKET Packet; PNDIS_PACKET PrevPacket; NDIS_STATUS Status; PNDIS_PACKET_RESERVED Reserved; PNDIS_M_OPEN_BLOCK Open; UINT Flags; BOOLEAN fReturn; ASSERT(MINIPORT_AT_DPC_LEVEL); ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMStartSends\n")); MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed'); // // Loop and process sends. // while ((Miniport->SendResourcesAvailable != 0) && (Miniport->FirstPendingPacket != NULL)) { // // Grab the packet off of the pending queue. // Packet = Miniport->FirstPendingPacket; Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); Open = Reserved->Open; NDISM_LOG_PACKET(Miniport, Packet, NULL, 's'); // // Is this arcnet using ethernet encapsulation? // if (Miniport->MediaType == NdisMediumArcnet878_2) { // // Build the header for arcnet. // Status = ndisMBuildArcnetHeader(Miniport, Open, Packet); if (NDIS_STATUS_PENDING == Status) { return(TRUE); } } // // Remove from pending queue // Miniport->FirstPendingPacket = Reserved->Next; // // Put on finish queue // PrevPacket = Miniport->LastMiniportPacket; Miniport->LastMiniportPacket = Packet; // // Send the packet. // NDISM_SEND_PACKET(Miniport, Open, Packet, &Status); // // Process the packet pending completion status. // if (NDIS_STATUS_PENDING == Status) { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Complete is pending\n")); } else { // // Clean-up arcnet's extra buffers. // if (Miniport->MediaType == NdisMediumArcnet878_2) { ndisMFreeArcnetHeader(Miniport, Packet); } // // Handle the completion and resources cases. // if (Status != NDIS_STATUS_RESOURCES) { NDISM_COMPLETE_SEND( Miniport, Open, Packet, PrevPacket, Status); } else { NDISM_COMPLETE_SEND_RESOURCES(Miniport, Packet, PrevPacket); } } } DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSends\n")); // // If there are no more resources available but // there are still packets to send then we need to // keep the workitem queue'd. // if ((0 == Miniport->SendResourcesAvailable) && (Miniport->FirstPendingPacket != NULL)) { fReturn = TRUE; } else { fReturn = FALSE; } NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED'); return(fReturn); } NDIS_STATUS FASTCALL ndisMSyncSend( IN PNDIS_MINIPORT_BLOCK Miniport, IN PNDIS_PACKET Packet ) /*++ Routine Description: Submits an immediate send to a miniport. The miniport has the send on the pending queue, and it is the only element on the send queue. This routine is also called with the lock held. Arguments: Miniport - Miniport to send to. Return Value: None. --*/ { PNDIS_PACKET PrevPacket; NDIS_STATUS Status; PNDIS_PACKET_RESERVED Reserved; PNDIS_M_OPEN_BLOCK Open; UINT Flags; ASSERT(MINIPORT_AT_DPC_LEVEL); ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Enter Sync send.\n")); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'cnys'); // // Get the Open block that the send is for from the packet. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); Open = Reserved->Open; // // Remove from Queue // Miniport->FirstPendingPacket = Reserved->Next; // // Put on finish queue // PrevPacket = Miniport->LastMiniportPacket; Miniport->LastMiniportPacket = Packet; MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED); // // Send the packet. // NDISM_SEND_PACKET(Miniport, Open, Packet, &Status); // // Process the status of the send. // if (NDIS_STATUS_PENDING == Status) { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Complete sync send is pending\n")); return(NDIS_STATUS_PENDING); } // // If send complete was called from the miniport's send handler // then our local PrevPacket pointer may no longer be valid.... // if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED)) { MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED); MiniportFindPacket(Miniport, Packet, &PrevPacket); } Miniport->LastMiniportPacket = PrevPacket; if (Status != NDIS_STATUS_RESOURCES) { #if DBG if (Status != NDIS_STATUS_SUCCESS) { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf'); } else { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus'); } #endif ADD_RESOURCE(Miniport, 'F'); // // Remove from finish queue // DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Completed 0x%x\n", Status)); if (PrevPacket == NULL) { // // Set up the next packet to send. // Miniport->FirstPacket = Reserved->Next; } else { PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next; if (Packet == Miniport->LastPacket) { Miniport->LastPacket = PrevPacket; } } DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("- Open 0x%x Reference 0x%x\n", Open, Open->References)); Open->References--; DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References)); if (Open->References == 0) ndisMFinishClose(Miniport, Open); } else { // // Status == NDIS_STATUS_RESOURCES!!!! // DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Deferring send\n")); // // Put on pending queue // Miniport->FirstPendingPacket = Packet; NDISM_LOG_PACKET(Miniport, Packet, NULL, 'oser'); // // Set flag // CLEAR_RESOURCE(Miniport, 'S'); Status = NDIS_STATUS_PENDING; } return(Status); } NDIS_STATUS ndisMWanSend( IN NDIS_HANDLE NdisBindingHandle, IN NDIS_HANDLE NdisLinkHandle, IN PVOID Packet ) { PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; BOOLEAN LocalLock; NDIS_STATUS Status; KIRQL OldIrql; NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); LOCK_MINIPORT(Miniport, LocalLock); // // Call MAC to send WAN packet // Status = ((PNDIS_M_WAN_SEND)(Miniport->DriverHandle->MiniportCharacteristics.SendHandler))( Miniport->MiniportAdapterContext, NdisLinkHandle, Packet); if (LocalLock) { // // Process any changes that may have occured. // NDISM_PROCESS_DEFERRED(Miniport); } UNLOCK_MINIPORT(Miniport, LocalLock); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); return Status; } VOID ndisMSendCompleteFullDuplex( IN NDIS_HANDLE MiniportAdapterHandle, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ) { #ifdef NDIS_NT PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; PNDIS_M_OPEN_BLOCK Open; PNDIS_PACKET_RESERVED Reserved; LONG Thread; BOOLEAN fAcquireMiniportLock = FALSE; ASSERT(MINIPORT_AT_DPC_LEVEL); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendCompleteFullDuplex\n")); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("packet 0x%x\n", Packet)); // // Acquire the send lock, unless it has alrady been acquired earlier // by this thread.... // Thread = InterlockedExchangeAdd(&Miniport->SendThread, 0); if (CURRENT_THREAD != Thread) { // // We need to try and grab the lock... // NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport); } MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED); // // If the packet is not equal to the first packet then we have to find // it because it may have completed out of order. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); if (Miniport->FirstPacket == Packet) { Miniport->FirstPacket = Reserved->Next; if (Miniport->LastMiniportPacket == Packet) { Miniport->LastMiniportPacket = NULL; } } else { PNDIS_PACKET PrevPacket; // // Search for the packet. // MiniportFindPacket(Miniport, Packet, &PrevPacket); ASSERT(PrevPacket != NULL); // // If we just completed the last packet then // we need to update our last packet pointer. // PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next; if (Packet == Miniport->LastPacket) { Miniport->LastPacket = PrevPacket; } // // If we just completed the last miniport packet then // last miniport packet is the previous packet. // if (Miniport->LastMiniportPacket == Packet) { Miniport->LastMiniportPacket = PrevPacket; } } // // Indicate to Protocol; // Open = Reserved->Open; // // Do we need to queue another workitem to process more sends? // if (Miniport->FirstPendingPacket != NULL) { NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); } #if DBG NDISM_LOG_PACKET(Miniport, NULL, NULL, 'pmoc'); if (Status != NDIS_STATUS_SUCCESS) { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf'); } else { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus'); } #endif ADD_RESOURCE(Miniport, 'P'); NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport); // // If the current thread has the miniport lock then we need to // release it.... // if (CURRENT_THREAD == Miniport->MiniportThread) { NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport); fAcquireMiniportLock = TRUE; } (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( Open->ProtocolBindingContext, Packet, Status); if (fAcquireMiniportLock) { NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport); } // // If the SendLock was acquired on entry then we need to make sure // that it's acquired on exit... // if (CURRENT_THREAD == Thread) { NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport); } DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendCompleteFullDuplex\n")); #endif } VOID NdisMSendComplete( IN NDIS_HANDLE MiniportAdapterHandle, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ) /*++ Routine Description: This function indicates the completion of a send. Arguments: MiniportAdapterHandle - points to the adapter block. Return Value: None. --*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; PNDIS_M_OPEN_BLOCK Open; PNDIS_PACKET_RESERVED Reserved; PSINGLE_LIST_ENTRY Link; ASSERT(MINIPORT_AT_DPC_LEVEL); ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendComplete\n")); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("packet 0x%x\n", Packet)); MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED); // // If the packet is not equal to the first packet then we have to find // it because it may have completed out of order. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); if (Miniport->FirstPacket == Packet) { Miniport->FirstPacket = Reserved->Next; if (Miniport->LastMiniportPacket == Packet) { Miniport->LastMiniportPacket = NULL; } } else { PNDIS_PACKET PrevPacket; // // Search for the packet. // MiniportFindPacket(Miniport, Packet, &PrevPacket); ASSERT(PrevPacket != NULL); // // If we just completed the last packet then // we need to update our last packet pointer. // PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next; if (Packet == Miniport->LastPacket) { Miniport->LastPacket = PrevPacket; } // // If we just completed the last miniport packet then // last miniport packet is the previous packet. // if (Miniport->LastMiniportPacket == Packet) { Miniport->LastMiniportPacket = PrevPacket; } } // // Indicate to Protocol; // Open = Reserved->Open; // // If this is arcnet, then free the appended header. // if (Miniport->MediaType == NdisMediumArcnet878_2) { ndisMFreeArcnetHeader(Miniport, Packet); } #if DBG NDISM_LOG_PACKET(Miniport, NULL, NULL, 'pmoc'); if (Status != NDIS_STATUS_SUCCESS) { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf'); } else { NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus'); } #endif NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport); (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( Open->ProtocolBindingContext, Packet, Status); NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport); ADD_RESOURCE(Miniport, 'P'); DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("- Open 0x%x Reference 0x%x\n", Open, Open->References)); Open->References--; DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References)); if (Open->References == 0) { ndisMFinishClose(Miniport,Open); } // // Do we need to queue another workitem to process more sends? // if (Miniport->FirstPendingPacket != NULL) { NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); } DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendComplete\n")); } VOID NdisMWanSendComplete( IN NDIS_HANDLE MiniportAdapterHandle, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ) /*++ Routine Description: This function indicates the status is complete. Arguments: MiniportAdapterHandle - points to the adapter block. Return Value: None. --*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; PNDIS_M_OPEN_BLOCK Open; ASSERT(MINIPORT_AT_DPC_LEVEL); ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); Open = Miniport->OpenQueue; while (Open != NULL) { // // Call Protocol to indicate status // NDISM_LOG_PACKET(Miniport, Packet, NULL, 'C'); NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport); (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) ( Open->ProtocolBindingContext, Packet, Status); NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport); Open = Open->MiniportNextOpen; } } VOID ndisMSendResourcesAvailableFullDuplex( IN NDIS_HANDLE MiniportAdapterHandle ) { #ifdef NDIS_NT PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; LONG Thread; ASSERT(MINIPORT_AT_DPC_LEVEL); Thread = InterlockedExchangeAdd(&Miniport->SendThread, 0); if (CURRENT_THREAD != Thread) { NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport); } DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendResourcesAvailableFullDuplex\n")); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'aser'); ADD_RESOURCE(Miniport, 'V'); // // Are there more sends to process? // if (Miniport->FirstPendingPacket != NULL) { NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); } if (CURRENT_THREAD != Thread) { NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport); } DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendResourcesAvailableFullDuplex\n")); #endif } VOID NdisMSendResourcesAvailable( IN NDIS_HANDLE MiniportAdapterHandle ) /*++ Routine Description: This function indicates that some send resources are available and are free for processing more sends. Arguments: MiniportAdapterHandle - points to the adapter block. Return Value: None. --*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; ASSERT(MINIPORT_AT_DPC_LEVEL); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendResourcesAvailable\n")); ADD_RESOURCE(Miniport, 'V'); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'aser'); // // Are there more sends to process? // if (Miniport->FirstPendingPacket != NULL) { NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); } DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendResourcesAvailable\n")); } /////////////////////////////////////////////////////////////////////////////////////// // // UPPER-EDGE SEND HANDLERS // /////////////////////////////////////////////////////////////////////////////////////// NDIS_STATUS ndisMSendFullDuplexToSendPackets( IN NDIS_HANDLE NdisBindingHandle, IN PNDIS_PACKET Packet ) { NDIS_STATUS Status = NDIS_STATUS_PENDING; #ifdef NDIS_NT PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; PNDIS_PACKET_RESERVED Reserved; KIRQL OldIrql; BOOLEAN fQueueWorkItem = FALSE; BOOLEAN fDeferredSend = FALSE; BOOLEAN LocalLock; UINT Flags; NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendFullDuplexToSendPackets\n")); // // Initialize the packet info. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); Reserved->Next = NULL; Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; // // Place the packet on the packet queue. // if (Miniport->FirstPacket == NULL) { // // Place the packet at the head of the queue. // Miniport->FirstPacket = Packet; } else { CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet); PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet; } Miniport->LastPacket = Packet; // // This packet has not been looped back yet! // MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT)); // // Check to see if a sync send is possible. // if (Miniport->FirstPendingPacket == NULL) { Miniport->FirstPendingPacket = Packet; } NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendFullDuplexToSendPackets\n")); NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql); #endif return(Status); } VOID ndisMSendPacketsFullDuplex( IN PNDIS_OPEN_BLOCK NdisOpenBlock, IN PPNDIS_PACKET PacketArray, IN UINT NumberOfPackets ) { #ifdef NDIS_NT PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle; PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle; PPNDIS_PACKET pPktArray; PNDIS_PACKET_RESERVED Reserved; BOOLEAN LocalLock; KIRQL OldIrql; UINT c; NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendPacketsFullDuplex\n")); // // Place the packets on the miniport queue. // for (c = 0, pPktArray = PacketArray; c < NumberOfPackets; c++, pPktArray++) { // // Get the first packet.... // NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_PENDING); // // Initialize the packet info. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray); Reserved->Next = NULL; Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; // // Place the packet on the packet queue. // if (Miniport->FirstPacket == NULL) { // // Place the packet at the head of the queue. // Miniport->FirstPacket = *pPktArray; } else { CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray); PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray; } Miniport->LastPacket = *pPktArray; // // This packet has not been looped back yet! // MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT)); // // Check to see if a sync send is possible. // if (Miniport->FirstPendingPacket == NULL) { Miniport->FirstPendingPacket = *pPktArray; } } // // Queue a workitem for the new sends. // NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendPacketsFullDuplex\n")); NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql); #endif } NDIS_STATUS ndisMSendToSendPackets( IN NDIS_HANDLE NdisBindingHandle, IN PNDIS_PACKET Packet ) { PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; PNDIS_PACKET_RESERVED Reserved; BOOLEAN LocalLock; NDIS_STATUS Status = NDIS_STATUS_PENDING; KIRQL OldIrql; NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendToSendPackets\n")); // // Increment the references on this open. // ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++; DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References)); // // Initialize the packet info. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); Reserved->Next = NULL; Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; // // Place the packet on the packet queue. // if (Miniport->FirstPacket == NULL) { // // Place the packet at the head of the queue. // Miniport->FirstPacket = Packet; } else { CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet); PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet; } Miniport->LastPacket = Packet; // // This packet has not been looped back yet! // MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT)); // // Check to see if a sync send is possible. // if (Miniport->FirstPendingPacket == NULL) { Miniport->FirstPendingPacket = Packet; } NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); // // Try to grab the local lock on the miniport block. // LOCK_MINIPORT(Miniport, LocalLock); // // If we have the local lock and there is not // a reset in progress then fire off the send. // if (LocalLock) { // // Process deferred. // NDISM_PROCESS_DEFERRED(Miniport); } UNLOCK_MINIPORT(Miniport, LocalLock); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendToSendPackets\n")); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES'); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); return(NDIS_STATUS_PENDING); } VOID ndisMSendPackets( IN PNDIS_OPEN_BLOCK NdisOpenBlock, IN PPNDIS_PACKET PacketArray, IN UINT NumberOfPackets ) { PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle; PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle; BOOLEAN LocalLock; KIRQL OldIrql; UINT c; PNDIS_PACKET_RESERVED Reserved; PPNDIS_PACKET pPktArray;; NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendPackets\n")); // // Place the packets on the miniport queue. // for (c = 0, pPktArray = PacketArray; c < NumberOfPackets; c++, pPktArray++) { // // Get the first packet.... // NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_PENDING); // // Initialize the packet info. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray); Reserved->Next = NULL; Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; // // Increment the references on this open. // ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++; DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References)); // // Place the packet on the packet queue. // if (Miniport->FirstPacket == NULL) { // // Place the packet at the head of the queue. // Miniport->FirstPacket = *pPktArray; } else { CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray); PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray; } Miniport->LastPacket = *pPktArray; // // This packet has not been looped back yet! // MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT)); // // Check to see if a sync send is possible. // if (Miniport->FirstPendingPacket == NULL) { Miniport->FirstPendingPacket = *pPktArray; } } // // Queue a workitem for the new sends. // NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); // // Try to grab the local lock on the miniport block. // LOCK_MINIPORT(Miniport, LocalLock); // // If we have the local lock and there is not // a reset in progress then fire off the send. // if (LocalLock) { // // Process deferred. // NDISM_PROCESS_DEFERRED(Miniport); } UNLOCK_MINIPORT(Miniport, LocalLock); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendPackets\n")); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); } VOID ndisMSendPacketsFullDuplexToSend( IN PNDIS_OPEN_BLOCK NdisOpenBlock, IN PPNDIS_PACKET PacketArray, IN UINT NumberOfPackets ) { #ifdef NDIS_NT PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle; PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle; PNDIS_PACKET_RESERVED Reserved; PPNDIS_PACKET pPktArray; BOOLEAN LocalLock; KIRQL OldIrql; UINT c; NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendPacketsFullDuplexToSend\n")); // // Place the packets on the miniport queue. // for (c = 0, pPktArray = PacketArray; c < NumberOfPackets; c++, pPktArray++) { // // Initialize the packet info. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray); Reserved->Next = NULL; Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; // // Place the packet on the packet queue. // if (Miniport->FirstPacket == NULL) { // // Place the packet at the head of the queue. // Miniport->FirstPacket = *pPktArray; } else { CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray); PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray; } Miniport->LastPacket = *pPktArray; // // This packet has not been looped back yet. // MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT)); // // Check to see if a sync send is possible. // if (Miniport->FirstPendingPacket == NULL) { Miniport->FirstPendingPacket = *pPktArray; } } // // Queue a workitem for the new sends. // NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendPacketsFullDuplexToSend\n")); NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql); #endif } NDIS_STATUS ndisMSendFullDuplex( IN NDIS_HANDLE NdisBindingHandle, IN PNDIS_PACKET Packet ) /*++ Routine Description: Arguments: Return Value: --*/ { NDIS_STATUS Status = NDIS_STATUS_PENDING; #ifdef NDIS_NT PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; PNDIS_PACKET_RESERVED Reserved; KIRQL OldIrql; BOOLEAN fQueueWorkItem = FALSE; BOOLEAN fDeferredSend = FALSE; BOOLEAN LocalLock; UINT Flags; NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendFullDuplex\n")); // // Initialize the packet info. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); Reserved->Next = NULL; Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; // // Place the packet on the packet queue. // if (Miniport->FirstPacket == NULL) { // // Place the packet at the head of the queue. // Miniport->FirstPacket = Packet; } else { CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet); PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet; } Miniport->LastPacket = Packet; // // This packet has not been looped back yet and it does not // contain any media specific information. // MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT)); if (NULL == Miniport->FirstPendingPacket) { Miniport->FirstPendingPacket = Packet; } NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendFullDuplex\n")); NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql); #endif return(Status); } VOID ndisMSendPacketsToSend( IN PNDIS_OPEN_BLOCK NdisOpenBlock, IN PPNDIS_PACKET PacketArray, IN UINT NumberOfPackets ) /*++ Routine Description: This routine will take a packet array and "thunk" it down for a driver that does not support a send packet handler. This involves queueing the packet array onto the miniport's packet queue and sending them one at a time. Arguments: NdisBindingHandle - Pointer to the NDIS_OPEN_BLOCK. PacketArray - Array of PNDIS_PACKET structures that are to be sent to the miniport as NDIS_PACKETs. NumberOfPackets - Number of elements in the PacketArray. Return Value: None. --*/ { PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle; PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle; PNDIS_PACKET Packet; PNDIS_PACKET_RESERVED Reserved; PPNDIS_PACKET pPktArray; BOOLEAN LocalLock; KIRQL OldIrql; UINT c; NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSendPacketsToSend\n")); // // Try to grab the local lock on the miniport block. // LOCK_MINIPORT(Miniport, LocalLock); // // Place the packets on the miniport queue. // for (c = 0, pPktArray = PacketArray; c < NumberOfPackets; c++, pPktArray++) { // // Initialize the packet info. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray); Reserved->Next = NULL; Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; // // Increment the references on this open. // ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++; DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References)); // // Place the packet on the packet queue. // if (Miniport->FirstPacket == NULL) { // // Place the packet at the head of the queue. // Miniport->FirstPacket = *pPktArray; } else { CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray); PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray; } Miniport->LastPacket = *pPktArray; // // This packet has not been looped back yet. // MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT)); // // Check to see if a sync send is possible. // if (Miniport->FirstPendingPacket == NULL) { Miniport->FirstPendingPacket = *pPktArray; } } // // Queue a workitem for the new sends. // NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); // // If we have the local lock and there is not // a reset in progress then fire off the send. // if (LocalLock) { // // Process deferred. // NDISM_PROCESS_DEFERRED(Miniport); } UNLOCK_MINIPORT(Miniport, LocalLock); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSendPacketsToSend\n")); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); } NDIS_STATUS ndisMSend( IN NDIS_HANDLE NdisBindingHandle, IN PNDIS_PACKET Packet ) { PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; PNDIS_PACKET_RESERVED Reserved; BOOLEAN LocalLock; BOOLEAN SyncSend = FALSE; NDIS_STATUS Status = NDIS_STATUS_PENDING; KIRQL OldIrql; NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMSend\n")); // // Try to grab the local lock on the miniport block. // LOCK_MINIPORT(Miniport, LocalLock); // // Increment the references on this open. // ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++; DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References)); // // Initialize the packet info. // Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); Reserved->Next = NULL; Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; // // Place the packet on the packet queue. // if (Miniport->FirstPacket == NULL) { // // Place the packet at the head of the queue. // Miniport->FirstPacket = Packet; } else { CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet); PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet; } Miniport->LastPacket = Packet; // // Mark the packet as not having been looped back yet. // MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT)); if (NULL == Miniport->FirstPendingPacket) { Miniport->FirstPendingPacket = Packet; SyncSend = TRUE; } // // If we have the local lock and there is not // a reset in progress then fire off the send. // if (LocalLock) { // // Can we do a sync send? // if (SyncSend && (Miniport->WorkQueue[NdisWorkItemHalt].Next == NULL)) { // // TODO: Make the call to sync send inline!!! // // Synchronous send. // Status = ndisMSyncSend(Miniport, Packet); } else { // // Process deferred. // NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); NDISM_PROCESS_DEFERRED(Miniport); } } else { // // We can't get the local lock so queue a workitem // to process the send later. // NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL); } UNLOCK_MINIPORT(Miniport, LocalLock); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMSend\n")); NDISM_LOG_PACKET(Miniport, Packet, (PVOID)Status, 'DNES'); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); return(Status); } VOID ndisMSendPacketsToFullMac( IN PNDIS_OPEN_BLOCK NdisOpenBlock, IN PPNDIS_PACKET PacketArray, IN UINT NumberOfPackets ) /*++ Routine Description: Arguments: Return Value: --*/ { UINT c; UINT Flags; PPNDIS_PACKET pPktArray; NDIS_STATUS Status; // // Send the packets to the mac one at a time. // for (c = 0, pPktArray = PacketArray; c < NumberOfPackets; c++, pPktArray++) { // // Send the packet to the mac driver. // Status = NdisOpenBlock->SendHandler( NdisOpenBlock->MacBindingHandle, *pPktArray); // // If the packet is not pending then complete it back to the protocol. // if (NDIS_STATUS_PENDING != Status) { // // Call the protocol's complete handler.... // (NdisOpenBlock->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( NdisOpenBlock->ProtocolBindingContext, *pPktArray, Status); } } } NDIS_STATUS ndisMResetWanSend( IN NDIS_HANDLE NdisBindingHandle, IN NDIS_HANDLE NdisLinkHandle, IN PVOID Packet ) { PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMResetWanSend\n")); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes'); NDISM_LOG_PACKET(Miniport, Packet, NULL, ' PIR'); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("ndisMResetWanSend: Reset in progress or Reset Requested\n")); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMResetWanSend\n")); return(NDIS_STATUS_RESET_IN_PROGRESS); } NDIS_STATUS ndisMResetSend( IN NDIS_HANDLE NdisBindingHandle, IN PNDIS_PACKET Packet ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMResetSend\n")); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes'); NDISM_LOG_PACKET(Miniport, Packet, NULL, ' PIR'); NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("ndisMResetSend: Reset in progress or Reset Requested\n")); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMResetSend\n")); return(NDIS_STATUS_RESET_IN_PROGRESS); } VOID ndisMResetSendPackets( IN PNDIS_OPEN_BLOCK NdisOpenBlock, IN PPNDIS_PACKET PacketArray, IN UINT NumberOfPackets ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle; PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle; UINT c; DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMResetSendPackets\n")); NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes'); for (c = 0; c < NumberOfPackets; c++) { NDISM_LOG_PACKET(Miniport, PacketArray[c], NULL, ' PIR'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("ndisMResetSendPackets: Reset in progress or Reset Requested\n")); // // For send packets we need to call the completion handler.... // (NdisBindingHandle->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( NdisBindingHandle->ProtocolBindingContext, PacketArray[c], NDIS_STATUS_RESET_IN_PROGRESS); } NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES'); DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMResetSendPackets\n")); }