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 NICConfigureForWakeUp( IN PFDO_DATA FdoData, IN BOOLEAN AddPattern ) /*++ Routine Description: Arguments: FdoData FdoData structure Return Value: Success - if successful. --*/ { #define MAX_WAKEUP_PATTERN_LENGTH 128 UCHAR Buffer[sizeof(NDIS_PM_PACKET_PATTERN) + MAX_WAKEUP_PATTERN_LENGTH]; PCHAR patternBuffer, nextMask, nextPattern; ULONG maskLen; PNDIS_PM_PACKET_PATTERN ndisPattern; ULONG bufLen; NTSTATUS status; ULONG unUsed; CHAR wakePattern[]={0xff,0xff,0xff,0xff,0xff,0xff}; //broadcast address patternBuffer = (PCHAR)&Buffer[0]; ndisPattern = (PNDIS_PM_PACKET_PATTERN)patternBuffer; RtlZeroMemory(ndisPattern, sizeof(NDIS_PM_PACKET_PATTERN)); ndisPattern->PatternSize = sizeof(wakePattern); maskLen = (ndisPattern->PatternSize-1)/8 + 1; nextMask = (PCHAR)patternBuffer + sizeof(NDIS_PM_PACKET_PATTERN); nextPattern = nextMask + maskLen; *nextMask = 0x3f; ndisPattern->MaskSize = maskLen; ndisPattern->PatternOffset = (ULONG) ((ULONG_PTR) nextPattern - (ULONG_PTR) patternBuffer); bufLen = sizeof(NDIS_PM_PACKET_PATTERN) + maskLen + ndisPattern->PatternSize; RtlCopyMemory(nextPattern, FdoData->CurrentAddress, ETHERNET_ADDRESS_LENGTH); if(AddPattern){ status = NICAddWakeUpPattern(FdoData, Buffer, bufLen, &unUsed, &unUsed); if(!NT_SUCCESS(status)){ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "NICAddWakeupPattern failed %x\n", status); } }else{ status = NICRemoveWakeUpPattern(FdoData, Buffer, bufLen, &unUsed, &unUsed); if(!NT_SUCCESS(status)){ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "NICRemoveWakeUpPattern failed %x\n", status); } } return status; }