void NTAPI WallALERecvAcceptClassify( IN const FWPS_INCOMING_VALUES* inFixedValues, IN const FWPS_INCOMING_METADATA_VALUES* inMetaValues, IN OUT void* layerData, IN const void* classifyContext, IN const FWPS_FILTER* filter, IN UINT64 flowContext, OUT FWPS_CLASSIFY_OUT* classifyOut ) /*++ --*/ { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING devName,dosName; WCHAR buffer[MAX_PATH_LEN]; PMY_UNICODE_STRING logData; PWALL_PENDED_PACKET pendedRecv = NULL; BOOLEAN bWakeUp = FALSE; ADDRESS_FAMILY addressFamily; LOG("into\n"); if(!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE)) { KdPrint(("write right not set!\n")); return; } if( layerData != NULL ) { FWPS_PACKET_INJECTION_STATE state; state = FwpsQueryPacketInjectionState( gInjectHandle, layerData, NULL); KdPrint(("inject state:%x\n",state )); if( state == FWPS_PACKET_INJECTED_BY_SELF || state == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF ) { classifyOut->actionType = FWP_ACTION_PERMIT; KdPrint(("inject by self\n")); goto exit; } } addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId); if(!IsAleReauthorize(inFixedValues)) { pendedRecv = WallAllocateAndInitPendedPacket( inFixedValues, inMetaValues, addressFamily, layerData, WALL_DATA_PACKET, FWP_DIRECTION_INBOUND ); if(pendedRecv == NULL ) { classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; goto exit; } ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_COMPLETION_HANDLE)); status = FwpsPendOperation0( inMetaValues->completionHandle, &pendedRecv->completionContext ); if (!NT_SUCCESS(status)) { classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; goto exit; } bWakeUp = IsListEmpty(&gPacketList->list) && IsListEmpty(&gConnList->list); ExInterlockedInsertTailList( &gPacketList->list,&pendedRecv->list,&gPacketList->lock ); pendedRecv = NULL; if( bWakeUp ) { RunMyProcess( WallInspectWallPackets,NULL ); } classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; } else {//reauth FWP_DIRECTION packetDirection; KIRQL irql,irql2; KdPrint(("recv reauth!\n")); classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; } exit: if( classifyOut->actionType == FWP_ACTION_PERMIT ) { RtlInitUnicodeString( &devName,(PWCHAR)inMetaValues->processPath->data ); RtlInitEmptyUnicodeString( &dosName,buffer,MAX_PATH_LEN * sizeof(WCHAR)); logData = MyExAllocatePool( sizeof( MY_UNICODE_STRING) + inMetaValues->processPath->size); if( logData != NULL) { logData->str.Buffer = logData->buffer; logData->str.MaximumLength = (USHORT)inMetaValues->processPath->size; status = DevicePathToDosPath( &devName,&dosName ); if( NT_SUCCESS( status )) { RtlCopyUnicodeString( (PUNICODE_STRING)logData,&dosName ); } else { RtlCopyUnicodeString( (PUNICODE_STRING)logData,&devName ); } RunMyProcess( WallWriteConnectLogData,logData ); logData = NULL; } } return; }
void TLInspectALERecvAcceptClassify( IN const FWPS_INCOMING_VALUES0* inFixedValues, IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues, IN OUT void* layerData, IN const FWPS_FILTER0* filter, IN UINT64 flowContext, OUT FWPS_CLASSIFY_OUT0* classifyOut ) /* ++ This is the classifyFn function for the ALE Recv-Accept (v4 and v6) callout. For an initial classify (where the FWP_CONDITION_FLAG_IS_REAUTHORIZE flag is not set), it is queued to the connection list for inspection by the worker thread. For re-auth, it is queued to the packet queue to be process by the worker thread like any other regular packets. -- */ { NTSTATUS status; KLOCK_QUEUE_HANDLE connListLockHandle; KLOCK_QUEUE_HANDLE packetQueueLockHandle; TL_INSPECT_PENDED_PACKET* pendedRecvAccept = NULL; TL_INSPECT_PENDED_PACKET* pendedPacket = NULL; ADDRESS_FAMILY addressFamily; FWPS_PACKET_INJECTION_STATE packetState; BOOLEAN signalWorkerThread; UNREFERENCED_PARAMETER(flowContext); UNREFERENCED_PARAMETER(filter); // // We don't have the necessary right to alter the classify, exit. // if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0) { goto Exit; } ASSERT(layerData != NULL); // // We don't re-inspect packets that we've inspected earlier. // packetState = FwpsQueryPacketInjectionState0( gInjectionHandle, layerData, NULL ); if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) || (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF)) { classifyOut->actionType = FWP_ACTION_PERMIT; goto Exit; } addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId); if (!IsAleReauthorize(inFixedValues)) { // // If the classify is the initial authorization for a connection, we // queue it to the pended connection list and notify the worker thread // for out-of-band processing. // pendedRecvAccept = AllocateAndInitializePendedPacket( inFixedValues, inMetaValues, addressFamily, layerData, TL_INSPECT_CONNECT_PACKET, FWP_DIRECTION_INBOUND ); if (pendedRecvAccept == NULL) { classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; goto Exit; } ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_COMPLETION_HANDLE)); // // Pend the ALE_AUTH_RECV_ACCEPT classify. // status = FwpsPendOperation0( inMetaValues->completionHandle, &pendedRecvAccept->completionContext ); if (!NT_SUCCESS(status)) { classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; goto Exit; } KeAcquireInStackQueuedSpinLock( &gConnListLock, &connListLockHandle ); KeAcquireInStackQueuedSpinLock( &gPacketQueueLock, &packetQueueLockHandle ); signalWorkerThread = IsListEmpty(&gConnList) && IsListEmpty(&gPacketQueue); InsertTailList(&gConnList, &pendedRecvAccept->listEntry); pendedRecvAccept = NULL; // ownership transferred KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle); KeReleaseInStackQueuedSpinLock(&connListLockHandle); classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; if (signalWorkerThread) { KeSetEvent( &gWorkerEvent, 0, FALSE ); } } else // re-auth @ ALE_AUTH_RECV_ACCEPT { FWP_DIRECTION packetDirection; // // The classify is the re-authorization for a existing connection, it // could have been triggered for one of the two cases -- // // 1) The re-auth is triggered by an outbound packet sent immediately // after a policy change at ALE_AUTH_RECV_ACCEPT layer. // 2) The re-auth is triggered by an inbound packet received // immediately after a policy change at ALE_AUTH_RECV_ACCEPT layer. // ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_PACKET_DIRECTION)); packetDirection = inMetaValues->packetDirection; pendedPacket = AllocateAndInitializePendedPacket( inFixedValues, inMetaValues, addressFamily, layerData, TL_INSPECT_REAUTH_PACKET, packetDirection ); if (pendedPacket == NULL) { classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; goto Exit; } if (packetDirection == FWP_DIRECTION_INBOUND) { pendedPacket->ipSecProtected = IsSecureConnection(inFixedValues); } KeAcquireInStackQueuedSpinLock( &gConnListLock, &connListLockHandle ); KeAcquireInStackQueuedSpinLock( &gPacketQueueLock, &packetQueueLockHandle ); if (!gDriverUnloading) { signalWorkerThread = IsListEmpty(&gPacketQueue) && IsListEmpty(&gConnList); InsertTailList(&gPacketQueue, &pendedPacket->listEntry); pendedPacket = NULL; // ownership transferred classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; } else { // // Driver is being unloaded, permit any connect classify. // signalWorkerThread = FALSE; classifyOut->actionType = FWP_ACTION_PERMIT; } KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle); KeReleaseInStackQueuedSpinLock(&connListLockHandle); if (signalWorkerThread) { KeSetEvent( &gWorkerEvent, 0, FALSE ); } } Exit: if (pendedPacket != NULL) { FreePendedPacket(pendedPacket); } if (pendedRecvAccept != NULL) { FreePendedPacket(pendedRecvAccept); } return; }
void NTAPI WallALEConnectClassify( IN const FWPS_INCOMING_VALUES* inFixedValues, IN const FWPS_INCOMING_METADATA_VALUES* inMetaValues, IN OUT void* layerData, IN const void* classifyContext, IN const FWPS_FILTER* filter, IN UINT64 flowContext, OUT FWPS_CLASSIFY_OUT* classifyOut ) /*++ 注意:此回调的Irql <= DISPATCH_LEVEL!!!!! --*/ { NTSTATUS status = STATUS_SUCCESS; PWALL_PENDED_PACKET pendedConn = NULL; BOOLEAN bWakeUp = FALSE; ADDRESS_FAMILY addressFamily; UNICODE_STRING devName,dosName; WCHAR buffer[MAX_PATH_LEN]; PMY_UNICODE_STRING logData = NULL; LOG("into\n"); if(!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE)) { KdPrint(("write right not set!\n")); return; } if( layerData != NULL ) { FWPS_PACKET_INJECTION_STATE state; state = FwpsQueryPacketInjectionState( gInjectHandle, layerData, NULL); if( state == FWPS_PACKET_INJECTED_BY_SELF || state == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF ) { classifyOut->actionType = FWP_ACTION_PERMIT; goto exit; } } addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId); if(!IsAleReauthorize(inFixedValues)) { pendedConn = WallAllocateAndInitPendedPacket( inFixedValues, inMetaValues, addressFamily, layerData, WALL_CONNECT_PACKET, FWP_DIRECTION_OUTBOUND ); if(pendedConn == NULL ) { classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; goto exit; } ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_COMPLETION_HANDLE)); status = FwpsPendOperation0( inMetaValues->completionHandle, &pendedConn->completionContext ); if (!NT_SUCCESS(status)) { classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; goto exit; } bWakeUp = IsListEmpty(&gPacketList->list) && IsListEmpty(&gConnList->list); ExInterlockedInsertTailList( &gConnList->list,&pendedConn->list,&gConnList->lock ); pendedConn = NULL; if( bWakeUp ) { RunMyProcess( WallInspectWallPackets,NULL ); } classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; } else {//reauth FWP_DIRECTION packetDirection; KIRQL irql,irql2; LOG("1\n"); ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_PACKET_DIRECTION)); packetDirection = inMetaValues->packetDirection; if (packetDirection == FWP_DIRECTION_OUTBOUND) { LIST_ENTRY* listEntry; BOOLEAN authComplete = FALSE; LOG("2\n"); KeAcquireSpinLock( &gConnList->lock,&irql ); LOG("22\n"); for (listEntry = gConnList->list.Flink; listEntry != (PLIST_ENTRY)gConnList; ) { pendedConn = (PWALL_PENDED_PACKET)listEntry; listEntry = listEntry->Flink; if (IsMatchingConnectPacket( inFixedValues, addressFamily, packetDirection, pendedConn ) && (pendedConn->authConnectDecision != 0)) { ASSERT((pendedConn->authConnectDecision == FWP_ACTION_PERMIT) || (pendedConn->authConnectDecision == FWP_ACTION_BLOCK)); LOG("3\n"); classifyOut->actionType = pendedConn->authConnectDecision; if( classifyOut->actionType == FWP_ACTION_BLOCK ){ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; } RemoveEntryList(&pendedConn->list); if (/*!gDriverUnloading &&*/ (pendedConn->netBufferList != NULL) && (pendedConn->authConnectDecision == FWP_ACTION_PERMIT)) { pendedConn->type = WALL_DATA_PACKET; LOG("4\n"); KeAcquireSpinLock( &gPacketList->lock,&irql2 ); bWakeUp = IsListEmpty(&gPacketList->list) && IsListEmpty(&gConnList->list); InsertTailList(&gPacketList->list, &pendedConn->list); pendedConn = NULL; // ownership transferred KeReleaseSpinLock( &gPacketList->lock,irql2 ); if (bWakeUp) { RunMyProcess( WallInspectWallPackets,NULL ); } }//end if permit authComplete = TRUE; break; }//end if match }//end if for KeReleaseSpinLock( &gConnList->lock,irql ); if (authComplete) { LOG("5\n"); goto exit; } else { pendedConn = NULL; } }//end if outbound classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; } exit: if( pendedConn != NULL ) { LOG("free packet\n"); WallFreePendedPacket( pendedConn ); pendedConn = NULL; } if( classifyOut->actionType == FWP_ACTION_PERMIT ) { RtlInitUnicodeString( &devName,(PWCHAR)inMetaValues->processPath->data ); RtlInitEmptyUnicodeString( &dosName,buffer,MAX_PATH_LEN * sizeof(WCHAR)); logData = MyExAllocatePool( sizeof( MY_UNICODE_STRING) + inMetaValues->processPath->size); if( logData != NULL) { logData->str.Buffer = logData->buffer; logData->str.MaximumLength = (USHORT)inMetaValues->processPath->size; status = DevicePathToDosPath( &devName,&dosName ); if( NT_SUCCESS( status )) { RtlCopyUnicodeString( (PUNICODE_STRING)logData,&dosName ); } else { RtlCopyUnicodeString( (PUNICODE_STRING)logData,&devName ); } KdPrint(("logData:%wZ\n",logData )); RunMyProcess( WallWriteConnectLogData,logData ); logData = NULL; } } return; }
void TLInspectALEConnectClassify( IN const FWPS_INCOMING_VALUES0* inFixedValues, IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues, IN OUT void* layerData, IN const FWPS_FILTER0* filter, IN UINT64 flowContext, OUT FWPS_CLASSIFY_OUT0* classifyOut ) /* ++ This is the classifyFn function for the ALE connect (v4 and v6) callout. For an initial classify (where the FWP_CONDITION_FLAG_IS_REAUTHORIZE flag is not set), it is queued to the connection list for inspection by the worker thread. For re-auth, we first check if it is triggered by an ealier FwpsCompleteOperation0 call by looking for an pended connect that has been inspected. If found, we remove it from the connect list and return the inspection result; otherwise we can conclude that the re-auth is triggered by policy change so we queue it to the packet queue to be process by the worker thread like any other regular packets. -- */ { NTSTATUS status; KLOCK_QUEUE_HANDLE connListLockHandle; KLOCK_QUEUE_HANDLE packetQueueLockHandle; TL_INSPECT_PENDED_PACKET* pendedConnect = NULL; TL_INSPECT_PENDED_PACKET* pendedPacket = NULL; ADDRESS_FAMILY addressFamily; FWPS_PACKET_INJECTION_STATE packetState; BOOLEAN signalWorkerThread; UNREFERENCED_PARAMETER(flowContext); UNREFERENCED_PARAMETER(filter); // // We don't have the necessary right to alter the classify, exit. // if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0) { goto Exit; } if (layerData != NULL) { // // We don't re-inspect packets that we've inspected earlier. // packetState = FwpsQueryPacketInjectionState0( gInjectionHandle, layerData, NULL ); if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) || (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF)) { classifyOut->actionType = FWP_ACTION_PERMIT; goto Exit; } } addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId); if (!IsAleReauthorize(inFixedValues)) { // // If the classify is the initial authorization for a connection, we // queue it to the pended connection list and notify the worker thread // for out-of-band processing. // pendedConnect = AllocateAndInitializePendedPacket( inFixedValues, inMetaValues, addressFamily, layerData, TL_INSPECT_CONNECT_PACKET, FWP_DIRECTION_OUTBOUND ); if (pendedConnect == NULL) { classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; goto Exit; } ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_COMPLETION_HANDLE)); // // Pend the ALE_AUTH_CONNECT classify. // status = FwpsPendOperation0( inMetaValues->completionHandle, &pendedConnect->completionContext ); if (!NT_SUCCESS(status)) { classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; goto Exit; } KeAcquireInStackQueuedSpinLock( &gConnListLock, &connListLockHandle ); KeAcquireInStackQueuedSpinLock( &gPacketQueueLock, &packetQueueLockHandle ); signalWorkerThread = IsListEmpty(&gConnList) && IsListEmpty(&gPacketQueue); InsertTailList(&gConnList, &pendedConnect->listEntry); pendedConnect = NULL; // ownership transferred KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle); KeReleaseInStackQueuedSpinLock(&connListLockHandle); classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; if (signalWorkerThread) { KeSetEvent( &gWorkerEvent, 0, FALSE ); } } else // re-auth @ ALE_AUTH_CONNECT { FWP_DIRECTION packetDirection; // // The classify is the re-authorization for an existing connection, it // could have been triggered for one of the three cases -- // // 1) The re-auth is triggered by a FwpsCompleteOperation0 call to // complete a ALE_AUTH_CONNECT classify pended earlier. // 2) The re-auth is triggered by an outbound packet sent immediately // after a policy change at ALE_AUTH_CONNECT layer. // 3) The re-auth is triggered by an inbound packet received // immediately after a policy change at ALE_AUTH_CONNECT layer. // ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_PACKET_DIRECTION)); packetDirection = inMetaValues->packetDirection; if (packetDirection == FWP_DIRECTION_OUTBOUND) { LIST_ENTRY* listEntry; BOOLEAN authComplete = FALSE; // // We first check whether this is a FwpsCompleteOperation0- triggered // reauth by looking for a pended connect that has the inspection // decision recorded. If found, we return that decision and remove // the pended connect from the list. // KeAcquireInStackQueuedSpinLock( &gConnListLock, &connListLockHandle ); for (listEntry = gConnList.Flink; listEntry != &gConnList; listEntry = listEntry->Flink) { pendedConnect = CONTAINING_RECORD( listEntry, TL_INSPECT_PENDED_PACKET, listEntry ); if (IsMatchingConnectPacket( inFixedValues, addressFamily, packetDirection, pendedConnect ) && (pendedConnect->authConnectDecision != 0)) { ASSERT((pendedConnect->authConnectDecision == FWP_ACTION_PERMIT) || (pendedConnect->authConnectDecision == FWP_ACTION_BLOCK)); classifyOut->actionType = pendedConnect->authConnectDecision; RemoveEntryList(&pendedConnect->listEntry); if (!gDriverUnloading && (pendedConnect->netBufferList != NULL) && (pendedConnect->authConnectDecision == FWP_ACTION_PERMIT)) { // // Now the outbound connection has been authorized. If the // pended connect has a net buffer list in it, we need it // morph it into a data packet and queue it to the packet // queue for send injecition. // pendedConnect->type = TL_INSPECT_DATA_PACKET; KeAcquireInStackQueuedSpinLock( &gPacketQueueLock, &packetQueueLockHandle ); signalWorkerThread = IsListEmpty(&gPacketQueue) && IsListEmpty(&gConnList); InsertTailList(&gPacketQueue, &pendedConnect->listEntry); pendedConnect = NULL; // ownership transferred KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle); if (signalWorkerThread) { KeSetEvent( &gWorkerEvent, 0, FALSE ); } } authComplete = TRUE; break; } } KeReleaseInStackQueuedSpinLock(&connListLockHandle); if (authComplete) { goto Exit; } } // // If we reach here it means this is a policy change triggered re-auth // for an pre-existing connection. For such a packet (inbound or // outbound) we queue it to the packet queue and inspect it just like // other regular data packets from TRANSPORT layers. // ASSERT(layerData != NULL); pendedPacket = AllocateAndInitializePendedPacket( inFixedValues, inMetaValues, addressFamily, layerData, TL_INSPECT_REAUTH_PACKET, packetDirection ); if (pendedPacket == NULL) { classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; goto Exit; } if (packetDirection == FWP_DIRECTION_INBOUND) { pendedPacket->ipSecProtected = IsSecureConnection(inFixedValues); } KeAcquireInStackQueuedSpinLock( &gConnListLock, &connListLockHandle ); KeAcquireInStackQueuedSpinLock( &gPacketQueueLock, &packetQueueLockHandle ); if (!gDriverUnloading) { signalWorkerThread = IsListEmpty(&gPacketQueue) && IsListEmpty(&gConnList); InsertTailList(&gPacketQueue, &pendedPacket->listEntry); pendedPacket = NULL; // ownership transferred classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; } else { // // Driver is being unloaded, permit any connect classify. // signalWorkerThread = FALSE; classifyOut->actionType = FWP_ACTION_PERMIT; } KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle); KeReleaseInStackQueuedSpinLock(&connListLockHandle); if (signalWorkerThread) { KeSetEvent( &gWorkerEvent, 0, FALSE ); } } Exit: if (pendedPacket != NULL) { FreePendedPacket(pendedPacket); } if (pendedConnect != NULL) { FreePendedPacket(pendedConnect); } return; }