FTM — Factory Test Mode / UTF API¶
Sources analyzed:
- qca-wifi-host-cmn/ftm/core/src/wlan_ftm_svc.c
-
qca-wifi-host-cmn/ftm/core/src/wlan_ftm_svc_i.h -
qca-wifi-host-cmn/ftm/dispatcher/inc/wlan_ftm_ucfg_api.h -
qca-wifi-host-cmn/ftm/dispatcher/src/wlan_ftm_ucfg_api.c -
qca-wifi-host-cmn/target_if/ftm/src/target_if_ftm.c -
qca-wifi-host-cmn/target_if/ftm/inc/target_if_ftm.h -
qca-wifi-host-cmn/os_if/linux/ftm/inc/wlan_cfg80211_ftm.h -
qca-wifi-host-cmn/os_if/linux/ftm/src/wlan_cfg80211_ftm.c -
qca-wifi-host-cmn/os_if/linux/ftm/inc/wlan_ioctl_ftm.h -
qcacld-3.0/core/hdd/src/wlan_hdd_ftm.c
Overview¶
The FTM subsystem (also called UTF — Unified Test Framework) is the low-level testing API Rob referred to in his email. It provides a raw command/response channel between a userspace FTM daemon and the WCN6750 blob, used for RF calibration, production testing, and hardware diagnostics.
Key distinction from HTT: FTM commands travel over WMI (Wireless Module Interface), not over the HTT data path. A re-implemented blob must handle
wmi_pdev_utf_event_idWMI events in addition to the HTT initialization sequence.
FTM mode is only active when the driver is loaded with
device_mode == QDF_GLOBAL_FTM_MODE (as opposed to the normal station or AP
modes). In normal operation this subsystem is idle.
Architecture¶
User space (FTM daemon / calibration tool)
│
├─ via ioctl: FTM_IOCTL_UNIFIED_UTF_CMD (0x1000)
│ FTM_IOCTL_UNIFIED_UTF_RSP (0x1001)
│ → wlan_ioctl_ftm_testmode_cmd()
│
└─ via nl80211: cfg80211 testmode (WLAN_CFG80211_FTM_CMD_WLAN_FTM = 0)
→ wlan_cfg80211_ftm_testmode_cmd()
↓ (both paths converge here)
ucfg_wlan_ftm_testmode_cmd() [dispatcher/ucfg layer]
↓
wlan_ftm_cmd_send() [core service]
↓
target_if_ftm_cmd_send() [target_if — blob boundary]
↓
wmi_unified_pdev_utf_cmd_send() [WMI UTF command → blob]
↓
════════════════════════════════════ [BLOB / WCN6750]
↓
wmi_pdev_utf_event_id [WMI UTF event ← blob]
↓
target_if_ftm_process_utf_event() [event handler]
↓
wlan_ftm_process_utf_event() [reassembly of fragments]
↓
wlan_cfg80211_ftm_rx_event() [back to user space via nl80211]
ucfg_wlan_ftm_testmode_rsp() [back to user space via ioctl]
Command Entry Points¶
ioctl path¶
/* wlan_ioctl_ftm.h */
#define FTM_IOCTL_UNIFIED_UTF_CMD 0x1000 /* host → blob */
#define FTM_IOCTL_UNIFIED_UTF_RSP 0x1001 /* blob → host (poll) */
wlan_ioctl_ftm_testmode_cmd(pdev, cmd, userdata) — handles both ioctl
codes. UTF_CMD sends data to the blob; UTF_RSP polls for and copies
the buffered response.
nl80211 / cfg80211 path¶
/* wlan_cfg80211_ftm.h */
enum wlan_cfg80211_ftm_attr {
WLAN_CFG80211_FTM_ATTR_CMD = 1, /* NLA_U32 — command type */
WLAN_CFG80211_FTM_ATTR_DATA = 2, /* NLA_BINARY — payload */
};
enum wlan_cfg80211_ftm_cmd {
WLAN_CFG80211_FTM_CMD_WLAN_FTM = 0,
};
#define WLAN_FTM_DATA_MAX_LEN 2048
wlan_cfg80211_ftm_testmode_cmd(pdev, data, len) — parses the NLA
attributes, then calls into the same ucfg layer as the ioctl path.
Responses are pushed back asynchronously via cfg80211_testmode_event().
Constants¶
| Name | Value | Description |
|---|---|---|
FTM_CMD_MAX_BUF_LENGTH |
2048 | Max payload per command/response, in bytes |
WLAN_FTM_DATA_MAX_LEN |
2048 | Same limit at the nl80211 layer |
FTM_IOCTL_UNIFIED_UTF_CMD |
0x1000 |
ioctl command code (send) |
FTM_IOCTL_UNIFIED_UTF_RSP |
0x1001 |
ioctl command code (receive) |
WLAN_CFG80211_FTM_CMD_WLAN_FTM |
0 |
nl80211 FTM command type |
Response Segmentation — ftm_seg_hdr_info¶
The blob may split large responses into multiple WMI events. Each event carries a 16-byte segment header:
/* wlan_ftm_svc_i.h */
struct ftm_seg_hdr_info {
uint32_t len; /* total length of the reassembled payload */
uint32_t msgref; /* message reference — ties fragments together */
uint32_t segment_info; /* [3:0] = current_seq, [7:4] = total_segments */
uint32_t pad; /* padding to align to 16 bytes */
};
| Field | Bits | Description |
|---|---|---|
len |
[31:0] | Full length of the reassembled response |
msgref |
[31:0] | Opaque reference number linking all segments |
current_seq |
[3:0] of segment_info |
0-based index of this segment |
total_segments |
[7:4] of segment_info |
Total number of segments expected |
pad |
[31:0] | Zero padding |
Reassembly in wlan_ftm_process_utf_event():
1. current_seq == 0 → reset offset and expected_seq to 0.
2. Copy event_buf[sizeof(seghdr_info):] into internal buffer at offset.
3. Advance offset += utf_datalen, increment expected_seq.
4. When expected_seq == total_segments → response complete; deliver to user.
pdev Private Object — wifi_ftm_pdev_priv_obj¶
The driver allocates one of these per pdev (physical device) when entering FTM mode:
struct wifi_ftm_pdev_priv_obj {
struct wlan_objmgr_pdev *pdev;
uint8_t *data; /* reassembly buffer, FTM_CMD_MAX_BUF_LENGTH bytes */
uint8_t current_seq; /* last received segment sequence number */
uint8_t expected_seq; /* next expected sequence number */
qdf_size_t length; /* length of last complete response */
qdf_size_t offset; /* write offset into data[] during reassembly */
enum wifi_ftm_pdev_cmd_type cmd_type; /* IOCTL or NL80211 */
};
cmd_type tracks the origin of the command so the response is routed back
through the correct path (ioctl buffer vs cfg80211 event).
What the Blob Must Implement¶
For a re-implemented WCN6750 firmware to support this API:
-
Register handler for
wmi_pdev_utf_cmd_id— receive opaque UTF payloads from the host. The blob treats the payload as an opaque byte array (the driver does not parse it). -
Send responses as
wmi_pdev_utf_event_idWMI events, with each event prefixed by aftm_seg_hdr_info(16 bytes). If the response fits in one event (total_segments = 1),current_seq = 0. -
Only be active in FTM mode — normal station/AP operation does not use this channel.
-
Respect the 2048-byte payload limit per segment.
Relationship to HTT¶
| Layer | Protocol | Used for |
|---|---|---|
| HTT | Copy Engine (CE 1/4) | Normal data path — RX/TX frames |
| FTM/UTF | WMI | Factory testing, RF calibration |
Both must be implemented by a replacement blob, but they operate
independently. The FTM channel is only active in QDF_GLOBAL_FTM_MODE;
HTT is active in all other modes.
Source File Map¶
| File | Role |
|---|---|
os_if/linux/ftm/src/wlan_cfg80211_ftm.c |
nl80211 entry point, NLA parsing |
os_if/linux/ftm/src/wlan_ioctl_ftm.c |
ioctl entry point |
ftm/dispatcher/src/wlan_ftm_ucfg_api.c |
ucfg dispatch + response reassembly |
ftm/core/src/wlan_ftm_svc.c |
pdev lifecycle, wlan_ftm_cmd_send() |
ftm/core/src/wlan_ftm_svc_i.h |
ftm_seg_hdr_info struct |
target_if/ftm/src/target_if_ftm.c |
WMI send/receive — blob boundary |