VOID FreeNdisPacket ( PNDIS_PACKET Packet ) /* * FUNCTION: Frees an NDIS packet * ARGUMENTS: * Packet = Pointer to NDIS packet to be freed */ { PNDIS_BUFFER Buffer, NextBuffer; TI_DbgPrint(DEBUG_PBUFFER, ("Packet (0x%X)\n", Packet)); /* Free all the buffers in the packet first */ NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL); for (; Buffer != NULL; Buffer = NextBuffer) { PVOID Data; UINT Length; NdisGetNextBuffer(Buffer, &NextBuffer); NdisQueryBuffer(Buffer, &Data, &Length); TI_DbgPrint(DEBUG_PBUFFER, ("Freeing ndis buffer (0x%X)\n", Buffer)); NdisFreeBuffer(Buffer); TI_DbgPrint(DEBUG_PBUFFER, ("Freeing exal buffer (0x%X)\n", Data)); ExFreePoolWithTag(Data, PACKET_BUFFER_TAG); } /* Finally free the NDIS packet discriptor */ NdisFreePacket(Packet); }
VOID FreeNdisPacketX ( PNDIS_PACKET Packet, PCHAR File, UINT Line ) /* * FUNCTION: Frees an NDIS packet * ARGUMENTS: * Packet = Pointer to NDIS packet to be freed */ { PNDIS_BUFFER Buffer, NextBuffer; TI_DbgPrint(DEBUG_PBUFFER, ("Packet (0x%X)\n", Packet)); /* Free all the buffers in the packet first */ NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL); for (; Buffer != NULL; Buffer = NextBuffer) { PVOID Data; UINT Length; NdisGetNextBuffer(Buffer, &NextBuffer); XNdisQueryBuffer(Buffer, &Data, &Length); UntrackFL(File,Line,Buffer); NdisFreeBuffer(Buffer); exFreePool(Data); } /* Finally free the NDIS packet descriptor */ UntrackFL(File,Line,Packet); NdisFreePacket(Packet); }
BOOLEAN FilterPacket_ReceiveHandler ( PVOID pHeadBuffer, ULONG ulHeadSize, PNDIS_PACKET pPacket ) /*++ Routine Description: Filters network packets for NDISReceiveHandler. Arguments: ... Return Value: TRUE: This packet should be blocked. FALSE: This packet should pass through. Author: xiaonie 2012/07/12 --*/ { ULONG ulPacketSize; PUCHAR pBuffer = NULL; NDIS_STATUS status; PNDIS_BUFFER pFirstBuffer, pNextBuffer; BOOLEAN bRet = FALSE; NdisQueryPacket(pPacket, NULL, NULL, NULL, &ulPacketSize); if (ulPacketSize == 0) return FALSE; DbgPrint("ulHeadSize == %d, ulPacketSize == %d in FilterPacket_ReceiveHandler!\r\n", ulHeadSize, ulPacketSize); status = NdisAllocateMemoryWithTag(&pBuffer, ulPacketSize + ulHeadSize, '!nmN'); if (status != NDIS_STATUS_SUCCESS/* || pBuffer == NULL */) return FALSE; //obtain content from the packet NdisMoveMemory(pBuffer, pHeadBuffer, ulHeadSize); ReadPacket(pPacket, pBuffer + ulHeadSize, ulPacketSize); bRet = RabbitHole(pBuffer, ulPacketSize + ulHeadSize); NdisFreeMemory(pBuffer, ulPacketSize + ulHeadSize, 0); return bRet; }
PVOID AdjustPacket( PNDIS_PACKET Packet, UINT Available, UINT Needed) /* * FUNCTION: Adjusts the amount of unused space at the beginning of the packet * ARGUMENTS: * Packet = Pointer to packet * Available = Number of bytes available at start of first buffer * Needed = Number of bytes needed for the header * RETURNS: * Pointer to start of packet */ { PNDIS_BUFFER NdisBuffer; INT Adjust; TI_DbgPrint(DEBUG_PBUFFER, ("Available = %d, Needed = %d.\n", Available, Needed)); Adjust = Available - Needed; NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL); /* If Adjust is zero there is no need to adjust this packet as there is no additional space at start the of first buffer */ if (Adjust != 0) { NdisBuffer->MappedSystemVa = (PVOID) ((ULONG_PTR)(NdisBuffer->MappedSystemVa) + Adjust); NdisBuffer->ByteOffset += Adjust; NdisBuffer->ByteCount -= Adjust; } return NdisBuffer->MappedSystemVa; }
/* Maps to ReceiverReleaseNetBufferList() in xennet6 */ static void ReceiverReleasePacket(PRECEIVER Receiver, PNDIS_PACKET Packet) { PMDL headMdl; NdisQueryPacket(Packet, NULL, NULL, &headMdl, NULL); ReceiverCommonReleaseMdlChain(&Receiver->Common, headMdl); NdisDprFreePacketNonInterlocked(Packet); }
void GetDataPtr( PNDIS_PACKET Packet, UINT Offset, PCHAR *DataOut, PUINT Size ) { PNDIS_BUFFER Buffer; NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL); if( !Buffer ) return; SkipToOffset( Buffer, Offset, DataOut, Size ); }
Boolean ssh_wan_send_to_adapter(SshNdisIMAdapter adapter, SshNdisPacket packet, SshInterceptorProtocol protocol) { UINT pkt_len; SshUInt32 ppp_protocol; PUCHAR pos; ULONG len; PNDIS_WAN_PACKET wan_pkt; switch (protocol) { case SSH_PROTOCOL_IP4: ppp_protocol = SSH_PPP_PROTOCOL_IP4; break; case SSH_PROTOCOL_IP6: ppp_protocol = SSH_PPP_PROTOCOL_IP6; break; default: SSH_DEBUG(SSH_D_ERROR, ("Cannot PPP-encapsulate non-IP protocol")); return FALSE; } NdisQueryPacket(packet->np, NULL, NULL, NULL, &pkt_len); /* Allocate a buffer large enough a PPP header and the packet. */ if (!(wan_pkt = ssh_wan_alloc_buffer_send(adapter, 4 + pkt_len))) goto fail; pos = wan_pkt->CurrentBuffer; len = 4 + pkt_len; /* Create PPP header. */ if (!ssh_wan_encode_ppp_header(&pos, &len, ppp_protocol, adapter->ppp_send_flags)) goto fail; /* Add the packet itself. */ ssh_interceptor_packet_copyout(&packet->ip, 0, pos, pkt_len); pos += pkt_len; len -= pkt_len; wan_pkt->CurrentLength = pos - wan_pkt->CurrentBuffer; /* Send WAN packet to adapter. */ ssh_wan_send_buffer(adapter, wan_pkt); return TRUE; fail: if (wan_pkt) ssh_wan_free_buffer_send(wan_pkt); return FALSE; }
BOOLEAN FilterPacket_ProtocolReceiveHandler ( PNDIS_PACKET pPacket ) /*++ Routine Description: Filters network packets for NDISProtocolReceiveHandler. Arguments: pPacket - Pointer to the packet buffer descriptor. Return Value: TRUE: This packet should be blocked. FALSE: This packet should pass through. Author: xiaonie 2012/07/12 --*/ { ULONG ulTotalPacketLength; PUCHAR pBuffer = NULL; BOOLEAN bRet = FALSE; NDIS_STATUS status; NdisQueryPacket(pPacket, NULL, NULL, NULL, &ulTotalPacketLength); if (ulTotalPacketLength == 0) return FALSE; status = NdisAllocateMemoryWithTag(&pBuffer, ulTotalPacketLength, '!nmN'); if (status != NDIS_STATUS_SUCCESS/* || pBuffer == NULL*/) return FALSE; ReadPacket(pPacket, pBuffer, ulTotalPacketLength); // filter it! bRet = RabbitHole(pBuffer, ulTotalPacketLength); NdisFreeMemory(pBuffer, ulTotalPacketLength, 0); return bRet; }
Boolean ssh_wan_send_to_protocol(SshNdisIMAdapter adapter, SshNdisPacket packet, SshInterceptorProtocol protocol) { UINT pkt_len; SshUInt32 ppp_protocol; PUCHAR buffer, pos; ULONG len; switch (protocol) { case SSH_PROTOCOL_IP4: ppp_protocol = SSH_PPP_PROTOCOL_IP4; break; case SSH_PROTOCOL_IP6: ppp_protocol = SSH_PPP_PROTOCOL_IP6; break; default: SSH_DEBUG(SSH_D_ERROR, ("Cannot PPP-encapsulate non-IP protocol")); return FALSE; } NdisQueryPacket(packet->np, NULL, NULL, NULL, &pkt_len); /* Allocate a buffer large enough a PPP header and the packet. */ buffer = ssh_wan_alloc_buffer_receive(adapter, 4 + pkt_len); if (buffer == NULL) goto fail; pos = buffer; len = 4 + pkt_len; /* Create PPP header. */ if (!ssh_wan_encode_ppp_header(&pos, &len, ppp_protocol, adapter->ppp_receive_flags)) goto fail; /* Add the packet itself. */ ssh_interceptor_packet_copyout(&packet->ip, 0, pos, pkt_len); pos += pkt_len; len -= pkt_len; /* Indicate WAN packet to protocol. */ ssh_wan_receive_buffer(adapter, buffer, pos - buffer); return TRUE; fail: if (buffer) ssh_wan_free_buffer_receive(buffer); return FALSE; }
VOID ArcFreeNdisPacket( IN PARC_PACKET Packet ) /*++ Routine description: This routine takes an arcnet packet and frees up the corresponding Ndis packet built for it. Arguments: Packet - The packet to free up. Return values: None --*/ { PNDIS_BUFFER NdisBuffer, NextNdisBuffer; NdisQueryPacket( &(Packet->TmpNdisPacket), NULL, NULL, &NdisBuffer, NULL ); while (NdisBuffer != NULL) { NdisGetNextBuffer( NdisBuffer, &NextNdisBuffer ); NdisFreeBuffer( NdisBuffer ); NdisBuffer = NextNdisBuffer; } NdisReinitializePacket(&(Packet->TmpNdisPacket)); }
/*----------------------------------------------------------------------------*/ VOID kalCopyFrame(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, OUT PUINT_8 pucDestBuffer) { PNDIS_PACKET prNdisPacket; PNDIS_BUFFER prNdisBuffer, prNextNdisBuffer; UINT u4PacketLen; UINT u4BytesToCopy; PVOID pvMbuf; UINT u4MbufLength; UINT u4BytesCopied; ASSERT(pvPacket); prNdisPacket = (PNDIS_PACKET) pvPacket; NdisQueryPacket(prNdisPacket, NULL, NULL, &prNdisBuffer, &u4PacketLen); u4BytesToCopy = u4PacketLen; u4BytesCopied = 0; while (u4BytesToCopy != 0) { #ifdef NDIS51_MINIPORT NdisQueryBufferSafe(prNdisBuffer, &pvMbuf, &u4MbufLength, HighPagePriority); #else NdisQueryBuffer(prNdisBuffer, &pvMbuf, &u4MbufLength); #endif /* NDIS51_MINIPORT */ if (pvMbuf == (PVOID) NULL) { ASSERT(pvMbuf); break; } NdisMoveMemory((PVOID) pucDestBuffer, pvMbuf, u4MbufLength); u4BytesToCopy -= u4MbufLength; u4BytesCopied += u4MbufLength; pucDestBuffer += u4MbufLength; NdisGetNextBuffer(prNdisBuffer, &prNextNdisBuffer); prNdisBuffer = prNextNdisBuffer; } ASSERT(u4BytesCopied == u4PacketLen); return; }
static void shared_free_pkt(ND_PKT* p) { #ifndef NDIS60 PNDIS_BUFFER b; NdisQueryPacket(p, NULL, NULL, &b, NULL); ASSERT(b); NdisFreeBuffer(b); NdisFreePacket(p); #else /* NDIS60 */ PNET_BUFFER nb; PMDL b; nb = NET_BUFFER_LIST_FIRST_NB(p); b = NET_BUFFER_FIRST_MDL(nb); ASSERT(b); NdisFreeMdl(b); NdisFreeNetBufferList(p); #endif /* NDIS60 */ }
UINT ResizePacket( PNDIS_PACKET Packet, UINT Size) /* * FUNCTION: Resizes an NDIS packet * ARGUMENTS: * Packet = Pointer to packet * Size = Number of bytes in first buffer * RETURNS: * Previous size of first buffer */ { PNDIS_BUFFER NdisBuffer; UINT OldSize; NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL); OldSize = NdisBuffer->ByteCount; if (Size != OldSize) NdisBuffer->ByteCount = Size; return OldSize; }
NTSTATUS IPSendDatagram(PIP_PACKET IPPacket, PNEIGHBOR_CACHE_ENTRY NCE, PIP_TRANSMIT_COMPLETE Complete, PVOID Context) /* * FUNCTION: Sends an IP datagram to a remote address * ARGUMENTS: * IPPacket = Pointer to an IP packet * RCN = Pointer to route cache node * RETURNS: * Status of operation * NOTES: * This is the highest level IP send routine. It possibly breaks the packet * into two or more fragments before passing it on to the next lower level * send routine (IPSendFragment) */ { UINT PacketSize; TI_DbgPrint(MAX_TRACE, ("Called. IPPacket (0x%X) NCE (0x%X)\n", IPPacket, NCE)); DISPLAY_IP_PACKET(IPPacket); /*OskitDumpBuffer( IPPacket->Header, IPPacket->TotalSize );*/ /* Fetch path MTU now, because it may change */ TI_DbgPrint(MID_TRACE,("PathMTU: %d\n", NCE->Interface->MTU)); NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, NULL, &PacketSize); NCE->Interface->Stats.OutBytes += PacketSize; return SendFragments(IPPacket, NCE, NCE->Interface->MTU, Complete, Context); }
extern VOID Pc586CopyFromPacketToPacket( IN PNDIS_PACKET Destination, IN UINT DestinationOffset, IN UINT BytesToCopy, IN PNDIS_PACKET Source, IN UINT SourceOffset, OUT PUINT BytesCopied ) /*++ Routine Description: Copy from an ndis packet to an ndis packet. Arguments: Destination - The packet should be copied in to. DestinationOffset - The offset from the beginning of the packet into which the data should start being placed. BytesToCopy - The number of bytes to copy from the source packet. Source - The ndis packet from which to copy data. SourceOffset - The offset from the start of the packet from which to start copying data. BytesCopied - The number of bytes actually copied from the source packet. This can be less than BytesToCopy if the source or destination packet is too short. Return Value: None --*/ { // // Holds the count of the number of ndis buffers comprising the // destination packet. // UINT DestinationBufferCount; // // Holds the count of the number of ndis buffers comprising the // source packet. // UINT SourceBufferCount; // // Points to the buffer into which we are putting data. // PNDIS_BUFFER DestinationCurrentBuffer; // // Points to the buffer from which we are extracting data. // PNDIS_BUFFER SourceCurrentBuffer; // // Holds the virtual address of the current destination buffer. // PVOID DestinationVirtualAddress; // // Holds the virtual address of the current source buffer. // PVOID SourceVirtualAddress; // // Holds the length of the current destination buffer. // UINT DestinationCurrentLength; // // Holds the length of the current source buffer. // UINT SourceCurrentLength; // // 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 of the destination. // NdisQueryPacket( Destination, NULL, &DestinationBufferCount, &DestinationCurrentBuffer, NULL ); // // Could have a null packet. // if (!DestinationBufferCount) return; NdisQueryBuffer( DestinationCurrentBuffer, NULL, &DestinationVirtualAddress, &DestinationCurrentLength ); // // Get the first buffer of the source. // NdisQueryPacket( Source, NULL, &SourceBufferCount, &SourceCurrentBuffer, NULL ); // // Could have a null packet. // if (!SourceBufferCount) return; NdisQueryBuffer( SourceCurrentBuffer, NULL, &SourceVirtualAddress, &SourceCurrentLength ); while (LocalBytesCopied < BytesToCopy) { // // Check to see whether we've exhausted the current destination // buffer. If so, move onto the next one. // if (!DestinationCurrentLength) { NdisGetNextBuffer( DestinationCurrentBuffer, &DestinationCurrentBuffer ); if (!DestinationCurrentBuffer) { // // We've reached the end of the packet. We return // with what we've done so far. (Which must be shorter // than requested.) // break; } NdisQueryBuffer( DestinationCurrentBuffer, NULL, &DestinationVirtualAddress, &DestinationCurrentLength ); continue; } // // Check to see whether we've exhausted the current source // buffer. If so, move onto the next one. // if (!SourceCurrentLength) { NdisGetNextBuffer( SourceCurrentBuffer, &SourceCurrentBuffer ); if (!SourceCurrentBuffer) { // // We've reached the end of the packet. We return // with what we've done so far. (Which must be shorter // than requested.) // break; } NdisQueryBuffer( SourceCurrentBuffer, NULL, &SourceVirtualAddress, &SourceCurrentLength ); continue; } // // Try to get us up to the point to start the copy. // if (DestinationOffset) { if (DestinationOffset > DestinationCurrentLength) { // // What we want isn't in this buffer. // DestinationOffset -= DestinationCurrentLength; DestinationCurrentLength = 0; continue; } else { DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress + DestinationOffset; DestinationCurrentLength -= DestinationOffset; DestinationOffset = 0; } } // // Try to get us up to the point to start the copy. // if (SourceOffset) { if (SourceOffset > SourceCurrentLength) { // // What we want isn't in this buffer. // SourceOffset -= SourceCurrentLength; SourceCurrentLength = 0; continue; } else { SourceVirtualAddress = (PCHAR)SourceVirtualAddress + SourceOffset; SourceCurrentLength -= SourceOffset; SourceOffset = 0; } } // // Copy the data. // { // // Holds the amount of data to move. // UINT AmountToMove; // // Holds the amount desired remaining. // UINT Remaining = BytesToCopy - LocalBytesCopied; AmountToMove = ((SourceCurrentLength <= DestinationCurrentLength)? (SourceCurrentLength):(DestinationCurrentLength)); AmountToMove = ((Remaining < AmountToMove)? (Remaining):(AmountToMove)); PC586_MOVE_MEMORY( DestinationVirtualAddress, SourceVirtualAddress, AmountToMove ); DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress + AmountToMove; SourceVirtualAddress = (PCHAR)SourceVirtualAddress + AmountToMove; LocalBytesCopied += AmountToMove; SourceCurrentLength -= AmountToMove; DestinationCurrentLength -= AmountToMove; } } *BytesCopied = LocalBytesCopied; }
VOID ReadPacket ( PNDIS_PACKET pPacket, PUCHAR pBuffer, ULONG ulBufSize ) /*++ Routine Description: Retrieves the buffer from a buffer descriptor. Arguments: Packet - Pointer to the buffer descriptor. pBuffer - Pointer to the buffer. ulBufSize - Size of the buffer. Return Value: None. Author: xiaonie 2012/07/12 --*/ { PVOID pVA; PNDIS_BUFFER pFirstBuffer, pNextBuffer; ULONG ulTotalLength; ULONG ulLen; PVOID pBuf = NULL; ULONG ulCount = 0; NdisQueryPacket(pPacket, NULL, NULL, &pFirstBuffer, NULL); while (pFirstBuffer != NULL) { NdisQueryBufferSafe(pFirstBuffer, &pVA, &ulLen, NormalPagePriority); if(!pVA) { // memory not enough DbgPrint("pVA == NULL, insufficient memory!\r\n"); break; } if (ulCount + ulLen > ulBufSize) { DbgPrint("ulCount + ulLen(%d) > ulBufSize(%d)\r\n", ulCount + ulLen, ulBufSize); break; } NdisMoveMemory(pBuffer + ulCount, pVA, ulLen); ulCount += ulLen; NdisGetNextBuffer(pFirstBuffer, &pNextBuffer); pFirstBuffer = pNextBuffer; } DbgPrint("ReadPacket: ulBufSize == %d, ulCount == %d\n", ulBufSize, ulCount); return; }
extern NDIS_STATUS SonicTransferData( OUT PNDIS_PACKET Packet, OUT PUINT BytesTransferred, IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_HANDLE MiniportReceiveContext, IN UINT ByteOffset, IN UINT BytesToTransfer ) /*++ Routine Description: A protocol calls the SonicTransferData request (indirectly via NdisTransferData) from within its Receive event handler to instruct the driver to copy the contents of the received packet a specified paqcket buffer. Arguments: MiniportAdapterContext - Context registered with the wrapper, really a pointer to the adapter. MiniportReceiveContext - The context value passed by the driver on its call to NdisMEthIndicateReceive. The driver can use this value to determine which packet, on which adapter, is being received. ByteOffset - An unsigned integer specifying the offset within the received packet at which the copy is to begin. If the entire packet is to be copied, ByteOffset must be zero. BytesToTransfer - An unsigned integer specifying the number of bytes to copy. It is legal to transfer zero bytes; this has no effect. If the sum of ByteOffset and BytesToTransfer is greater than the size of the received packet, then the remainder of the packet (starting from ByteOffset) is transferred, and the trailing portion of the receive buffer is not modified. Packet - A pointer to a descriptor for the packet storage into which the MAC is to copy the received packet. BytesTransfered - A pointer to an unsigned integer. The MAC writes the actual number of bytes transferred into this location. This value is not valid if the return status is STATUS_PENDING. Return Value: The function value is the status of the operation. --*/ { // // Buffer is the buffer to copy from. // PCHAR Buffer = (PCHAR)MiniportReceiveContext + ByteOffset; // // Holds the count of the number of ndis buffers comprising the // destination packet. // UINT DestinationBufferCount; // // Points to the buffer into which we are putting data. // PNDIS_BUFFER DestinationCurrentBuffer; // // Points to the location in Buffer from which we are extracting data. // PUCHAR SourceCurrentAddress; // // Holds the virtual address of the current destination buffer. // PVOID DestinationVirtualAddress; // // Holds the length of the current destination buffer. // UINT DestinationCurrentLength; // // Keep a local variable of BytesTransferred so we aren't referencing // through a pointer. // UINT LocalBytesTransferred = 0; // // MiniportAdapterContext is not referenced. // MiniportAdapterContext; // // Take care of boundary condition of zero length copy. // if (BytesToTransfer == 0) { *BytesTransferred = 0; return NDIS_STATUS_SUCCESS; } // // Get the first buffer of the destination. // NdisQueryPacket( Packet, NULL, &DestinationBufferCount, &DestinationCurrentBuffer, NULL ); // // Could have a null packet. // if (DestinationBufferCount == 0) { *BytesTransferred = 0; return NDIS_STATUS_SUCCESS; } NdisQueryBuffer( DestinationCurrentBuffer, &DestinationVirtualAddress, &DestinationCurrentLength ); // // Set up the source address. // SourceCurrentAddress = Buffer; while (LocalBytesTransferred < BytesToTransfer) { // // Check to see whether we've exhausted the current destination // buffer. If so, move onto the next one. // if (DestinationCurrentLength == 0) { NdisGetNextBuffer( DestinationCurrentBuffer, &DestinationCurrentBuffer ); if (DestinationCurrentBuffer == NULL) { // // We've reached the end of the packet. We return // with what we've done so far. (Which must be shorter // than requested.) // break; } NdisQueryBuffer( DestinationCurrentBuffer, &DestinationVirtualAddress, &DestinationCurrentLength ); continue; } // // Copy the data. // { // // Holds the amount of data to move. // UINT AmountToMove; // // Holds the amount desired remaining. // UINT Remaining = BytesToTransfer - LocalBytesTransferred; AmountToMove = DestinationCurrentLength; AmountToMove = ((Remaining < AmountToMove)? (Remaining):(AmountToMove)); SONIC_MOVE_MEMORY( DestinationVirtualAddress, SourceCurrentAddress, AmountToMove ); SourceCurrentAddress += AmountToMove; LocalBytesTransferred += AmountToMove; DestinationCurrentLength -= AmountToMove; } } *BytesTransferred = LocalBytesTransferred; return NDIS_STATUS_SUCCESS; }
NDIS_STATUS ProIndicatePacket( PLOGICAL_ADAPTER Adapter, PNDIS_PACKET Packet) /* * FUNCTION: Indicates a packet to bound protocols * ARGUMENTS: * Adapter = Pointer to logical adapter * Packet = Pointer to packet to indicate * RETURNS: * STATUS_SUCCESS in all cases * NOTES: * - XXX ATM, this only handles loopback packets - is that its designed function? */ { UINT BufferedLength; UINT PacketLength; KIRQL OldIrql; PUCHAR LookaheadBuffer; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); #if DBG MiniDisplayPacket(Packet); #endif NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength); LookaheadBuffer = ExAllocatePool(NonPagedPool, PacketLength); if (!LookaheadBuffer) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n")); return NDIS_STATUS_RESOURCES; } NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n")); KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql); { BufferedLength = CopyPacketToBuffer(LookaheadBuffer, Packet, 0, PacketLength); Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()] = Packet; } KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); if (BufferedLength > Adapter->MediumHeaderSize) { /* XXX Change this to call SendPackets so we don't have to duplicate this wacky logic */ MiniIndicateData(Adapter, NULL, LookaheadBuffer, Adapter->MediumHeaderSize, &LookaheadBuffer[Adapter->MediumHeaderSize], BufferedLength - Adapter->MediumHeaderSize, PacketLength - Adapter->MediumHeaderSize); } else { MiniIndicateData(Adapter, NULL, LookaheadBuffer, Adapter->MediumHeaderSize, NULL, 0, 0); } ExFreePool(LookaheadBuffer); KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql); { Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()] = NULL; } KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); return NDIS_STATUS_SUCCESS; }
NDIS_STATUS NTAPI ProSend( IN NDIS_HANDLE MacBindingHandle, IN PNDIS_PACKET Packet) /* * FUNCTION: Forwards a request to send a packet to an NDIS miniport * ARGUMENTS: * MacBindingHandle = Adapter binding handle * Packet = Pointer to NDIS packet descriptor * RETURNS: * NDIS_STATUS_SUCCESS if the packet was successfully sent * NDIS_STATUS_PENDING if the miniport was busy or a serialized miniport returned NDIS_STATUS_RESOURCES */ { PADAPTER_BINDING AdapterBinding; PLOGICAL_ADAPTER Adapter; PNDIS_BUFFER NdisBuffer; PDMA_CONTEXT Context; NDIS_STATUS NdisStatus; UINT PacketLength; KIRQL OldIrql; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); ASSERT(MacBindingHandle); AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle); ASSERT(AdapterBinding); Adapter = AdapterBinding->Adapter; ASSERT(Adapter); /* if the following is not true, KeRaiseIrql() below will break */ ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); /* XXX what is this crazy black magic? */ Packet->Reserved[1] = (ULONG_PTR)MacBindingHandle; /* * Test the packet to see if it is a MAC loopback. * * We may have to loop this packet if miniport cannot. * If dest MAC address of packet == MAC address of adapter, * this is a loopback frame. */ if ((Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) && MiniAdapterHasAddress(Adapter, Packet)) { #if WORKER_TEST MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, Packet, FALSE); return NDIS_STATUS_PENDING; #else return ProIndicatePacket(Adapter, Packet); #endif } else { if (Adapter->NdisMiniportBlock.ScatterGatherListSize != 0) { NDIS_DbgPrint(MID_TRACE, ("Using Scatter/Gather DMA\n")); NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, &PacketLength); Context = ExAllocatePool(NonPagedPool, sizeof(DMA_CONTEXT)); if (!Context) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n")); return NDIS_STATUS_RESOURCES; } Context->Adapter = Adapter; Context->Packet = Packet; KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); KeFlushIoBuffers(NdisBuffer, FALSE, TRUE); NdisStatus = Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->GetScatterGatherList( Adapter->NdisMiniportBlock.SystemAdapterObject, Adapter->NdisMiniportBlock.PhysicalDeviceObject, NdisBuffer, MmGetMdlVirtualAddress(NdisBuffer), PacketLength, ScatterGatherSendPacket, Context, TRUE); KeLowerIrql(OldIrql); if (!NT_SUCCESS(NdisStatus)) { NDIS_DbgPrint(MIN_TRACE, ("GetScatterGatherList failed! (%x)\n", NdisStatus)); return NdisStatus; } return NDIS_STATUS_PENDING; } return proSendPacketToMiniport(Adapter, Packet); } }
extern VOID Pc586ProcessLoopback( IN PPC586_ADAPTER Adapter ) /*++ Routine Description: This routine is responsible for indicating *one* packet on the loopback queue either completing it or moving on to the finish send queue. Arguments: Adapter - The adapter whose loopback queue we are processing. Return Value: None. --*/ { NdisAcquireSpinLock(&Adapter->Lock); if (Adapter->FirstLoopBack) { // // Packet at the head of the loopback list. // PNDIS_PACKET PacketToMove; // // The reserved portion of the above packet. // PPC586_RESERVED Reserved; // // Buffer for loopback. // CHAR Loopback[PC586_SIZE_OF_RECEIVE_BUFFERS]; // // The first buffer in the ndis packet to be loopbacked. // PNDIS_BUFFER FirstBuffer; // // The total amount of user data in the packet to be // loopbacked. // UINT TotalPacketLength; // // Eventually the address of the data to be indicated // to the transport. // PVOID BufferAddress; // // Eventually the length of the data to be indicated // to the transport. // UINT BufferLength; PacketToMove = Adapter->FirstLoopBack; Pc586RemovePacketFromLoopBack(Adapter); NdisReleaseSpinLock(&Adapter->Lock); Reserved = PPC586_RESERVED_FROM_PACKET(PacketToMove); // // See if we need to copy the data from the packet // into the loopback buffer. // // We need to copy to the local loopback buffer if // the first buffer of the packet is less than the // minimum loopback size AND the first buffer isn't // the total packet. // NdisQueryPacket( PacketToMove, NULL, NULL, &FirstBuffer, &TotalPacketLength ); NdisQueryBuffer( FirstBuffer, NULL, &BufferAddress, &BufferLength ); if ((BufferLength < PC586_SIZE_OF_RECEIVE_BUFFERS) && (BufferLength != TotalPacketLength)) { Pc586CopyFromPacketToBuffer( PacketToMove, 0, PC586_SIZE_OF_RECEIVE_BUFFERS, Loopback, &BufferLength ); BufferAddress = Loopback; } // // Indicate the packet to every open binding // that could want it. // MacFilterIndicateReceive( Adapter->FilterDB, PacketToMove, ((PCHAR)BufferAddress), BufferAddress, BufferLength, TotalPacketLength ); // // Remove the packet from the loopback queue and // either indicate that it is finished or put // it on the finishing up queue for the real transmits. // NdisAcquireSpinLock(&Adapter->Lock); if (!Reserved->STAGE.STAGE4.ReadyToComplete) { // // We can decrement the reference count on the open by one since // it is no longer being "referenced" by the packet on the // loopback queue. // PPC586_OPEN_FROM_BINDING_HANDLE( Reserved->MacBindingHandle )->References--; Pc586PutPacketOnFinishTrans( Adapter, PacketToMove ); } else { PPC586_OPEN Open; // // Increment the reference count on the open so that // it will not be deleted out from under us while // where indicating it. // Open = PPC586_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle); Open->References++; NdisReleaseSpinLock(&Adapter->Lock); NdisCompleteSend( Open->NdisBindingContext, Reserved->RequestHandle, ((Reserved->STAGE.STAGE4.SuccessfulTransmit)? (NDIS_STATUS_SUCCESS):(NDIS_STATUS_FAILURE)) ); NdisAcquireSpinLock(&Adapter->Lock); // // We can decrement the reference count by two since it is // no longer being referenced to indicate and it is no longer // being "referenced" by the packet on the loopback queue. // Open->References -= 2; } // // If there is nothing else on the loopback queue // then indicate that reception is "done". // if (!Adapter->FirstLoopBack) { // // We need to signal every open binding that the // "receives" are complete. We increment the reference // count on the open binding while we're doing indications // so that the open can't be deleted out from under // us while we're indicating (recall that we can't own // the lock during the indication). // PPC586_OPEN Open; PLIST_ENTRY CurrentLink; CurrentLink = Adapter->OpenBindings.Flink; while (CurrentLink != &Adapter->OpenBindings) { Open = CONTAINING_RECORD( CurrentLink, PC586_OPEN, OpenList ); Open->References++; NdisReleaseSpinLock(&Adapter->Lock); NdisIndicateReceiveComplete(Open->NdisBindingContext); NdisAcquireSpinLock(&Adapter->Lock); Open->References--; CurrentLink = CurrentLink->Flink; } } } NdisReleaseSpinLock(&Adapter->Lock); }
NDIS_STATUS TOK162Send( IN NDIS_HANDLE MiniportAdapterContext, IN PNDIS_PACKET Packet, IN UINT Flags ) /*++ Routine Description: The TOK162Send request instructs a Miniport to transmit a packet through the adapter onto the medium. Arguments: MiniportAdapterContext - The context value returned by the Miniport when the adapter was initialized. In reality, it is a pointer to TOK162_ADAPTER. Packet - A pointer to a descriptor for the packet that is to be transmitted. Return Value: The function value is the status of the operation. --*/ { // // Pointer to the adapter. // PTOK162_ADAPTER Adapter = PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); // // Pointer to transmit block // PTOK162_SUPER_TRANSMIT_LIST temp; // // The number of NDIS buffers in the entire packet. // UINT NdisBufferCount; // // The total amount of data in the ndis packet. // UINT TotalDataLength; // // Points to the current ndis buffer being walked. // PNDIS_BUFFER CurrentBuffer; // // Aux pointer to number of available transmit blocks // PUINT AvailBlocks; // // log send called // IF_LOG('h'); // // Get original count // AvailBlocks = &Adapter->NumberOfAvailableTransmitBlocks; // // See if we have any transmits available // if (*AvailBlocks > 0) { (*AvailBlocks)--; temp = Adapter->AvailableTransmit; Adapter->AvailableTransmit = temp->NextEntry; temp->NextActive = NULL; // // Timestamp the transmit block // temp->Timeout = FALSE; // // If the adapter is currently executing a transmit, add this to the // end of the waiting list. Otherwise, download it. // if (Adapter->ActiveTransmitHead != NULL) { Adapter->ActiveTransmitTail->NextActive = temp; Adapter->ActiveTransmitTail = temp; } else { Adapter->ActiveTransmitHead = temp; Adapter->ActiveTransmitTail = temp; } // // Another transmit is being queued // Adapter->TransmitsQueued++; // // Number of sends since last reset increments by one // Adapter->TotalSends++; // // Assign the packet to the block // temp->Packet = Packet; // // Figure out if we need to constrain the packet. // NdisQueryPacket( Packet, &temp->NumberOfBuffers, &NdisBufferCount, &CurrentBuffer, &TotalDataLength ); // // See if the packet exceeds MAX_BUFFERS_PER_TRANSMIT or is too short. // We will have to constrain in either event. // if ( (temp->NumberOfBuffers <= MAX_BUFFERS_PER_TRANSMIT) && (TotalDataLength >= MINIMUM_TOKENRING_PACKET_SIZE) ) { // // Need to constrain the packet, increment the counter // TOK162DownLoadPacket(Adapter,temp,CurrentBuffer); // // log leaving send // IF_LOG('H'); // // We are pending. // return(NDIS_STATUS_PENDING); } else { // // Need to constrain the packet, increment the counter // TOK162ConstrainPacket(Adapter, temp, CurrentBuffer, NdisBufferCount, TotalDataLength ); // // log leaving send // IF_LOG('H'); // // We are pending. // return(NDIS_STATUS_PENDING); } // // If no transmit block was available, return RESOURCE error // } else { // // log resource error // IF_LOG('*'); // // Restart the transmits // WRITE_ADAPTER_USHORT(Adapter, PORT_OFFSET_COMMAND, ENABLE_TRANSMIT_VALID ); return NDIS_STATUS_RESOURCES; } }
int filter_packet(int direction, int iface, PNDIS_PACKET packet) { PNDIS_BUFFER buffer; UINT packet_len, buffer_len, hdr_len; int result; void *pointer; struct ether_hdr *ether_hdr; struct ip_hdr *ip_hdr; //lint -e506 -e613 -e774 -e831 -e550 NdisQueryPacket(packet, NULL, NULL, &buffer, &packet_len); if (packet_len < sizeof(struct ether_hdr)) { DBGOUT(("filter_packet: too small packet for ether_hdr! (%u)\n", packet_len)); return FILTER_UNKNOWN; } /* process ether_hdr */ NdisQueryBufferSafe(buffer, ðer_hdr, &buffer_len, LowPagePriority); if (buffer_len < sizeof(struct ether_hdr)) { DBGOUT(("filter_packet: too small buffer for ether_hdr! (%u)\n", buffer_len)); return FILTER_UNKNOWN; } // go to the next header if (buffer_len > sizeof(struct ether_hdr)) { pointer = (char *)ether_hdr + sizeof(struct ether_hdr); buffer_len -= sizeof(struct ether_hdr); } else { // use next buffer in chain NdisGetNextBuffer(buffer, &buffer); NdisQueryBufferSafe(buffer, &pointer, &buffer_len, LowPagePriority); } if (ether_hdr->ether_type == ETHERNET_TYPE_IP) { /* process ip_hdr */ if (buffer_len < sizeof(struct ip_hdr)) { DBGOUT(("filter_packet: too small buffer for ip_hdr! (%u)\n", buffer_len)); return FILTER_UNKNOWN; } ip_hdr = (struct ip_hdr *)pointer; hdr_len = ip_hdr->ip_hl * 4; if (buffer_len < hdr_len) { DBGOUT(("filter_packet: too small buffer for ip_hdr! (%u vs. %u)\n", buffer_len, hdr_len)); return FILTER_UNKNOWN; } // go to the next header if (buffer_len > hdr_len) { pointer = (char *)ip_hdr + hdr_len; buffer_len -= hdr_len; } else { // use next buffer in chain NdisGetNextBuffer(buffer, &buffer); NdisQueryBufferSafe(buffer, &pointer, &buffer_len, LowPagePriority); } result = process_transp(direction, iface, ip_hdr->ip_p, ip_hdr, pointer, buffer_len); if (result != FILTER_ALLOW) return result; } // default behavior return FILTER_ALLOW; }
int divert_filter_send(PADAPT pAdapt, PNDIS_PACKET Packet, int in) { #define HDR_SIZE 54 int len, cnt; PNDIS_BUFFER buf; char crap[HDR_SIZE]; int rc = 0, rd; struct ether_header *pEthHdr; // See ../B2Winet/ethernet.h struct ip *pIPHeader; struct tcphdr *tcp; struct divert_packet *dp; int off = 0; // 14; NDISPROT_ETH_HEADER UNALIGNED *pEthHeader; NdisAcquireSpinLock(&pAdapt->Lock); NdisQueryPacket(Packet, NULL, &cnt, &buf, &len); if (len < HDR_SIZE) goto Out; FltReadOnPacket(Packet, crap, HDR_SIZE, 0, &rd); if (rd < HDR_SIZE) goto Out; pEthHdr = (struct ether_header*) crap; pEthHeader = pEthHdr; if (ntohs( pEthHdr->ether_type ) != ETHERTYPE_IP) goto Out; if (in && get_pa(pEthHeader->SrcAddr)) goto Out; pIPHeader = (struct ip * ) (pEthHdr + 1); if (pIPHeader->ip_p != IPPROTO_TCP) goto Out; tcp = (struct tcphr*) (pIPHeader + 1); #if 0 if (ntohs(tcp->th_dport) == 666) rc = 1; #endif lock(); if (!_open) goto F**k; dp = get_packet(); if (!dp) { DbgPrint("divert_packet() - outta space dude\n"); goto F**k; } dp->dp_len = len - off; FltReadOnPacket(Packet, dp->dp_packet, dp->dp_len, off, &rd); // rd = dp->dp_len; if (rd != dp->dp_len) goto F**k; dp->dp_flags = 1; kick_pending(); rc = 1; F**k: unlock(); Out: NdisReleaseSpinLock(&pAdapt->Lock); return rc; #undef HDR_SIZE }
NDIS_STATUS NIC_DRIVER_OBJECT::DriverSend( IN PNDIS_PACKET pPacket, IN UINT uFlags) { PCQUEUE_GEN_HEADER pobj; if (!(pobj = m_TQueue.Dequeue())) { m_bOutofResources = 1; DEBUG_PRINT((TEXT("[DM9ISA_d]: m_bOutofResources\n"))); return NDIS_STATUS_RESOURCES; } PNDIS_BUFFER pndisFirstBuffer; UINT uPhysicalBufferCount; UINT uBufferCount; UINT uTotalPacketLength; PNDIS_BUFFER pndisCurrBuffer; PU8 pcurr = (PU8)CQueueGetUserPointer(pobj); PVOID ptrBuffer; UINT nBuffer; U32 idx, check; NdisQueryPacket( pPacket, &uPhysicalBufferCount, &uBufferCount, &pndisFirstBuffer, &uTotalPacketLength); if (uTotalPacketLength > ETH_MAX_FRAME_SIZE) { return NDIS_STATUS_FAILURE; } uPhysicalBufferCount &= 0xFFFF; for (idx = 0, check = 0, pndisCurrBuffer = pndisFirstBuffer; idx < uBufferCount; idx++, pndisCurrBuffer = pndisCurrBuffer->Next) { NdisQueryBuffer(pndisCurrBuffer, &ptrBuffer, &nBuffer); if (!nBuffer) continue; NdisMoveMemory(pcurr, ptrBuffer, nBuffer); pcurr += nBuffer; check += nBuffer; } // of for gathering buffer if (uTotalPacketLength != check) return NDIS_STATUS_FAILURE; pobj->pPacket = (PVOID)pPacket; pobj->uFlags = uFlags; pobj->nLength = uTotalPacketLength; m_pLower->DeviceSend(pobj); #ifdef IMPL_SEND_INDICATION return NDIS_STATUS_PENDING; #else return NDIS_STATUS_SUCCESS; #endif }
NDIS_STATUS ElnkSend( IN NDIS_HANDLE MacBindingHandle, IN PNDIS_PACKET Packet ) /*++ Routine Description: The ElnkSend request instructs a MAC to transmit a packet through the adapter onto the medium. Arguments: MacBindingHandle - The context value returned by the MAC when the adapter was opened. In reality, it is a pointer to ELNK_OPEN. Packet - A pointer to a descriptor for the packet that is to be transmitted. Return Value: The function value is the status of the operation. --*/ { // // Holds the status that should be returned to the caller. // NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING; // // Pointer to the adapter. // PELNK_ADAPTER Adapter; if ELNKDEBUG DPrint2("ElnkSend Packet = %x\n",Packet); Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); NdisAcquireSpinLock(&Adapter->Lock); Adapter->References++; if (!Adapter->ResetInProgress) { PELNK_OPEN Open; Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); if (!Open->BindingShuttingDown) { UINT TotalPacketSize; // // Increment the references on the open while we are // accessing it in the interface. // Open->References++; NdisReleaseSpinLock(&Adapter->Lock); // // It is reasonable to do a quick check and fail if the packet // is larger than the maximum an ethernet can handle. // NdisQueryPacket( Packet, NULL, NULL, NULL, &TotalPacketSize ); NdisAcquireSpinLock(&Adapter->Lock); if ((!TotalPacketSize) || (TotalPacketSize > MAXIMUM_ETHERNET_PACKET_SIZE)) { Open->References--; StatusToReturn = NDIS_STATUS_RESOURCES; } else { PELNK_RESERVED Reserved = PELNK_RESERVED_FROM_PACKET(Packet); PNDIS_BUFFER FirstBuffer; PUCHAR BufferVA; UINT Length; // // Set Reserved->Loopback. // NdisQueryPacket(Packet, NULL, NULL, &FirstBuffer, NULL); // // Get VA of first buffer // NdisQueryBuffer( FirstBuffer, (PVOID *)&BufferVA, &Length ); if (Open->ProtOptionFlags & NDIS_PROT_OPTION_NO_LOOPBACK){ Reserved->Loopback = FALSE; } else { Reserved->Loopback = EthShouldAddressLoopBack(Adapter->FilterDB, BufferVA); } Reserved->MacBindingHandle = MacBindingHandle; // // Put on the stage queue. // if (!Adapter->LastStagePacket) { Adapter->FirstStagePacket = Packet; } else { PELNK_RESERVED_FROM_PACKET(Adapter->LastStagePacket)->Next = Packet; } Adapter->LastStagePacket = Packet; Reserved->Next = NULL; Adapter->TransmitsQueued++; // // Only try to push it through the stage queues // if somebody else isn't already doing it and // there is some hope of moving some packets // ahead. // while (!Adapter->AlreadyProcessingStage && Adapter->FirstStagePacket && Adapter->StageOpen ) { ElnkStagedAllocation(Adapter); } } // // We leave the reference for the pending send. // } else { StatusToReturn = NDIS_STATUS_CLOSING; } } else { StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS; } ELNK_DO_DEFERRED(Adapter); return StatusToReturn; }
extern VOID Pc586CopyFromPacketToBuffer( 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, NULL, &VirtualAddress, &CurrentLength ); while (LocalBytesCopied < BytesToCopy) { if (!CurrentLength) { 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, NULL, &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)); PC586_MOVE_MEMORY( Buffer, VirtualAddress, AmountToMove ); Buffer = (PCHAR)Buffer + AmountToMove; VirtualAddress = (PCHAR)VirtualAddress + AmountToMove; LocalBytesCopied += AmountToMove; CurrentLength -= AmountToMove; } } *BytesCopied = LocalBytesCopied; }
INT PacketReceivePacket( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet ) { UINT bytesTransfered = 0; POPEN_INSTANCE open; PIRP irp; PNDIS_PACKET myPacket; PLIST_ENTRY packetListEntry; ULONG bufferLength; PPACKET_RESERVED reserved; PIO_STACK_LOCATION irpSp; PMDL mdl; PVOID startAddress; NTSTATUS status; // DebugPrint(("PacketReceivePacket\n")); open = (POPEN_INSTANCE)ProtocolBindingContext; packetListEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock ); if (packetListEntry == NULL) { // DebugPrint(("No pending read, dropping packets\n")); return 0; } reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement); myPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); irp = RESERVED(myPacket)->Irp; irpSp = IoGetCurrentIrpStackLocation(irp); // We don't have to worry about the situation where the IRP is cancelled // after we remove it from the queue and before we reset the cancel // routine because the cancel routine has been coded to cancel an IRP // only if it's in the queue. IoSetCancelRoutine(irp, NULL); // Following block of code locks the destination packet // MDLs in a safe manner. This is a temporary workaround // for NdisCopyFromPacketToPacket that currently doesn't use // safe functions to lock pages of MDL. This is required to // prevent system from bugchecking under low memory resources. // { PVOID virtualAddress; PNDIS_BUFFER firstBuffer, nextBuffer; ULONG totalLength; NdisQueryPacket(Packet, NULL, NULL, &firstBuffer, &totalLength); while( firstBuffer ) { NdisQueryBufferSafe( firstBuffer, &virtualAddress, &totalLength, NormalPagePriority ); if(!virtualAddress) { status = STATUS_INSUFFICIENT_RESOURCES; goto CleanExit; } NdisGetNextBuffer(firstBuffer, &nextBuffer); firstBuffer = nextBuffer; } } NdisChainBufferAtFront( myPacket, irp->MdlAddress ); bufferLength=irpSp->Parameters.Read.Length; NdisCopyFromPacketToPacket( myPacket, 0, bufferLength, Packet, 0, &bytesTransfered ); CleanExit: NdisFreePacket(myPacket); irp->IoStatus.Status = status; irp->IoStatus.Information = bytesTransfered; IoCompleteRequest(irp, IO_NO_INCREMENT); // DebugPrint(("BytesTransfered:%d\n", bytesTransfered)); IoDecrement(open); return 0; }
NDIS_STATUS LpxReceiveIndication ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookAheadBufferSize, IN UINT PacketSize ) /*++ Routine Description: This routine receives control from the physical provider as an indication that a frame has been received on the physical link. This routine is time critical, so we only allocate a buffer and copy the packet into it. We also perform minimal validation on this packet. It gets queued to the device context to allow for processing later. Arguments: BindingContext - The Adapter Binding specified at initialization time. ReceiveContext - A magic cookie for the MAC. HeaderBuffer - pointer to a buffer containing the packet header. HeaderBufferSize - the size of the header. LookaheadBuffer - pointer to a buffer containing the negotiated minimum amount of buffer I get to look at (not including header). LookaheadBufferSize - the size of the above. May be less than asked for, if that's all there is. PacketSize - Overall size of the packet (not including header). Return Value: NDIS_STATUS - status of operation, one of: NDIS_STATUS_SUCCESS if packet accepted, NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol, NDIS_any_other_thing if I understand, but can't handle. --*/ { PDEVICE_CONTEXT deviceContext; USHORT protocol; PNDIS_PACKET packet; NDIS_STATUS status; UINT bytesTransfered = 0; UINT startOffset = 0; DebugPrint( 4, ("LpxReceiveIndication, Entered\n") ); deviceContext = (PDEVICE_CONTEXT)ProtocolBindingContext; // // validation // if (HeaderBufferSize != ETHERNET_HEADER_LENGTH) { DebugPrint( 4, ("HeaderBufferSize = %x\n", HeaderBufferSize) ); return NDIS_STATUS_NOT_RECOGNIZED; } RtlCopyMemory( (PUCHAR)&protocol, &((PUCHAR)HeaderBuffer)[12], sizeof(USHORT) ); // // Discard 802.2 LLC SNAP field. // // if Ether Type less than 0x0600 ( 1536 ) // if (NTOHS(protocol) < 0x0600 && protocol != HTONS(0x0060) && // LOOP: Ethernet Loopback protocol != HTONS(0x0200) && // PUP : Xerox PUP packet protocol != HTONS(0x0201)) { // PUPAP: Xerox PUP address trans packet #if __LPX__ NdisCopyLookaheadData( (PUCHAR)&protocol, &((PUCHAR)LookAheadBuffer)[LENGTH_8022LLCSNAP - 2], sizeof(USHORT), deviceContext->MacOptions ); #endif PacketSize -= LENGTH_8022LLCSNAP; LookAheadBufferSize -= LENGTH_8022LLCSNAP; startOffset = LENGTH_8022LLCSNAP; } if (protocol != HTONS(ETH_P_LPX)) { DebugPrint( 4, ("Type = %x\n", protocol) ); return NDIS_STATUS_NOT_RECOGNIZED; } // // Check to see if the device context is initialized. // //ACQUIRE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); if (!FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_START) || FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_STOP)) { //RELEASE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); DebugPrint( 4,("Device is not initialized. Drop packet\n") ); return NDIS_STATUS_NOT_RECOGNIZED; } ASSERT( deviceContext->NdisBindingHandle ); //RELEASE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); // // DROP PACKET for DEBUGGING!!!! // #if 1 //DBG // Enabled for testing if (PacketRxDropRate) { PacketRxCountForDrop++; if ((PacketRxCountForDrop % 1000) <= PacketRxDropRate) { PLPX_HEADER lpxHeader = (PLPX_HEADER)LookAheadBuffer; #if 0 if ((PacketRxCountForDrop % (PacketRxDropRate*20)) == 0) DebugPrint( 1, ("[Drop(%x,%x,%x))]\n", NTOHS(lpxHeader->Lsctl), NTOHS(lpxHeader->Sequence), NTOHS(lpxHeader->AckSequence)) ); #endif DebugPrint( 1, ("D") ); return NDIS_STATUS_NOT_RECOGNIZED; } } #endif ASSERT( startOffset == 0 ); DebugPrint( 4, ("LpxReceiveIndication, PacketSize = %d, LookAheadBufferSize = %d, LPX_HEADER size = %d\n", PacketSize, LookAheadBufferSize, sizeof(LPX_HEADER)) ); if (LookAheadBufferSize >= sizeof(LPX_HEADER)) { PNDIS_BUFFER firstBuffer; PUCHAR packetData; PLPX_HEADER lpxHeader; USHORT lpxHeaderSize; lpxHeader = (PLPX_HEADER)((PBYTE)LookAheadBuffer + startOffset); lpxHeaderSize = sizeof(LPX_HEADER); #if __LPX_OPTION_ADDRESSS__ if (FlagOn(lpxHeader->Option, LPX_OPTION_SOURCE_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; } if (FlagOn(lpxHeader->Option, LPX_OPTION_DESTINATION_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; } #endif if (NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) == lpxHeaderSize) { status = RcvPacketAlloc( deviceContext, 0, &packet ); if (status == STATUS_SUCCESS) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = 0; RESERVED(packet)->PacketRawDataOffset = 0; LpxTransferDataComplete( deviceContext, packet, NDIS_STATUS_SUCCESS, LookAheadBufferSize ); return NDIS_STATUS_SUCCESS; } } else if (LookAheadBufferSize >= NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK)) { status = RcvPacketAlloc( deviceContext, NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize, &packet ); if (status == STATUS_SUCCESS) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize; RESERVED(packet)->PacketRawDataOffset = 0; NdisQueryPacket( packet, NULL, NULL, &firstBuffer, NULL ); packetData = MmGetMdlVirtualAddress( firstBuffer ); NdisCopyLookaheadData( packetData, (PBYTE)LookAheadBuffer + startOffset + lpxHeaderSize, RESERVED(packet)->PacketRawDataLength, deviceContext->MacOptions ); LpxTransferDataComplete( deviceContext, packet, NDIS_STATUS_SUCCESS, LookAheadBufferSize ); return NDIS_STATUS_SUCCESS; } } else { status = RcvPacketAlloc( deviceContext, startOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK), &packet ); if (status == STATUS_SUCCESS) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = startOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK); RESERVED(packet)->PacketRawDataOffset = startOffset + lpxHeaderSize; } } } else { PLPX_HEADER lpxHeader; PNDIS_BUFFER firstBuffer; PUCHAR packetData; UINT packetDataLength; ASSERT( FALSE ); status = RcvPacketAlloc( deviceContext, PacketSize, &packet ); if (status == STATUS_SUCCESS) { RtlCopyMemory( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RESERVED(packet)->PacketRawDataLength = PacketSize; RESERVED(packet)->PacketRawDataOffset = startOffset; NdisQueryPacket( packet, NULL, NULL, &firstBuffer, NULL ); NdisQueryBufferSafe( firstBuffer, &packetData, &packetDataLength, HighPagePriority ); lpxHeader = (PLPX_HEADER)(packetData + RESERVED(packet)->PacketRawDataOffset); RtlZeroMemory( lpxHeader, sizeof(LPX_HEADER) ); RESERVED(packet)->HeaderCopied = FALSE; } } if (status != NDIS_STATUS_SUCCESS) { return NDIS_STATUS_NOT_RECOGNIZED; } ASSERT( packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS ); if (deviceContext->NdisBindingHandle) { //ASSERT( FALSE ); NdisTransferData( &status, deviceContext->NdisBindingHandle, MacReceiveContext, 0, //RESERVED(packet)->PacketRawDataOffset, RESERVED(packet)->PacketRawDataLength, packet, &bytesTransfered ); if (status == NDIS_STATUS_PENDING) { LPX_ASSERT( FALSE ); status = NDIS_STATUS_SUCCESS; } else if (status == NDIS_STATUS_SUCCESS) { LpxTransferDataComplete( deviceContext, packet, status, bytesTransfered ); } else { LPX_ASSERT( FALSE ); DebugPrint( 1, ("NdisTransferData() failed. STATUS=%08lx\n", status) ); } } else { status = NDIS_STATUS_NOT_RECOGNIZED; DebugPrint( 1, ("Invalid device status. STATUS=%08lx\n", status) ); } return status; }
/* We've received a csum_blank packet, but we don't want to let Windows see it like. Calculate the checksum and dump it in the packet. This only works for TCP and UDP on IPv4; on anything else it's a no-op. */ static VOID FixupChecksum(PNDIS_PACKET packet) { PNDIS_BUFFER pbuf; PNDIS_BUFFER pbuf_next; UINT bufLength; UINT len; struct ethhdr *eh; struct iphdr *ih; uint32_t csum_accumulator; uint32_t *ptr; uint16_t *csum_field; NdisQueryPacket(packet, NULL, NULL, &pbuf, NULL); NdisQueryBufferSafe(pbuf, &eh, &bufLength, NormalPagePriority); if (!eh || bufLength < sizeof(*eh)) return; if (eh->proto != TPID_IPV4) { static BOOLEAN warned; if (!warned) { TraceWarning(("Asked to perform checksum calculation on non-IP ethernet prototocol %x!\n", eh->proto)); warned = TRUE; } return; } ih = (struct iphdr *)(eh + 1); bufLength -= sizeof(*eh); if (bufLength < sizeof(*ih) || bufLength < (UINT)(ih->len_version & 0x0f) * 4) return; ptr = (uint32_t *)((ULONG_PTR)ih + (ih->len_version & 0x0f)*4); len = ntohs(ih->tot_len) - (ih->len_version & 0x0f) * 4; bufLength -= (ih->len_version & 0x0f) * 4; if (bufLength > len) bufLength = len; if (ih->proto == IPPROTO_UDP) { if (bufLength < sizeof(struct udphdr)) return; csum_field = &((struct udphdr *)ptr)->checksum; } else if (ih->proto == IPPROTO_TCP) { if (bufLength < sizeof(struct tcphdr)) return; csum_field = &((struct tcphdr *)ptr)->checksum; } else { static BOOLEAN warned; /* Uh oh: don't know what this protocol is, so can't do checksum calculation for it. */ if (!warned) { TraceWarning(("Asked to perform checksum calculation for unknown protocol %d!\n", ih->proto)); warned = TRUE; } return; } if (ih->proto == IPPROTO_TCP) { struct tcp_pseudo_header tph; uint16_t csum; tph.saddr = ih->src; tph.daddr = ih->dest; tph.mbz = 0; tph.ptcl = IPPROTO_TCP; tph.length = htons((uint16_t)len); csum_accumulator = acc_ip_csum(&tph, sizeof(tph), 0); csum = fold_ip_csum(csum_accumulator); if (*csum_field != csum) TraceWarning(("invlid pseudo header checksum: expected %04x, found %04x\n", csum, *csum_field)); *csum_field = csum; } csum_accumulator = acc_ip_csum(ptr, bufLength, 0); len -= bufLength; while (len) { NdisGetNextBuffer(pbuf, &pbuf_next); if (pbuf_next == NULL) break; pbuf = pbuf_next; NdisQueryBufferSafe(pbuf, &ptr, &bufLength, NormalPagePriority); /* The buffer is already mapped into our RX buffer pool, so we should always be able to get a virtual address for it. */ XM_ASSERT(ptr != NULL); if (bufLength > len) bufLength = len; csum_accumulator = acc_ip_csum(ptr, bufLength, csum_accumulator); len -= bufLength; } *csum_field = ~fold_ip_csum(csum_accumulator); }
VOID LpxTransferDataComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status, IN UINT BytesTransfered ) { PDEVICE_CONTEXT pDeviceContext; PLPX_HEADER lpxHeader; PNDIS_BUFFER firstBuffer; PUCHAR packetData; UINT packetDataLength; USHORT lpxHeaderSize; UNREFERENCED_PARAMETER( BytesTransfered ); pDeviceContext = (PDEVICE_CONTEXT)ProtocolBindingContext; if (Status != NDIS_STATUS_SUCCESS) { ASSERT( FALSE ); DebugPrint( 1, ("[LPX] LpxTransferDataComplete error %x\n", Status) ); PacketFree( pDeviceContext, Packet ); return; } if (RESERVED(Packet)->HeaderCopied == FALSE) { NdisQueryPacket( Packet, NULL, NULL, &firstBuffer, NULL ); NdisQueryBufferSafe( firstBuffer, &packetData, &packetDataLength, HighPagePriority ); lpxHeader = (PLPX_HEADER)(packetData + RESERVED(Packet)->PacketRawDataOffset); lpxHeaderSize = sizeof(LPX_HEADER); #if __LPX_OPTION_ADDRESSS__ if (FlagOn(lpxHeader->Option, LPX_OPTION_SOURCE_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; } if (FlagOn(lpxHeader->Option, LPX_OPTION_DESTINATION_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; } #endif RtlCopyMemory( &RESERVED(Packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(Packet)->HeaderCopied = TRUE; RESERVED(Packet)->PacketRawDataLength = RESERVED(Packet)->PacketRawDataOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK); RESERVED(Packet)->PacketRawDataOffset += lpxHeaderSize; } lpxHeaderSize = sizeof(LPX_HEADER); #if __LPX_OPTION_ADDRESSS__ if (FlagOn(RESERVED(Packet)->LpxHeader.Option, LPX_OPTION_SOURCE_ADDRESS)) { if (!FlagOn(RESERVED(Packet)->LpxHeader.Option, LPX_OPTION_DESTINATION_ADDRESS)) { RtlCopyMemory( RESERVED(Packet)->OptionSourceAddress, RESERVED(Packet)->OptionDestinationAddress, ETHERNET_ADDRESS_LENGTH ); } lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; ASSERT( RtlEqualMemory(RESERVED(Packet)->EthernetHeader.SourceAddress, RESERVED(Packet)->OptionSourceAddress, ETHERNET_ADDRESS_LENGTH) ); } if (FlagOn(RESERVED(Packet)->LpxHeader.Option, LPX_OPTION_DESTINATION_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; ASSERT( RtlEqualMemory(RESERVED(Packet)->EthernetHeader.DestinationAddress, RESERVED(Packet)->OptionDestinationAddress, ETHERNET_ADDRESS_LENGTH) ); } #endif if (NTOHS(RESERVED(Packet)->LpxHeader.PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize != RESERVED(Packet)->PacketRawDataLength - RESERVED(Packet)->PacketRawDataOffset) { ASSERT( FALSE ); PacketFree( pDeviceContext, Packet ); return; } ExInterlockedInsertTailList( &pDeviceContext->PacketInProgressList, &(RESERVED(Packet)->ListEntry), &pDeviceContext->PacketInProgressQSpinLock ); return; }