Esempio n. 1
0
VOID
MPSendPackets(
    IN NDIS_HANDLE             MiniportAdapterContext,
    IN PPNDIS_PACKET           PacketArray,
    IN UINT                    NumberOfPackets
    )
/*++

Routine Description:

    Send Packet Array handler. Either this or our SendPacket handler is called
    based on which one is enabled in our Miniport Characteristics.

Arguments:

    MiniportAdapterContext     Pointer to our adapter
    PacketArray                Set of packets to send
    NumberOfPackets            Self-explanatory

Return Value:

    None

--*/
{
    PADAPT              pAdapt = (PADAPT)MiniportAdapterContext;
    NDIS_STATUS         Status;
    UINT                i;
    PVOID               MediaSpecificInfo = NULL;
    UINT                MediaSpecificInfoSize = 0;
    

    for (i = 0; i < NumberOfPackets; i++)
    {
        PNDIS_PACKET    Packet, MyPacket;
        ULONG          SndFltAction;

        Packet = PacketArray[i];

        //
        // The driver should fail the send if the virtual miniport is in low 
        // power state
        //
        if (pAdapt->MPDeviceState > NdisDeviceStateD0)
        {
            NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
                            Packet,
                            NDIS_STATUS_FAILURE);
            continue;
        }

        //
        // Call Send Packet Filter
        //
        SndFltAction = FltFilterSendPacket(
                        pAdapt,
                        Packet,
                        FALSE // Caller is running at IRQL <= DISPATCH_LEVEL
                        );

        //
        // Possibly Block (Drop) Packet
        // ----------------------------
        // Lying send. Report SUCCESS, even though it really hasn't
        // been sent.
        //
        if( SndFltAction & ACTION_BLOCK_PACKET ) {
            NdisMSendComplete( ADAPT_MINIPORT_HANDLE(pAdapt), Packet, NDIS_STATUS_SUCCESS);
            continue;
        }

#ifdef NDIS51

        //
        // Use NDIS 5.1 packet stacking:
        //
        {
            PNDIS_PACKET_STACK        pStack;
            BOOLEAN                   Remaining;

            //
            // Packet stacks: Check if we can use the same packet for sending down.
            //
            pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
            if (Remaining)
            {
                //
                // We can reuse "Packet".
                //
                // NOTE: if we needed to keep per-packet information in packets
                // sent down, we can use pStack->IMReserved[].
                //
                ASSERT(pStack);
                //
                // If the below miniport is going to low power state, stop sending down any packet.
                //
                NdisAcquireSpinLock(&pAdapt->Lock);
                if (pAdapt->PTDeviceState > NdisDeviceStateD0)
                {
                    NdisReleaseSpinLock(&pAdapt->Lock);
                    NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
                                        Packet,
                                        NDIS_STATUS_FAILURE);
                }
                else
                {
                    pAdapt->OutstandingSends++;
                    NdisReleaseSpinLock(&pAdapt->Lock);
                
                    NdisSend(&Status,
                              pAdapt->BindingHandle,
                              Packet);
        
                    if (Status != NDIS_STATUS_PENDING)
                    {
                        NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
                                            Packet,
                                            Status);
                   
                        ADAPT_DECR_PENDING_SENDS(pAdapt);
                    }
                }
                continue;
            }
        }
#endif
        do 
        {
            NdisAcquireSpinLock(&pAdapt->Lock);
            //
            // If the below miniport is going to low power state, stop sending down any packet.
            //
            if (pAdapt->PTDeviceState > NdisDeviceStateD0)
            {
                NdisReleaseSpinLock(&pAdapt->Lock);
                Status = NDIS_STATUS_FAILURE;
                break;
            }
            pAdapt->OutstandingSends++;
            NdisReleaseSpinLock(&pAdapt->Lock);
            
            NdisAllocatePacket(&Status,
                               &MyPacket,
                               pAdapt->SendPacketPoolHandle);

            if (Status == NDIS_STATUS_SUCCESS)
            {
                PSEND_RSVD        SendRsvd;

                SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
                SendRsvd->OriginalPkt = Packet;

                MyPacket->Private.Flags = NdisGetPacketFlags(Packet);

                MyPacket->Private.Head = Packet->Private.Head;
                MyPacket->Private.Tail = Packet->Private.Tail;
#ifdef WIN9X
                //
                // Work around the fact that NDIS does not initialize this
                // to FALSE on Win9x.
                //
                MyPacket->Private.ValidCounts = FALSE;
#endif // WIN9X

                //
                // Copy the OOB data from the original packet to the new
                // packet.
                //
                NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
                            NDIS_OOB_DATA_FROM_PACKET(Packet),
                            sizeof(NDIS_PACKET_OOB_DATA));
                //
                // Copy relevant parts of the per packet info into the new packet
                //
#ifndef WIN9X
                NdisIMCopySendPerPacketInfo(MyPacket, Packet);
#endif

                //
                // Copy the Media specific information
                //
                NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
                                                    &MediaSpecificInfo,
                                                    &MediaSpecificInfoSize);

                if (MediaSpecificInfo || MediaSpecificInfoSize)
                {
                    NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
                                                        MediaSpecificInfo,
                                                        MediaSpecificInfoSize);
                }

                NdisSend(&Status,
                         pAdapt->BindingHandle,
                         MyPacket);

                if (Status != NDIS_STATUS_PENDING)
                {
#ifndef WIN9X
                    NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
#endif
                    NdisFreePacket(MyPacket);
                    ADAPT_DECR_PENDING_SENDS(pAdapt);
                }
            }
            else
            {
                //
                // The driver cannot allocate a packet.
                // 
                ADAPT_DECR_PENDING_SENDS(pAdapt);
            }
        }
        while (FALSE);

        if (Status != NDIS_STATUS_PENDING)
        {
            NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
                              Packet,
                              Status);
        }
    }
}
Esempio n. 2
0
VOID
MPSendPackets(
    IN NDIS_HANDLE             MiniportAdapterContext,
    IN PPNDIS_PACKET           PacketArray,
    IN UINT                    NumberOfPackets
    )
/*++

Routine Description:

    Send Packet Array handler. Either this or our SendPacket handler is called
    based on which one is enabled in our Miniport Characteristics.

Arguments:

    MiniportAdapterContext     Pointer to our adapter
    PacketArray                Set of packets to send
    NumberOfPackets            Self-explanatory

Return Value:

    None

--*/
{
    PADAPT              pAdapt = (PADAPT)MiniportAdapterContext;
    NDIS_STATUS         Status;
    UINT                i;
    PVOID               MediaSpecificInfo = NULL;
    UINT                MediaSpecificInfoSize = 0;
	FILTER_STATUS		fStatus;
	PUCHAR				pBuffer;
	int					nBufLen;
    

    for (i = 0; i < NumberOfPackets; i++)
    {
        PNDIS_PACKET    Packet, MyPacket;

        Packet = PacketArray[i];

		//KdPrint(("微端口MPSendPackets方法,开始报文分析\n"));
		getMemoryCopyFromPacket(Packet, &pBuffer, &nBufLen);
		KdPrint(("\n==> 微端口MPSendPackets方法,开始分析报文\n"));
		fStatus = analyzeBuffer(pAdapt, pBuffer, &nBufLen, MODE_SEND);
		//fStatus = AnalysisPacket(Packet, FALSE);
		//fStatus = FILTER_STATUS_PASS;
		if (fStatus == FILTER_STATUS_DROP)
		{
			//丢弃
			KdPrint(("<== 微端口MPSendPackets方法,进入FILTER_STATUS_DROP模式\n"));
			freeMemory(pBuffer);
			// 在这个函数中,任何一个被放弃的包,都必须调用NdisMSendComplete。
			NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt), Packet, NDIS_STATUS_FAILURE);
			continue; 
		}
		/*
		else if (fStatus == FILTER_STATUS_MODIFY_REDIRECT)
		{
			//没有发送时接收转发这种情况
		}
		*/
		else if (fStatus == FILTER_STATUS_MODIFY_SEND)
		{
			//修改+发送
			KdPrint(("<== 微端口MPSendPackets方法,进入FILTER_STATUS_MODIFY_SEND模式\n"));
			MyPacket = createPacketFromMemory_SendPool(pAdapt, pBuffer, nBufLen);
			//freePacketBufferOnly(Packet);

			// The driver should fail the send if the virtual miniport is in low 
			// power state
			//
			if (pAdapt->MPDeviceState > NdisDeviceStateD0)
			{
				NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
					Packet,
					NDIS_STATUS_FAILURE);
				continue;
			}
			//这里原来有NDIS51的一个简化处理,放在此文件最下面了
			do 
			{
				PSEND_RSVD        SendRsvd;

				NdisAcquireSpinLock(&pAdapt->Lock);
				//
				// If the below miniport is going to low power state, stop sending down any packet.
				//
				if (pAdapt->PTDeviceState > NdisDeviceStateD0)
				{
					NdisReleaseSpinLock(&pAdapt->Lock);
					Status = NDIS_STATUS_FAILURE;
					break;
				}
				pAdapt->OutstandingSends++;
				NdisReleaseSpinLock(&pAdapt->Lock);
				
				//NdisAllocatePacket(&Status,
				//	&MyPacket,
				//	pAdapt->SendPacketPoolHandle);
				
				SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
				SendRsvd->OriginalPkt = Packet;
				
				NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
				NdisSetPacketFlags(MyPacket, NDIS_FLAGS_RESERVED4); //我们做个标记
				
				//现在我们自己构造buffer,所以不需要用原packet的buffer了
				//NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
				//NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
				
				//
				// Copy the OOB data from the original packet to the new
				// packet.
				//
				NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
					NDIS_OOB_DATA_FROM_PACKET(Packet),
					sizeof(NDIS_PACKET_OOB_DATA));
				//
				// Copy relevant parts of the per packet info into the new packet
				//
				NdisIMCopySendPerPacketInfo(MyPacket, Packet);
				
				//
				// Copy the Media specific information
				//
				NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
					&MediaSpecificInfo,
					&MediaSpecificInfoSize);
				
				if (MediaSpecificInfo || MediaSpecificInfoSize)
				{
					NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
						MediaSpecificInfo,
						MediaSpecificInfoSize);
				}
				
				NdisSend(&Status,
					pAdapt->BindingHandle,
					MyPacket);
				
				if (Status != NDIS_STATUS_PENDING)
				{
					NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
					//NdisFreePacket(MyPacket);
					freePacketBufferAndMemory(MyPacket);
					ADAPT_DECR_PENDING_SENDS(pAdapt);
				}
			}
			while (FALSE);
			
			if (Status != NDIS_STATUS_PENDING)
			{
				NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
					Packet,
					Status);
			}
		}
		else //FILTER_STATUS_PASS
		{
			//按PASS处理
			KdPrint(("<== 微端口MPSendPackets方法,进入FILTER_STATUS_PASS模式\n"));
			freeMemory(pBuffer);
			//
			// The driver should fail the send if the virtual miniport is in low 
			// power state
			//
			if (pAdapt->MPDeviceState > NdisDeviceStateD0)
			{
				NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
								Packet,
								NDIS_STATUS_FAILURE);
				continue;
			}
			//这里原来有NDIS51的一个简化处理,放在此文件最下面了
			do 
			{
				NdisAcquireSpinLock(&pAdapt->Lock);
				//
				// If the below miniport is going to low power state, stop sending down any packet.
				//
				if (pAdapt->PTDeviceState > NdisDeviceStateD0)
				{
					NdisReleaseSpinLock(&pAdapt->Lock);
					Status = NDIS_STATUS_FAILURE;
					break;
				}
				pAdapt->OutstandingSends++;
				NdisReleaseSpinLock(&pAdapt->Lock);
            
				NdisAllocatePacket(&Status,
								   &MyPacket,
								   pAdapt->SendPacketPoolHandle);

				if (Status == NDIS_STATUS_SUCCESS)
				{
					PSEND_RSVD        SendRsvd;

					SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
					SendRsvd->OriginalPkt = Packet;

					NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
					NdisClearPacketFlags(MyPacket, NDIS_FLAGS_RESERVED4); //防止和上面的包混淆

					NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
					NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);

					//
					// Copy the OOB data from the original packet to the new
					// packet.
					//
					NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
								NDIS_OOB_DATA_FROM_PACKET(Packet),
								sizeof(NDIS_PACKET_OOB_DATA));
					//
					// Copy relevant parts of the per packet info into the new packet
					//
					NdisIMCopySendPerPacketInfo(MyPacket, Packet);

					//
					// Copy the Media specific information
					//
					NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
														&MediaSpecificInfo,
														&MediaSpecificInfoSize);

					if (MediaSpecificInfo || MediaSpecificInfoSize)
					{
						NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
															MediaSpecificInfo,
															MediaSpecificInfoSize);
					}

					NdisSend(&Status,
							 pAdapt->BindingHandle,
							 MyPacket);

					if (Status != NDIS_STATUS_PENDING)
					{
						NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
						NdisFreePacket(MyPacket);
						ADAPT_DECR_PENDING_SENDS(pAdapt);
					}
				}
				else
				{
					//
					// The driver cannot allocate a packet.
					// 
					ADAPT_DECR_PENDING_SENDS(pAdapt);
				}
			}
			while (FALSE);

			if (Status != NDIS_STATUS_PENDING)
			{
				NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
								  Packet,
								  Status);
			}
		}
    }
}
Esempio n. 3
0
NDIS_STATUS
MPSend(
    IN NDIS_HANDLE             MiniportAdapterContext,
    IN PNDIS_PACKET            Packet,
    IN UINT                    Flags
    )
/*++

Routine Description:

    Send Packet handler. Either this or our SendPackets (array) handler is called
    based on which one is enabled in our Miniport Characteristics.

Arguments:

    MiniportAdapterContext    Pointer to the adapter
    Packet                    Packet to send
    Flags                     Unused, passed down below

Return Value:

    Return code from NdisSend

--*/
{
    PADAPT              pAdapt = (PADAPT)MiniportAdapterContext;
    NDIS_STATUS         Status;
    PNDIS_PACKET        MyPacket;
    PVOID               MediaSpecificInfo = NULL;
    ULONG               MediaSpecificInfoSize = 0;
    ULONG               SndFltAction;

    //
    // The driver should fail the send if the virtual miniport is in low 
    // power state
    //
    if (pAdapt->MPDeviceState > NdisDeviceStateD0) {
         return NDIS_STATUS_FAILURE;
    }

	//
	// Call Send Packet Filter
	//
	SndFltAction = FltFilterSendPacket(
                     pAdapt,
                     Packet,
                     TRUE     // Caller is running at IRQL DISPATCH_LEVEL
                     );

	//
	// Possibly Block (Drop) Packet
	// ----------------------------
	// Lying send. Report SUCCESS, even though it really hasn't
	// been sent.
	//
	if( SndFltAction & ACTION_BLOCK_PACKET) {
      return NDIS_STATUS_SUCCESS;
   }

#ifdef NDIS51
    //
    // Use NDIS 5.1 packet stacking:
    //
    {
        PNDIS_PACKET_STACK        pStack;
        BOOLEAN                   Remaining;

        //
        // Packet stacks: Check if we can use the same packet for sending down.
        //

        pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
        if (Remaining)
        {
            //
            // We can reuse "Packet".
            //
            // NOTE: if we needed to keep per-packet information in packets
            // sent down, we can use pStack->IMReserved[].
            //
            ASSERT(pStack);
            //
            // If the below miniport is going to low power state, stop sending down any packet.
            //
            NdisAcquireSpinLock(&pAdapt->Lock);
            if (pAdapt->PTDeviceState > NdisDeviceStateD0)
            {
                NdisReleaseSpinLock(&pAdapt->Lock);
                return NDIS_STATUS_FAILURE;
            }
            pAdapt->OutstandingSends++;
            NdisReleaseSpinLock(&pAdapt->Lock);
            NdisSend(&Status,
                     pAdapt->BindingHandle,
                     Packet);

            if (Status != NDIS_STATUS_PENDING)
            {
                ADAPT_DECR_PENDING_SENDS(pAdapt);
            }

            return(Status);
        }
    }
#endif // NDIS51

    //
    // We are either not using packet stacks, or there isn't stack space
    // in the original packet passed down to us. Allocate a new packet
    // to wrap the data with.
    //
    //
    // If the below miniport is going to low power state, stop sending down any packet.
    //
    NdisAcquireSpinLock(&pAdapt->Lock);
    if (pAdapt->PTDeviceState > NdisDeviceStateD0)
    {
        NdisReleaseSpinLock(&pAdapt->Lock);
        return NDIS_STATUS_FAILURE;
    
    }
    pAdapt->OutstandingSends++;
    NdisReleaseSpinLock(&pAdapt->Lock);
    
    NdisAllocatePacket(&Status,
                       &MyPacket,
                       pAdapt->SendPacketPoolHandle);

    if (Status == NDIS_STATUS_SUCCESS)
    {
        PSEND_RSVD            SendRsvd;

        //
        // Save a pointer to the original packet in our reserved
        // area in the new packet. This is needed so that we can
        // get back to the original packet when the new packet's send
        // is completed.
        //
        SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
        SendRsvd->OriginalPkt = Packet;

        MyPacket->Private.Flags = Flags;

        //
        // Set up the new packet so that it describes the same
        // data as the original packet.
        //
        MyPacket->Private.Head = Packet->Private.Head;
        MyPacket->Private.Tail = Packet->Private.Tail;
#ifdef WIN9X
        //
        // Work around the fact that NDIS does not initialize this
        // to FALSE on Win9x.
        //
        MyPacket->Private.ValidCounts = FALSE;
#endif

        //
        // Copy the OOB Offset from the original packet to the new
        // packet.
        //
        NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
                       NDIS_OOB_DATA_FROM_PACKET(Packet),
                       sizeof(NDIS_PACKET_OOB_DATA));

#ifndef WIN9X
        //
        // Copy the right parts of per packet info into the new packet.
        // This API is not available on Win9x since task offload is
        // not supported on that platform.
        //
        NdisIMCopySendPerPacketInfo(MyPacket, Packet);
#endif
        
        //
        // Copy the Media specific information
        //
        NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
                                            &MediaSpecificInfo,
                                            &MediaSpecificInfoSize);

        if (MediaSpecificInfo || MediaSpecificInfoSize)
        {
            NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
                                                MediaSpecificInfo,
                                                MediaSpecificInfoSize);
        }

        NdisSend(&Status,
                 pAdapt->BindingHandle,
                 MyPacket);


        if (Status != NDIS_STATUS_PENDING)
        {
#ifndef WIN9X
            NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
#endif
            NdisFreePacket(MyPacket);
            ADAPT_DECR_PENDING_SENDS(pAdapt);
        }
    }
    else
    {
        ADAPT_DECR_PENDING_SENDS(pAdapt);
        //
        // We are out of packets. Silently drop it. Alternatively we can deal with it:
        //    - By keeping separate send and receive pools
        //    - Dynamically allocate more pools as needed and free them when not needed
        //
    }

    return(Status);
}
Esempio n. 4
0
NDIS_STATUS
MPSend(
    IN NDIS_HANDLE             MiniportAdapterContext,
    IN PNDIS_PACKET            Packet,
    IN UINT                    Flags
    )
/*++

Routine Description:

    Send Packet handler. Either this or our SendPackets (array) handler is called
    based on which one is enabled in our Miniport Characteristics.

Arguments:

    MiniportAdapterContext    Pointer to the adapter
    Packet                    Packet to send
    Flags                     Unused, passed down below

Return Value:

    Return code from NdisSend

--*/
{
    PADAPT              pAdapt = (PADAPT)MiniportAdapterContext;
    NDIS_STATUS         Status;
	FILTER_STATUS		fStatus;
    PNDIS_PACKET        MyPacket;
    PVOID               MediaSpecificInfo = NULL;
    ULONG               MediaSpecificInfoSize = 0;

    //
    // The driver should fail the send if the virtual miniport is in low 
    // power state
    //
    if (pAdapt->MPDeviceState > NdisDeviceStateD0)
    {
         return NDIS_STATUS_FAILURE;
    }
	//***************************此函数作废!!!!!!!!!!!!!!!************************************
	//KdPrint(("微端口MPSend方法,开始报文分析\n"));
	fStatus = AnalysisPacket(Packet, MODE_SEND);
	//getPacketBuffer(Packet, )
	//fStatus = FILTER_STATUS_PASS;
	if (fStatus == FILTER_STATUS_DROP)
	{
		return NDIS_STATUS_FAILURE;
	}
	else if(fStatus == FILTER_STATUS_MODIFY_REDIRECT)
	{
		// 转发......
		// 修改包中的目标地址,和正常发送一样将包向下发送
		// TODO.
	}

#ifdef NDIS51
    //
    // Use NDIS 5.1 packet stacking:
    //
    {
        PNDIS_PACKET_STACK        pStack;
        BOOLEAN                   Remaining;

        //
        // Packet stacks: Check if we can use the same packet for sending down.
        //

        pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
        if (Remaining)
        {
            //
            // We can reuse "Packet".
            //
            // NOTE: if we needed to keep per-packet information in packets
            // sent down, we can use pStack->IMReserved[].
            //
            ASSERT(pStack);
            //
            // If the below miniport is going to low power state, stop sending down any packet.
            //
            NdisAcquireSpinLock(&pAdapt->Lock);
            if (pAdapt->PTDeviceState > NdisDeviceStateD0)
            {
                NdisReleaseSpinLock(&pAdapt->Lock);
                return NDIS_STATUS_FAILURE;
            }
            pAdapt->OutstandingSends++;
            NdisReleaseSpinLock(&pAdapt->Lock);
            NdisSend(&Status,
                     pAdapt->BindingHandle,
                     Packet);

            if (Status != NDIS_STATUS_PENDING)
            {
                ADAPT_DECR_PENDING_SENDS(pAdapt);
            }

            return(Status);
        }
    }
#endif // NDIS51

    //
    // We are either not using packet stacks, or there isn't stack space
    // in the original packet passed down to us. Allocate a new packet
    // to wrap the data with.
    //
    //
    // If the below miniport is going to low power state, stop sending down any packet.
    //
    NdisAcquireSpinLock(&pAdapt->Lock);
    if (pAdapt->PTDeviceState > NdisDeviceStateD0)
    {
        NdisReleaseSpinLock(&pAdapt->Lock);
        return NDIS_STATUS_FAILURE;
    
    }
    pAdapt->OutstandingSends++;
    NdisReleaseSpinLock(&pAdapt->Lock);
    
    NdisAllocatePacket(&Status,
                       &MyPacket,
                       pAdapt->SendPacketPoolHandle);

    if (Status == NDIS_STATUS_SUCCESS)
    {
        PSEND_RSVD            SendRsvd;

        //
        // Save a pointer to the original packet in our reserved
        // area in the new packet. This is needed so that we can
        // get back to the original packet when the new packet's send
        // is completed.
        //
        SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
        SendRsvd->OriginalPkt = Packet;

        NdisGetPacketFlags(MyPacket) = Flags;

        //
        // Set up the new packet so that it describes the same
        // data as the original packet.
        //
        NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
        NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
#ifdef WIN9X
        //
        // Work around the fact that NDIS does not initialize this
        // to FALSE on Win9x.
        //
        NDIS_PACKET_VALID_COUNTS(MyPacket) = FALSE;
#endif

        //
        // Copy the OOB Offset from the original packet to the new
        // packet.
        //
        NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
                       NDIS_OOB_DATA_FROM_PACKET(Packet),
                       sizeof(NDIS_PACKET_OOB_DATA));

#ifndef WIN9X
        //
        // Copy the right parts of per packet info into the new packet.
        // This API is not available on Win9x since task offload is
        // not supported on that platform.
        //
        NdisIMCopySendPerPacketInfo(MyPacket, Packet);
#endif
        
        //
        // Copy the Media specific information
        //
        NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
                                            &MediaSpecificInfo,
                                            &MediaSpecificInfoSize);

        if (MediaSpecificInfo || MediaSpecificInfoSize)
        {
            NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
                                                MediaSpecificInfo,
                                                MediaSpecificInfoSize);
        }

        NdisSend(&Status,
                 pAdapt->BindingHandle,
                 MyPacket);


        if (Status != NDIS_STATUS_PENDING)
        {
#ifndef WIN9X
            NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
#endif
            NdisFreePacket(MyPacket);
            ADAPT_DECR_PENDING_SENDS(pAdapt);
        }
    }
    else
    {
        ADAPT_DECR_PENDING_SENDS(pAdapt);
        //
        // We are out of packets. Silently drop it. Alternatively we can deal with it:
        //    - By keeping separate send and receive pools
        //    - Dynamically allocate more pools as needed and free them when not needed
        //
    }

    return(Status);
}