Modern (connected) standby modes for Windows on Snapdragon® Platforms
Use cases for modern standby, plus implementation and testing
Implementing and testing modern standby modes for Windows on Snapdragon
Using two Windows driver samples from GitHub and the following instructions, you can implement and test modern standby modes on Snapdragon platforms. The driver samples require modifications for Windows on Snapdragon, which are given below.
You can find more background information at “What is modern standby” in Microsoft documentation.
echosrv — Winsock Kernel (WSK) driver
Microsoft’s Echo sample kernel driver uses Windows Kernel sockets. The driver listens to incoming TCP IPv4/IPv6 requests and echoes the received packets back. The only modification to the GitHub version is the API (PoSetSystemState) to wake up the system from sleep.
- Obtain the driver at https://github.com/microsoft/Windows-driver-samples/tree/master/network/wsk/echosrv.
- Add the following lines to \network\wsk\echosrv\wsksmple.c:
PoSetSystemState(ES_DISPLAY_REQUIRED | ES_USER_PRESENT | ES_SYSTEM_REQUIRED );
// Check if Always on Always connected is supported
POWER_PLATFORM_INFORMATION PlatformInfo = {0};
NTSTATUS Status = ZwPowerInformation(PlatformInformation,
NULL,
0,
&PlatformInfo,
sizeof(PlatformInfo));
if (NT_SUCCESS(Status) && PlatformInfo.AoAc)
{
; // "AoAC is enabled!
}
else
{
; // "AoAC is NOT enabled!
}
ndisprot — NDIS protocol driver
Modifications to this driver support the Wake-On-LAN (WOL) bitmap pattern. They include using OID_PM_ADD_WOL_PATTERN to add a specific bitmap pattern to the network interface card (NIC), and also similar OIDs to query the power management capabilities, query the patterns and remove them if needed. The changes are necessary because when the NIC goes to lower power states (D2/D3), it listens for packets with particular, preconfigured patterns and drops all other packets.
- Obtain the driver at https://github.com/microsoft/Windows-driver-samples/tree/master/network/ndis/ndisprot/6x
- Add the following lines to the switch (FunctionCode) statement in \network\ndis\ndisprot\6x\sys\ntdisp.c:
case IOCTL_NDISPROT_REMOVE_WOL:
NPROT_ASSERT((FunctionCode & 0x3) == METHOD_BUFFERED);
if (pOpenContext != NULL)
{
Status = ndisprotSetOidValue(
pOpenContext,
pIrp->AssociatedIrp.SystemBuffer,
pIrpSp->Parameters.DeviceIoControl.InputBufferLength
);
BytesReturned = 0;
NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
}
else
{
NtStatus = STATUS_DEVICE_NOT_CONNECTED;
}
break;
);
BytesReturned = 0;
NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
}
else
{
NtStatus = STATUS_DEVICE_NOT_CONNECTED;
}
break;
case IOCTL_NDISPROT_ADD_PAT:
PBYTE pBegin;
PBYTE pMask ;
PBYTE pPattern;
ULONG MaskSize = 6;
ULONG PatternSize = 48;
pBegin = (PBYTE)pIrp->AssociatedIrp.SystemBuffer + FIELD_OFFSET(NDISPROT_SET_OID, Data);
PNDIS_PM_WOL_PATTERN NdisPattern;
NdisPattern = (PNDIS_PM_WOL_PATTERN) pBegin;
memset(NdisPattern, 0, sizeof(NDIS_PM_WOL_PATTERN));
NdisPattern->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
NdisPattern->Header.Revision = NDIS_PM_WOL_PATTERN_REVISION_2 ;
NdisPattern->Header.Size = NDIS_SIZEOF_NDIS_PM_WOL_PATTERN_REVISION_2 ;
NdisPattern->Priority = NDIS_PM_WOL_PRIORITY_NORMAL;
NdisPattern->WoLPacketType = NdisPMWoLPacketBitmapPattern;
WCHAR str[] = L"QCPat";
USHORT strLen = 10;
NdisPattern->FriendlyName.Length = strLen;
RtlCopyMemory(NdisPattern->FriendlyName.String, str, strLen);
// Put the mask buffer right after the structure
// The pattern buffer is located after the mask
NdisPattern->NextWoLPatternOffset = 0 ;
NdisPattern->WoLPattern.WoLBitMapPattern.MaskOffset = sizeof(NDIS_PM_WOL_PATTERN);
NdisPattern->WoLPattern.WoLBitMapPattern.PatternOffset = sizeof(NDIS_PM_WOL_PATTERN) + MaskSize;
NdisPattern->WoLPattern.WoLBitMapPattern.MaskSize = MaskSize;
NdisPattern->WoLPattern.WoLBitMapPattern.PatternSize = PatternSize;
// Each bit masks 1 byte in the pattern buffer.
// Here only the last 6 bytes in the pattern are unmasked
pMask = pBegin + sizeof(NDIS_PM_WOL_PATTERN);
memset(pMask , 0, MaskSize);
pMask[5] = 0xfc;
pPattern = pBegin + sizeof(NDIS_PM_WOL_PATTERN) + MaskSize ;
// Ethernet Header: 14 Bytes, IP Header: 20 Bytes, UDP Header : 8 Bytes
// Combined headers: 42 Bytes, so the payload is starting @ offset 42
memset(pPattern, 0, PatternSize);
pPattern[42] = 0x11;
pPattern[43] = 0x20;
pPattern[44] = 0x30;
pPattern[45] = 0x12;
pPattern[46] = 0x40;
pPattern[47] = 0x50;
NPROT_ASSERT((FunctionCode & 0x3) == METHOD_BUFFERED);
if (pOpenContext != NULL)
{
Status = ndisprotSetOidValue(
pOpenContext,
pIrp->AssociatedIrp.SystemBuffer,
pIrpSp->Parameters.DeviceIoControl.InputBufferLength
Installing the drivers
The drivers are not signed. To install them, sign them using a test certificate or testsigning. Be sure to disable driver signature enforcement.
- Install the WSK driver.
sc create echosrv type=kernel binpath=
\echosrv.sy - Download ndisprot630.inf from the following location:https://github.com/Microsoft/Windows-driver-samples/tree/master/network/ndis/ndisprot/6x/sys/630
To install the NDIS protocol driver, go to Network Connections, select an adapter and open Properties. Click Install, then Protocol, then Add, and then Have disk. Then point to the location of the .inf and driver. Select Sample NDIS Protocol Driver.
Starting the drivers
You can choose to enable the drivers automatically by modifying the .inf files, or you can use the following commands:sc start echosrv
net start ndisprot
Adding the WOL pattern
- prottest.exe is located in the same directory as the NDIS driver. In PowerShell, run prottest -e to enumerate device IDs, as shown below.
- To add the WOL bitmap pattern to the NIC, run prottest -a. In the example below, prottest -a adds the bitmap pattern to device ID 3.
prottest with no arguments displays help.
prottest -q queries for any patterns currently specified.
prottest -c returns supported WOL packet types.
At this point, echosrv is listening to TCP packets on port 40007 and the WOL bitmap pattern is set up. When the computer is in sleep mode, a packet that matches the WOL pattern can wake it. - To test, use a PowerShell script to send a WOL packet and a TCP packet from a remote device to the target device while the target device is in sleep (S0 Low Power Idle connected) mode. For example:
Wakeup-Target -IPAddress "fe80::cd1d:936f:fcbf:2fc%12"
Stopping
- Use the following commands to stop the drivers:
sc stop echosrv
net stop ndisprot - Use the following command to uninstall ndisprot from the NIC adapter properties:
sc delete echosrv
Checking and troubleshooting
Modern standby status — Use a remote device to check the modern standby status of a target device.
- Make sure the two devices can communicate; for example, by pinging each other.
- Make sure the target device is in modern (connected) standby. It should not be in S4 (hibernate) or S5 (shutdown) mode.
- Run Get-Service echosrv on the target device to ensure that the WSK driver is running.
- The echosrv driver listens on port 40007. Run the following command on the target device to confirm that there is a listening socket on that port.
Get-NetTCPConnection -LocalPort 40007
prottest.exe — If prottest.exe is not working, you may need to install Visual C++.
Modern standby support — Run the following command to confirm that modern (connected) standby is supported and enabled (S0 Low Power Idle Connected):Powercfg /a
Power states — Run the following command to study system power states:Powercfg /sleepstudy
As shown in the excerpt below, the report reveals the amount of time spent in each mode (Active, Standby, Hibernate, Sleep, etc.) along with the reason for entering and exiting each state.
If you run into any issues or have any questions, please put your information in our Developer Inquiry Form at the bottom of our landing page.
Snapdragon is a product of Qualcomm Technologies, Inc. and/or its subsidiaries.