NTSTATUS NICLinkDetection( PFDO_DATA FdoData ) /*++ Routine Description: Timer function for postponed link negotiation. Called from the NICWatchDogEvtTimerFunc. After the link detection is over we will complete any pending ioctl or send IRPs. Arguments: FdoData Pointer to our FdoData Return Value: NT status --*/ { NTSTATUS status = STATUS_SUCCESS; MEDIA_STATE CurrMediaState; PNDISPROT_QUERY_OID pQuery = NULL; PNDISPROT_SET_OID pSet = NULL; PVOID DataBuffer; ULONG BytesWritten; NDIS_OID Oid; PVOID InformationBuffer; size_t bufSize; WDFREQUEST request; // // Handle the link negotiation. // if (FdoData->bLinkDetectionWait) { status = ScanAndSetupPhy(FdoData); } else { status = PhyDetect(FdoData); } if (status == STATUS_PENDING) { return status; } // // Reset some variables for link detection // FdoData->bLinkDetectionWait = FALSE; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "NICLinkDetection - negotiation done\n"); WdfSpinLockAcquire(FdoData->Lock); MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION); WdfSpinLockRelease(FdoData->Lock); // // Any OID query request pending? // status = NICGetIoctlRequest(FdoData->PendingIoctlQueue, IOCTL_NDISPROT_QUERY_OID_VALUE, &request); if(NT_SUCCESS(status)) { status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_QUERY_OID), &DataBuffer, &bufSize); if(NT_SUCCESS(status)) { pQuery = (PNDISPROT_QUERY_OID)DataBuffer; Oid = pQuery->Oid; InformationBuffer = &pQuery->Data[0]; switch(Oid) { case OID_GEN_LINK_SPEED: *((PULONG)InformationBuffer) = FdoData->usLinkSpeed * 10000; BytesWritten = sizeof(ULONG); break; case OID_GEN_MEDIA_CONNECT_STATUS: default: ASSERT(Oid == OID_GEN_MEDIA_CONNECT_STATUS); CurrMediaState = NICIndicateMediaState(FdoData); RtlMoveMemory(InformationBuffer, &CurrMediaState, sizeof(NDIS_MEDIA_STATE)); BytesWritten = sizeof(NDIS_MEDIA_STATE); } WdfRequestCompleteWithInformation(request, status, BytesWritten); } } // // Any OID set request pending? // status = NICGetIoctlRequest(FdoData->PendingIoctlQueue, IOCTL_NDISPROT_SET_OID_VALUE, &request); if(NT_SUCCESS(status)) { ULONG PacketFilter; status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_SET_OID), &DataBuffer, &bufSize); if(NT_SUCCESS(status)) { pSet = (PNDISPROT_SET_OID)DataBuffer; Oid = pSet->Oid; InformationBuffer = &pSet->Data[0]; if (Oid == OID_GEN_CURRENT_PACKET_FILTER) { RtlMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG)); WdfSpinLockAcquire(FdoData->Lock); status = NICSetPacketFilter( FdoData, PacketFilter); WdfSpinLockRelease(FdoData->Lock); if (status == STATUS_SUCCESS) { FdoData->PacketFilter = PacketFilter; } WdfRequestCompleteWithInformation(request, status, 0); } } } // // Any read pending? // WdfSpinLockAcquire(FdoData->RcvLock); // // Start the NIC receive unit // status = NICStartRecv(FdoData); if (status != STATUS_SUCCESS) { MP_SET_HARDWARE_ERROR(FdoData); } WdfSpinLockRelease(FdoData->RcvLock); // // Send packets which have been queued while link detection was going on. // NICCheckForQueuedSends(FdoData); return status; }
NTSTATUS NICHandleSetOidRequest( __in PFDO_DATA FdoData, __in PIRP Irp ) /*++ Routine Description: This routine handles ioctl request for Set OIDs. Most of the IOCTL requests are only if the upper edge is NDIS. Arguments: Return Value: --*/ { NTSTATUS status = STATUS_SUCCESS; PNDISPROT_SET_OID pSet; NDIS_OID Oid; ULONG PacketFilter; PVOID InformationBuffer = NULL; ULONG InformationBufferLength = 0; KIRQL oldIrql; PVOID DataBuffer; ULONG BufferLength, unUsed; PIO_STACK_LOCATION pIrpSp; DEVICE_POWER_STATE newDeviceState, oldDeviceState; pIrpSp = IoGetCurrentIrpStackLocation(Irp); DataBuffer = Irp->AssociatedIrp.SystemBuffer; BufferLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength; DebugPrint(LOUD, DBG_IOCTLS, "--> HandleSetOIDRequest\n"); Oid = 0; do { if (BufferLength < sizeof(NDISPROT_SET_OID)) { status = STATUS_BUFFER_OVERFLOW; break; } pSet = (PNDISPROT_SET_OID)DataBuffer; Oid = pSet->Oid; InformationBuffer = &pSet->Data[0]; InformationBufferLength = BufferLength - FIELD_OFFSET(NDISPROT_SET_OID, Data); switch(Oid) { case OID_802_3_MULTICAST_LIST: // // Verify the length // if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) { return(STATUS_INVALID_BUFFER_SIZE); } // // Save the number of MC list size // FdoData->MCAddressCount = InformationBufferLength / ETH_LENGTH_OF_ADDRESS; ASSERT(FdoData->MCAddressCount <= NIC_MAX_MCAST_LIST); InformationBufferLength = InformationBufferLength > sizeof(FdoData->MCList) ? sizeof(FdoData->MCList):InformationBufferLength; // // Save the MC list // RtlMoveMemory( FdoData->MCList, InformationBuffer, InformationBufferLength); KeAcquireSpinLock(&FdoData->Lock, &oldIrql); KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock); status = NICSetMulticastList(FdoData); KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock); KeReleaseSpinLock(&FdoData->Lock, oldIrql); break; case OID_GEN_CURRENT_PACKET_FILTER: // // Verify the Length // if (InformationBufferLength != sizeof(ULONG)) { return(STATUS_INVALID_BUFFER_SIZE); } RtlMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG)); // // any bits not supported? // if (PacketFilter & ~NIC_SUPPORTED_FILTERS) { return(STATUS_NOT_SUPPORTED); } // // any filtering changes? // if (PacketFilter == FdoData->PacketFilter) { break; } KeAcquireSpinLock(&FdoData->Lock, &oldIrql); KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock); if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION)) { // // The device is busy doing link detection. Let us queue // the IRP. When the link detection is over, the watchdog // timer DPC will complete this IRP. // ASSERT(!FdoData->SetRequest); status = PciDrvQueueIoctlIrp(FdoData, Irp); KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock); KeReleaseSpinLock(&FdoData->Lock, oldIrql); break; } status = NICSetPacketFilter( FdoData, PacketFilter); KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock); KeReleaseSpinLock(&FdoData->Lock, oldIrql); if (status == STATUS_SUCCESS) { FdoData->PacketFilter = PacketFilter; } break; case OID_PNP_SET_POWER: if (InformationBufferLength != sizeof(NDIS_DEVICE_POWER_STATE )) { return(STATUS_BUFFER_TOO_SMALL); } newDeviceState = *(PDEVICE_POWER_STATE UNALIGNED)InformationBuffer; oldDeviceState = FdoData->DevicePowerState; FdoData->DevicePowerState = newDeviceState; if (oldDeviceState == PowerDeviceD0) { status = PciDrvPowerBeginQueuingIrps( FdoData->Self, 1, // One for current OID request. FALSE // Do not query for state change. ); ASSERT(NT_SUCCESS(status)); } // // Set the power state - Cannot fail this request // status = NICSetPower(FdoData, newDeviceState ); if (status != STATUS_SUCCESS) { DebugPrint(ERROR, DBG_IOCTLS, "SET Power: Hardware error !!!\n"); break; } if (newDeviceState == PowerDeviceD0) { // // Our hardware is now on again. Here we empty our existing queue of // requests and let in new ones. // FdoData->QueueState = AllowRequests; PciDrvProcessQueuedRequests(FdoData); } status = STATUS_SUCCESS; break; case OID_PNP_ADD_WAKE_UP_PATTERN: // // call a function that would program the adapter's wake // up pattern, return success // DebugPrint(TRACE, DBG_IOCTLS, "--> OID_PNP_ADD_WAKE_UP_PATTERN\n"); if (IsPoMgmtSupported(FdoData) ) { status = NICAddWakeUpPattern(FdoData, InformationBuffer, InformationBufferLength, &unUsed, &unUsed); } else { status = STATUS_NOT_SUPPORTED; } break; case OID_PNP_REMOVE_WAKE_UP_PATTERN: // // call a function that would remove the adapter's wake // up pattern, return success // DebugPrint(TRACE, DBG_IOCTLS, "--> OID_PNP_ADD_WAKE_UP_PATTERN\n"); if (IsPoMgmtSupported(FdoData) ) { status = NICRemoveWakeUpPattern(FdoData, InformationBuffer, InformationBufferLength, &unUsed, &unUsed); } else { status = STATUS_NOT_SUPPORTED; } break; case OID_PNP_ENABLE_WAKE_UP: // // call a function that would enable wake up on the adapter // return success // DebugPrint(TRACE, DBG_IOCTLS, "--> OID_PNP_ENABLE_WAKE_UP\n"); if (IsPoMgmtSupported(FdoData)) { ULONG WakeUpEnable; RtlMoveMemory(&WakeUpEnable, InformationBuffer,sizeof(ULONG)); // // The WakeUpEable can only be 0, or NDIS_PNP_WAKE_UP_PATTERN_MATCH since the driver only // supports wake up pattern match // if ((WakeUpEnable != 0) && ((WakeUpEnable & NDIS_PNP_WAKE_UP_PATTERN_MATCH) != NDIS_PNP_WAKE_UP_PATTERN_MATCH )) { status = STATUS_NOT_SUPPORTED; FdoData->AllowWakeArming = FALSE; break; } // // When the driver goes to low power state, it would check WakeUpEnable to decide // which wake up methed it should use to wake up the machine. If WakeUpEnable is 0, // no wake up method is enabled. // FdoData->AllowWakeArming = TRUE; status = STATUS_SUCCESS; } else { status = STATUS_NOT_SUPPORTED; } break; default: status = STATUS_NOT_SUPPORTED; break; } }while (FALSE); DebugPrint(LOUD, DBG_IOCTLS, "<-- HandleSetOIDRequest\n"); return (status); }
NTSTATUS MPSetPowerD0( PFDO_DATA FdoData ) /*++ Routine Description: This routine is called when the adapter receives a SetPower to D0. Arguments: Adapter Pointer to the adapter structure PowerState NewPowerState Return Value: --*/ { NTSTATUS status; //KIRQL oldIrql; // // MPSetPowerD0Private Initializes the adapte, issues a selective reset. // MPSetPowerD0Private (FdoData); ASSERT(FdoData->DevicePowerState == PowerDeviceD0); // // Set up the packet filter // WdfSpinLockAcquire(FdoData->Lock); status = NICSetPacketFilter( FdoData, FdoData->OldPacketFilter); // // If Set Packet Filter succeeds, restore the old packet filter // if (status == STATUS_SUCCESS) { FdoData->PacketFilter = FdoData->OldPacketFilter; } WdfSpinLockRelease(FdoData->Lock); // // Set up the multicast list address // WdfSpinLockAcquire(FdoData->RcvLock); status = NICSetMulticastList(FdoData); NICStartRecv(FdoData); WdfSpinLockRelease(FdoData->RcvLock); return status; }