-
Notifications
You must be signed in to change notification settings - Fork 12
Wireless Profile Sync Settings Management Architecture
This document describes the architecture introduced by the wireless profile synchronization feature in Console. It lets an operator read and toggle two independent Intel® AMT wireless synchronization behaviors on a managed device without rewriting the whole WiFi port configuration:
- Local profile sync — whether the AMT firmware may synchronize WiFi profiles with the local host operating system.
- UEFI profile sync — whether WiFi profiles are shared with the platform UEFI/BIOS (pre-boot) WiFi stack, subject to hardware capability.
Two systems are involved: Console (the management application) and the AMT Device
(the managed endpoint). Console exposes a user-facing REST API on one side and
talks to the device over WS-Management (WSMAN) on the other, using the Intel® AMT
SDK semantics implemented by the go-wsman-messages library. Both sync toggles
are driven through the single AMT_WiFiPortConfigurationService instance on the
device.
flowchart LR
Client[REST client] -->|GET / POST localProfileSync/:guid<br/>GET / POST uefiProfileSync/:guid| ConsoleAPI[Console REST API]
subgraph Console
ConsoleAPI --> UseCase[Devices Use Case]
UseCase --> WSMAN[wsman.Management adapter]
end
WSMAN -->|SOAP / XML over HTTPS| Svc
subgraph Device[Intel® AMT Device]
Svc[AMT_WiFiPortConfigurationService]
Caps[AMT_BootCapabilities]
end
WSMAN -.UEFI gate.-> Caps
Console exposes four endpoints for this feature, paired GET/POST per sync target.
- REST/JSON endpoints: internal/controller/httpapi/v1/devicemanagement.go
- handlers: internal/controller/httpapi/v1/wifiprofilesync.go
- payload/response types: internal/entity/dto/v1/wifiprofilesync.go
| Method | Path | Payload | Handler | Success response |
|---|---|---|---|---|
| GET | /api/v1/amt/networkSettings/wireless/localProfileSync/:guid | N/A | getWirelessLocalProfileSync | 200 OK + { "enabled": bool }
|
| POST | /api/v1/amt/networkSettings/wireless/localProfileSync/:guid | WirelessProfileSyncRequest | putWirelessLocalProfileSync | 200 OK + { "enabled": bool }
|
| GET | /api/v1/amt/networkSettings/wireless/uefiProfileSync/:guid | N/A | getWirelessUEFIProfileSync | 200 OK + { "enabled": bool }
|
| POST | /api/v1/amt/networkSettings/wireless/uefiProfileSync/:guid | WirelessProfileSyncRequest | putWirelessUEFIProfileSync | 200 OK + { "enabled": bool }
|
WirelessProfileSyncRequest / WirelessProfileSyncResponse fields:
| Field (JSON) | Type | Binding tag | Validation note |
|---|---|---|---|
enabled (request) |
*bool |
required |
Mandatory. A custom UnmarshalJSON rejects a missing or null enabled with ErrProfileSyncEnabledRequired, returned as 400 Bad Request. |
enabled (response) |
bool |
— | The effective state after the operation, re-read from the device. |
The request type carries a pointer (*bool) so Console can distinguish "field
absent" from false. The BoolValue() helper safely dereferences it (returns
false when nil) before passing the desired state into the use case.
Console talks to the device through the wsman.Management interface in
internal/usecase/devices/wsman/interfaces.go,
implemented by ConnectionEntry in
internal/usecase/devices/wsman/message.go.
Each method is a thin wrapper over a go-wsman-messages call. The operations
relevant to this feature:
| Method | Purpose | SDK / class |
|---|---|---|
| GetWiFiPorts() | enumerate/pull WiFi ports; returns ErrNoWiFiPort when none exist |
CIM_WiFiPort |
| GetWiFiPortConfigurationService() | read the current WiFi port configuration service state | AMT_WiFiPortConfigurationService.Get |
| PutWiFiPortConfigurationService(req) | overwrite the WiFi port configuration service with a full request | AMT_WiFiPortConfigurationService.Put |
| GetPowerCapabilities() | read boot capabilities; used to gate UEFI sync | AMT_BootCapabilities |
The Put requires a complete wifiportconfiguration.WiFiPortConfigurationServiceRequest.
The use case never builds one from scratch: buildWiFiPortConfigRequest copies
every field verbatim from the current WiFiPortConfigurationServiceResponse and
overlays only the two sync-related fields, so unrelated firmware state is not
clobbered.
| AMT SDK request field | Source |
|---|---|
RequestedState, EnabledState, HealthState, ElementName
|
Copied from current settings |
SystemCreationClassName, SystemName, CreationClassName, Name
|
Copied from current settings |
LastConnectedSsidUnderMeControl, NoHostCsmeSoftwarePolicy
|
Copied from current settings |
LocalProfileSynchronizationEnabled |
Local-sync flow → resolved sync state; UEFI flow → copied from current settings |
UEFIWiFiProfileShareEnabled |
UEFI flow → resolved effective state; local-sync flow → copied from current settings |
The local sync field is an enum, not a boolean. The use case maps between the REST boolean and the SDK enum:
| Console boolean |
LocalProfileSynchronizationEnabled enum |
|---|---|
true |
LocalUserProfileSynchronizationEnabled (1) |
false |
LocalSyncDisabled (0) |
isLocalProfileSyncEnabled performs the reverse mapping (true only when the
state equals LocalUserProfileSynchronizationEnabled). The UEFI field
(UEFIWiFiProfileShareEnabled) is already a boolean and maps directly.
Implemented in
internal/usecase/devices/wifiprofilesync.go.
All four use-case methods begin the same way: setupWirelessProfileManagement
(shared with WiFi profile management) loads the device by GUID and opens a WSMAN
client, then GetWiFiPorts() asserts the device actually has a WiFi interface —
returning ErrNoWiFiPort (→ 404 Not Found) otherwise — before any
configuration read or write.
GET flow — GetWirelessLocalProfileSync / GetWirelessUEFIProfileSync read the
current WiFiPortConfigurationService and project out the single relevant
field:
sequenceDiagram
participant C as REST client
participant API as Console API
participant UC as Devices Use Case
participant W as wsman.Management
participant D as AMT Device
C->>API: GET localProfileSync/:guid (or uefiProfileSync)
API->>UC: GetWirelessLocalProfileSync(guid)
UC->>W: setup client + GetWiFiPorts()
W->>D: Enumerate + Pull CIM_WiFiPort
alt no WiFi interface
W-->>UC: ErrNoWiFiPort
UC-->>API: ErrNoWiFiPort
API-->>C: 404 Not Found
else WiFi interface present
UC->>W: GetWiFiPortConfigurationService()
W->>D: AMT_WiFiPortConfigurationService.Get
D-->>W: service state
UC-->>API: enabled (bool)
API-->>C: 200 OK + { "enabled": bool }
end
POST flow (local sync) — PutWirelessLocalProfileSync reads current state,
compares it to the requested value, and only issues a Put when they
differ (read-before-write). When no change is needed it returns the current
value without touching the device:
sequenceDiagram
participant C as REST client
participant API as Console API
participant UC as Devices Use Case
participant W as wsman.Management
participant D as AMT Device
C->>API: POST localProfileSync/:guid { "enabled": true }
API->>UC: PutWirelessLocalProfileSync(guid, true)
UC->>W: setup client + GetWiFiPorts()
UC->>W: GetWiFiPortConfigurationService()
W->>D: AMT_WiFiPortConfigurationService.Get
D-->>W: current state
UC->>UC: map bool -> LocalProfileSynchronizationEnabled enum
alt current == requested
UC-->>API: current value (no write)
else current != requested
UC->>UC: buildWiFiPortConfigRequest(current, newSync, current UEFI)
UC->>W: PutWiFiPortConfigurationService(req)
W->>D: AMT_WiFiPortConfigurationService.Put
D-->>W: updated state
UC-->>API: updated value
end
API-->>C: 200 OK + { "enabled": bool }
POST flow (UEFI sync) — PutWirelessUEFIProfileSync adds a capability gate.
When the caller requests enable, the use case reads
GetPowerCapabilities() and uses the device's
UEFIWiFiCoExistenceAndProfileShare capability as the effective target. On
hardware that does not support pre-boot WiFi sharing this capability is
false, so an enable request resolves to false and no write occurs —
unsupported hardware can never be turned on. Disable requests skip the
capability read:
sequenceDiagram
participant C as REST client
participant API as Console API
participant UC as Devices Use Case
participant W as wsman.Management
participant D as AMT Device
C->>API: POST uefiProfileSync/:guid { "enabled": true }
API->>UC: PutWirelessUEFIProfileSync(guid, true)
UC->>W: setup client + GetWiFiPorts()
UC->>W: GetWiFiPortConfigurationService()
W->>D: AMT_WiFiPortConfigurationService.Get
D-->>W: current state
opt enable requested
UC->>W: GetPowerCapabilities()
W->>D: AMT_BootCapabilities
D-->>W: UEFIWiFiCoExistenceAndProfileShare
UC->>UC: effective = capability value
end
alt current == effective
UC-->>API: current value (no write)
else current != effective
UC->>UC: buildWiFiPortConfigRequest(current, current sync, effective UEFI)
UC->>W: PutWiFiPortConfigurationService(req)
W->>D: AMT_WiFiPortConfigurationService.Put
D-->>W: updated state
UC-->>API: updated value
end
API-->>C: 200 OK + { "enabled": bool }
Other behaviors:
-
No WiFi interface — every flow surfaces
wsman.ErrNoWiFiPort; the handlers in internal/controller/httpapi/v1/wifiprofilesync.go translate it to404 Not Foundwith a descriptive message, while all other errors fall through to the sharedErrorResponsemapping. -
Invalid payload — a missing/null
enabledfield is rejected at bind time (ShouldBindJSON→ customUnmarshalJSON) and returned as400 Bad Request. - Idempotent writes — the read-before-write check means repeating a POST with an already-applied value performs a Get only, leaving the device untouched and returning the current state.
-
Independent fields — toggling local sync preserves the current UEFI value
and vice versa, because
buildWiFiPortConfigRequestcarries the untouched field through from the current settings.
| Area | File |
|---|---|
| HTTP handlers | internal/controller/httpapi/v1/wifiprofilesync.go |
| Route registration | internal/controller/httpapi/v1/devicemanagement.go |
| OpenAPI / Fuego declaration | internal/controller/openapi/devicemanagement.go |
| DTOs (request/response) | internal/entity/dto/v1/wifiprofilesync.go |
| Use case (business logic) | internal/usecase/devices/wifiprofilesync.go |
| Shared WSMAN setup helper | internal/usecase/devices/wifiprofile.go |
| WS layer interface | internal/controller/ws/v1/interface.go |
| Use case interface | internal/usecase/devices/interfaces.go |
| WSMAN interface | internal/usecase/devices/wsman/interfaces.go |
| WSMAN adapter (SDK calls) | internal/usecase/devices/wsman/message.go |
| AMT SDK dependency | go-wsman-messages/v2 — amt/wifiportconfiguration, amt/boot |
| API collection | MPS Postman collection (console_mps_apis.postman_collection.json) |
| Handler tests | internal/controller/httpapi/v1/wifiprofilesync_test.go |
| DTO tests | internal/entity/dto/v1/wifiprofilesync_test.go |
| Use case tests | internal/usecase/devices/wifiprofilesync_test.go |