diff options
| author | Yang You (UU) <[email protected]> | 2026-06-17 10:33:03 -0700 |
|---|---|---|
| committer | Yang You (UU) <[email protected]> | 2026-06-17 10:33:03 -0700 |
| commit | 4c89b2cd0cf2e94bc2e933e9ccf7d35c7b26a140 (patch) | |
| tree | 6e8201e56ede0e2c92489b1c7ce0230c90329295 /network/wlan/wificx/drivercode | |
| parent | 52f73736b407acb1f8a0af513c9614a5354cea5b (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.h | 17 | ||||
| -rw-r--r-- | network/wlan/wificx/drivercode/wifihal.cpp | 134 | ||||
| -rw-r--r-- | network/wlan/wificx/drivercode/wifihal.h | 15 | ||||
| -rw-r--r-- | network/wlan/wificx/drivercode/wifirequest.cpp | 2 | ||||
| -rw-r--r-- | network/wlan/wificx/drivercode/wifitransition.cpp | 128 | ||||
| -rw-r--r-- | network/wlan/wificx/drivercode/wifitransition.h | 2 |
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( + ¶ms, 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; }; |
