summaryrefslogtreecommitdiff
path: root/network/wlan/wificx/drivercode
diff options
context:
space:
mode:
authorYang You (UU) <[email protected]>2026-06-17 10:33:03 -0700
committerYang You (UU) <[email protected]>2026-06-17 10:33:03 -0700
commit4c89b2cd0cf2e94bc2e933e9ccf7d35c7b26a140 (patch)
tree6e8201e56ede0e2c92489b1c7ce0230c90329295 /network/wlan/wificx/drivercode
parent52f73736b407acb1f8a0af513c9614a5354cea5b (diff)
check in the demo for OEM solution based on Service Command channel.
Diffstat (limited to 'network/wlan/wificx/drivercode')
-rw-r--r--network/wlan/wificx/drivercode/SharedTypes.h17
-rw-r--r--network/wlan/wificx/drivercode/wifihal.cpp134
-rw-r--r--network/wlan/wificx/drivercode/wifihal.h15
-rw-r--r--network/wlan/wificx/drivercode/wifirequest.cpp2
-rw-r--r--network/wlan/wificx/drivercode/wifitransition.cpp128
-rw-r--r--network/wlan/wificx/drivercode/wifitransition.h2
6 files changed, 295 insertions, 3 deletions
diff --git a/network/wlan/wificx/drivercode/SharedTypes.h b/network/wlan/wificx/drivercode/SharedTypes.h
index 43fd815a..e454378b 100644
--- a/network/wlan/wificx/drivercode/SharedTypes.h
+++ b/network/wlan/wificx/drivercode/SharedTypes.h
@@ -13,4 +13,19 @@
// =============================
// {bb67559a-06f6-4eb0-81e9-21fdc3b60efb}
DEFINE_GUID(GUID_WIFICX_SAMPLE_CLIENT_INTERFACE, 0xbb67559a, 0x06f6, 0x4eb0, 0x81, 0xe9, 0x21, 0xfd, 0xc3, 0xb6, 0x0e, 0xfb);
-#define WIFI_DRIVER_DEFAULT_POOL_TAG 'shiW' // WIFI IHV Sample Driver \ No newline at end of file
+#define WIFI_DRIVER_DEFAULT_POOL_TAG 'shiW' // WIFI IHV Sample Driver
+
+// =============================
+// OEM Device Service contract
+// =============================
+// This GUID/opcode pair MUST match the OEM user-mode app (OEM\OemDeviceService.cpp).
+// {2d6f9a14-3a1d-4f0a-9b7e-1c2e3a4b5c6d}
+DEFINE_GUID(GUID_OEM_SAMPLE_DEVICE_SERVICE,
+ 0x2d6f9a14, 0x3a1d, 0x4f0a, 0x9b, 0x7e, 0x1c, 0x2e, 0x3a, 0x4b, 0x5c, 0x6d);
+
+// Opcode understood by the driver for the "hello / nice to meet you" exchange.
+#define OEM_DEVICE_SERVICE_OPCODE_HELLO 0x00000001
+
+// Payload strings exchanged with the OEM app.
+#define OEM_DEVICE_SERVICE_REQUEST_STRING "Hello, My Driver"
+#define OEM_DEVICE_SERVICE_RESPONSE_STRING "Nice to meet you, My OEM" \ No newline at end of file
diff --git a/network/wlan/wificx/drivercode/wifihal.cpp b/network/wlan/wificx/drivercode/wifihal.cpp
index fead61b3..e7aaec1f 100644
--- a/network/wlan/wificx/drivercode/wifihal.cpp
+++ b/network/wlan/wificx/drivercode/wifihal.cpp
@@ -982,3 +982,137 @@ NTSTATUS WifiHAL::WifiIhvDisconnect(const WDI_TASK_DISCONNECT_PARAMETERS&, const
return STATUS_SUCCESS;
}
+
+// -------- WDI_GET_SUPPORTED_DEVICE_SERVICES (OID_WDI_GET_SUPPORTED_DEVICES) --------
+// Property GET: the request has no input (Inputs is empty). Builds the
+// WDI_TLV_DEVICE_SERVICE_GUID_LIST result advertising GUID_OEM_SAMPLE_DEVICE_SERVICE and
+// serializes it via the generated TLV generator, so the OS learns which device services
+// this driver supports.
+// OutBuffer receives the full WDI message (header + TLVs); BytesWritten = total length.
+_Use_decl_annotations_
+NTSTATUS WifiHAL::WifiIhvGetSupportedDeviceServices(const WDI_GET_SUPPORTED_DEVICE_SERVICES_INPUTS& Inputs, void* OutBuffer, ULONG OutBufferLen, ULONG& BytesWritten)
+{
+ UNREFERENCED_PARAMETER(Inputs); // GET request carries no input data
+
+ BytesWritten = sizeof(WDI_MESSAGE_HEADER);
+
+ if (OutBuffer == nullptr || OutBufferLen < sizeof(WDI_MESSAGE_HEADER))
+ {
+ WFCError("GetSupportedDeviceServices: invalid out buffer (OutBufferLen=%u)", OutBufferLen);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // WDI_TLV_DEVICE_SERVICE_GUID_LIST: a list containing our single device service GUID.
+ // WDI_GUID_LIST_CONTAINER is ArrayOfElements<GUID>; SimpleAssign points it at our
+ // stack array (the generator copies the data while serializing the TLV).
+ GUID supportedServices[] = { GUID_OEM_SAMPLE_DEVICE_SERVICE };
+
+ WDI_GET_SUPPORTED_DEVICE_SERVICES_PARAMETERS results{};
+ results.DeviceServiceGUIDList.SimpleAssign(supportedServices, ARRAYSIZE(supportedServices));
+
+ // Generate the TLV byte stream. ReservedHeaderLength reserves room for the
+ // WDI_MESSAGE_HEADER at the front of the produced buffer.
+ ULONG generatedLength = 0;
+ UINT8* pGenerated = nullptr;
+
+ NDIS_STATUS genStatus = GenerateWdiGetSupportedDeviceServices(
+ &results, sizeof(WDI_MESSAGE_HEADER), m_TlvContext, &generatedLength, &pGenerated);
+
+ NTSTATUS ntStatus = Wifi::ConvertNDISSTATUSToNTSTATUS(genStatus);
+ if (!NT_SUCCESS(ntStatus) || pGenerated == nullptr)
+ {
+ WFCError("GetSupportedDeviceServices: Generate failed, status=%!STATUS!", ntStatus);
+ return ntStatus;
+ }
+
+ if (OutBufferLen < generatedLength)
+ {
+ WFCError("GetSupportedDeviceServices: out buffer too small (have=%u need=%u)",
+ OutBufferLen, generatedLength);
+ FreeGenerated(pGenerated);
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ RtlCopyMemory(OutBuffer, pGenerated, generatedLength);
+ BytesWritten = generatedLength;
+ FreeGenerated(pGenerated);
+
+ WFCInfo("GetSupportedDeviceServices: advertised %u device service(s), %u bytes",
+ ARRAYSIZE(supportedServices), BytesWritten);
+ return STATUS_SUCCESS;
+}
+
+// -------- OEM Device Service Command (OID_WDI_DEVICE_SERVICE_COMMAND) --------
+// Reads the request data blob (WDI_TLV_DEVICE_SERVICE_PARAMS_DATA_BLOB) parsed into
+// Inputs.Params, expects "Hello, My Driver", and returns "Nice to meet you, My OEM"
+// as the response data blob, serialized via the generated TLV generator.
+// OutBuffer receives the full WDI message (header + TLVs); BytesWritten = total length.
+_Use_decl_annotations_
+NTSTATUS WifiHAL::WifiIhvDeviceServiceCommand(const WDI_DEVICE_SERVICE_COMMAND_INPUTS& Inputs, void* OutBuffer, ULONG OutBufferLen, ULONG& BytesWritten)
+{
+ BytesWritten = sizeof(WDI_MESSAGE_HEADER);
+
+ if (OutBuffer == nullptr || OutBufferLen < sizeof(WDI_MESSAGE_HEADER))
+ {
+ WFCError("OEM device service: invalid out buffer (OutBufferLen=%u)", OutBufferLen);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Log the request data blob ("Hello, My Driver"), if present.
+ if (Inputs.Optional.Params_IsPresent &&
+ Inputs.Params.ElementCount > 0 &&
+ Inputs.Params.pElements[0].ElementCount > 0 &&
+ Inputs.Params.pElements[0].pElements != nullptr)
+ {
+ WFCInfo("OEM device service: opcode=0x%08X, received %u-byte data blob: %hs",
+ Inputs.Opcode,
+ Inputs.Params.pElements[0].ElementCount,
+ reinterpret_cast<const char*>(Inputs.Params.pElements[0].pElements));
+ }
+ else
+ {
+ WFCInfo("OEM device service: opcode=0x%08X, no input data blob", Inputs.Opcode);
+ }
+
+ // Build the response data blob ("Nice to meet you, My OEM"), including the null terminator.
+ // SimpleAssign points the blob at this buffer (no copy); the generator copies the bytes
+ // while serializing, and the buffer outlives that call.
+ UINT8 responseBytes[] = OEM_DEVICE_SERVICE_RESPONSE_STRING;
+
+ WDI_BYTE_BLOB responseBlob{};
+ responseBlob.SimpleAssign(responseBytes, static_cast<UINT32>(sizeof(responseBytes)));
+
+ WDI_DEVICE_SERVICE_COMMAND_PARAMETERS params{};
+ params.Optional.Params_IsPresent = TRUE;
+ params.Params.SimpleAssign(&responseBlob, 1);
+
+ // Serialize WDI_TLV_DEVICE_SERVICE_PARAMS_DATA_BLOB into the response message.
+ ULONG generatedLength = 0;
+ UINT8* pGenerated = nullptr;
+
+ NDIS_STATUS genStatus = GenerateWdiDeviceServiceCommand(
+ &params, sizeof(WDI_MESSAGE_HEADER), m_TlvContext, &generatedLength, &pGenerated);
+
+ NTSTATUS ntStatus = Wifi::ConvertNDISSTATUSToNTSTATUS(genStatus);
+ if (!NT_SUCCESS(ntStatus) || pGenerated == nullptr)
+ {
+ WFCError("OEM device service: Generate failed, status=%!STATUS!", ntStatus);
+ return ntStatus;
+ }
+
+ if (OutBufferLen < generatedLength)
+ {
+ WFCError("OEM device service: out buffer too small (have=%u need=%u)",
+ OutBufferLen, generatedLength);
+ FreeGenerated(pGenerated);
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ RtlCopyMemory(OutBuffer, pGenerated, generatedLength);
+ BytesWritten = generatedLength;
+ FreeGenerated(pGenerated);
+
+ WFCInfo("OEM device service: responded with \"%hs\" (%u bytes)",
+ reinterpret_cast<const char*>(responseBytes), BytesWritten);
+ return STATUS_SUCCESS;
+}
diff --git a/network/wlan/wificx/drivercode/wifihal.h b/network/wlan/wificx/drivercode/wifihal.h
index 38e1166a..f776f425 100644
--- a/network/wlan/wificx/drivercode/wifihal.h
+++ b/network/wlan/wificx/drivercode/wifihal.h
@@ -28,6 +28,21 @@ public:
NTSTATUS WifiIhvConnect(_In_ const WDI_TASK_CONNECT_PARAMETERS& ConnectParameters, _In_ const PWDI_MESSAGE_HEADER pWdiHeader, _In_ UINT BytesWritten);
NTSTATUS WifiIhvSetSaeAuthParams(_In_ const WDI_SET_SAE_AUTH_PARAMS_COMMAND& setSAEAuthParams, _In_ const PWDI_MESSAGE_HEADER pWdiHeader, _In_ UINT BytesWritten);
NTSTATUS WifiIhvDisconnect(_In_ const WDI_TASK_DISCONNECT_PARAMETERS& disconnectParameters, _In_ const PWDI_MESSAGE_HEADER pWdiHeader, _In_ UINT BytesWritten);
+
+ // Device service property handlers (OID_WDI_GET_SUPPORTED_DEVICES / OID_WDI_DEVICE_SERVICE_COMMAND).
+ // Match the PropertyTransitionTraits handler shape: (const parsed input&, out-buffer,
+ // out-buffer length, bytesWritten&). The handler serializes the response TLV stream into
+ // OutBuffer and reports the number of bytes written; the dispatch layer completes the request.
+ NTSTATUS WifiIhvGetSupportedDeviceServices(
+ _In_ const WDI_GET_SUPPORTED_DEVICE_SERVICES_INPUTS& Inputs,
+ _Out_writes_bytes_to_(OutBufferLen, BytesWritten) void* OutBuffer,
+ _In_ ULONG OutBufferLen,
+ _Out_ ULONG& BytesWritten);
+ NTSTATUS WifiIhvDeviceServiceCommand(
+ _In_ const WDI_DEVICE_SERVICE_COMMAND_INPUTS& Inputs,
+ _Out_writes_bytes_to_(OutBufferLen, BytesWritten) void* OutBuffer,
+ _In_ ULONG OutBufferLen,
+ _Out_ ULONG& BytesWritten);
private:
NTSTATUS WifiIhvPerformAssociation(_In_ const struct ArrayOfElements<WDI_CONNECT_BSS_ENTRY_CONTAINER>* pPreferredBSSEntryList, _In_ const struct ArrayOfElements<WDI_AUTH_ALGORITHM>* pAuthenticationAlgorithms, _In_ const PWDI_MESSAGE_HEADER pWdiHeader);
NTSTATUS WifiIhvSendLinkStateIndication(_In_ const PWDI_MESSAGE_HEADER pWdiHeader, ULONG numLinks);
diff --git a/network/wlan/wificx/drivercode/wifirequest.cpp b/network/wlan/wificx/drivercode/wifirequest.cpp
index fd02bd91..c84c1d97 100644
--- a/network/wlan/wificx/drivercode/wifirequest.cpp
+++ b/network/wlan/wificx/drivercode/wifirequest.cpp
@@ -95,4 +95,4 @@ _Use_decl_annotations_
void WifiIhvSendM4IndicationToOs(WDFDEVICE Device, UINT16 WifiRequestMessageId, const PWDI_MESSAGE_HEADER pWdiHeader, NTSTATUS WifiRequestM4Status)
{
WifiIhvSendIndicationToOs(Device, pWdiHeader, WifiRequestMessageId, pWdiHeader->TransactionId, WifiRequestM4Status, nullptr, 0);
-} \ No newline at end of file
+}
diff --git a/network/wlan/wificx/drivercode/wifitransition.cpp b/network/wlan/wificx/drivercode/wifitransition.cpp
index 41106932..2e1b7ef2 100644
--- a/network/wlan/wificx/drivercode/wifitransition.cpp
+++ b/network/wlan/wificx/drivercode/wifitransition.cpp
@@ -192,6 +192,98 @@ NTSTATUS RunTransition(TransitionContext& ctx)
return m4Status;
}
+// ============================================================================
+// Property GET/SET messages (single M3 completion)
+// ----------------------------------------------------------------------------
+// Unlike the M3/M4 task flow above, a property GET/SET is a single M3 step that
+// returns its result synchronously in the request's in/out buffer. The HAL
+// handler writes the response TLV stream and reports the real number of bytes
+// written (by reference); the request is completed (M3) with that length.
+// No M4 indication.
+// ============================================================================
+template<
+ UINT16 TMsgId,
+ typename TParam,
+ bool TDumpTlvStream,
+ NDIS_STATUS (*TParseFn)(ULONG, const UINT8*, PCTLV_CONTEXT, TParam*),
+ void (*TCleanupFn)(TParam*),
+ NTSTATUS (WifiHAL::*TPreFn)(), // optional pre-check hook (may be nullptr)
+ NTSTATUS (WifiHAL::*TPropertyFn)(const TParam&, void*, ULONG, ULONG&) // mandatory property HAL handler
+>
+struct PropertyM3Traits
+{
+ using ParamType = TParam;
+
+ NTSTATUS Parse(TransitionContext& ctx, ParamType& p)
+ {
+ if (ctx.InLen < sizeof(WDI_MESSAGE_HEADER))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ auto* tlvBytes = static_cast<UCHAR*>(ctx.RawBuffer) + sizeof(WDI_MESSAGE_HEADER);
+ auto tlvLen = static_cast<ULONG>(ctx.InLen - sizeof(WDI_MESSAGE_HEADER));
+
+ if (TDumpTlvStream)
+ {
+ DumpMessageTlvByteStream(TMsgId, TRUE, ctx.DevCtx->TlvContext.PeerVersion, tlvLen, tlvBytes, 0, nullptr);
+ }
+
+ auto ndisStatus = TParseFn(tlvLen, tlvBytes, &ctx.DevCtx->TlvContext, &p);
+ return Wifi::ConvertNDISSTATUSToNTSTATUS(ndisStatus);
+ }
+
+ void Cleanup(ParamType& p) { TCleanupFn(&p); }
+
+ // Runs the optional pre-check then the property handler. The handler writes the
+ // out-buffer and reports the number of bytes written.
+ NTSTATUS Handle(TransitionContext& ctx, ParamType& p, ULONG& bytesWritten)
+ {
+ bytesWritten = sizeof(WDI_MESSAGE_HEADER);
+
+ WifiHAL* hal = GetWifiHalFromHandle(ctx.Device);
+
+ if (TPreFn)
+ {
+ NTSTATUS preStatus = (hal->*TPreFn)();
+ if (!NT_SUCCESS(preStatus))
+ {
+ return preStatus;
+ }
+ }
+
+ return (hal->*TPropertyFn)(p, ctx.RawBuffer, ctx.OutLen, bytesWritten);
+ }
+};
+
+// Primary traits template for property GET/SET messages (specialize per MessageId)
+template<UINT16 MsgId>
+struct PropertyTraits;
+
+// Generic runner for property GET/SET messages: parse -> handle -> complete (M3).
+// Completes the request synchronously with the number of bytes the HAL wrote.
+template<UINT16 MsgId>
+NTSTATUS RunPropertyM3(TransitionContext& ctx)
+{
+ PropertyTraits<MsgId> traits;
+ typename PropertyTraits<MsgId>::ParamType params{};
+
+ NTSTATUS status = traits.Parse(ctx, params);
+ if (!NT_SUCCESS(status))
+ {
+ traits.Cleanup(params);
+ WifiRequestComplete(ctx.WifiRequest, status, sizeof(WDI_MESSAGE_HEADER));
+ return status;
+ }
+
+ ULONG bytesWritten = sizeof(WDI_MESSAGE_HEADER);
+ status = traits.Handle(ctx, params, bytesWritten);
+
+ traits.Cleanup(params);
+ WifiRequestComplete(ctx.WifiRequest, status, bytesWritten);
+ return status;
+}
+
//// -------- SCENARIO: [Connect with a SAE WI-FI7 network --------
/// Demo: Handle WDI_TASK_CONNECT + WDI_SET_SAE_AUTH_PARAMS then WDI_TASK_DISCONNECT
/// Scope:
@@ -313,6 +405,38 @@ struct TransitionTraits<WDI_TASK_SET_RADIO_STATE>
{
};
+// -------- WDI_GET_SUPPORTED_DEVICE_SERVICES (property GET) --------
+// Request body is empty (header sufficient); the HAL produces the
+// WDI_TLV_DEVICE_SERVICE_GUID_LIST result into the out-buffer.
+template<>
+struct PropertyTraits<WDI_GET_SUPPORTED_DEVICE_SERVICES>
+ : PropertyM3Traits<
+ WDI_GET_SUPPORTED_DEVICE_SERVICES,
+ WDI_GET_SUPPORTED_DEVICE_SERVICES_INPUTS,
+ true, // dump TLV stream
+ ParseWdiGetSupportedDeviceServices,
+ CleanupParsedWdiGetSupportedDeviceServices,
+ &WifiHAL::WifiIhvIsDeviceReadyForRequest, // pre-check
+ &WifiHAL::WifiIhvGetSupportedDeviceServices // property handler
+ >
+{};
+
+// -------- WDI_DEVICE_SERVICE_COMMAND (property SET/GET) --------
+// Reads the request data blob (WDI_TLV_DEVICE_SERVICE_PARAMS_*) and the HAL writes
+// the response data blob into the out-buffer.
+template<>
+struct PropertyTraits<WDI_DEVICE_SERVICE_COMMAND>
+ : PropertyM3Traits<
+ WDI_DEVICE_SERVICE_COMMAND,
+ WDI_DEVICE_SERVICE_COMMAND_INPUTS,
+ true, // dump TLV stream
+ ParseWdiDeviceServiceCommand,
+ CleanupParsedWdiDeviceServiceCommand,
+ &WifiHAL::WifiIhvIsDeviceReadyForRequest, // pre-check
+ &WifiHAL::WifiIhvDeviceServiceCommand // property handler
+ >
+{};
+
// Runtime dispatcher switches on MessageId and invokes the matching compile-time runner.
NTSTATUS RunTransitionByMessage(TransitionContext& ctx, UINT16 messageId)
{
@@ -330,6 +454,10 @@ NTSTATUS RunTransitionByMessage(TransitionContext& ctx, UINT16 messageId)
return RunTransition<WDI_TASK_DISCONNECT>(ctx);
case WDI_SET_SAE_AUTH_PARAMS:
return RunTransition<WDI_SET_SAE_AUTH_PARAMS>(ctx);
+ case WDI_GET_SUPPORTED_DEVICE_SERVICES:
+ return RunPropertyM3<WDI_GET_SUPPORTED_DEVICE_SERVICES>(ctx);
+ case WDI_DEVICE_SERVICE_COMMAND:
+ return RunPropertyM3<WDI_DEVICE_SERVICE_COMMAND>(ctx);
default:
UINT bytesWritten = sizeof(WDI_MESSAGE_HEADER);
WifiRequestComplete(ctx.WifiRequest, STATUS_NOT_SUPPORTED, bytesWritten);
diff --git a/network/wlan/wificx/drivercode/wifitransition.h b/network/wlan/wificx/drivercode/wifitransition.h
index a0addf88..c48d4a78 100644
--- a/network/wlan/wificx/drivercode/wifitransition.h
+++ b/network/wlan/wificx/drivercode/wifitransition.h
@@ -11,7 +11,7 @@ struct TransitionContext
PWIFI_IHV_DEVICE_CONTEXT DevCtx;
WIFIREQUEST WifiRequest;
PWDI_MESSAGE_HEADER Header;
- void* RawBuffer;
+ void* RawBuffer; // from WifiRequestGetInOutBuffer in EvtWifiDeviceSendCommand
UINT InLen;
UINT OutLen;
};