本文是 《qca-wifi-host-cmn objmgr 解析》 的续篇。objmgr 的“骨架”梳理完之后,读代码时最容易卡住的反而是几个更基础的问题:
- HDD Adapter 到底是什么?
- PSOC / PDEV / VDEV / PEER 分别是什么?
- Link Info 是什么?
- Link Info 和 VDEV 是什么关系?
- Adapter 和 VDEV 是什么关系?
这一篇就把它们一次讲透:从 Linux 网络设备讲起,一层层往下剥,目标是初学者也能看懂。
This article is a sequel to qca-wifi-host-cmn objmgr Analysis. With the objmgr “skeleton” laid out, what actually trips people up while reading the code turns out to be a few more basic questions:
- What exactly is the HDD Adapter?
- What are PSOC / PDEV / VDEV / PEER, respectively?
- What is Link Info?
- How do Link Info and VDEV relate to each other?
- How do Adapter and VDEV relate to each other?
This post answers them all in one go: starting from Linux network devices, we peel off the layers one by one, with the goal of making it understandable even for beginners.
术语表(先扫一眼,读不懂再回来查)
下面这些缩写会在全文反复出现。第一次读不用背,遇到卡壳时回来查即可。
分层 / 模块
| 缩写 | 全称 | 一句话解释 |
|---|---|---|
| HDD | Host Device Driver | qcacld-3.0 的 OS 适配层,对接 Linux 的 net_device / cfg80211(代码里文件头写作 “WLAN Host Device Driver”) |
| UMAC | Upper MAC | 跨平台的“上层 MAC”协议层,即 qca-wifi-host-cmn,负责 MLME、扫描、连接管理等 |
| LMAC | Lower MAC | 固件里的“下层 MAC”,负责实时性强的时序、速率控制等 |
| SME | Station Management Entity | HDD 与 UMAC 之间的“会话管理”入口,HDD 通过 sme_xxx() 调用下层 |
| MLME | MAC Sublayer Management Entity | 802.11 的 MAC 管理状态机(扫描/认证/关联/断开) |
| objmgr | Object Manager | qca-wifi-host-cmn 里的对象管理器,管理 PSOC/PDEV/VDEV/PEER 四层对象 |
| DP | Data Path | 真正的数据收发路径(core/dp/、qca-wifi-host-cmn/dp/),注意不是 HDD |
对象 / 接口
| 缩写 | 全称 | 一句话解释 |
|---|---|---|
| PSOC | Pseudo SoC | 一颗 Wi-Fi 芯片(objmgr 顶层对象) |
| PDEV | Physical Device | 一个射频子系统(radio / PHY),同一时刻只在一个信道上工作(objmgr 第二层) |
| VDEV | Virtual Device | 一个虚拟接口(objmgr 第三层) |
| PEER | Peer | 一个对端设备(objmgr 第四层) |
| VAP | Virtual AP | 虚拟接入点,即一个虚拟 Wi-Fi 接口(≈ VDEV) |
| MLD | Multi-Link Device | Wi-Fi 7 中由多条链路组成的“逻辑设备” |
| MLO | Multi-Link Operation | Wi-Fi 7 多链路操作,一个连接同时用多条链路 |
Linux / 无线子系统
| 缩写 | 全称 | 一句话解释 |
|---|---|---|
| net_device | Network Device | Linux 内核里的一张网卡(如 wlan0) |
| cfg80211 | Configuration 802.11 | Linux 内核的无线配置框架,iw/wpa_supplicant 通过它下发命令 |
| nl80211 | Netlink 802.11 | cfg80211 对用户空间暴露的 netlink 接口 |
| wiphy | Wireless PHY | cfg80211 里描述一个无线硬件(对应 PSOC/PDEV) |
| wdev | Wireless Device | cfg80211 里描述一个无线接口(对应一个 VAP) |
| wext | Wireless Extensions | 老的无线 ioctl 接口(已被 cfg80211 取代,代码里仍保留兼容) |
特性 / 状态
| 缩写 | 全称 | 一句话解释 |
|---|---|---|
| DBS | Dual Band Simultaneous | 双频并发,2.4G 和 5G 可同时工作(对应多个 PDEV) |
| SSR | SubSystem Restart | 子系统重启,固件崩溃后驱动整体重启恢复 |
| OCB | Outside Context of BSS | 车联网(V2X)用的通信模式 |
| NDI | NAN Data Interface | NAN(邻居感知网络)的数据接口 |
| NAN | Neighbor Awareness Networking | Wi-Fi 邻居感知网络(Wi-Fi Aware) |
| FTM | Factory Test Mode | 工厂测试模式 |
先建立一个直觉:Wi-Fi 驱动在“模拟”什么?
在 Linux 里,一张网卡就是一个 网络设备(net_device),比如 eth0、wlan0。
用户空间(wpa_supplicant、hostapd、iw、ip)看到的是:
1 | wlan0 -> 一个 STA 接口(连路由器) |
但 Wi-Fi 芯片内部并不是“一个接口对应一个硬件”。一颗 Wi-Fi 芯片(SoC)可以同时:
- 在 2.4G 上做 STA,在 5G 上做 AP(并发 / concurrency)
- 支持多个虚拟接口(VAP,Virtual AP)
- 支持 Wi-Fi 7 的 MLO(Multi-Link Operation,一个连接同时用多条链路)
所以驱动内部需要一套分层对象模型来描述“硬件 → radio(射频子系统)→ 虚拟接口 → 对端设备”。
这套模型就是 objmgr,它的四个核心对象是:
1 | PSOC → PDEV → VDEV → PEER |
而 HDD Adapter 和 Link Info 是 qcacld-3.0(上层 OS 适配层) 里的概念,
它们负责把 Linux 的 net_device 和 objmgr 里的 VDEV 连接起来。
一句话先记住:
Adapter 是 Linux 侧的“网卡接口”,VDEV 是固件/UMAC 侧的“虚拟设备”,Link Info 是两者之间的“桥”。
全景图:一张图看懂所有对象
- 蓝色:objmgr 对象(在
qca-wifi-host-cmn里,跨平台通用) - 橙色:HDD Adapter(在
qcacld-3.0里,Linux 专用) - 绿色:Link Info(在
qcacld-3.0里,连接 Adapter 和 VDEV)
objmgr 四层对象:PSOC / PDEV / VDEV / PEER
先讲清楚“固件侧”的四个对象。它们定义在:
| 对象 | 头文件 |
|---|---|
| PSOC | qca-wifi-host-cmn/umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h |
| PDEV | qca-wifi-host-cmn/umac/cmn_services/obj_mgr/inc/wlan_objmgr_pdev_obj.h |
| VDEV | qca-wifi-host-cmn/umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h |
| PEER | qca-wifi-host-cmn/umac/cmn_services/obj_mgr/inc/wlan_objmgr_peer_obj.h |
PSOC —— “一颗 Wi-Fi 芯片”
PSOC = Pseudo SoC(伪 SoC)。它代表一颗物理 Wi-Fi 芯片。
你可以把它理解成“整张网卡”。它保存的是全局的、芯片级别的信息:
1 | /* wlan_objmgr_psoc_obj.h */ |
关键点:
soc_objmgr.wlan_pdev_list[]:这颗芯片下所有的 PDEVsoc_objmgr.wlan_vdev_list[]:这颗芯片下所有的 VDEV(最多WLAN_UMAC_PSOC_MAX_VDEVS = 51)soc_objmgr.peer_list:这颗芯片下所有的 PEERsoc_nif.soc_fw_caps:固件能力位图(比如是否支持 11ax、11be)
类比:PSOC 就像一台“电脑主机”,里面可以插多张“显卡”(PDEV)。
创建入口:wlan_objmgr_psoc_obj_create()(wlan_objmgr_psoc_obj.c)。
PDEV —— “一个射频子系统(radio / PHY)”
PDEV = Physical Device。它代表一个独立的射频子系统(radio / PHY):
一套能调谐到某个信道、同一时刻只在一个信道上收发的完整收发系统(基带 + 若干射频链 + 对应天线)。
一颗芯片可能有多个 radio。比如支持 DBS(Dual Band Simultaneous,双频并发) 的芯片,
可以同时有 2.4G 和 5G 两个独立的 radio,那就是 2 个 PDEV;
单射频芯片(或 DBS 芯片工作在单 MAC 硬件模式下)则只有 1 个 PDEV。
注意:radio 不是天线,也不是一条射频链。2x2 MIMO 指的是一个 radio 内部有 2 条射频链、2 根天线,
它们锁定在同一个信道上并行收发——所以“只有 1 个 PDEV 却支持 2x2 MIMO”是完全正常的。
PDEV 的数量只决定“能同时在几个信道上收发”(并发能力),与 MIMO 阶数(NSS,空间流数)是两个正交的维度。
固件在 service ready 时按**当前硬件模式(hw mode)**上报 radio 数,DBS 激活后才会从 1 个 PDEV 变成 2 个。
1 | /* wlan_objmgr_pdev_obj.h */ |
关键点:
pdev_objmgr.wlan_vdev_list:这个 radio 上创建的所有 VDEVpdev_objmgr.wlan_psoc:反向指针,指回所属的 PSOCpdev_objmgr.max_vdev_count = WLAN_UMAC_PDEV_MAX_VDEVS = 17
类比:PDEV 就像一张“显卡”,它有自己的“显存”(信道、硬件能力),
上面可以跑多个“程序”(VDEV)。
创建入口:wlan_objmgr_pdev_obj_create()(wlan_objmgr_pdev_obj.c)。
VDEV —— “一个虚拟接口”
VDEV = Virtual Device。它代表一个虚拟 Wi-Fi 接口,也就是我们常说的 VAP(Virtual AP)。
一个 VDEV 对应一种“角色(opmode)”:
| opmode | 含义 |
|---|---|
QDF_STA_MODE |
客户端(连路由器) |
QDF_SAP_MODE |
SoftAP(开热点) |
QDF_P2P_CLIENT_MODE |
P2P 客户端 |
QDF_P2P_GO_MODE |
P2P GO |
QDF_P2P_DEVICE_MODE |
P2P Device |
QDF_MONITOR_MODE |
监听模式 |
QDF_OCB_MODE |
车联网 OCB |
QDF_NDI_MODE |
NAN Data Interface |
1 | /* wlan_objmgr_vdev_obj.h */ |
其中 vdev_mlme 里存着这个接口最核心的信息:
1 | struct wlan_objmgr_vdev_mlme { |
类比:VDEV 就像显卡上跑的一个“程序窗口”,每个窗口有自己的角色和状态。
创建入口:wlan_objmgr_vdev_obj_create()(wlan_objmgr_vdev_obj.c)。
注意它的第一个参数是 pdev,说明 VDEV 必须挂在某个 PDEV 下。
PEER —— “一个对端设备”
PEER = 对端。它代表一个和你有数据交互的远端设备。
- STA 模式下:PEER 就是你连的那个 AP
- SAP 模式下:每个连上你热点的手机/电脑都是一个 PEER
- P2P 模式下:对端设备是 PEER
1 | /* wlan_objmgr_peer_obj.h */ |
类比:PEER 就像“和你通信的那个人”。
创建入口:wlan_objmgr_peer_obj_create(),第一个参数是 vdev,说明 PEER 挂在 VDEV 下。
四层对象的关系图
包含关系(1 对多):
1 | 1 PSOC ──< N PDEV ──< N VDEV ──< N PEER |
每个对象里都有反向指针,可以往上找:
pdev->pdev_objmgr.wlan_psoc→ PSOCvdev->vdev_objmgr.wlan_pdev→ PDEVpeer->peer_objmgr.vdev→ VDEV
HDD Adapter —— Linux 侧的“网卡接口”
现在进入 qcacld-3.0。HDD = Host Device Driver,是 Linux 平台的适配层。
(代码里 qcacld-3.0/core/hdd/inc/*.h 的文件头注释统一写作 “WLAN Host Device Driver”。)
Adapter 的本质:net_device 的私有数据
在 Linux 里创建一个网络接口时,会分配一个 struct net_device。
驱动可以在这块内存后面附加自己的“私有数据”,通过 netdev_priv() 拿到。
qcacld 就是这么做的:
1 | /* wlan_hdd_main.h */ |
也就是说:
hdd_adapter就是net_device的私有数据。
拿到net_device指针,就能拿到hdd_adapter;反之亦然。
Adapter 里有什么
1 | /* qcacld-3.0/core/hdd/inc/wlan_hdd_main.h */ |
几个关键成员:
| 成员 | 作用 |
|---|---|
dev |
对应的 net_device,用户看到的 wlan0 |
device_mode |
这个接口是 STA 还是 AP 还是 P2P |
hdd_ctx |
全局上下文,里面有 psoc 和 pdev |
deflink |
默认 link,指向 link_info[0] |
link_info[] |
link 数组,每个元素对应一个 VDEV |
hdd_context —— 全局上下文
hdd_adapter 里有个 hdd_ctx,它是整个驱动的“总管家”:
1 | /* wlan_hdd_main.h */ |
注意:hdd_context 是 HDD 层和 objmgr 层的“接口”。
它同时持有 psoc 和 pdev,所以从任何一个 adapter 都能一路找到 objmgr 对象:
1 | adapter->hdd_ctx->psoc → PSOC |
Adapter 的创建
入口是 hdd_open_adapter()(wlan_hdd_main.c)。它会:
- 根据
session_type(STA/SAP/P2P…)分配net_device和hdd_adapter - 设置
adapter->device_mode - 注册到内核(
hdd_register_interface) - 初始化
link_info[](hdd_adapter_init_link_info) - 把 adapter 挂到
hdd_ctx->hdd_adapters链表
重要:Adapter 创建 ≠ VDEV 创建。
Adapter 在接口被创建时就有了(hdd_open_adapter),
而 VDEV 是在接口 up 的时候才创建的(hdd_vdev_create)。
这就是为什么link_info->vdev一开始是NULL。
Link Info —— Adapter 和 VDEV 之间的桥
为什么需要 Link Info?
在 Wi-Fi 6 及以前,一个接口 = 一个 VDEV,关系很简单,直接放个 vdev_id 就够了。
但到了 Wi-Fi 7 MLO,情况变了:
一个接口(一个 net_device)可以同时使用多条链路(link)。
每条链路在固件里都是一个独立的 VDEV。
比如一个 STA 接口 wlan0 同时连到 AP 的 2.4G 和 5G 两个频段:
1 | wlan0 (一个 net_device / 一个 adapter) |
所以 adapter 里不能再只放一个 vdev_id,而要放一个数组,每个元素描述一条链路。
这个数组元素就是 wlan_hdd_link_info。
Link Info 的结构
1 | /* qcacld-3.0/core/hdd/inc/wlan_hdd_main.h */ |
Link Info 是“每条链路”的上下文,它同时持有:
- 往上的指针:
adapter(属于哪个接口) - 往下的指针:
vdev(对应哪个固件虚拟设备) - 链路专属数据:
session(STA/AP/Monitor 各自的上下文)、rssi、stats等
session 联合体:不同角色的专属数据
session 是一个 union,根据接口角色使用不同的成员:
访问宏:
1 |
deflink:默认链路
Adapter 里有一个 deflink 指针,永远指向 link_info[0]:
1 |
|
对于非 MLO 的普通接口,只有一条链路,所有代码都用 adapter->deflink 就够了。
对于 MLO 接口,才会遍历整个 link_info[] 数组。
遍历宏:
1 |
Adapter 和 VDEV 是什么关系?
这是最核心的问题。答案是:
Adapter 是 Linux 侧的接口,VDEV 是固件侧的虚拟设备。
一个 Adapter 通过它的link_info[]数组,关联到一个或多个 VDEV。
关系图
三种典型场景
场景 A:普通 STA(非 MLO)
1 | adapter (wlan0) |
一个 adapter 一个 vdev,link_info[1]、link_info[2] 都是空的。
场景 B:MLO STA(Wi-Fi 7,多链路)
1 | adapter (wlan0) |
一个 adapter 两个 vdev,用户只看到一个 wlan0,但固件里有两个 VDEV。
场景 C:SAP + STA 并发
1 | adapter (wlan0, STA) ──> link_info[0] ──> vdev 0 |
两个 adapter,各自一个 vdev。它们可能在不同的 PDEV 上(DBS)。
双向查找
Adapter → VDEV(通过 link_info):
1 | /* 拿到默认链路的 vdev */ |
VDEV → Adapter(通过 osdev 私有指针):
1 | /* wlan_hdd_main.c */ |
这里的 legacy_osif_priv 就是在 hdd_store_vdev_info() 里设置的:
1 | /* wlan_hdd_main.c */ |
所以:
1 | link_info->vdev → VDEV |
创建流程(Adapter 和 VDEV 如何绑定)
Link Info 和 VDEV 是什么关系?
一句话:
Link Info 是 VDEV 在 HDD 层的“代理/包装”。
一个 Link Info 对应一个 VDEV(1:1),
但一个 Adapter 可以拥有多个 Link Info(1:N)。
1:1 对应
每个 link_info 里恰好有一个 vdev 指针,每个 VDEV 也恰好被一个 link_info 引用:
职责分工
| 维度 | Link Info(HDD 层) | VDEV(objmgr 层) |
|---|---|---|
| 定位 | Linux 适配层 | 跨平台通用层 |
| 关注点 | OS 接口、用户可见状态 | 固件交互、协议状态机 |
| 典型数据 | rssi、snr、stats、session(STA/AP 上下文) |
opmode、mlme_state、bss_chan、peer_list |
| 生命周期 | 随 adapter 创建/销毁 | 随接口 up/down 创建/销毁 |
| 谁创建 | hdd_adapter_init_link_info() |
wlan_objmgr_vdev_obj_create() |
为什么要有 Link Info 这一层?
因为 objmgr 是跨平台的(Linux / Android / 其他 OS 都能用),
它不能包含 Linux 特有的东西(比如 net_device、wireless_dev、cfg80211)。
所以 qcacld 用 link_info 作为适配层:
- 把 Linux 的东西(
adapter、session)放在link_info里 - 把通用的东西(
opmode、mlme_state)放在vdev里 - 两者通过指针互相引用
完整关系总图
把前面所有内容合起来:
生命周期对比
不同对象的创建/销毁时机不同,这是初学者最容易踩坑的地方:
| 对象 | 创建时机 | 销毁时机 | 触发函数 |
|---|---|---|---|
| PSOC | 驱动 probe / 固件 ready | 驱动 remove / SSR | wlan_objmgr_psoc_obj_create |
| PDEV | PSOC 创建后 | PSOC 销毁时 | wlan_objmgr_pdev_obj_create |
| Adapter | 用户创建接口(iw phy ... interface add) |
用户删除接口 | hdd_open_adapter |
| Link Info | Adapter 创建时(数组一次性分配) | Adapter 销毁时 | hdd_adapter_init_link_info |
| VDEV | 接口 up 时 | 接口 down 时 | hdd_vdev_create / hdd_vdev_destroy |
| PEER | 连接建立时(关联/认证) | 断开连接时 | wlan_objmgr_peer_obj_create |
关键记忆点:
- Adapter 和 Link Info 是“接口级”的,接口存在它们就存在。
- VDEV 是“连接级”的,接口 up 才有,down 就没了。
- 所以代码里访问
link_info->vdev前,一定要判空!
端到端故事线:跟着一次连接走一遍
前面各节是“分块讲解”。这一节我们把它们串起来,跟着用户的一次真实操作,
看对象是怎么一层层被创建、被引用的。这是理解整套模型最快的方式。
我们假设用户执行:
1 | # 1. 创建接口(如果还没有) |
全景时序图
分阶段拆解
阶段 1:创建接口 —— 只有 Adapter 和 Link Info
| 步骤 | 函数 | 产生的对象 |
|---|---|---|
用户敲 iw phy ... interface add |
cfg80211 → hdd_open_adapter() |
net_device + hdd_adapter |
| 初始化链路数组 | hdd_adapter_init_link_info() |
link_info[](vdev 全为 NULL) |
关键:此时还没有 VDEV。
adapter->deflink->vdev == NULL。
阶段 2:接口 up —— 创建 VDEV 并双向绑定
| 步骤 | 函数 | 说明 |
|---|---|---|
用户敲 ip link set wlan0 up |
cfg80211 → hdd_vdev_create(link_info) |
传入的是 link_info,不是 adapter |
| 创建固件侧对象 | sme_vdev_create() → wlan_objmgr_vdev_obj_create() |
在 PDEV 下创建 VDEV |
| 建立双向指针 | hdd_store_vdev_info(link_info, vdev) |
link_info->vdev = vdev;osdev->legacy_osif_priv = link_info |
关键:VDEV 是“接口 up”时才有的。这就是为什么访问
link_info->vdev前必须判空。
阶段 3:连接 AP —— 创建 PEER
| 步骤 | 函数 | 说明 |
|---|---|---|
用户敲 iw dev wlan0 connect MyAP |
cfg80211 → wlan_hdd_cfg80211_connect() |
cfg80211 的 connect 回调 |
| 进入 HDD 连接逻辑 | wlan_hdd_cm_connect() |
adapter = netdev_priv(ndev),vdev = adapter->deflink->vdev |
| 下发到 UMAC | osif_cm_connect(ndev, vdev, req, params) |
连接管理器开始扫描/认证/关联 |
| 关联成功,创建对端 | wlan_objmgr_peer_obj_create(vdev, ...) |
PEER 挂在 VDEV 下 |
| 回调通知 HDD | hdd_cm_connect_complete(vdev, rsp) |
更新 link_info->session.station 等状态 |
关键:PEER 是“连接建立”时才有的。STA 模式下 PEER 就是那个 AP。
阶段 4:断开 / down —— 逐层销毁
| 步骤 | 函数 | 说明 |
|---|---|---|
iw dev wlan0 disconnect |
wlan_hdd_cm_disconnect() |
销毁 PEER |
ip link set wlan0 down |
hdd_vdev_destroy(link_info) |
销毁 VDEV,link_info->vdev = NULL |
| 删除接口 | hdd_close_adapter() |
销毁 Adapter 和 Link Info |
一句话记住这条链
1 | 用户操作 iw / ip |
记忆口诀:
建接口 → 有 Adapter/Link Info;up → 有 VDEV;连上 → 有 PEER;down/断开 → 逆序销毁。
MLO 场景深入(Wi-Fi 7)
MLO 是理解 Link Info 存在意义的关键。我们单独讲一下。
什么是 MLO
MLO(Multi-Link Operation) 是 Wi-Fi 7 的核心特性:
一个 STA 可以同时和 AP 的多条链路(不同频段)通信,聚合带宽、降低延迟。
MLO 下的对象关系
以 MLMR(多链路多射频) 为例:link 0 走 2.4G radio,link 1 走 5G radio,
两条链路各自占一个 PDEV,可以同时收发:
MLO 形态与 PDEV 的关系:link 是 VDEV 层面的概念,但每个 VDEV 仍然必须挂在某个 PDEV(radio)下:
- MLMR(多链路多射频):每个 link 各占一个 PDEV,链路同时收发——即上图;
- MLSR / EMLSR(单射频):所有 link 共用同一个 PDEV,同一时刻只有一条链路在收发(eMLSR 靠在链路间快速切换来降低延迟);
- EMLMR(增强多射频):radio 数少于 link 数,PDEV 在链路间动态指派。
代码里
wlan_mlo_get_pdev_hw_link_id()/wlan_mlo_get_pdev_by_hw_link_id()就是 link 与 PDEV 之间的映射接口。
三种 MAC 地址
MLO 下每个 VDEV 有三个 MAC 地址,别搞混:
| 地址 | 字段 | 含义 |
|---|---|---|
| MLD MAC | vdev_mlme.mldaddr |
整个 MLO 连接的“逻辑地址”,对上层可见 |
| Link MAC | vdev_mlme.linkaddr |
每条链路的物理地址,对空口可见 |
| Interface MAC | vdev_mlme.macaddr |
接口地址(非 MLO 时等于 linkaddr) |
MLO 相关常量
1 | /* qcacld-3.0/configs/config_to_feature.h */ |
所以 link_info[] 数组大小默认是 3,即一个 adapter 最多 3 条链路。
速查表 & 常见问题
一句话总结
| 概念 | 一句话解释 | 所在层 |
|---|---|---|
| PSOC | 一颗 Wi-Fi 芯片 | objmgr |
| PDEV | 一个射频子系统(radio / PHY) | objmgr |
| VDEV | 一个虚拟接口(VAP) | objmgr |
| PEER | 一个对端设备 | objmgr |
| Adapter | Linux 的一个网络接口(net_device) | HDD |
| Link Info | 一条链路的上下文,连接 Adapter 和 VDEV | HDD |
关系速查
1 | PSOC 1 ──< N PDEV |
常见问题
Q1:Adapter 和 VDEV 是一一对应的吗?
不是。普通接口是 1:1,但 MLO 接口是 1:N(一个 adapter 多个 vdev)。
准确说法是:一个 Link Info 对应一个 VDEV,一个 Adapter 对应一个或多个 Link Info。
Q2:为什么 link_info->vdev 有时候是 NULL?
因为 VDEV 是在接口 up 时才创建的,而 Link Info 在接口创建时就存在了。
接口 down 后 VDEV 被销毁,link_info->vdev 也会被清空。
Q3:adapter->deflink 是什么?
是 link_info[0] 的快捷方式。非 MLO 场景下所有代码都用它。
Q4:怎么从 VDEV 找到 Adapter?
1 | vdev->vdev_nif.osdev->legacy_osif_priv → link_info |
Q5:怎么从 Adapter 找到 PSOC/PDEV?
1 | adapter->hdd_ctx->psoc → PSOC |
Q6:hdd_context 和 wlan_objmgr_psoc 有什么区别?
hdd_context 是 HDD 层的全局上下文(含 Linux 相关的东西,如 wiphy、config);
wlan_objmgr_psoc 是 objmgr 层的芯片对象(跨平台通用)。
hdd_context 里持有 psoc 和 pdev 指针,是两层的桥梁。
关键代码位置索引
本文涉及的关键代码都位于 WANG-Guangxin/wlan-driver,下表链接固定在提交 da0ed2c,为永久链接:
结语
用一句话串起来:
用户空间看到的是 Adapter(net_device);
驱动内部用 Link Info 把 Adapter 和固件的 VDEV 连起来;
VDEV 挂在 PDEV 上,PDEV 挂在 PSOC 上;
每个 VDEV 下挂着若干 PEER(对端设备)。
理解了这套对象模型,再看 qcacld 的代码就会清晰很多:
看到 adapter 就知道是 Linux 接口层,看到 vdev 就知道是固件交互层,
看到 link_info 就知道是在处理某一条具体链路。
Glossary (skim it first, come back when something is unclear)
The abbreviations below recur throughout the article. Don’t memorize them on the first read — come back and check whenever you get stuck.
Layers / Modules
| Abbreviation | Full name | One-sentence explanation |
|---|---|---|
| HDD | Host Device Driver | The OS adaptation layer of qcacld-3.0, interfacing with Linux net_device / cfg80211 (file headers in the code say “WLAN Host Device Driver”) |
| UMAC | Upper MAC | The cross-platform “upper MAC” protocol layer, i.e. qca-wifi-host-cmn, responsible for MLME, scanning, connection management, etc. |
| LMAC | Lower MAC | The “lower MAC” inside the firmware, handling timing-critical sequencing, rate control, etc. |
| SME | Station Management Entity | The “session management” entry between HDD and UMAC; HDD invokes the layers below through sme_xxx() |
| MLME | MAC Sublayer Management Entity | The 802.11 MAC management state machine (scan/authentication/association/disconnect) |
| objmgr | Object Manager | The object manager inside qca-wifi-host-cmn, managing the four object layers PSOC/PDEV/VDEV/PEER |
| DP | Data Path | The actual data TX/RX path (core/dp/, qca-wifi-host-cmn/dp/), note: not HDD |
Objects / Interfaces
| Abbreviation | Full name | One-sentence explanation |
|---|---|---|
| PSOC | Pseudo SoC | One Wi-Fi chip (the top-level objmgr object) |
| PDEV | Physical Device | One radio subsystem (radio/PHY) that works on only one channel at a time (the second objmgr layer) |
| VDEV | Virtual Device | One virtual interface (the third objmgr layer) |
| PEER | Peer | One remote device (the fourth objmgr layer) |
| VAP | Virtual AP | A virtual access point, i.e. one virtual Wi-Fi interface (≈ VDEV) |
| MLD | Multi-Link Device | The “logical device” composed of multiple links in Wi-Fi 7 |
| MLO | Multi-Link Operation | Wi-Fi 7 multi-link operation: one connection uses multiple links simultaneously |
Linux / Wireless Subsystem
| Abbreviation | Full name | One-sentence explanation |
|---|---|---|
| net_device | Network Device | One network card in the Linux kernel (e.g. wlan0) |
| cfg80211 | Configuration 802.11 | The kernel’s wireless configuration framework; iw/wpa_supplicant issue commands through it |
| nl80211 | Netlink 802.11 | The netlink interface cfg80211 exposes to userspace |
| wiphy | Wireless PHY | Describes one wireless hardware device in cfg80211 (corresponds to PSOC/PDEV) |
| wdev | Wireless Device | Describes one wireless interface in cfg80211 (corresponds to one VAP) |
| wext | Wireless Extensions | The legacy wireless ioctl interface (superseded by cfg80211, still kept for compatibility in the code) |
Features / States
| Abbreviation | Full name | One-sentence explanation |
|---|---|---|
| DBS | Dual Band Simultaneous | Dual-band concurrency: 2.4G and 5G can work at the same time (corresponds to multiple PDEVs) |
| SSR | SubSystem Restart | Subsystem restart: the driver restarts as a whole to recover after a firmware crash |
| OCB | Outside Context of BSS | The communication mode used by V2X (vehicular networking) |
| NDI | NAN Data Interface | The data interface of NAN (Neighbor Awareness Networking) |
| NAN | Neighbor Awareness Networking | Wi-Fi Neighbor Awareness Networking (Wi-Fi Aware) |
| FTM | Factory Test Mode | Factory test mode |
First, build an intuition: what is the Wi-Fi driver “simulating”?
In Linux, a network card is a network device (net_device), such as eth0, wlan0.
What userspace (wpa_supplicant, hostapd, iw, ip) sees is:
1 | wlan0 -> a STA interface (connects to a router) |
But inside the Wi-Fi chip, it is not “one interface per piece of hardware”. A single Wi-Fi chip (SoC) can simultaneously:
- act as a STA on 2.4G and an AP on 5G (concurrency)
- support multiple virtual interfaces (VAP, Virtual AP)
- support Wi-Fi 7 MLO (Multi-Link Operation: one connection uses multiple links at the same time)
So the driver internally needs a layered object model to describe “hardware → radio → virtual interface → remote device”.
That model is objmgr, whose four core objects are:
1 | PSOC → PDEV → VDEV → PEER |
HDD Adapter and Link Info are concepts in qcacld-3.0 (the upper OS adaptation layer);
they are responsible for connecting the Linux net_device with the objmgr VDEV.
Remember this one line first:
Adapter is the “network interface” on the Linux side, VDEV is the “virtual device” on the firmware/UMAC side, and Link Info is the “bridge” between the two.
The big picture: one diagram to understand all objects
- Blue: objmgr objects (in
qca-wifi-host-cmn, cross-platform) - Orange: HDD Adapter (in
qcacld-3.0, Linux-specific) - Green: Link Info (in
qcacld-3.0, connecting Adapter and VDEV)
The four objmgr layers: PSOC / PDEV / VDEV / PEER
Let’s first clarify the four “firmware-side” objects. They are defined in:
| Object | Header file |
|---|---|
| PSOC | qca-wifi-host-cmn/umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h |
| PDEV | qca-wifi-host-cmn/umac/cmn_services/obj_mgr/inc/wlan_objmgr_pdev_obj.h |
| VDEV | qca-wifi-host-cmn/umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h |
| PEER | qca-wifi-host-cmn/umac/cmn_services/obj_mgr/inc/wlan_objmgr_peer_obj.h |
PSOC — “one Wi-Fi chip”
PSOC = Pseudo SoC. It represents one physical Wi-Fi chip.
You can think of it as “the whole network card”. It holds global, chip-level information:
1 | /* wlan_objmgr_psoc_obj.h */ |
Key points:
soc_objmgr.wlan_pdev_list[]: all PDEVs under this chipsoc_objmgr.wlan_vdev_list[]: all VDEVs under this chip (at mostWLAN_UMAC_PSOC_MAX_VDEVS = 51)soc_objmgr.peer_list: all PEERs under this chipsoc_nif.soc_fw_caps: the firmware capability bitmap (e.g. whether 11ax/11be is supported)
Analogy: PSOC is like a “computer host” — you can plug multiple “graphics cards” (PDEVs) into it.
Creation entry: wlan_objmgr_psoc_obj_create() (wlan_objmgr_psoc_obj.c).
PDEV — “one radio subsystem (radio / PHY)”
PDEV = Physical Device. It represents one independent radio subsystem (radio / PHY):
a complete TX/RX system (baseband + a number of RF chains + their antennas) that tunes to one channel and transmits and receives on only one channel at a time.
A chip can have multiple radios. For example, a chip supporting DBS (Dual Band Simultaneous)
can have two independent radios, 2.4G and 5G, working at the same time — that means 2 PDEVs;
a single-radio chip (or a DBS chip operating in single-MAC hardware mode) has only 1 PDEV.
Note: a radio is not an antenna, and not a single RF chain either. 2x2 MIMO means one radio has 2 RF chains and 2 antennas inside,
locked onto the same channel for parallel TX/RX — so “only 1 PDEV yet 2x2 MIMO” is perfectly normal.
The number of PDEVs only determines “how many channels you can be on at the same time” (concurrency), which is orthogonal to the MIMO order (NSS, spatial streams).
The firmware reports the radio count at service ready according to the currently active hardware mode (hw mode); only after DBS is activated does the driver go from 1 PDEV to 2.
1 | /* wlan_objmgr_pdev_obj.h */ |
Key points:
pdev_objmgr.wlan_vdev_list: all VDEVs created on this radiopdev_objmgr.wlan_psoc: back pointer to the PSOC it belongs topdev_objmgr.max_vdev_count = WLAN_UMAC_PDEV_MAX_VDEVS = 17
Analogy: PDEV is like a “graphics card” — it has its own “video memory” (channels, radio capabilities),
and multiple “programs” (VDEVs) can run on it.
Creation entry: wlan_objmgr_pdev_obj_create() (wlan_objmgr_pdev_obj.c).
VDEV — “one virtual interface”
VDEV = Virtual Device. It represents one virtual Wi-Fi interface, i.e. what we usually call a VAP (Virtual AP).
Each VDEV corresponds to one “role (opmode)”:
| opmode | Meaning |
|---|---|
QDF_STA_MODE |
Client (connects to a router) |
QDF_SAP_MODE |
SoftAP (runs a hotspot) |
QDF_P2P_CLIENT_MODE |
P2P client |
QDF_P2P_GO_MODE |
P2P GO |
QDF_P2P_DEVICE_MODE |
P2P Device |
QDF_MONITOR_MODE |
Monitor mode |
QDF_OCB_MODE |
V2X OCB |
QDF_NDI_MODE |
NAN Data Interface |
1 | /* wlan_objmgr_vdev_obj.h */ |
Among them, vdev_mlme holds the most core information of this interface:
1 | struct wlan_objmgr_vdev_mlme { |
Analogy: VDEV is like a “program window” running on the graphics card; each window has its own role and state.
Creation entry: wlan_objmgr_vdev_obj_create() (wlan_objmgr_vdev_obj.c).
Note that its first argument is pdev, which means a VDEV must hang under some PDEV.
PEER — “one remote device”
PEER = remote end. It represents a remote device that exchanges data with you.
- In STA mode: the PEER is the AP you are connected to
- In SAP mode: every phone/computer connected to your hotspot is a PEER
- In P2P mode: the remote device is a PEER
1 | /* wlan_objmgr_peer_obj.h */ |
Analogy: PEER is like “the person you are talking to”.
Creation entry: wlan_objmgr_peer_obj_create(); its first argument is vdev, which means a PEER hangs under a VDEV.
Relationship diagram of the four layers
Containment (1-to-many):
1 | 1 PSOC ──< N PDEV ──< N VDEV ──< N PEER |
Every object also has a back pointer so you can walk upward:
pdev->pdev_objmgr.wlan_psoc→ PSOCvdev->vdev_objmgr.wlan_pdev→ PDEVpeer->peer_objmgr.vdev→ VDEV
HDD Adapter — the “network interface” on the Linux side
Now we enter qcacld-3.0. HDD = Host Device Driver is the adaptation layer for the Linux platform.
(The file header comments under qcacld-3.0/core/hdd/inc/*.h uniformly say “WLAN Host Device Driver”.)
The essence of Adapter: the private data of net_device
When creating a network interface in Linux, a struct net_device is allocated.
The driver can append its own “private data” after that memory and retrieve it via netdev_priv().
That is exactly what qcacld does:
1 | /* wlan_hdd_main.h */ |
In other words:
hdd_adapteris the private data ofnet_device.
Given anet_devicepointer, you can get thehdd_adapter, and vice versa.
What’s inside an Adapter
1 | /* qcacld-3.0/core/hdd/inc/wlan_hdd_main.h */ |
A few key members:
| Member | Purpose |
|---|---|
dev |
the corresponding net_device, what the user sees as wlan0 |
device_mode |
whether this interface is STA, AP, or P2P |
hdd_ctx |
the global context, which contains psoc and pdev |
deflink |
the default link, pointing to link_info[0] |
link_info[] |
the link array; each element corresponds to one VDEV |
hdd_context — the global context
Inside hdd_adapter there is an hdd_ctx, the “head butler” of the whole driver:
1 | /* wlan_hdd_main.h */ |
Note: hdd_context is the “interface” between the HDD layer and the objmgr layer.
It holds both psoc and pdev, so from any adapter you can find the objmgr objects all the way up:
1 | adapter->hdd_ctx->psoc → PSOC |
Adapter creation
The entry point is hdd_open_adapter() (wlan_hdd_main.c). It will:
- allocate
net_deviceandhdd_adapteraccording tosession_type(STA/SAP/P2P…) - set
adapter->device_mode - register with the kernel (
hdd_register_interface) - initialize
link_info[](hdd_adapter_init_link_info) - link the adapter into
hdd_ctx->hdd_adapters
Important: Adapter creation ≠ VDEV creation.
The Adapter exists as soon as the interface is created (hdd_open_adapter),
while the VDEV is only created when the interface is brought up (hdd_vdev_create).
That is whylink_info->vdevisNULLat the beginning.
Link Info — the bridge between Adapter and VDEV
Why is Link Info needed?
Before Wi-Fi 6, one interface = one VDEV; the relationship was simple, and a single vdev_id was enough.
But with Wi-Fi 7 MLO, things changed:
One interface (one net_device) can use multiple links simultaneously.
Each link is an independent VDEV in the firmware.
For example, a STA interface wlan0 connects to the AP on both 2.4G and 5G at the same time:
1 | wlan0 (one net_device / one adapter) |
So the adapter can no longer hold a single vdev_id; it needs an array, with each element describing one link.
That array element is wlan_hdd_link_info.
The structure of Link Info
1 | /* qcacld-3.0/core/hdd/inc/wlan_hdd_main.h */ |
Link Info is the per-link context; it simultaneously holds:
- the upward pointer:
adapter(which interface it belongs to) - the downward pointer:
vdev(which firmware virtual device it corresponds to) - link-specific data:
session(the respective STA/AP/Monitor contexts),rssi,stats, etc.
The session union: role-specific data
session is a union; different members are used depending on the interface role:
Access macros:
1 |
deflink: the default link
The Adapter has a deflink pointer that always points to link_info[0]:
1 |
|
For an ordinary non-MLO interface there is only one link, so all code just uses adapter->deflink.
Only for MLO interfaces does the code walk the whole link_info[] array.
The iteration macro:
1 |
What is the relationship between Adapter and VDEV?
This is the most central question. The answer:
Adapter is the interface on the Linux side, VDEV is the virtual device on the firmware side.
One Adapter is associated with one or more VDEVs through itslink_info[]array.
Relationship diagram
Three typical scenarios
Scenario A: ordinary STA (non-MLO)
1 | adapter (wlan0) |
One adapter, one vdev; link_info[1] and link_info[2] are all empty.
Scenario B: MLO STA (Wi-Fi 7, multi-link)
1 | adapter (wlan0) |
One adapter, two vdevs; the user only sees one wlan0, but there are two VDEVs in the firmware.
Scenario C: SAP + STA concurrency
1 | adapter (wlan0, STA) ──> link_info[0] ──> vdev 0 |
Two adapters, each with one vdev. They may sit on different PDEVs (DBS).
Bidirectional lookup
Adapter → VDEV (via link_info):
1 | /* get the vdev of the default link */ |
VDEV → Adapter (via the osdev private pointer):
1 | /* wlan_hdd_main.c */ |
The legacy_osif_priv here is set in hdd_store_vdev_info():
1 | /* wlan_hdd_main.c */ |
So:
1 | link_info->vdev → VDEV |
Creation flow (how Adapter and VDEV get bound)
What is the relationship between Link Info and VDEV?
In one sentence:
Link Info is the “proxy/wrapper” of the VDEV at the HDD layer.
One Link Info corresponds to one VDEV (1:1),
but one Adapter can own multiple Link Infos (1:N).
The 1:1 correspondence
Each link_info holds exactly one vdev pointer, and each VDEV is referenced by exactly one link_info:
Division of responsibility
| Dimension | Link Info (HDD layer) | VDEV (objmgr layer) |
|---|---|---|
| Positioning | Linux adaptation layer | Cross-platform common layer |
| Focus | OS interface, user-visible state | Firmware interaction, protocol state machine |
| Typical data | rssi, snr, stats, session (STA/AP context) |
opmode, mlme_state, bss_chan, peer_list |
| Lifetime | created/destroyed with the adapter | created/destroyed as the interface goes up/down |
| Who creates it | hdd_adapter_init_link_info() |
wlan_objmgr_vdev_obj_create() |
Why does the Link Info layer exist?
Because objmgr is cross-platform (Linux / Android / other OSes can all use it),
it cannot contain Linux-specific things (such as net_device, wireless_dev, cfg80211).
So qcacld uses link_info as the adaptation layer:
- Linux-specific things (
adapter,session) live inlink_info - Generic things (
opmode,mlme_state) live invdev - The two reference each other through pointers
The complete relationship diagram
Putting everything above together:
Lifetime comparison
Different objects are created/destroyed at different times — this is where beginners trip up most easily:
| Object | Created | Destroyed | Trigger function |
|---|---|---|---|
| PSOC | driver probe / firmware ready | driver remove / SSR | wlan_objmgr_psoc_obj_create |
| PDEV | after PSOC creation | when the PSOC is destroyed | wlan_objmgr_pdev_obj_create |
| Adapter | user creates the interface (iw phy ... interface add) |
user deletes the interface | hdd_open_adapter |
| Link Info | when the Adapter is created (array allocated at once) | when the Adapter is destroyed | hdd_adapter_init_link_info |
| VDEV | when the interface goes up | when the interface goes down | hdd_vdev_create / hdd_vdev_destroy |
| PEER | when the connection is established (association/authentication) | when the connection is torn down | wlan_objmgr_peer_obj_create |
Key takeaways:
- Adapter and Link Info are “interface-level”: they exist as long as the interface exists.
- VDEV is “connection-level”: it exists only while the interface is up, and is gone once it goes down.
- Therefore, before accessing
link_info->vdevin code, always check it for NULL!
End-to-end storyline: follow one connection through
The previous sections explained things piece by piece. This section ties them together by following one real user operation and watching how objects get created and referenced layer by layer. This is the fastest way to understand the whole model.
Assume the user runs:
1 | # 1. create the interface (if not yet present) |
The full sequence diagram
Phase-by-phase breakdown
Phase 1: create the interface — only Adapter and Link Info
| Step | Function | Objects produced |
|---|---|---|
user runs iw phy ... interface add |
cfg80211 → hdd_open_adapter() |
net_device + hdd_adapter |
| initialize the link array | hdd_adapter_init_link_info() |
link_info[] (all vdev are NULL) |
Key point: there is no VDEV yet.
adapter->deflink->vdev == NULL.
Phase 2: interface up — create the VDEV and bind both directions
| Step | Function | Notes |
|---|---|---|
user runs ip link set wlan0 up |
cfg80211 → hdd_vdev_create(link_info) |
the argument is link_info, not the adapter |
| create the firmware-side object | sme_vdev_create() → wlan_objmgr_vdev_obj_create() |
creates the VDEV under the PDEV |
| establish the bidirectional pointers | hdd_store_vdev_info(link_info, vdev) |
link_info->vdev = vdev; osdev->legacy_osif_priv = link_info |
Key point: the VDEV only exists after the interface is up. That is why
link_info->vdevmust be null-checked before access.
Phase 3: connect to the AP — create the PEER
| Step | Function | Notes |
|---|---|---|
user runs iw dev wlan0 connect MyAP |
cfg80211 → wlan_hdd_cfg80211_connect() |
cfg80211’s connect callback |
| enter the HDD connect logic | wlan_hdd_cm_connect() |
adapter = netdev_priv(ndev), vdev = adapter->deflink->vdev |
| hand down to UMAC | osif_cm_connect(ndev, vdev, req, params) |
the connection manager starts scanning/authentication/association |
| association succeeds, create the remote | wlan_objmgr_peer_obj_create(vdev, ...) |
the PEER hangs under the VDEV |
| callback notifies HDD | hdd_cm_connect_complete(vdev, rsp) |
updates link_info->session.station and other state |
Key point: the PEER only exists once the connection is established. In STA mode, the PEER is that AP.
Phase 4: disconnect / down — destroy layer by layer
| Step | Function | Notes |
|---|---|---|
iw dev wlan0 disconnect |
wlan_hdd_cm_disconnect() |
destroys the PEER |
ip link set wlan0 down |
hdd_vdev_destroy(link_info) |
destroys the VDEV, link_info->vdev = NULL |
| delete the interface | hdd_close_adapter() |
destroys the Adapter and Link Info |
Remember the chain in one line
1 | User operation iw / ip |
Mnemonic:
Create the interface → Adapter/Link Info exist; up → VDEV exists; connected → PEER exists; down/disconnect → destroyed in reverse order.
A deeper look at MLO (Wi-Fi 7)
MLO is the key to understanding why Link Info exists, so let’s cover it separately.
What is MLO
MLO (Multi-Link Operation) is the core feature of Wi-Fi 7:
a STA can communicate with the AP over multiple links (different bands) simultaneously, aggregating bandwidth and reducing latency.
Object relationships under MLO
Taking MLMR (Multi-Link Multi-Radio) as an example: link 0 rides the 2.4G radio and link 1 rides the 5G radio; each link occupies its own PDEV, so both can transmit and receive at the same time:
MLO modes vs. PDEV: a link is a VDEV-level concept, but every VDEV still has to hang under some PDEV (radio):
- MLMR (Multi-Link Multi-Radio): each link occupies its own PDEV, links TX/RX simultaneously — the figure above;
- MLSR / EMLSR (single radio): all links share the same PDEV; only one link is active at a time (eMLSR lowers latency by fast-switching between links);
- EMLMR (enhanced multi-radio): fewer radios than links; PDEVs are assigned dynamically to links.
wlan_mlo_get_pdev_hw_link_id()/wlan_mlo_get_pdev_by_hw_link_id()in the code are exactly the link ↔ PDEV mapping interfaces.
The three MAC addresses
Under MLO each VDEV has three MAC addresses — don’t mix them up:
| Address | Field | Meaning |
|---|---|---|
| MLD MAC | vdev_mlme.mldaddr |
the “logical address” of the whole MLO connection, visible to upper layers |
| Link MAC | vdev_mlme.linkaddr |
the physical address of each link, visible on the air interface |
| Interface MAC | vdev_mlme.macaddr |
the interface address (equal to linkaddr when not MLO) |
MLO-related constants
1 | /* qcacld-3.0/configs/config_to_feature.h */ |
So the default size of the link_info[] array is 3, i.e. one adapter has at most 3 links.
Cheat sheet & FAQ
One-sentence summary
| Concept | One-sentence explanation | Layer |
|---|---|---|
| PSOC | one Wi-Fi chip | objmgr |
| PDEV | one radio subsystem (radio/PHY) | objmgr |
| VDEV | one virtual interface (VAP) | objmgr |
| PEER | one remote device | objmgr |
| Adapter | one Linux network interface (net_device) | HDD |
| Link Info | the context of one link, connecting Adapter and VDEV | HDD |
Relationship quick reference
1 | PSOC 1 ──< N PDEV |
FAQ
Q1: Are Adapter and VDEV one-to-one?
No. An ordinary interface is 1:1, but an MLO interface is 1:N (one adapter, multiple vdevs).
The precise statement: one Link Info corresponds to one VDEV, and one Adapter corresponds to one or more Link Infos.
Q2: Why is link_info->vdev sometimes NULL?
Because the VDEV is only created when the interface goes up, while Link Info exists as soon as the interface is created.
When the interface goes down, the VDEV is destroyed and link_info->vdev is cleared.
Q3: What is adapter->deflink?
A shortcut for link_info[0]. All code uses it in non-MLO scenarios.
Q4: How do I get from a VDEV to the Adapter?
1 | vdev->vdev_nif.osdev->legacy_osif_priv → link_info |
Q5: How do I get from an Adapter to the PSOC/PDEV?
1 | adapter->hdd_ctx->psoc → PSOC |
Q6: What’s the difference between hdd_context and wlan_objmgr_psoc?
hdd_context is the HDD layer’s global context (containing Linux-specific things such as wiphy, config);
wlan_objmgr_psoc is the objmgr layer’s chip object (cross-platform).
hdd_context holds the psoc and pdev pointers, acting as the bridge between the two layers.
Key code location index
All key code in this article lives in WANG-Guangxin/wlan-driver; the links below are pinned to commit da0ed2c, so they are permanent:
Conclusion
Tying it all together in one sentence:
Userspace sees the Adapter (net_device);
inside the driver, Link Info connects the Adapter to the firmware’s VDEV;
the VDEV hangs under a PDEV, and the PDEV hangs under a PSOC;
each VDEV has several PEERs (remote devices) under it.
Once you understand this object model, the qcacld code becomes much clearer:
when you see adapter, you know it is the Linux interface layer; when you see vdev, you know it is the firmware interaction layer;
when you see link_info, you know it is handling one specific link.


