/************************************************************ Start the sending of a packet ************************************************************/ DWORD PacketWrite(POPEN_INSTANCE Open, DWORD dwDDB, DWORD hDevice, PDIOCPARAMETERS pDiocParms ) { PNDIS_PACKET pPacket; PNDIS_BUFFER pNdisBuffer; NDIS_STATUS Status; TRACE_ENTER( "SendPacket" ); PacketAllocatePacketBuffer( &Status, Open, &pPacket, pDiocParms, IOCTL_PROTOCOL_WRITE ); if ( Status != NDIS_STATUS_SUCCESS ) { return 0; } NdisSend( &Status, Open->AdapterHandle, pPacket ); if ( Status != NDIS_STATUS_PENDING ) { PacketSendComplete( Open, pPacket, Status ); } TRACE_LEAVE( "SendPacket" ); return(-1); }
NTSTATUS NTAPI NduDispatchWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; PNDIS_PACKET Packet; NDIS_STATUS Status; ULONG BytesCopied = 0; ASSERT(DeviceObject == GlobalDeviceObject); /* Create a packet and buffer descriptor for this user buffer */ Packet = CreatePacketFromPoolBuffer(AdapterContext, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Write.Length); if (Packet) { /* Send it via NDIS */ NdisSend(&Status, AdapterContext->BindingHandle, Packet); /* Wait for the send */ if (Status == NDIS_STATUS_PENDING) { KeWaitForSingleObject(&AdapterContext->AsyncEvent, Executive, KernelMode, FALSE, NULL); Status = AdapterContext->AsyncStatus; } /* Check if it succeeded */ if (Status == NDIS_STATUS_SUCCESS) BytesCopied = IrpSp->Parameters.Write.Length; CleanupAndFreePacket(Packet, FALSE); } else { /* No memory */ Status = STATUS_NO_MEMORY; } /* Complete the IRP */ Irp->IoStatus.Status = Status; Irp->IoStatus.Information = BytesCopied; IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); return Status; }
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; }
DWORD PacketWrite(POPEN_INSTANCE Open, DWORD dwDDB, DWORD hDevice, PDIOCPARAMETERS pDiocParms) { // write a packet PNDIS_PACKET pPacket; NDIS_STATUS Status; PacketAllocatePacketBuffer(&Status, Open, &pPacket, pDiocParms, IOCTL_EPACKET_WRITE); if (Status != NDIS_STATUS_SUCCESS) return 0; // This will return immediately with no data written // Call the MAC NdisSend(&Status, Open->AdapterHandle, pPacket); if (Status != NDIS_STATUS_PENDING) { // The send didn't pend so call the completion handler now PacketSendComplete(Open, pPacket, Status); } return(-1); // This will make DeviceIOControl return ERROR_IO_PENDING }
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); } } }
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); }
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 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); }
/*-------------------------------------------------------------------------- ssh_interceptor_send() Sends packet either down to the network or up to the protocol. --------------------------------------------------------------------------*/ void ssh_interceptor_send(SshInterceptor interceptor, SshInterceptorPacket ip, size_t media_header_len) { SshNdisPacket packet; ULONG first_buf_len = SSH_ETHERH_HDRLEN; SshNdisIMAdapter adapter; SshCpuContext cpu_ctx; Boolean use_one_buffer = FALSE; ULONG new_value; /* Sanity checks for arguments */ SSH_ASSERT(interceptor != NULL); SSH_ASSERT(ip != NULL); SSH_ASSERT((ip->flags & SSH_PACKET_FROMADAPTER) != (ip->flags & SSH_PACKET_FROMPROTOCOL)); #ifndef _WIN32_WCE SSH_ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); #endif /* _WIN32_WCE */ cpu_ctx = &interceptor->cpu_ctx[ssh_kernel_get_cpu()]; packet = CONTAINING_RECORD(ip, SshNdisPacketStruct, ip); #ifdef DEBUG_LIGHT packet->f.flags.in_engine = 0; #endif /* DEBUG_LIGHT */ adapter = (SshNdisIMAdapter)packet->adapter_in; /* Check if adapter where the packet should be sent is different where the packet originated from */ if (adapter && (adapter->ifnum == ip->ifnum_out)) { new_value = InterlockedIncrement(&adapter->ref_count); packet->adapter_out = (SshAdapter)adapter; } else { SshAdapter gen_adapter = NULL; if (ip->ifnum_out < SSH_INTERCEPTOR_MAX_ADAPTERS) { ssh_kernel_rw_mutex_lock_read(&interceptor->adapter_lock); gen_adapter = interceptor->adapter_table[ip->ifnum_out]; if (gen_adapter) { new_value = InterlockedIncrement(&gen_adapter->ref_count); packet->adapter_out = gen_adapter; } ssh_kernel_rw_mutex_unlock_read(&interceptor->adapter_lock); } if (gen_adapter == NULL) goto free_packet; adapter = (SshNdisIMAdapter)gen_adapter; } SSH_ASSERT(new_value > 0); /* Check that active adapter found and it supports the protocol */ if (!ssh_adapter_is_enabled((SshNdisIMAdapter)adapter)) { SSH_DEBUG(SSH_D_FAIL, ("active network connection not found")); goto free_packet; } #ifndef _WIN32_WCE /* Check if packet is plain IPv4 (IPv6) and then add ethernet framing */ if (ip->protocol == SSH_PROTOCOL_IP4 || ip->protocol == SSH_PROTOCOL_IP6) { if (!ssh_wan_packet_encapsulate((SshAdapter)adapter, ip)) { SSH_DEBUG(SSH_D_FAIL, ("packet framing failed")); goto free_packet; } /* Some dial-up drivers seem to expect to receive whole packet in one NDIS buffer. */ if (ip->flags & SSH_PACKET_FROMADAPTER) use_one_buffer = TRUE; } #endif /* _WIN32_WCE */ /* Add the VLAN tagging, if any */ if (packet->vlan_tag_count > 0) { if (adapter != (SshNdisIMAdapter)packet->adapter_in) { /* Engine forwards this packet to different interface. Check whether this is VLAN/QoS enabled interface and reconstruct tagging accordingly. */ switch (adapter->options & (NDIS_MAC_OPTION_8021Q_VLAN | NDIS_MAC_OPTION_8021P_PRIORITY)) { case 0: /* Adapter doesn't support IEEE 802.1q/p; drop VLAN tag(s). */ packet->vlan_tag_count = 0; break; case NDIS_MAC_OPTION_8021P_PRIORITY: /* Adapter supports only priority (QoS) tagging. */ packet->vlan_tags[0].vlan_id = 0; packet->vlan_tag_count = 1; break; default: /* Adapter supports also VLAN. Change the VLAN ID of the first tag to the one configued to this NIC driver. */ packet->vlan_tags[0].vlan_id = adapter->vlan_id; break; } } if (packet->vlan_tag_count) { unsigned char *vlan_tags; SshUInt16 i; vlan_tags = ssh_interceptor_packet_insert(ip, SSH_ETHERH_OFS_TYPE, packet->vlan_tag_count * 4); if (vlan_tags == NULL) { SSH_DEBUG(SSH_D_FAIL, ("Failed to add VLAN tags")); return; } for (i = 0; i < packet->vlan_tag_count; i++) { unsigned char *tag = vlan_tags + (i * 4); SSH_PUT_16BIT(tag, SSH_ETHERTYPE_VLAN); SSH_PUT_16BIT((tag + 2), (packet->vlan_tags[i].vlan_id << 4 | packet->vlan_tags[i].qos)); } } } NDIS_SET_PACKET_HEADER_SIZE(packet->np, SSH_ETHERH_HDRLEN); NDIS_SET_PACKET_STATUS(packet->np, NDIS_STATUS_SUCCESS); #ifdef _WIN32_WCE if (adapter->media == NdisMediumWan) { if (ip->flags & SSH_PACKET_FROMPROTOCOL) { if (!ssh_wan_send_to_adapter(adapter, packet, ip->protocol)) SSH_DEBUG(SSH_D_FAIL, ("Cannot send packet to WAN adapter")); } else if (ip->flags & SSH_PACKET_FROMADAPTER) { if (!ssh_wan_send_to_protocol(adapter, packet, ip->protocol)) SSH_DEBUG(SSH_D_FAIL, ("Cannot send packet to WAN protocol")); } else { SSH_DEBUG(SSH_D_ERROR, ("Dropping WAN packet without direction")); } ssh_interceptor_packet_free(&packet->ip); return; } #endif /* _WIN32_WCE */ if (ip->flags & SSH_PACKET_FROMPROTOCOL) { NDIS_STATUS status; /* Send packet to network */ NdisSetPacketFlags(packet->np, NDIS_FLAGS_DONT_LOOPBACK); if (cpu_ctx->in_packet_cb || cpu_ctx->in_route_cb || cpu_ctx->in_timeout_cb) { SSH_DEBUG(SSH_D_NICETOKNOW, ("Risk for recursive call; enqueueing packet 0x%p", packet)); #ifdef DEBUG_LIGHT packet->f.flags.in_send_queue = 1; #endif /* DEBUG_LIGHT */ if (cpu_ctx->in_packet_cb) { ssh_net_packet_enqueue(&cpu_ctx->send_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_send_queue = 1; } else if (cpu_ctx->in_route_cb) { ssh_net_packet_enqueue(&cpu_ctx->route_send_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_route_send_queue = 1; } else if (cpu_ctx->in_timeout_cb) { ssh_net_packet_enqueue( &cpu_ctx->timeout_send_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_timeout_send_queue = 1; } } else { #ifdef DEBUG_LIGHT SSH_DEBUG(SSH_D_NICETOKNOW, ("Sending packet 0x%p to underlying driver", packet)); packet->f.flags.in_miniport = 1; #endif /* DEBUG_LIGHT */ NdisSend(&status, adapter->binding_handle, packet->np); if (status != NDIS_STATUS_PENDING) { SSH_DEBUG(SSH_D_NICETOKNOW, ("Send operation completed synchronously; " "packet=0x%p, status=%@", ssh_ndis_status_render, status)); ssh_interceptor_packet_free(&packet->ip); } } } else if (ip->flags & SSH_PACKET_FROMADAPTER) { /* Packet is ready now so check packet consistency */ if (use_one_buffer) first_buf_len = packet->packet_len; else first_buf_len += adapter->lookahead_size; first_buf_len = MIN(first_buf_len, packet->packet_len); if (!ssh_packet_get_contiguous_data((SshNetDataPacket)packet, 0, first_buf_len, FALSE)) { SSH_DEBUG(SSH_D_FAIL, ("Invalid packet")); goto free_packet; } if (cpu_ctx->in_packet_cb || cpu_ctx->in_route_cb || cpu_ctx->in_timeout_cb) { SSH_DEBUG(SSH_D_NICETOKNOW, ("Risk for recursive call; enqueueing packet 0x%p", packet)); #ifdef DEBUG_LIGHT packet->f.flags.in_recv_queue = 1; #endif /* DEBUG_LIGHT */ if (cpu_ctx->in_packet_cb) { ssh_net_packet_enqueue(&cpu_ctx->recv_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_recv_queue = 1; } else if (cpu_ctx->in_route_cb) { ssh_net_packet_enqueue(&cpu_ctx->route_recv_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_route_recv_queue = 1; } else if (cpu_ctx->in_timeout_cb) { ssh_net_packet_enqueue( &cpu_ctx->timeout_recv_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_timeout_recv_queue = 1; } } else { SSH_DEBUG(SSH_D_NICETOKNOW, ("Indicating packet 0x%p to upper layers", packet)); #ifdef DEBUG_LIGHT packet->f.flags.in_protocol = 1; #endif /* DEBUG_LIGHT */ NdisMIndicateReceivePacket(adapter->handle, &packet->np, 1); } } else { SSH_NOTREACHED; } return; free_packet: /* Otherwise just drop the packet */ SSH_DEBUG(SSH_D_FAIL, ("ssh_interceptor_send(): dropping packet")); ssh_interceptor_packet_free(&packet->ip); }