NDIS_STATUS AllocatePacketWithBuffer( PNDIS_PACKET *NdisPacket, PCHAR Data, UINT Len ) { PNDIS_PACKET Packet; PNDIS_BUFFER Buffer; NDIS_STATUS Status; PCHAR NewData; NewData = ExAllocatePoolWithTag( NonPagedPool, Len, PACKET_BUFFER_TAG ); if( !NewData ) return NDIS_STATUS_RESOURCES; if( Data ) RtlCopyMemory(NewData, Data, Len); NdisAllocatePacket( &Status, &Packet, GlobalPacketPool ); if( Status != NDIS_STATUS_SUCCESS ) { ExFreePoolWithTag( NewData, PACKET_BUFFER_TAG ); return Status; } NdisAllocateBuffer( &Status, &Buffer, GlobalBufferPool, NewData, Len ); if( Status != NDIS_STATUS_SUCCESS ) { ExFreePoolWithTag( NewData, PACKET_BUFFER_TAG ); FreeNdisPacket( Packet ); return Status; } NdisChainBufferAtFront( Packet, Buffer ); *NdisPacket = Packet; return NDIS_STATUS_SUCCESS; }
NDIS_STATUS AllocatePacketWithBufferX( PNDIS_PACKET *NdisPacket, PCHAR Data, UINT Len, PCHAR File, UINT Line ) { PNDIS_PACKET Packet; PNDIS_BUFFER Buffer; NDIS_STATUS Status; PCHAR NewData; NewData = exAllocatePool( NonPagedPool, Len ); if( !NewData ) return NDIS_STATUS_NOT_ACCEPTED; // XXX if( Data ) RtlCopyMemory(NewData, Data, Len); NdisAllocatePacket( &Status, &Packet, GlobalPacketPool ); if( Status != NDIS_STATUS_SUCCESS ) { exFreePool( NewData ); return Status; } TrackWithTag(NDIS_PACKET_TAG, Packet, File, Line); NdisAllocateBuffer( &Status, &Buffer, GlobalBufferPool, NewData, Len ); if( Status != NDIS_STATUS_SUCCESS ) { exFreePool( NewData ); FreeNdisPacket( Packet ); } TrackWithTag(NDIS_BUFFER_TAG, Buffer, File, Line); NdisChainBufferAtFront( Packet, Buffer ); *NdisPacket = Packet; return NDIS_STATUS_SUCCESS; }
NTSTATUS DispatchWrite(PDEVICE_OBJECT pDevObj, PIRP pIrp) { NTSTATUS status; // 取得描述适配器的OPEN_INSTANCE结构的指针 OPEN_INSTANCE *pOpen = (OPEN_INSTANCE *)pDevObj->DeviceExtension; // 增加IO引用计数 IoIncrement(pOpen); do { if(!pOpen->bBound) { status = STATUS_DEVICE_NOT_READY; break; } // 从封包池中申请一个封包 PNDIS_PACKET pPacket; NdisAllocatePacket((NDIS_STATUS*)&status, &pPacket, pOpen->hPacketPool); if(status != NDIS_STATUS_SUCCESS) // 封包被申请完了! { status = STATUS_INSUFFICIENT_RESOURCES; break; } RESERVED(pPacket)->pIrp = pIrp; // 保存IRP指针,在完成例程中还要使用 // 附加写缓冲区到封包 NdisChainBufferAtFront(pPacket, pIrp->MdlAddress); // 注意,既然我们已经标识此IRP未决,我们必须返回STATUS_PENDING,即便是 // 我们恰巧同步完成了这个IRP IoMarkIrpPending(pIrp); // 发送封包到下层NIC设备 NdisSend((NDIS_STATUS*)&status, pOpen->hAdapter, pPacket); if(status != NDIS_STATUS_PENDING) { ProtocolSendComplete(pOpen, pPacket, status); } return STATUS_PENDING; }while(FALSE); if(status != STATUS_SUCCESS) { IoDecrement(pOpen); pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return status; }
void CAR6KMini::car6k_sendEapolKeyMsg (A_UINT8 descType, A_BOOL secure, A_BOOL mic, A_BOOL ack, A_BOOL tx, A_UINT32 index, A_UINT8 isPW, A_BOOL doEncrypt, A_UINT64 keyRSC, const A_UINT8 nonce[], const A_UINT32 keyLength, A_UINT32 keyDataLen, const A_UINT8 *keyData, const A_UINT32 keyBufferLength, A_UINT8 *bssid) { STATION *station; station = GetStation(bssid,0); NDIS_STATUS Status; PNDIS_PACKET pPacket; PNDIS_BUFFER pBuffer; A_UINT32 *magic; A_UINT16 length; memset (m_wpa_buffer, 0 , sizeof (m_wpa_buffer)); crypto_sendEapolKeyMsg ( descType,secure, mic, ack, tx, index, isPW,doEncrypt,keyRSC, nonce,keyLength,keyDataLen, keyData, keyBufferLength, bssid,m_CurrentAddress,m_keyCounter,&replayCtr, station,m_wpa_buffer,&length); NdisAllocatePacket (&Status, &pPacket, m_TxPacketPool); magic = (UINT32 *) pPacket->ProtocolReserved; if (NDIS_STATUS_SUCCESS != Status) { NDIS_DEBUG_PRINTF (ATH_LOG_ERR, "AR6K: ERROR - NdisAllocatePacket failed\n"); return; } NdisAllocateBuffer (&Status, &pBuffer, m_TxBufferPool, m_wpa_buffer, length); if (NDIS_STATUS_SUCCESS != Status) { NdisFreePacket (pPacket); NDIS_DEBUG_PRINTF (ATH_LOG_ERR, "AR6K: ERROR - NdisAllocateBuffer failed\n"); return; } pBuffer->Next = NULL; NdisChainBufferAtFront (pPacket,pBuffer); *(magic) = TAG_WPA_SEND_PCK; SendPackets (&pPacket,1); return; }
NTSTATUS PacketRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { POPEN_INSTANCE open; PNDIS_PACKET pPacket; NDIS_STATUS status; NTSTATUS ntStatus; PIO_STACK_LOCATION irpSp; // DebugPrint(("Read\n")); open = DeviceObject->DeviceExtension; IoIncrement(open); if(!open->Bound) { ntStatus = STATUS_DEVICE_NOT_READY; goto ERROR; } irpSp = IoGetCurrentIrpStackLocation(Irp); if (irpSp->Parameters.Read.Length < ETHERNET_HEADER_LENGTH) { ntStatus = STATUS_BUFFER_TOO_SMALL; goto ERROR; } NdisAllocatePacket( &status, &pPacket, open->PacketPool ); if (status != NDIS_STATUS_SUCCESS) { // DebugPrint(("Packet: Read- No free packets\n")); ntStatus = STATUS_INSUFFICIENT_RESOURCES; goto ERROR; } RESERVED(pPacket)->Irp=Irp; RESERVED(pPacket)->pMdl=NULL; IoMarkIrpPending(Irp); IoSetCancelRoutine(Irp, PacketCancelRoutine); ExInterlockedInsertTailList( &open->RcvList, &RESERVED(pPacket)->ListElement, &open->RcvQSpinLock); return STATUS_PENDING; ERROR: Irp->IoStatus.Status = ntStatus; IoCompleteRequest (Irp, IO_NO_INCREMENT); IoDecrement(open); return ntStatus; }
NTSTATUS MPIndicatePacket(PHWT_ADAPTER Adapter, PVOID Input, ULONG InputSize, PDEV_RET Output, ULONG OutputSize, PIRP Irp) { PVOID data = NULL; NDIS_STATUS ndis_status = NDIS_STATUS_FAILURE; PNDIS_BUFFER ndis_buffer = NULL; PNDIS_PACKET ndis_packet = NULL; do { data = ExAllocatePoolWithTag(NonPagedPool, InputSize, 'tkpi'); RtlCopyMemory(data, Input, InputSize); NdisAllocateBuffer(&ndis_status, &ndis_buffer, Adapter->AllocateBufferPool, data, InputSize); if (ndis_status != NDIS_STATUS_SUCCESS) break; NdisAllocatePacket(&ndis_status, &ndis_packet, Adapter->AllocatePacketPool); if (ndis_status != NDIS_STATUS_SUCCESS) break; NdisReinitializePacket(ndis_packet); *(PVOID*)ndis_packet->MiniportReserved = data; NdisChainBufferAtBack(ndis_packet, ndis_buffer); NDIS_SET_PACKET_HEADER_SIZE(ndis_packet, sizeof(ETHERNET_HEADER)); NDIS_SET_PACKET_STATUS(ndis_packet, NDIS_STATUS_SUCCESS); NdisMIndicateReceivePacket(Adapter->AdapterHandle, &ndis_packet, 1); Output->hResult = S_OK; ndis_status = NDIS_STATUS_SUCCESS; } while(FALSE); if (ndis_status != NDIS_STATUS_SUCCESS && ndis_status != STATUS_PENDING) { if (ndis_packet) NdisFreePacket(ndis_packet); if (ndis_buffer) NdisFreeBuffer(ndis_buffer); if (data) ExFreePoolWithTag(data, 'tkpi'); } return ndis_status; }
// Create a packet buffer PACKET_BUFFER *NeoNewPacketBuffer() { PACKET_BUFFER *p; NDIS_STATUS ret; // Memory allocation p = NeoZeroMalloc(sizeof(PACKET_BUFFER)); // Memory allocation for packet p->Buf = NeoMalloc(NEO_MAX_PACKET_SIZE); // Allocate the buffer pool NdisAllocateBufferPool(&ret, &p->BufferPool, 1); // Allocate the buffer NdisAllocateBuffer(&ret, &p->NdisBuffer, p->BufferPool, p->Buf, NEO_MAX_PACKET_SIZE); // Secure the packet pool NdisAllocatePacketPool(&ret, &p->PacketPool, 1, PROTOCOL_RESERVED_SIZE_IN_PACKET); // Secure the packet NdisAllocatePacket(&ret, &p->NdisPacket, p->PacketPool); NDIS_SET_PACKET_HEADER_SIZE(p->NdisPacket, NEO_PACKET_HEADER_SIZE); // Attach the buffer to the packet NdisChainBufferAtFront(p->NdisPacket, p->NdisBuffer); return p; }
NTSTATUS NdisProtWrite( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: Dispatch routine to handle IRP_MJ_WRITE. Arguments: pDeviceObject - pointer to our device object pIrp - Pointer to request packet Return Value: NT status code. --*/ { PIO_STACK_LOCATION pIrpSp; ULONG DataLength; NTSTATUS NtStatus; NDIS_STATUS Status; PNDISPROT_OPEN_CONTEXT pOpenContext; PNDIS_PACKET pNdisPacket; PNDIS_BUFFER pNdisBuffer; NDISPROT_ETH_HEADER UNALIGNED *pEthHeader; #ifdef NDIS51 PVOID CancelId; #endif UNREFERENCED_PARAMETER(pDeviceObject); pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pOpenContext = pIrpSp->FileObject->FsContext; pNdisPacket = NULL; do { if (pOpenContext == NULL) { DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n", pIrpSp->FileObject)); NtStatus = STATUS_INVALID_HANDLE; break; } NPROT_STRUCT_ASSERT(pOpenContext, oc); if (pIrp->MdlAddress == NULL) { DEBUGP(DL_FATAL, ("Write: NULL MDL address on IRP %p\n", pIrp)); NtStatus = STATUS_INVALID_PARAMETER; break; } // // Try to get a virtual address for the MDL. // pEthHeader = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); if (pEthHeader == NULL) { DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for" " IRP %p, MDL %p\n", pIrp, pIrp->MdlAddress)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Sanity-check the length. // DataLength = MmGetMdlByteCount(pIrp->MdlAddress); if (DataLength < sizeof(NDISPROT_ETH_HEADER)) { DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n", DataLength)); NtStatus = STATUS_BUFFER_TOO_SMALL; break; } if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER))) { DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)" " larger than max frame size (%d)\n", pOpenContext, DataLength, pOpenContext->MaxFrameSize)); NtStatus = STATUS_INVALID_BUFFER_SIZE; break; } // // To prevent applications from sending packets with spoofed // mac address, we will do the following check to make sure the source // address in the packet is same as the current MAC address of the NIC. // if ((pIrp->RequestorMode == UserMode) && !NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN)) { DEBUGP(DL_WARN, ("Write: Failing with invalid Source address")); NtStatus = STATUS_INVALID_PARAMETER; break; } NPROT_ACQUIRE_LOCK(&pOpenContext->Lock); if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock); DEBUGP(DL_FATAL, ("Write: Open %p is not bound" " or in low power state\n", pOpenContext)); NtStatus = STATUS_INVALID_HANDLE; break; } // // Allocate a send packet. // NPROT_ASSERT(pOpenContext->SendPacketPool != NULL); NdisAllocatePacket( &Status, &pNdisPacket, pOpenContext->SendPacketPool); if (Status != NDIS_STATUS_SUCCESS) { NPROT_RELEASE_LOCK(&pOpenContext->Lock); DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send pkt\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Allocate a send buffer if necessary. // if (pOpenContext->bRunningOnWin9x) { NdisAllocateBuffer( &Status, &pNdisBuffer, pOpenContext->SendBufferPool, pEthHeader, DataLength); if (Status != NDIS_STATUS_SUCCESS) { NPROT_RELEASE_LOCK(&pOpenContext->Lock); NdisFreePacket(pNdisPacket); DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send buf\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } } else { pNdisBuffer = pIrp->MdlAddress; } NdisInterlockedIncrement((PLONG)&pOpenContext->PendedSendCount); NPROT_REF_OPEN(pOpenContext); // pended send IoMarkIrpPending(pIrp); // // Initialize the packet ref count. This packet will be freed // when this count goes to zero. // NPROT_SEND_PKT_RSVD(pNdisPacket)->RefCount = 1; #ifdef NDIS51 // // NDIS 5.1 supports cancelling sends. We set up a cancel ID on // each send packet (which maps to a Write IRP), and save the // packet pointer in the IRP. If the IRP gets cancelled, we use // NdisCancelSendPackets() to cancel the packet. // CancelId = NPROT_GET_NEXT_CANCEL_ID(); NDIS_SET_PACKET_CANCEL_ID(pNdisPacket, CancelId); pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext; pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNdisPacket; NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry); IoSetCancelRoutine(pIrp, NdisProtCancelWrite); #endif // NDIS51 NPROT_RELEASE_LOCK(&pOpenContext->Lock); // // Set a back pointer from the packet to the IRP. // NPROT_IRP_FROM_SEND_PKT(pNdisPacket) = pIrp; NtStatus = STATUS_PENDING; pNdisBuffer->Next = NULL; NdisChainBufferAtFront(pNdisPacket, pNdisBuffer); #if SEND_DBG { PUCHAR pData; pData = MmGetSystemAddressForMdlSafe(pNdisBuffer, NormalPagePriority); NPROT_ASSERT(pEthHeader == pData); DEBUGP(DL_VERY_LOUD, ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n", pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength)); DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48)); } #endif // SEND_DBG NdisSendPackets(pOpenContext->BindingHandle, &pNdisPacket, 1); } while (FALSE); if (NtStatus != STATUS_PENDING) { pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return (NtStatus); }
void CAR6KMini::ReceiveWMIDataPacket( HTC_EVENT_INFO *evInfo) // // This function processes data from an HTC_BUFFER_RECEIVED indication // not on the WMI_CONTROL_MBOX endpoint. // { ndis_mini_buf_t *pb = (ndis_mini_buf_t *)evInfo->cookie; NDIS_STATUS Status; NDIS_PACKET *pPacket; NDIS_BUFFER *pBuffer; PBYTE pData; ULONG cbData; BOOL doDix = FALSE; USHORT etherType; SNAP_HEADER *pSnapHdr; MAC_ADDRESS *pDestAddr,*tempAddr; BOOL mcForUs = FALSE; NDIS_DEBUG_PRINTF(ATH_LOG_TRC | ATH_LOG_RECV, "AR6K: +ReceiveWMIDataPacket"); if (evInfo->status != A_OK) { NDIS_DEBUG_PRINTF(ATH_LOG_ERR, "AR6K: ERROR - ReceiveWMIPacket Error in receiving : status = %x\n", evInfo->status); if (A_OK != HTCBufferReceive(m_pHTCTarget, ENDPOINT2, a_netbuf_to_data(pb), AR6000_BUFFER_SIZE, pb)) { a_netbuf_free(pb); } goto done; } // evInfo->actualLength is the length of the pb->data including // 2 bytes: WMI_DATA_HEADER [optional - only if HTC header is 46 00] // 14 bytes: 802.3 MAC header // 8 bytes: SNAP header (with EthType as last 2 bytes) // N bytes: payload (e.g. IP packet) pData = evInfo->buffer; cbData = evInfo->actualLength; // Remove the WMI_DATA_HDR. if (cbData < sizeof(WMI_DATA_HDR)) { NDIS_DEBUG_PRINTF(ATH_LOG_ERR, "AR6K: ERROR - ReceiveWMIPacket missing WMI header (%u bytes)\n", evInfo->actualLength); if ( A_OK != HTCBufferReceive(m_pHTCTarget, ENDPOINT2, a_netbuf_to_data(pb), AR6000_BUFFER_SIZE, pb)) { a_netbuf_free(pb); } goto done; } pData += sizeof(WMI_DATA_HDR); cbData -= sizeof(WMI_DATA_HDR); if (cbData < sizeof(ETHERNET_MAC_HEADER) + sizeof(SNAP_HEADER)) { NDIS_DEBUG_PRINTF(ATH_LOG_ERR, "AR6K: ERROR - ReceiveWMIPacket missing MAC + SNAP (%u bytes)\n", cbData); if ( A_OK != HTCBufferReceive(m_pHTCTarget, ENDPOINT2, a_netbuf_to_data(pb), AR6000_BUFFER_SIZE, pb)) { a_netbuf_free(pb); } goto done; } #ifdef WMM Lock(); wmi_implicit_create_pstream((wmi_t *)m_pWMI, pb, DNLINK_TRAFFIC,1); Unlock(); #endif //WMM pDestAddr=(MAC_ADDRESS *)pData; /* Apply NDIS receive filter */ if (isGrp(pDestAddr)) { if (isBcast(pDestAddr)) { if (!(m_CurrentPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) { if ( A_OK != HTCBufferReceive(m_pHTCTarget, ENDPOINT2, a_netbuf_to_data(pb), AR6000_BUFFER_SIZE, pb)) { a_netbuf_free(pb); } goto done; } } else { isMcForUs(pDestAddr,&mcForUs); if (!(m_CurrentPacketFilter & (NDIS_PACKET_TYPE_MULTICAST | NDIS_PACKET_TYPE_ALL_MULTICAST)) || !(mcForUs)) { if ( A_OK != HTCBufferReceive(m_pHTCTarget, ENDPOINT2, a_netbuf_to_data(pb), AR6000_BUFFER_SIZE, pb)) { a_netbuf_free(pb); } goto done; } } } else { tempAddr=(MAC_ADDRESS *) m_PermanentAddress; if ((A_MACADDR_COMP(pDestAddr,tempAddr) != 0) && !(m_CurrentPacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)) { if ( A_OK != HTCBufferReceive(m_pHTCTarget, ENDPOINT2, a_netbuf_to_data(pb), AR6000_BUFFER_SIZE, pb)) { a_netbuf_free(pb); } goto done; } } // Allocate an NDIS_PACKET from our packet pool. NdisAllocatePacket(&Status, &pPacket, m_RxPacketPool); if (NDIS_STATUS_SUCCESS != Status) { NDIS_DEBUG_PRINTF(ATH_LOG_ERR, "AR6K: ERROR - NdisAllocatePacket failed\n"); if ( A_OK != HTCBufferReceive(m_pHTCTarget, ENDPOINT2, a_netbuf_to_data(pb), AR6000_BUFFER_SIZE, pb)) { a_netbuf_free(pb); } goto done; } // Check for ethernetType in SNAP header for NOVELL_IPX, APPLE_TALK_ARP etc // remove 802.3 length and SNAP header if it is not of these types pSnapHdr=(SNAP_HEADER *)(pData+sizeof(ETHERNET_MAC_HEADER)); etherType=A_BE2CPU16(pSnapHdr->Type); doDix=((A_MEMCMP(pSnapHdr,&bridgeTunnel, sizeof(CAP_CONST))) == 0); if((!doDix) && ((A_MEMCMP(pSnapHdr,&vrfc1042, sizeof(CAP_CONST))) == 0)) { doDix = ((etherType != APPLE_TALK_ARP) && (etherType != NOVELL_IPX)); } // Get rid of the 802.3 length and SNAP header by copying // the 802.3 DestMACAddr and SrcMACAddr forward so they // immediately precede the EthType at the end of the SNAP header. // That gives us a DIX packet. if (doDix) { memmove(pData + sizeof(SNAP_HEADER), pData, ETHERNET_MAC_ADDRESS_LENGTH * 2); pData += sizeof(SNAP_HEADER); cbData -= sizeof(SNAP_HEADER); } // Setup the fields of NDIS_BUFFER to point to our data. pBuffer = &pb->NdisBuffer; NdisInitializeBuffer(pBuffer, pData, cbData); // Chain the NDIS_BUFFER to the start of the NDIS_PACKET NdisChainBufferAtBack(pPacket, pBuffer); NDIS_SET_PACKET_HEADER_SIZE(pPacket, sizeof(ETHERNET_MAC_HEADER)); NDIS_SET_PACKET_STATUS(pPacket, NDIS_STATUS_SUCCESS); #ifdef NDIS_BUS_DRIVER NDIS_PACKET *PacketArray[1]; PacketArray[0]=pPacket; NdisMIndicateReceivePacket(m_MiniportAdapterHandle, PacketArray, 1); #else // Perform the indicate on the timer thread because tying up the // SDIO receive indication thread can result in a deadlock. PLIST_ENTRY pEntry = (PLIST_ENTRY)(pPacket->MiniportReserved); Lock(); InsertTailList(&m_RxPendingPacketList, pEntry); NdisSetEvent(&m_RxPendingEvent); Unlock(); #endif done: NDIS_DEBUG_PRINTF(ATH_LOG_TRC | ATH_LOG_RECV, "AR6K: -ReceiveWMIDataPacket"); }
/*+ * * AllocateAdapterMemory * * Routine Description: * * This routine allocates memory for: * * - Transmit descriptor ring * - Receive descriptor ring * - Receive buffers * - Transmit buffer * - Setup buffer * * Arguments: * * Adapter - The adapter to allocate memory for. * * Functional description * * For each allocated zone, we maintain a set of pointers: * - virtual & physical addresses of the allocated block * - virtual & physical addresses of the aligned structure (descriptor ring, buffer,...) * whithin the block * * Return Value: * * Returns FALSE if an allocation fails. * -*/ extern BOOLEAN AllocateAdapterMemory( IN PDC21X4_ADAPTER Adapter ) { PDC21X4_TRANSMIT_DESCRIPTOR TransmitDescriptor; PDC21X4_RECEIVE_DESCRIPTOR ReceiveDescriptor; NDIS_STATUS Status; PRCV_HEADER RcvHeader; PNDIS_PACKET Packet; ULONG AllocSize; PULONG AllocVa; NDIS_PHYSICAL_ADDRESS AllocPa; ULONG Va; ULONG Pa; UINT i; ULONG Offset; INT TransmitDescriptorRingSize; INT ReceiveDescriptorRingSize; Adapter->RcvHeaderSize = ((RCV_HEADER_SIZE + Adapter->CacheLineSize - 1) / Adapter->CacheLineSize) * Adapter->CacheLineSize; #if _DBG DbgPrint("Alloc Rcv_ring[%d desc.], Txm_ring[%d desc.], setup_buf[%d]...\n", Adapter->ReceiveRingSize, TRANSMIT_RING_SIZE, DC21X4_SETUP_BUFFER_SIZE ); #endif // Allocate space for transmit descriptor ring, // the receive descriptor ring and the setup buffer TransmitDescriptorRingSize = Adapter->DescriptorSize * TRANSMIT_RING_SIZE; ReceiveDescriptorRingSize = Adapter->DescriptorSize * Adapter->ReceiveRingSize; Adapter->DescriptorRing.AllocSize = TransmitDescriptorRingSize + ReceiveDescriptorRingSize + DC21X4_SETUP_BUFFER_SIZE + Adapter->CacheLineSize; NdisMAllocateSharedMemory( Adapter->MiniportAdapterHandle, Adapter->DescriptorRing.AllocSize, FALSE, // NON-CACHED (PVOID *)&Adapter->DescriptorRing.AllocVa, // virtual ... &Adapter->DescriptorRing.AllocPa // and physical address of the allocation ); // Check the allocation success if ((PVOID)Adapter->DescriptorRing.AllocVa == (PVOID)NULL) { return FALSE; } if (NdisGetPhysicalAddressHigh(Adapter->DescriptorRing.AllocPa) != 0) { return FALSE; } NdisZeroMemory ( (PVOID)(Adapter->DescriptorRing.AllocVa), (ULONG)(Adapter->DescriptorRing.AllocSize) ); // Align to the next cache line boundary AlignStructure ( &Adapter->DescriptorRing, Adapter->CacheLineSize ); Adapter->TransmitDescriptorRingVa = Adapter->DescriptorRing.Va; Adapter->TransmitDescriptorRingPa = Adapter->DescriptorRing.Pa; Offset = TransmitDescriptorRingSize; Adapter->ReceiveDescriptorRingVa = Adapter->DescriptorRing.Va + Offset; Adapter->ReceiveDescriptorRingPa = Adapter->DescriptorRing.Pa + Offset; Offset += ReceiveDescriptorRingSize; Adapter->SetupBufferVa = Adapter->DescriptorRing.Va + Offset; Adapter->SetupBufferPa = Adapter->DescriptorRing.Pa + Offset; //Initialize the setup buffer NdisZeroMemory ( (PVOID)(Adapter->SetupBufferVa), DC21X4_SETUP_BUFFER_SIZE ); // Allocate a pool of NDIS buffers NdisAllocateBufferPool( &Status, &Adapter->FlushBufferPoolHandle, ( Adapter->ReceiveRingSize + Adapter->ExtraReceiveBuffers + DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS + DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS ) ); if (Status != NDIS_STATUS_SUCCESS) { return FALSE; } // Allocate a pool of packets. #if _DBG DbgPrint("Allocate PacketPool [%d packets]\n", Adapter->ExtraReceivePackets); #endif NdisAllocatePacketPool( &Status, &Adapter->ReceivePacketPool, Adapter->ExtraReceivePackets, 0 ); if (Status != NDIS_STATUS_SUCCESS) { return FALSE; } // Allocate all of the packets out of the packet pool // and place them on a queue. for (i = 0; i < Adapter->ExtraReceivePackets; i++) { // Allocate a packet from the pool. NdisAllocatePacket( &Status, &Packet, Adapter->ReceivePacketPool ); if (Status != NDIS_STATUS_SUCCESS) { return(FALSE); } // Set the header size in the packet's Out-Of-Band information. // All other fields in the Out-Of-Band information have been // initialized to 0 by NdisAllocatePacket(). NDIS_SET_PACKET_HEADER_SIZE(Packet, ETH_HEADER_SIZE); // Place it on the receive packet free list. RCV_RESERVED(Packet)->Next = Adapter->FreePacketList; Adapter->FreePacketList = Packet; } // Clear out the free receive list of buffers. Adapter->FreeRcvList = NULL; // We allocate the receive buffers. We allocate both // the buffers for the descriptor ring and the extra // buffers and place them all on the free queue. #if _DBG DbgPrint("Allocate Receive Buffers [%d]\n", Adapter->ExtraReceiveBuffers+Adapter->ReceiveRingSize); #endif // Attempt to allocate all the receive buffer space // in one block // If it fails,allocate each buffer individually // Allocation size Adapter->RcvBufferSpace.AllocSize = ((Adapter->ExtraReceiveBuffers + Adapter->ReceiveRingSize) * (DC21X4_RECEIVE_BUFFER_SIZE + Adapter->RcvHeaderSize)) + Adapter->CacheLineSize; NdisMAllocateSharedMemory( Adapter->MiniportAdapterHandle, Adapter->RcvBufferSpace.AllocSize, TRUE, (PVOID *)&Adapter->RcvBufferSpace.AllocVa, &Adapter->RcvBufferSpace.AllocPa ); // Check the allocation success if (((PVOID)Adapter->RcvBufferSpace.AllocVa != (PVOID)NULL) && (NdisGetPhysicalAddressHigh(Adapter->RcvBufferSpace.AllocPa) == 0)) { NdisZeroMemory ( (PVOID)(Adapter->RcvBufferSpace.AllocVa), (ULONG)(Adapter->RcvBufferSpace.AllocSize) ); // Align to the next cache line boundary AlignStructure ( &Adapter->RcvBufferSpace, Adapter->CacheLineSize ); // Allocation size needed for the receive buffer AllocSize = DC21X4_RECEIVE_BUFFER_SIZE + Adapter->RcvHeaderSize; Offset=0; } else { // Allocation size needed for the receive buffer AllocSize = DC21X4_RECEIVE_BUFFER_SIZE + Adapter->RcvHeaderSize + Adapter->CacheLineSize; Adapter->RcvBufferSpace.Va=0; } for (i = 0; i < (Adapter->ExtraReceiveBuffers + Adapter->ReceiveRingSize); i++ ) { if (Adapter->RcvBufferSpace.Va != 0) { Va = Adapter->RcvBufferSpace.Va + Offset; Pa = Adapter->RcvBufferSpace.Pa + Offset; Offset += AllocSize; } else { // Allocate a receive buffer. NdisMAllocateSharedMemory( Adapter->MiniportAdapterHandle, AllocSize, TRUE, (PVOID *)&AllocVa, &AllocPa ); if (((PVOID)AllocVa == (PVOID)NULL) || (NdisGetPhysicalAddressHigh(AllocPa) != 0)) { return FALSE; } NdisZeroMemory(AllocVa, AllocSize); // Align on the cache line boundary Offset = Adapter->CacheLineSize - ((ULONG)AllocVa % Adapter->CacheLineSize); Va = (ULONG)(AllocVa) + Offset; Pa = NdisGetPhysicalAddressLow(AllocPa) + Offset; } //The receive header points to the aligned va. RcvHeader = (PRCV_HEADER)Va; RcvHeader->AllocVa = (ULONG)AllocVa; RcvHeader->AllocPa = AllocPa; RcvHeader->AllocSize = (USHORT)AllocSize; // These addresses point to the data buffer RcvHeader->Va = (ULONG)(Va + Adapter->RcvHeaderSize); RcvHeader->Pa = Pa + Adapter->RcvHeaderSize; RcvHeader->Size = DC21X4_RECEIVE_BUFFER_SIZE; #if DBG RcvHeader->Signature = 'dHxR'; #if _DBG DbgPrint( "%-3d RcvHeader: %lx, RcvBuffer: %lx/%lx, HeaderSize: %lx\n", i,RcvHeader, RcvHeader->Va, RcvHeader->Pa, Adapter->RcvHeaderSize ); #endif #endif // Allocate an NDIS flush buffer for each receive buffer. NdisAllocateBuffer( &Status, &RcvHeader->FlushBuffer, Adapter->FlushBufferPoolHandle, (PVOID)RcvHeader->Va, DC21X4_RECEIVE_BUFFER_SIZE ); if (Status != NDIS_STATUS_SUCCESS) { return FALSE; } // Grab a packet off of the free packet list and // associate it with the buffer. Packet = Adapter->FreePacketList; Adapter->FreePacketList = RCV_RESERVED(Packet)->Next; // Chain the buffer on the packet. NdisChainBufferAtFront(Packet, RcvHeader->FlushBuffer); // Save a pointer to the receive header with the packet. RCV_RESERVED(Packet)->RcvHeader = RcvHeader; // Save the packet with the receive header. RcvHeader->Packet = Packet; // Place the descriptor on the free queue. RcvHeader->Next = Adapter->FreeRcvList; Adapter->FreeRcvList = RcvHeader; Adapter->CurrentReceiveBufferCount++; } #if _DBG DbgPrint("Init Rcv ring..\n"); #endif // Assign the receive buffers to the descriptors. for (i = 0, ReceiveDescriptor = (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa, Pa = Adapter->ReceiveDescriptorRingPa; i < Adapter->ReceiveRingSize; i++, (PCHAR)ReceiveDescriptor += Adapter->DescriptorSize, Pa += Adapter->DescriptorSize ) { // Grab a receive buffer from the free list. ASSERT(Adapter->FreeRcvList != NULL); RcvHeader = Adapter->FreeRcvList; Adapter->FreeRcvList = RcvHeader->Next; Adapter->CurrentReceiveBufferCount--; // Associate the buffer with the descriptor. ReceiveDescriptor->RcvHeader = RcvHeader; ReceiveDescriptor->FirstBufferAddress = RcvHeader->Pa; ReceiveDescriptor->Status = DESC_OWNED_BY_DC21X4; ReceiveDescriptor->Control = DC21X4_RECEIVE_BUFFER_SIZE; ReceiveDescriptor->Next = (PDC21X4_RECEIVE_DESCRIPTOR)((PCHAR)ReceiveDescriptor + Adapter->DescriptorSize); } //last descriptor of the ring (PCHAR)ReceiveDescriptor -= Adapter->DescriptorSize; ReceiveDescriptor->Control |= DC21X4_RDES_SECOND_ADDR_CHAINED; ReceiveDescriptor->SecondBufferAddress = Adapter->ReceiveDescriptorRingPa; ReceiveDescriptor->Next = (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa; #if _DBG DbgPrint("Init Txm ring..\n"); #endif // Initialize the Transmit Descriptor ring for (i=0, TransmitDescriptor = (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa, Pa = Adapter->TransmitDescriptorRingPa; i < TRANSMIT_RING_SIZE; i++, (PCHAR)TransmitDescriptor += Adapter->DescriptorSize, Pa += Adapter->DescriptorSize ) { TransmitDescriptor->MapTableIndex = i * NUMBER_OF_SEGMENT_PER_DESC; TransmitDescriptor->DescriptorPa = Pa; TransmitDescriptor->Next = (PDC21X4_TRANSMIT_DESCRIPTOR)((PCHAR)TransmitDescriptor + Adapter->DescriptorSize); } //last descriptor of the ring (PCHAR)TransmitDescriptor -= Adapter->DescriptorSize; TransmitDescriptor->Control = DC21X4_TDES_SECOND_ADDR_CHAINED; TransmitDescriptor->SecondBufferAddress = Adapter->TransmitDescriptorRingPa; TransmitDescriptor->Next = (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa; // Txm buffers for (i = 0;i < DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS;i ++) { Adapter->MaxTransmitBuffer[i].AllocSize = DC21X4_MAX_TRANSMIT_BUFFER_SIZE + Adapter->CacheLineSize; NdisMAllocateSharedMemory( Adapter->MiniportAdapterHandle, Adapter->MaxTransmitBuffer[i].AllocSize, TRUE, // CACHED (PVOID *)&Adapter->MaxTransmitBuffer[i].AllocVa, // virtual ... &Adapter->MaxTransmitBuffer[i].AllocPa // and physical address of the buffer allocation ); // Check the allocation success if (((PVOID)Adapter->MaxTransmitBuffer[i].AllocVa == (PVOID)NULL) || (NdisGetPhysicalAddressHigh(Adapter->MaxTransmitBuffer[i].AllocPa) != 0)) { return FALSE; } // Align the buffer on the cache line boundary AlignStructure ( &Adapter->MaxTransmitBuffer[i], Adapter->CacheLineSize ); // Allocate an NDIS flush buffer for each transmit buffer NdisAllocateBuffer( &Status, &Adapter->MaxTransmitBuffer[i].FlushBuffer, Adapter->FlushBufferPoolHandle, (PVOID)Adapter->MaxTransmitBuffer[i].Va, DC21X4_MAX_TRANSMIT_BUFFER_SIZE ); if (Status != NDIS_STATUS_SUCCESS) { return FALSE; } } // Allocate the minimal packet buffers Adapter->MinTransmitBuffer[0].AllocSize = (DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS * DC21X4_MIN_TRANSMIT_BUFFER_SIZE) + Adapter->CacheLineSize; NdisMAllocateSharedMemory( Adapter->MiniportAdapterHandle, Adapter->MinTransmitBuffer[0].AllocSize, TRUE, // CACHED (PVOID *)&Adapter->MinTransmitBuffer[0].AllocVa, // virtual ... &Adapter->MinTransmitBuffer[0].AllocPa // and physical address of the buffer allocation ); // Check the allocation success if (((PVOID)Adapter->MinTransmitBuffer[0].AllocVa == (PVOID)NULL) || (NdisGetPhysicalAddressHigh(Adapter->MinTransmitBuffer[0].AllocPa) != 0)) { Adapter->DontUseMinTransmitBuffer = TRUE; return TRUE; } // Align the buffer on the cache line boundary AlignStructure ( &Adapter->MinTransmitBuffer[0], Adapter->CacheLineSize ); for (i = 0;i < DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS;i ++) { Offset = i * DC21X4_MIN_TRANSMIT_BUFFER_SIZE; Adapter->MinTransmitBuffer[i].Va = Adapter->MinTransmitBuffer[0].Va + Offset; Adapter->MinTransmitBuffer[i].Pa = Adapter->MinTransmitBuffer[0].Pa + Offset; // Allocate an NDIS flush buffer for each transmit buffer NdisAllocateBuffer( &Status, &Adapter->MinTransmitBuffer[i].FlushBuffer, Adapter->FlushBufferPoolHandle, (PVOID)Adapter->MinTransmitBuffer[i].Va, DC21X4_MIN_TRANSMIT_BUFFER_SIZE ); if (Status != NDIS_STATUS_SUCCESS) { return FALSE; } } // Allocation has completed successfully return TRUE; }
NDIS_STATUS NICAllocAdapter( PMP_ADAPTER *pAdapter) { PMP_ADAPTER Adapter = NULL; PNDIS_PACKET Packet; PNDIS_BUFFER Buffer; PUCHAR pTCBMem; PTCB pTCB; NDIS_STATUS Status; LONG index; DEBUGP(MP_TRACE, ("--> NICAllocAdapter\n")); PAGED_CODE(); *pAdapter = NULL; do { // // Allocate memory for adapter context // Status = NdisAllocateMemoryWithTag( &Adapter, sizeof(MP_ADAPTER), NIC_TAG); if(Status != NDIS_STATUS_SUCCESS) { DEBUGP(MP_ERROR, ("Failed to allocate memory for adapter context\n")); break; } // // Zero the memory block // NdisZeroMemory(Adapter, sizeof(MP_ADAPTER)); NdisInitializeListHead(&Adapter->List); // // Initialize Send & Recv listheads and corresponding // spinlocks. // //NdisInitializeListHead(&Adapter->RecvWaitList); //NdisInitializeListHead(&Adapter->SendWaitList); //NdisInitializeListHead(&Adapter->SendFreeList); NdisAllocateSpinLock(&Adapter->SendLock); //NdisInitializeListHead(&Adapter->RecvFreeList); NdisAllocateSpinLock(&Adapter->RecvLock); //allocate a packet pool NdisAllocatePacketPool( &Status, &Adapter->LdnRecvPacketPoolHandle, 1, PROTOCOL_RESERVED_SIZE_IN_PACKET); if(Status != NDIS_STATUS_SUCCESS) { DEBUGP(MP_ERROR, ("NdisAllocatePacketPool failed\n")); break; } //allocate a single packet in the pool NdisAllocatePacket( &Status, &Adapter->LdnRecvPacket, Adapter->LdnRecvPacketPoolHandle); if(Status != NDIS_STATUS_SUCCESS) { DEBUGP(MP_ERROR, ("NdisAllocatePacket failed\n")); break; } //allocate a buffer pool NdisAllocateBufferPool( &Status, &Adapter->LdnRecvBufferPoolHandle, 1); if(Status != NDIS_STATUS_SUCCESS) { DEBUGP(MP_ERROR, ("NdisAllocateBufferPool for recv buffer failed\n")); break; } //allocate a single buffer in the buffer pool NdisAllocateBuffer( &Status, &Adapter->LdnRecvPacketBuffer, Adapter->LdnRecvBufferPoolHandle, (PVOID)&Adapter->LdnRecvPacketBufferData[0], NIC_BUFFER_SIZE); if(Status != NDIS_STATUS_SUCCESS) { DEBUGP(MP_ERROR, ("NdisAllocateBuffer failed\n")); break; } //chain the buffer to the packet NdisChainBufferAtBack(Adapter->LdnRecvPacket, Adapter->LdnRecvPacketBuffer); NDIS_SET_PACKET_STATUS(Adapter->LdnRecvPacket, NDIS_STATUS_RESOURCES); NDIS_SET_PACKET_HEADER_SIZE(Adapter->LdnRecvPacket, ETH_HEADER_SIZE); /*// // Allocate lookside list for Receive Control blocks. // NdisInitializeNPagedLookasideList( &Adapter->RecvLookaside, NULL, // No Allocate function NULL, // No Free function 0, // Reserved for system use sizeof(RCB), NIC_TAG, 0); // Reserved for system use MP_SET_FLAG(Adapter, fMP_ADAPTER_RECV_LOOKASIDE); // // Allocate packet pool for receive indications // NdisAllocatePacketPool( &Status, &Adapter->RecvPacketPoolHandle, NIC_MAX_BUSY_RECVS, PROTOCOL_RESERVED_SIZE_IN_PACKET); if(Status != NDIS_STATUS_SUCCESS) { DEBUGP(MP_ERROR, ("NdisAllocatePacketPool failed\n")); break; } // // Initialize receive packets // for(index=0; index < NIC_MAX_BUSY_RECVS; index++) { // // Allocate a packet descriptor for receive packets // from a preallocated pool. // NdisAllocatePacket( &Status, &Packet, Adapter->RecvPacketPoolHandle); if(Status != NDIS_STATUS_SUCCESS) { DEBUGP(MP_ERROR, ("NdisAllocatePacket failed\n")); break; } NDIS_SET_PACKET_HEADER_SIZE(Packet, ETH_HEADER_SIZE); // // Insert it into the list of free receive packets. // NdisInterlockedInsertTailList( &Adapter->RecvFreeList, (PLIST_ENTRY)&Packet->MiniportReserved[0], &Adapter->RecvLock); } // // Allocate a huge block of memory for all TCB's // Status = NdisAllocateMemoryWithTag( &pTCBMem, sizeof(TCB) * NIC_MAX_BUSY_SENDS, NIC_TAG); if(Status != NDIS_STATUS_SUCCESS) { DEBUGP(MP_ERROR, ("Failed to allocate memory for TCB's\n")); break; } NdisZeroMemory(pTCBMem, sizeof(TCB) * NIC_MAX_BUSY_SENDS); Adapter->TCBMem = pTCBMem; // // Allocate a buffer pool for send buffers. // NdisAllocateBufferPool( &Status, &Adapter->SendBufferPoolHandle, NIC_MAX_BUSY_SENDS); if(Status != NDIS_STATUS_SUCCESS) { DEBUGP(MP_ERROR, ("NdisAllocateBufferPool for send buffer failed\n")); break; } // // Divide the TCBMem blob into TCBs and create a buffer // descriptor for the Data portion of the TCBs. // for(index=0; index < NIC_MAX_BUSY_SENDS; index++) { pTCB = (PTCB) pTCBMem; // // Create a buffer descriptor for the Data portion of the TCBs. // Buffer descriptors are nothing but MDLs on NT systems. // NdisAllocateBuffer( &Status, &Buffer, Adapter->SendBufferPoolHandle, (PVOID)&pTCB->Data[0], NIC_BUFFER_SIZE); if(Status != NDIS_STATUS_SUCCESS) { DEBUGP(MP_ERROR, ("NdisAllocateBuffer failed\n")); break; } // // Initialize the TCB structure. // pTCB->Buffer = Buffer; pTCB->pData = (PUCHAR) &pTCB->Data[0]; pTCB->Adapter = Adapter; NdisInterlockedInsertTailList( &Adapter->SendFreeList, &pTCB->List, &Adapter->SendLock); pTCBMem = pTCBMem + sizeof(TCB); }*/ } while(FALSE); *pAdapter = Adapter; // // In the failure case, the caller of this routine will end up // calling NICFreeAdapter to free all the successfully allocated // resources. // DEBUGP(MP_TRACE, ("<-- NICAllocAdapter\n")); return(Status); }
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); } } }
/****************************************************************************** * * Name: AllocateRxQ() * * Description: Allocate Rx Buffer * * Arguments: PMRVDRV_ADAPTER Adapter * * Return Value: NDIS_STATUS_SUCCESS or NDIS_STATUS_FAILURE * * Notes: * *****************************************************************************/ NDIS_STATUS AllocateRxQ( IN PMRVDRV_ADAPTER Adapter ) { ULONG i; NDIS_STATUS tStatus; BOOLEAN bSuccess = TRUE; PACKET_QUEUE_NODE **pNode; PNDIS_PACKET_OOB_DATA pOOB; /// Initialize rx-related variables Adapter->RxBufferPoolHandle = Adapter->RxPacketPoolHandle = NULL; // InitializeQKeeper(&Adapter->RxPacketFreeQueue); // for ( i=0; i < MRVDRV_NUM_RX_PKT_IN_QUEUE; i++ ) { Adapter->pRxBufVM[i] = NULL; Adapter->pRxBuffer[i] = NULL; Adapter->pRxPacket[i] = NULL; } /// Allocate all needed memory space do { // packet pool NdisAllocatePacketPoolEx( &tStatus, &Adapter->RxPacketPoolHandle, MRVDRV_NUM_RX_PKT_IN_QUEUE, MRVDRV_NUM_RX_PKT_IN_QUEUE, PROTOCOL_RESERVED_SIZE_IN_PACKET); if ( tStatus != NDIS_STATUS_SUCCESS ) { DBGPRINT(DBG_LOAD | DBG_ERROR, (L"Unable to allocate packet pool!\n")); return tStatus; } // buffer pool NdisAllocateBufferPool( &tStatus, &Adapter->RxBufferPoolHandle, MRVDRV_NUM_RX_PKT_IN_QUEUE); if ( tStatus != NDIS_STATUS_SUCCESS ) { DBGPRINT(DBG_LOAD | DBG_ERROR, (L"Unable to allocate buffer pool!\n")); bSuccess = FALSE; break; } // assign space to used three array for ( i=0; i < MRVDRV_NUM_RX_PKT_IN_QUEUE; i++ ) { // data payload space array tStatus = NdisAllocateMemoryWithTag( &Adapter->pRxBufVM[i], MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, MRVDRV_MEMORY_TAG); //to hide unused packet header ahead of pointer. //(ULONG)Adapter->pRxBufVM[i] += (sizeof(RxPD)+sizeof(pkt.Len)+sizeof(pkt.Type)); (ULONG)Adapter->pRxBufVM[i] += MRVDRV_ETH_RX_HIDDEN_HEADER_SIZE; if ( tStatus != NDIS_STATUS_SUCCESS ) { bSuccess = FALSE; break; } // buffer array NdisAllocateBuffer( &tStatus, &Adapter->pRxBuffer[i], Adapter->RxBufferPoolHandle, Adapter->pRxBufVM[i], (MRVDRV_ETH_RX_PACKET_BUFFER_SIZE-MRVDRV_ETH_RX_HIDDEN_HEADER_SIZE)); if ( tStatus != NDIS_STATUS_SUCCESS ) { bSuccess = FALSE; break; } // packet array NdisAllocatePacket( &tStatus, &Adapter->pRxPacket[i], Adapter->RxPacketPoolHandle); if ( tStatus != NDIS_STATUS_SUCCESS ) { bSuccess = FALSE; break; } // init OBB space pOOB = NDIS_OOB_DATA_FROM_PACKET(Adapter->pRxPacket[i]); NdisZeroMemory(pOOB, sizeof(NDIS_PACKET_OOB_DATA)); NDIS_SET_PACKET_HEADER_SIZE(Adapter->pRxPacket[i], MRVDRV_ETH_HEADER_SIZE); // chain the packet and buffer NdisChainBufferAtFront(Adapter->pRxPacket[i], Adapter->pRxBuffer[i]); // fill packet node Adapter->RxPacketQueueNode[i].pPacket = Adapter->pRxPacket[i]; pNode = (PACKET_QUEUE_NODE **)Adapter->pRxPacket[i]->MiniportReserved; *pNode = &Adapter->RxPacketQueueNode[i]; // insert to free queue InsertQNodeAtTail(&Adapter->RxPacketFreeQueue, &Adapter->RxPacketQueueNode[i]); } // end of for(;;) } while (0); if ( ! bSuccess ) { // clean up all FreeRxQ(Adapter); return NDIS_STATUS_FAILURE; } Adapter->sNumOutstandingRxPacket = 0; return NDIS_STATUS_SUCCESS; }
PNDIS_PACKET SecLabAllocateReceivePacket( PADAPT pAdapt, IN UINT DataLength, OUT PUCHAR * ppDataBuffer ) /*++ Routine Description: 分配用于拷贝和排队接收包的资源. Arguments: DataLength - 封包的总长度,包括包头和数据 ppDataBuffer - 返回的缓冲区地址 Return Value: 如果成功则返回包的指针,否则为空. --*/ { PNDIS_PACKET pNdisPacket; PNDIS_BUFFER pNdisBuffer; PUCHAR pDataBuffer; NDIS_STATUS Status; pNdisPacket = NULL; pNdisBuffer = NULL; pDataBuffer = NULL; do { NdisAllocateMemoryWithTag((PVOID *)(&pDataBuffer), DataLength,'lceS'); if (pDataBuffer == NULL) { DbgPrint("Can not Allocate resoures for packet"); break; } // // 将其转化为NDIS_BUFFER. // NdisAllocateBuffer( &Status, &pNdisBuffer, RecvBufferPool, pDataBuffer, DataLength); if (Status != NDIS_STATUS_SUCCESS) { DbgPrint("failed to allocate Ndis Buffer"); break; } NdisAllocatePacket(&Status, &pNdisPacket, pAdapt->RecvPacketPoolHandle); if (Status != NDIS_STATUS_SUCCESS) { DbgPrint("failed to alloc NDIS packet"); break; } NDIS_SET_PACKET_STATUS(pNdisPacket, 0); SECLAB_RCV_PKT_TO_ORIGINAL_BUFFER(pNdisPacket) = NULL; NdisChainBufferAtFront(pNdisPacket, pNdisBuffer); *ppDataBuffer = pDataBuffer; break; } while (FALSE); if (pNdisPacket == NULL) { // // Clean up // if (pNdisBuffer != NULL) { NdisFreeBuffer(pNdisBuffer); } if (pDataBuffer != NULL) { NdisFreeMemory(pDataBuffer, 0, 0); } } return (pNdisPacket); }
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); } } } }
NDIS_STATUS NdisuioReceive( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID pHeaderBuffer, IN UINT HeaderBufferSize, IN PVOID pLookaheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ) /*++ Routine Description: Our protocol receive handler called by NDIS, typically if we have a miniport below that doesn't indicate packets. We make a local packet/buffer copy of this data, queue it up, and kick off the read service routine. Arguments: ProtocolBindingContext - pointer to open context MacReceiveContext - for use in NdisTransferData pHeaderBuffer - pointer to data header HeaderBufferSize - size of the above pLookaheadBuffer - pointer to buffer containing lookahead data LookaheadBufferSize - size of the above PacketSize - size of the entire packet, minus header size. Return Value: NDIS_STATUS_NOT_ACCEPTED - if this packet is uninteresting NDIS_STATUS_SUCCESS - if we processed this successfully --*/ { PNDISUIO_OPEN_CONTEXT pOpenContext; NDIS_STATUS Status; PNDISUIO_ETH_HEADER pEthHeader; PNDIS_PACKET pRcvPacket; PUCHAR pRcvData; UINT BytesTransferred; PNDIS_BUFFER pOriginalNdisBuffer, pPartialNdisBuffer; PIRP pIrp; PLIST_ENTRY pIrpEntry; ULONG BytesRemaining; // at pDst PPACKET_GROUP pGroup; //ULONG pDst; pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext; NUIO_STRUCT_ASSERT(pOpenContext, oc); pRcvPacket = NULL; pRcvData = NULL; Status = NDIS_STATUS_SUCCESS; DEBUGP(DL_LOUD, ("Receive: Open %p, LookaheadBufferSize %d, PacketSize %d\n", pOpenContext, LookaheadBufferSize, PacketSize)); NdisInterlockedAddLargeStatistic((PLARGE_INTEGER)&pOpenContext->ReceivedPackets, 1); do { if (HeaderBufferSize != sizeof(NDISUIO_ETH_HEADER)) { Status = NDIS_STATUS_NOT_ACCEPTED; break; } pEthHeader = (PNDISUIO_ETH_HEADER)pHeaderBuffer; NUIO_ACQUIRE_LOCK(&pOpenContext->Lock); // // Someone is reading, and this is the first packet. // if (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads) && NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue)) { // // Get the first pended Read IRP // pIrpEntry = pOpenContext->PendedReads.Flink; pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry); // // 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(pIrp, NULL); NUIO_REMOVE_ENTRY_LIST(pIrpEntry); pOpenContext->PendedReadCount--; NUIO_RELEASE_LOCK(&pOpenContext->Lock); NUIO_DEREF_OPEN(pOpenContext); // Service: dequeue rcv packet // // Copy as much data as possible from the receive packet to // the IRP MDL. // #ifndef WIN9X pGroup = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); //NUIO_ASSERT(pDst != NULL); // since it was already mapped #else pGroup = MmGetSystemAddressForMdl(pIrp->MdlAddress); // Win9x #endif BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress); BytesRemaining -= sizeof(PACKET_GROUP); // // copy the ethernet header into the actual readbuffer // NdisMoveMappedMemory(pGroup->Data, pHeaderBuffer, HeaderBufferSize); if (PacketSize == LookaheadBufferSize) { BytesTransferred = MIN(LookaheadBufferSize, BytesRemaining); NdisCopyLookaheadData(pGroup->Data + HeaderBufferSize, pLookaheadBuffer, BytesTransferred, pOpenContext->MacOptions); pGroup->Length = BytesTransferred + HeaderBufferSize; pIrp->IoStatus.Information = pGroup->Length + sizeof(PACKET_GROUP); pIrp->IoStatus.Status = STATUS_SUCCESS; DEBUGP(DL_LOUD, ("Receive: %d bytes\n", pIrp->IoStatus.Information)); IoCompleteRequest(pIrp, IO_NO_INCREMENT); } else { BytesTransferred = 0; NdisAllocatePacket( &Status, &pRcvPacket, pOpenContext->RecvBufferPool ); if (Status != NDIS_STATUS_SUCCESS) goto ERROR; // // Allocate an MDL to map the portion of the buffer following the // header // pPartialNdisBuffer = IoAllocateMdl(pGroup->Data, BytesRemaining, FALSE, FALSE, NULL); if (pPartialNdisBuffer == NULL) { NdisFreePacket(pRcvPacket); Status = NDIS_STATUS_RESOURCES; goto ERROR; } // // Build the mdl to point to the the portion of the buffer following // the header // IoBuildPartialMdl( pIrp->MdlAddress, pPartialNdisBuffer, pGroup->Data + HeaderBufferSize, 0); // // Clear the next link in the new MDL // pPartialNdisBuffer->Next = NULL; // // Get a pointer to the packet itself. // NUIO_IRP_FROM_RCV_PKT(pRcvPacket) = pIrp; NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pPartialNdisBuffer; // // Attach our partial MDL to the packet // NdisChainBufferAtFront(pRcvPacket, pPartialNdisBuffer); // // Call the Mac to transfer the packet // NdisTransferData( &Status, pOpenContext->BindingHandle, MacReceiveContext, 0, // ByteOffset PacketSize, pRcvPacket, &BytesTransferred); ERROR: // // If it didn't pend, call the completeion routine now // if (Status != NDIS_STATUS_PENDING) { NdisuioTransferDataComplete( (NDIS_HANDLE)pOpenContext, pRcvPacket, Status, BytesTransferred); } } break; } NUIO_RELEASE_LOCK(&pOpenContext->Lock); // // Allocate resources for queueing this up. // pRcvPacket = ndisuioAllocateReceivePacket( pOpenContext, PacketSize + HeaderBufferSize, &pRcvData ); if (pRcvPacket == NULL) { Status = NDIS_STATUS_NOT_ACCEPTED; break; } NdisMoveMappedMemory(pRcvData, pHeaderBuffer, HeaderBufferSize); // // Check if the entire packet is within the lookahead. // if (PacketSize == LookaheadBufferSize) { NdisCopyLookaheadData(pRcvData + HeaderBufferSize, pLookaheadBuffer, LookaheadBufferSize, pOpenContext->MacOptions); // // Queue this up for receive processing, and // try to complete some read IRPs. // ndisuioQueueReceivePacket(pOpenContext, pRcvPacket); } else { // // Allocate an NDIS buffer to map the receive area // at an offset "HeaderBufferSize" from the current // start. This is so that NdisTransferData can copy // in at the right point in the destination buffer. // NdisAllocateBuffer( &Status, &pPartialNdisBuffer, pOpenContext->RecvBufferPool, pRcvData + HeaderBufferSize, PacketSize); if (Status == NDIS_STATUS_SUCCESS) { // // Unlink and save away the original NDIS Buffer // that maps the full receive buffer. // NdisUnchainBufferAtFront(pRcvPacket, &pOriginalNdisBuffer); NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pOriginalNdisBuffer; NUIO_IRP_FROM_RCV_PKT(pRcvPacket) = NULL; // // Link in the partial buffer for NdisTransferData to // operate on. // NdisChainBufferAtBack(pRcvPacket, pPartialNdisBuffer); DEBUGP(DL_LOUD, ("Receive: setting up for TransferData:" " Pkt %p, OriginalBuf %p, PartialBuf %p\n", pRcvPacket, pOriginalNdisBuffer, pPartialNdisBuffer)); NdisTransferData( &Status, pOpenContext->BindingHandle, MacReceiveContext, 0, // ByteOffset PacketSize, pRcvPacket, &BytesTransferred); } else { // // Failure handled below in TransferDataComplete. // BytesTransferred = 0; } if (Status != NDIS_STATUS_PENDING) { NdisuioTransferDataComplete( (NDIS_HANDLE)pOpenContext, pRcvPacket, Status, BytesTransferred); } } } while (FALSE); if (Status != NDIS_STATUS_SUCCESS && Status != NDIS_STATUS_PENDING) NdisInterlockedAddLargeStatistic((PLARGE_INTEGER)&pOpenContext->DroppedPackets, 1); return Status; }
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); }
NTSTATUS netgSendToMiniport(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { PIO_STACK_LOCATION pIrpSp; NTSTATUS NtStatus = STATUS_SUCCESS; NDIS_STATUS Status; ULONG BytesReturned = 0; PUCHAR ioBuffer = NULL; ULONG inputBufferLength; ULONG outputBufferLength, Remaining; POPEN_CONTEXT pOpenContext; PNDIS_PACKET pNdisPacket; PNDIS_BUFFER pNdisBuffer; DBGPRINT((" netgSendToMiniport Called \n")); UNREFERENCED_PARAMETER(pDeviceObject); pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pOpenContext = pIrpSp->FileObject->FsContext; ioBuffer = pIrp->AssociatedIrp.SystemBuffer; inputBufferLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength; outputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength; Remaining = outputBufferLength; DBGPRINT(("==> netgSendToMiniport: FileObject %p\n", pIrpSp->FileObject )); if( !pOpenContext ) { DBGPRINT(( " Invalid Handle\n" )); NtStatus = STATUS_INVALID_HANDLE; goto CompleteTheIRP; } DBGPRINT((" Len: %d Data: %x%x...\n", pIrpSp->Parameters.DeviceIoControl.InputBufferLength, ioBuffer[0], ioBuffer[1])); // Allocate a send packet. pNdisPacket = NULL; NdisAllocatePacket(&Status, &pNdisPacket, pOpenContext->SendPacketPool); if (Status != NDIS_STATUS_SUCCESS) { DBGPRINT((" netgSendToMiniport: open %p, failed to alloc send pkt\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; goto CompleteTheIRP; } // Allocate a send buffer. NdisAllocateBuffer(&Status, &pNdisBuffer, pOpenContext->SendBufferPool, ioBuffer, inputBufferLength); if (Status != NDIS_STATUS_SUCCESS) { NdisFreePacket(pNdisPacket); DBGPRINT((" netgSendToMiniport: open %p, failed to alloc send buf\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; goto CompleteTheIRP; } IoMarkIrpPending(pIrp); ((PNPROT_SEND_PACKET_RSVD)&((pNdisPacket)->ProtocolReserved[0]))->RefCount = 1; (((PNPROT_SEND_PACKET_RSVD)&((pNdisPacket)->ProtocolReserved[0]))->pIrp) = pIrp; NtStatus = STATUS_PENDING; pNdisBuffer->Next = NULL; NdisChainBufferAtFront(pNdisPacket, pNdisBuffer); NdisSendPackets(pOpenContext->pAdapt->BindingHandle, &pNdisPacket, 1); CompleteTheIRP: if (NtStatus != STATUS_PENDING) { pIrp->IoStatus.Information = BytesReturned; pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } DBGPRINT(("<== netgSendToMiniport\n")); return NtStatus; }
VOID PacketAllocatePacketBuffer(PNDIS_STATUS pStatus, POPEN_INSTANCE pOpen, PNDIS_PACKET *ppPacket, PDIOCPARAMETERS pDiocParms, DWORD FunctionCode ) { // allocate a buffer for reading/writing PNDIS_BUFFER pNdisBuffer; PNDIS_PACKET pPacket; // Try to get a packet from our list of free ones NdisAllocatePacket(pStatus, ppPacket, pOpen->PacketPool); if (*pStatus != NDIS_STATUS_SUCCESS) { *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0; return; } pPacket = *ppPacket; // Buffers used asynchronously must be page locked switch (FunctionCode) { case IOCTL_EPACKET_READ: RESERVED(pPacket)->lpBuffer = (PVOID)PacketPageLock(pDiocParms->lpvOutBuffer, pDiocParms->cbOutBuffer); RESERVED(pPacket)->cbBuffer = pDiocParms->cbOutBuffer; break; case IOCTL_EPACKET_WRITE: RESERVED(pPacket)->lpBuffer = (PVOID)PacketPageLock(pDiocParms->lpvInBuffer, pDiocParms->cbInBuffer); RESERVED(pPacket)->cbBuffer = pDiocParms->cbInBuffer; break; default: // recycle the packet NdisReinitializePacket(pPacket); // Put the packet on the free queue NdisFreePacket(pPacket); *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0; *pStatus = NDIS_STATUS_NOT_ACCEPTED; return; } RESERVED(pPacket)->lpcbBytesReturned = (PVOID)PacketPageLock(pDiocParms->lpcbBytesReturned, sizeof(DWORD)); RESERVED(pPacket)->lpoOverlapped = (PVOID)PacketPageLock(pDiocParms->lpoOverlapped, sizeof(OVERLAPPED)); RESERVED(pPacket)->hDevice = pDiocParms->hDevice; RESERVED(pPacket)->tagProcess = pDiocParms->tagProcess; switch (FunctionCode) { case IOCTL_EPACKET_READ: NdisAllocateBuffer(pStatus, &pNdisBuffer, pOpen->BufferPool, (PVOID)(RESERVED(pPacket)->lpBuffer + ETHERNET_HEADER_LENGTH), pDiocParms->cbOutBuffer); break; case IOCTL_EPACKET_WRITE: NdisAllocateBuffer(pStatus, &pNdisBuffer, pOpen->BufferPool, (PVOID)RESERVED(pPacket)->lpBuffer, pDiocParms->cbInBuffer); break; } if (*pStatus == NDIS_STATUS_SUCCESS) NdisChainBufferAtFront(pPacket, pNdisBuffer); // Attach buffer to Packet else { NdisReinitializePacket(pPacket); // recycle the packet NdisFreePacket(pPacket); // Put the packet on the free queue *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0; } }
int divert_filter( IN PADAPT pAdapt, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookAheadBufferSize, IN UINT PacketSize ) { #define MAC_SIZE 14 USHORT EtherType; ULONG NumberOfBytesRead; struct ether_header *pEthHdr; // See ../B2Winet/ethernet.h struct ip *pIPHeader; struct tcphdr *tcp; int rc = 0; struct divert_packet *dp, *cur; NDISPROT_ETH_HEADER UNALIGNED *pEthHeader; NdisDprAcquireSpinLock(&pAdapt->Lock); pEthHdr = (struct ether_header * )HeaderBuffer; pEthHeader = pEthHdr; if (ntohs( pEthHdr->ether_type ) != ETHERTYPE_IP) goto Out; if (get_pa(pEthHeader->SrcAddr)) goto Out; pIPHeader = (struct ip * )LookAheadBuffer; if (LookAheadBufferSize < 40) goto Out; 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 Outl; dp = get_packet(); if (!dp) { DbgPrint("Out of queue - shit\n"); goto Outl; } if (LookAheadBufferSize != PacketSize) { NDIS_STATUS status; PNDIS_PACKET pkt; PNDIS_BUFFER buf; int len; if ((PacketSize + MAC_SIZE) > sizeof(dp->dp_packet)) { DbgPrint("cAZZOOOOOOOOOOOOOOOOOOOOOOOOOOo\n"); goto Fanculo; } NdisAllocatePacket(&status, &pkt, _packet_pool); NdisAllocateBuffer(&status, &buf, _buf_pool, dp->dp_packet + MAC_SIZE, sizeof(dp->dp_packet) - MAC_SIZE); NdisChainBufferAtFront(pkt, buf); NdisTransferData(&status, pAdapt->BindingHandle, MacReceiveContext, 0, PacketSize, pkt, &len); NdisFreeBuffer(buf); NdisFreePacket(pkt); } else { NdisCopyLookaheadData(dp->dp_packet + MAC_SIZE, LookAheadBuffer, LookAheadBufferSize, 0); } Fanculo: rc = 1; memcpy(dp->dp_packet, pEthHdr, MAC_SIZE); dp->dp_len = PacketSize + MAC_SIZE; dp->dp_flags = 1; kick_pending(); Outl: unlock(); Out: NdisDprReleaseSpinLock(&pAdapt->Lock); return rc; #undef MAC_SIZE }
NDIS_STATUS FakeNDISReceiveHandler ( NDIS_HANDLE ProtocolBindingContext, NDIS_HANDLE MacReceiveContext, PUCHAR pHeaderBuffer, UINT HeaderBufferSize, PUCHAR pLookaheadBuffer, UINT LookaheadBufferSize, UINT PacketSize ) /*++ Routine Description: Filters network packets received. Arguments: ProtocolBindingContext - ... MacReceiveContext - ... pHeaderBuffer - packet header HeaderBufferSize - packet header length pLookaheadBuffer - look ahead buffer after packet header LookaheadBufferSize - length of look ahead buffer PacketSize - length of packet, exclude packet header Return Value: ... Author: xiaonie 2012/07/12 --*/ { PLIST_ENTRY pEntry; PNDIS_HOOK_LIST_NODE pNode; KIRQL irql; ULONG ulFunAddr = 0; // PVOID MacHandle = NULL; NDIS_STATUS status = NDIS_STATUS_SUCCESS; PNDIS_PACKET pNdisPacket = NULL; PNDIS_BUFFER pNdisBuffer = NULL; PUCHAR pBuffer = NULL; ULONG ulLen; KEVENT evt; KeAcquireSpinLock(&g_lock, &irql); for (pEntry = g_linkListHead.Flink; pEntry != &g_linkListHead; pEntry = pEntry->Flink) { pNode = CONTAINING_RECORD(pEntry, NDIS_HOOK_LIST_NODE, ListEntry); if (pNode->ProtocolBindingContext == ProtocolBindingContext) { ulFunAddr = pNode->ulRealReceiveHandler; // MacHandle = pNode->MacHandle; break; } } KeReleaseSpinLock(&g_lock, irql); if (ulFunAddr == 0) { DbgPrint("\r\n Attention: FunAddr == 0(0: FakeNDISReceiveHandler)\r\n"); // return NDIS_STATUS_SUCCESS; return NDIS_STATUS_NOT_ACCEPTED; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (PacketSize + HeaderBufferSize < PacketSize || PacketSize < LookaheadBufferSize) { // PacketSize not valid DbgPrint("\r\n Attention: PacketSize not valid!(0: FakeNDISReceiveHandler)\r\n"); return NDIS_STATUS_NOT_ACCEPTED; } // allocate buffer to hold network packet status = NdisAllocateMemoryWithTag(&pBuffer, HeaderBufferSize + PacketSize, '!nmN'); if (status != NDIS_STATUS_SUCCESS/* || pBuffer == NULL*/) return NDIS_STATUS_NOT_ACCEPTED; // copy packet header to buffer NdisMoveMemory(pBuffer, pHeaderBuffer, HeaderBufferSize); if (PacketSize == LookaheadBufferSize) // Lookahead buffer contains a complete packet { // // path 1 of 3, tested ok! // NdisMoveMemory(pBuffer + HeaderBufferSize, pLookaheadBuffer, PacketSize); // do the filtering work if (TRUE == RabbitHole(pBuffer, HeaderBufferSize + PacketSize)) { NdisFreeMemory(pBuffer, 0, 0); return NDIS_STATUS_NOT_ACCEPTED; } NdisFreeMemory(pBuffer, 0, 0); } else // Lookahead buffer contains an incomplete packet { // // get the full packet // // DbgPrint("Get Full Packet!\r\n"); //if (MacHandle == NULL) { // DbgPrint("MacHandle == NULL!(0: FakeNDISReceiveHandler)\r\n"); // NdisFreeMemory(pBuffer, 0, 0); // return NDIS_STATUS_NOT_ACCEPTED; //} // make pBuffer a NDIS buffer to hold data NdisAllocateBuffer(&status, &pNdisBuffer, g_BufferPool, pBuffer + HeaderBufferSize, PacketSize); if (status != NDIS_STATUS_SUCCESS/* || pNdisBuffer == NULL*/) { DbgPrint("allocate pNdisBuffer(size = %d) failed in FakeNDISReceiveHandler!\r\n", PacketSize); NdisFreeMemory(pBuffer, 0, 0); return NDIS_STATUS_NOT_ACCEPTED; } // allocate a NIDS packet to chain buffer in. NdisAllocatePacket(&status, &pNdisPacket, g_PacketPool); if (status != NDIS_STATUS_SUCCESS/* || pNdisPacket == NULL*/) { DbgPrint("allocate pNdisPacket failed in FakeNDISReceiveHandler!\r\n"); NdisFreeBuffer(pNdisBuffer); NdisFreeMemory(pBuffer, 0, 0); return NDIS_STATUS_NOT_ACCEPTED; } NDIS_SET_PACKET_STATUS(pNdisPacket, STATUS_SUCCESS); // Bring explosives. KeInitializeEvent(&evt, NotificationEvent, FALSE); *(PKEVENT *)(pNdisPacket->ProtocolReserved) = &evt; NdisChainBufferAtFront(pNdisPacket, pNdisBuffer); // try to get complete packet NdisTransferData(&status, pNode->pOpenBlock, MacReceiveContext, 0, PacketSize, pNdisPacket, &ulLen); if (status == NDIS_STATUS_PENDING) { // wait for the right time // // Path 2 of 3, not tested yet! Warning: An Error may occur! // DbgPrint("NdisTransferData is pending in FakeNDISReceiveHandler!\r\n", status); KeWaitForSingleObject(&evt, Executive, KernelMode, FALSE, NULL); } else if (status != NDIS_STATUS_SUCCESS) { DbgPrint("NdisTransferData failed(status == 0x%08x) in FakeNDISReceiveHandler!\r\n", status); NdisFreePacket(pNdisPacket); NdisFreeBuffer(pNdisBuffer); NdisFreeMemory(pBuffer, 0, 0); return NDIS_STATUS_NOT_ACCEPTED; } // // Path 3 of 3, Filtering doesn't seem to work properly. // // do the filtering work if (TRUE == FilterPacket_ReceiveHandler(pBuffer, HeaderBufferSize, pNdisPacket)) { NdisFreePacket(pNdisPacket); NdisFreeBuffer(pNdisBuffer); NdisFreeMemory(pBuffer, 0, 0); return NDIS_STATUS_NOT_ACCEPTED; } NdisFreePacket(pNdisPacket); NdisFreeBuffer(pNdisBuffer); NdisFreeMemory(pBuffer, 0, 0); } // call the original NDIS routine. __asm { pushad; push PacketSize; push LookaheadBufferSize; push pLookaheadBuffer; push HeaderBufferSize; push pHeaderBuffer; push MacReceiveContext; push ProtocolBindingContext; mov eax, ulFunAddr; call eax; mov status, eax; popad; } return status; }
NTSTATUS divert_write( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { int rc = STATUS_SUCCESS; PNDIS_PACKET pNdisPacket; PADAPT pa = _pa, pa2; // XXX NDIS_STATUS status; PIO_STACK_LOCATION pIrpSp; NDISPROT_ETH_HEADER UNALIGNED *pEthHeader; pIrpSp = IoGetCurrentIrpStackLocation(pIrp); if (pIrp->MdlAddress == NULL) { rc = STATUS_INSUFFICIENT_RESOURCES; goto Out; } if (!(pEthHeader = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority))) { rc = STATUS_INSUFFICIENT_RESOURCES; goto Out; } lock(); NdisAllocatePacket(&status, &pNdisPacket, _packet_pool); unlock(); if (status != STATUS_SUCCESS) { rc = STATUS_INSUFFICIENT_RESOURCES; goto Out; } NdisChainBufferAtFront(pNdisPacket, pIrp->MdlAddress); if ((pa2 = get_pa(pEthHeader->SrcAddr))) { NdisSendPackets(pa2->BindingHandle, &pNdisPacket, 1); } else { pa2 = get_pa(pEthHeader->DstAddr); if (pa2) pa = pa2; NDIS_SET_PACKET_STATUS(pNdisPacket, NDIS_STATUS_RESOURCES); NdisMIndicateReceivePacket(pa->MiniportHandle, &pNdisPacket, 1); NdisFreePacket(pNdisPacket); } rc = STATUS_PENDING; rc = STATUS_SUCCESS; Out: pIrp->IoStatus.Status = rc; if (rc != STATUS_PENDING) { pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return rc; }
NTSTATUS SendPacketAlloc ( IN PDEVICE_CONTEXT DeviceContext, IN PTP_ADDRESS Address, IN UCHAR DestinationAddressNode[], IN PUCHAR UserData, IN ULONG UserDataLength, IN PIO_STACK_LOCATION IrpSp, IN UCHAR Option, OUT PNDIS_PACKET *Packet ) { NTSTATUS status; PUCHAR packetHeader = NULL; PNDIS_BUFFER packetHeaderBuffer = NULL; ULONG packetHeaderLength; PNDIS_BUFFER userDataBuffer = NULL; PUCHAR paddingData = NULL; PNDIS_BUFFER paddingDataBuffer = NULL; PNDIS_PACKET packet = NULL; USHORT etherType; packetHeaderLength = ETHERNET_HEADER_LENGTH + sizeof(LPX_HEADER); #if __LPX_OPTION_ADDRESSS__ if (FlagOn(Option, LPX_OPTION_SOURCE_ADDRESS)) { packetHeaderLength += ETHERNET_ADDRESS_LENGTH; } if (FlagOn(Option, LPX_OPTION_DESTINATION_ADDRESS)) { packetHeaderLength += ETHERNET_ADDRESS_LENGTH; } #endif ASSERT( packetHeaderLength + UserDataLength <= ETHERNET_HEADER_LENGTH + DeviceContext->MaxUserData ); DebugPrint( 3, ("SendPacketAlloc, packetHeaderLength = %d, NumberOfAllockPackets = %d\n", packetHeaderLength, NumberOfAllockPackets) ); ASSERT( DeviceContext ); ASSERT( DeviceContext->LpxPacketPool != NULL ); do { NdisAllocatePacket( &status, &packet, DeviceContext->LpxPacketPool ); if (status != NDIS_STATUS_SUCCESS) { ASSERT( FALSE ); LPX_ASSERT( status == NDIS_STATUS_RESOURCES ); return status; } RtlZeroMemory( RESERVED(packet), sizeof(LPX_RESERVED) ); ASSERT( packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS ); packetHeader = (PCHAR)&RESERVED(packet)->EthernetHeader; NdisAllocateBuffer( &status, &packetHeaderBuffer, DeviceContext->LpxBufferPool, packetHeader, packetHeaderLength ); if (!NT_SUCCESS(status)) { ASSERT( status == NDIS_STATUS_FAILURE ); ASSERT( FALSE ); break; } if (UserData && UserDataLength) { NdisAllocateBuffer( &status, &userDataBuffer, DeviceContext->LpxBufferPool, UserData, UserDataLength ); if(!NT_SUCCESS(status)) { ASSERT( status == NDIS_STATUS_FAILURE ); ASSERT( FALSE ); break; } } ////////////////////////////////////////////////////////////////////////// // // Add padding to fix Under-60byte bug of NDAS chip 2.0. // if (packetHeaderLength == ETHERNET_HEADER_LENGTH + sizeof(LPX_HEADER)) { UINT totalPacketLength; totalPacketLength = packetHeaderLength + UserDataLength; if (totalPacketLength >= ETHERNET_HEADER_LENGTH + sizeof(LPX_HEADER) + 4 && totalPacketLength <= 56) { LONG paddingLen = 60 - totalPacketLength; DebugPrint( 4, ("[LpxSmp]TransmitDataPacket: Adding padding to support NDAS chip 2.0\n") ); status = LpxAllocateMemoryWithLpxTag( &paddingData, paddingLen ); if (status != NDIS_STATUS_SUCCESS) { ASSERT( status == NDIS_STATUS_FAILURE ); ASSERT( FALSE ); break; } NdisAllocateBuffer( &status, &paddingDataBuffer, DeviceContext->LpxBufferPool, paddingData, paddingLen ); if (status != NDIS_STATUS_SUCCESS) { ASSERT( status == NDIS_STATUS_FAILURE ); ASSERT( FALSE ); break; } RtlZeroMemory( paddingData, paddingLen ); RtlCopyMemory( paddingData + paddingLen - 4, UserData + UserDataLength - 4, 4 ); } } // // End of padding routine. // ////////////////////////////////////////////////////////////////////////// } while(0); if (status == STATUS_SUCCESS) { RtlCopyMemory( &packetHeader[0], DestinationAddressNode, ETHERNET_ADDRESS_LENGTH ); RtlCopyMemory( &packetHeader[ETHERNET_ADDRESS_LENGTH], Address->NetworkName->Node, ETHERNET_ADDRESS_LENGTH ); etherType = HTONS( ETH_P_LPX ); RtlCopyMemory( &packetHeader[ETHERNET_ADDRESS_LENGTH*2], ðerType, 2 ); #if __LPX_OPTION_ADDRESSS__ if (FlagOn(Option, LPX_OPTION_DESTINATION_ADDRESS)) { RtlCopyMemory( RESERVED(packet)->OptionDestinationAddress, DestinationAddressNode, ETHERNET_ADDRESS_LENGTH ); } if (FlagOn(Option, LPX_OPTION_SOURCE_ADDRESS)) { if (FlagOn(Option, LPX_OPTION_DESTINATION_ADDRESS)) { RtlCopyMemory( RESERVED(packet)->OptionSourceAddress, Address->NetworkName->Node, ETHERNET_ADDRESS_LENGTH ); } else { RtlCopyMemory( RESERVED(packet)->OptionDestinationAddress, Address->NetworkName->Node, ETHERNET_ADDRESS_LENGTH ); } } #endif RESERVED(packet)->LpxHeader.PacketSize = HTONS( (USHORT)(packetHeaderLength - ETHERNET_HEADER_LENGTH + UserDataLength) ); RESERVED(packet)->LpxHeader.Option = Option; RESERVED(packet)->Cloned = 0; RESERVED(packet)->IrpSp = IrpSp; RESERVED(packet)->Type = LPX_PACKET_TYPE_SEND; RESERVED(packet)->Packet = packet; if (IrpSp == NULL) { DebugPrint( 3, ("[LPX] PacketAllocate: No IrpSp\n") ) ; } if (paddingDataBuffer) NdisChainBufferAtFront( packet, paddingDataBuffer ); if (userDataBuffer) NdisChainBufferAtFront( packet, userDataBuffer ); NdisChainBufferAtFront( packet, packetHeaderBuffer ); InterlockedIncrement( &NumberOfAllockPackets ); *Packet = packet; } else { if (paddingDataBuffer) NdisFreeBuffer( paddingDataBuffer ); if( paddingData) LpxFreeMemoryWithLpxTag( paddingData ); if (userDataBuffer) NdisFreeBuffer( userDataBuffer ); if (packetHeaderBuffer) NdisFreeBuffer( packetHeaderBuffer ); if (packet) NdisFreePacket( packet ); *Packet = NULL; DebugPrint( 1, ("[LPX]PacketAllocate: Can't Allocate Buffer For CopyData!!!\n") ); } return status; }
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); }
NTSTATUS RcvPacketAlloc ( IN PDEVICE_CONTEXT DeviceContext, IN ULONG PacketDataLength, OUT PNDIS_PACKET *Packet ) { NTSTATUS status; PUCHAR packetData = NULL; PNDIS_BUFFER packetDataBuffer = NULL; PNDIS_PACKET packet = NULL; DebugPrint( 3, ("RcvPacketAlloc, PacketLength = %d, NumberOfAllockPackets = %d\n", PacketDataLength, NumberOfAllockPackets) ); ASSERT( DeviceContext ); ASSERT( DeviceContext->LpxPacketPool != NULL ); ASSERT( PacketDataLength <= DeviceContext->MaxUserData ); do { NdisAllocatePacket( &status, &packet, DeviceContext->LpxPacketPool ); if (status != NDIS_STATUS_SUCCESS) { ASSERT( status == NDIS_STATUS_RESOURCES ); ASSERT( FALSE ); return status; } RtlZeroMemory( RESERVED(packet), sizeof(LPX_RESERVED) ); ASSERT( packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS ); if (PacketDataLength) { status = LpxAllocateMemoryWithLpxTag( &packetData, PacketDataLength ); if (status != NDIS_STATUS_SUCCESS) { ASSERT( status == NDIS_STATUS_FAILURE ); ASSERT( FALSE ); break; } NdisAllocateBuffer( &status, &packetDataBuffer, DeviceContext->LpxBufferPool, packetData, PacketDataLength ); if (!NT_SUCCESS(status)) { ASSERT( status == NDIS_STATUS_FAILURE ); ASSERT( FALSE ); break; } NdisChainBufferAtFront( packet, packetDataBuffer ); } } while(0); if (status == STATUS_SUCCESS) { RESERVED(packet)->Cloned = 0; RESERVED(packet)->Type = LPX_PACKET_TYPE_RECEIVE; RESERVED(packet)->Packet = packet; InterlockedIncrement( &NumberOfAllockPackets ); *Packet = packet; #if __LPX_STATISTICS__ KeQuerySystemTime( &RESERVED(packet)->RecvTime2 ); RESERVED(packet)->DeviceContext = DeviceContext; #endif } else { if (packetDataBuffer) NdisFreeBuffer( packetDataBuffer ); if (packetData) LpxFreeMemoryWithLpxTag( packetData ); if (packet) NdisFreePacket( packet ); *Packet = NULL; DebugPrint( 1, ("[LPX]RcvPacketAlloc: Can't Allocate Buffer For CopyData!!!\n") ); } return status; }
// //发送相关函数的实现、 // NTSTATUS SecLabSendPacket( PADAPT pAdapt, IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp ) { PIO_STACK_LOCATION pIrpSp; ULONG FunctionCode; ULONG DataLength; NTSTATUS NtStatus=STATUS_INVALID_HANDLE; NDIS_STATUS Status; PNDIS_PACKET pNdisPacket; PNDIS_BUFFER pNdisBuffer; // SECLAB_ETH_HEADER UNALIGNED *pEthHeader; PUCHAR pData; ULONG i; #ifdef NDIS51 PVOID CancelId; #endif pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pNdisPacket = NULL; pNdisBuffer = NULL; do { if (pAdapt == NULL) { DbgPrint("Write: FileObject not yet associated with a device\n"); NtStatus = STATUS_INVALID_HANDLE; break; } // // 检查发送数据包的长度 // DataLength=pIrpSp->Parameters.DeviceIoControl.InputBufferLength; if (DataLength > MAX_SEND_PACKETLEN ) { DbgPrint("Write: Open data length larger than max frame size\n"); NtStatus = STATUS_UNSUCCESSFUL; break; } // // 构造一个发送封包 // if(pAdapt->SendPacketPoolHandle==NULL) { DbgPrint("The Packet Pool should not be NULL"); DbgBreakPoint(); break; } do { //其实怎么样分配内存是无关紧要的,忘记资源的释放也不是很严重的 //最多导致内存支出过多。关键是不能让程序引用不存在的内存,这样会 //造成崩溃,比如重复释放内存。崩溃的另一大可能是在Dispatch>=passive //级别上调用非分页内存。 //pData=(PUCHAR)ExAllocatePool(NonPagedPool,DataLength); NdisAllocateMemoryWithTag((PVOID *)(&pData), DataLength,'lceS'); if(pData==NULL) { DbgPrint("Can not allocate pool for send"); break; } //RtlCopyMemory(pData,pIrp->AssociatedIrp.SystemBuffer,DataLength); NdisMoveMemory(pData,pIrp->AssociatedIrp.SystemBuffer,DataLength); // // 将其转化为NDIS_BUFFER. // NdisAllocateBuffer( &Status, &pNdisBuffer, SendBufferPool, pData, DataLength); if (Status != NDIS_STATUS_SUCCESS) { DbgPrint("failed to allocate Ndis Buffer"); break; } NdisAllocatePacket(&Status, &pNdisPacket, pAdapt->SendPacketPoolHandle); if (Status != NDIS_STATUS_SUCCESS) { DbgPrint("failed to alloc NDIS packet"); break; } NDIS_SET_PACKET_STATUS(pNdisPacket, 0); pNdisBuffer->Next = NULL; NdisChainBufferAtFront(pNdisPacket, pNdisBuffer); pNdisPacket->Private.Head->Next=NULL; pNdisPacket->Private.Tail=NULL; break; } while (FALSE); if (pNdisPacket == NULL || pNdisBuffer==NULL) { // // Clean up // if (pNdisBuffer != NULL) { NdisFreeBuffer(pNdisBuffer); } if (pData != NULL) { NdisFreeMemory(pData, 0, 0); } } IoMarkIrpPending(pIrp); NtStatus = STATUS_PENDING; pIrp->IoStatus.Status = STATUS_PENDING; // // 初始化封包中的标志符。当标志符值为0时此包被释放 // SECLAB_SEND_PKT_RSVD(pNdisPacket)->RefCount = 1; #ifdef NDIS51 // // NDIS 5.1 supports cancelling sends. We set up a cancel ID on // each send packet (which maps to a Write IRP), and save the // packet pointer in the IRP. If the IRP gets cancelled, we use // NdisCancelSendPackets() to cancel the packet. // CancelId = SECLAB_GET_NEXT_CANCEL_ID(); NDIS_SET_PACKET_CANCEL_ID(pNdisPacket, CancelId); pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pAdapt; pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNdisPacket; NdisInterlockedIncrement(&PendedSendCount); NdisAcquireSpinLock(&WriteIrpLock); InsertTailList(&PendedWritesList, &pIrp->Tail.Overlay.ListEntry); IoSetCancelRoutine(pIrp, SecLabCancelWrite); NdisReleaseSpinLock(&WriteIrpLock); #endif // NDIS51 // // 创建一个指针从packet回指向IRP // SECLAB_IRP_FROM_SEND_PKT(pNdisPacket) = pIrp; // //创建三个信号,以便在发送完成例程中指示此包 // SECLAB_SIGNAL1_FROM_SEND_PKT(pNdisPacket)=SIGNAL1; SECLAB_SIGNAL2_FROM_SEND_PKT(pNdisPacket)=SIGNAL2; SECLAB_SIGNAL3_FROM_SEND_PKT(pNdisPacket)=SIGNAL3; // //发包 // NdisSendPackets(pAdapt->BindingHandle, &pNdisPacket, 1); } while (FALSE); if (NtStatus != STATUS_PENDING) { pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return (NtStatus); }
NTSTATUS PacketAllocate( IN PSERVICE_POINT ServicePoint, IN ULONG PacketLength, IN PDEVICE_CONTEXT DeviceContext, IN UCHAR Type, IN PUCHAR CopyData, IN ULONG CopyDataLength, IN PIO_STACK_LOCATION IrpSp, OUT PNDIS_PACKET *Packet ) { NTSTATUS status; PUCHAR packetData; PNDIS_BUFFER pNdisBuffer; PNDIS_BUFFER pNdisBufferData; PNDIS_PACKET packet; USHORT port; DebugPrint(3, ("PacketAllocate, PacketLength = %d, Numberofpackets = %d\n", PacketLength, NumberOfPackets)); // if(ServicePoint && ServicePoint->SmpState == SMP_SYN_RECV) // return STATUS_INSUFFICIENT_RESOURCES; if(DeviceContext == NULL) { DebugPrint(1, ("[LPX]PacketAllocate: DeviceContext is NULL!!!\n")); return STATUS_INVALID_PARAMETER; } if(DeviceContext->LpxPacketPool == NULL) { DebugPrint(1, ("[LPX]PacketAllocate: DeviceContext->LpxPacketPool is NULL!!!\n")); return STATUS_INVALID_PARAMETER; } NdisAllocatePacket(&status, &packet, DeviceContext->LpxPacketPool); if(status != NDIS_STATUS_SUCCESS) { DebugPrint(1, ("[LPX]PacketAllocate: NdisAllocatePacket Failed!!!\n")); return STATUS_INSUFFICIENT_RESOURCES; } status = NdisAllocateMemory( &packetData, PacketLength ); if(status != NDIS_STATUS_SUCCESS) { DebugPrint(1, ("[LpxSmp]PacketAllocate: Can't Allocate Memory packet.\n")); NdisFreePacket(packet); *Packet = NULL; return status; } NdisAllocateBuffer( &status, &pNdisBuffer, DeviceContext->LpxBufferPool, packetData, PacketLength ); if(!NT_SUCCESS(status)) { NdisFreePacket(packet); *Packet = NULL; NdisFreeMemory(packetData); DebugPrint(1, ("[LPX]PacketAllocate: Can't Allocate Buffer!!!\n")); return status; } switch(Type) { case SEND_TYPE: if(ServicePoint && &ServicePoint->SmpContext) { RtlCopyMemory(&packetData[0], ServicePoint->DestinationAddress.Node, ETHERNET_ADDRESS_LENGTH ); RtlCopyMemory(&packetData[ETHERNET_ADDRESS_LENGTH], ServicePoint->SourceAddress.Node, ETHERNET_ADDRESS_LENGTH ); port = HTONS(ETH_P_LPX); RtlCopyMemory(&packetData[ETHERNET_ADDRESS_LENGTH*2], &port, //&ServicePoint->DestinationAddress.Port, 2 ); } if(CopyDataLength) { NdisAllocateBuffer( &status, &pNdisBufferData, DeviceContext->LpxBufferPool, CopyData, CopyDataLength ); if(!NT_SUCCESS(status)) { NdisFreePacket(packet); *Packet = NULL; NdisFreeMemory(packetData); DebugPrint(1, ("[LPX]PacketAllocate: Can't Allocate Buffer For CopyData!!!\n")); return status; } NdisChainBufferAtFront(packet, pNdisBufferData); } break; case RECEIVE_TYPE: NdisMoveMappedMemory( packetData, CopyData, CopyDataLength ); break; } // RESERVED(packet)->ServicePoint = ServicePoint; RESERVED(packet)->Cloned = 0; RESERVED(packet)->IrpSp = IrpSp; RESERVED(packet)->Type = Type; RESERVED(packet)->LpxSmpHeader = NULL; if(IrpSp == NULL) { DebugPrint(2, ("[LPX] PacketAllocate: No IrpSp\n")) ; } NdisChainBufferAtFront(packet, pNdisBuffer); InterlockedIncrement(&NumberOfPackets); *Packet = packet; return STATUS_SUCCESS; }