OpenHarmony标准系统USB网络共享架构与RNDIS工作流程分析:从设备枚举到DHCP/NAT通信
OpenHarmony USB 网络共享源码解析:RNDIS 枚举、DHCP 地址分配与 NAT 转发流程
文章由移远通信技术股份有限公司提供。
声明: 以下内容包含了个人理解,仅供参考,如有不合理处,请联系笔者修改
摘要
在 OpenHarmony 标准系统中,USB 网络共享涉及 USB Manager、NetworkShare、DHCP、NetsysController 和 Linux 内核网络协议栈等多个组件。
实际开发中,经常会出现这样一种现象:Windows PC 已经成功识别 USB RNDIS 网络适配器,也能够获取 IPv4 地址,但依然无法访问互联网。
为什么 RNDIS 设备已经枚举成功,网络共享却没有真正生效?OpenHarmony 又是如何协调 USB 功能切换、网络接口创建、DHCP Server、IP Forwarding 和 NAT 的?
本文以 OpenHarmony 公开源码为依据,重点分析 NetworkShareService、NetworkShareTracker、NetworkShareMainStateMachine 和 NetworkShareSubStateMachine 的调用关系,并通过可复现的诊断步骤,建立从 USB 枚举到互联网访问的完整分析链路。
本文不仅介绍各模块的职责,还重点讨论:
- USB 网络共享启动请求如何传递到 USB Manager;
- RNDIS 网络接口创建后,系统如何配置接口地址并启动共享状态机;
- DHCP 地址池如何生成,哪些配置错误会导致启动失败;
- IP 转发、NAT 和接口转发分别负责什么;
- 为什么 DHCP 成功不代表 PC 一定能够访问互联网;
- 如何通过主机命令、设备状态和源码日志逐步定位问题。
关键词: OpenHarmony、RNDIS、USB 网络共享、NetworkShare、DHCP、NAT、IP Forwarding、状态机、源码分析
目录
- 研究背景与源码范围
- USB 网络共享整体架构
- NetworkShare 启动入口及调用链
- USB RNDIS 功能切换与网络接口管理
- 主子状态机设计与事件处理
- DHCP 地址分配与错误分支分析
- IP Forwarding、NAT 与上游网络管理
- 一次完整的网络数据包转发过程
- USB 网络共享故障诊断方法
- 典型问题分析:DHCP 成功却无法联网
- 工程设计特点、风险与适用边界
- 总结
- 参考资料
1. 研究背景与源码范围
1.1 应用场景
假设有一台运行 OpenHarmony 标准系统的设备,当前通过 Wi-Fi 连接互联网。
用户将设备通过 USB 数据线连接到 Windows PC,并希望 PC 使用 OpenHarmony 设备的网络访问互联网。
在典型的 IPv4 网络共享场景中,OpenHarmony 设备承担了网关、DHCP Server 和网络转发节点等角色。
其网络关系如下:
| 设备或接口 | 网络角色 | 主要职责 |
|---|---|---|
| Wi-Fi 路由器 | 上游网络 | 提供外部网络连接 |
| OpenHarmony Wi-Fi 接口 | Upstream | 设备访问互联网的出口 |
| OpenHarmony USB RNDIS 接口 | Downstream | 为 USB 客户端提供网络入口 |
| Windows RNDIS 网卡 | DHCP Client | 获取 IP 并发送网络请求 |
| NetworkShare | 共享业务管理 | 管理共享状态和转发资源 |
| DHCP Server | 地址分配服务 | 为下游客户端提供 IPv4 配置 |
| NAT | 地址转换 | 实现典型 IPv4 共享场景的地址转换 |
这里需要区分两个概念:
Upstream(上游接口) 是提供外部网络连接的接口。
Downstream(下游接口) 是提供网络共享接入的接口。
在本文的例子中,Wi-Fi 是上游,USB RNDIS 是下游。
1.2 为什么 RNDIS 成功不代表网络共享成功?
因为 USB 网络共享至少包含四个相对独立的阶段。
| 阶段 | 成功标志 | 尚不能说明 |
|---|---|---|
| USB 枚举 | Windows 识别 RNDIS 设备 | DHCP 一定正常 |
| 网络接口配置 | RNDIS 接口可用并配置了 IP | PC 已经获得地址 |
| DHCP 通信 | PC 获得有效 IPv4 配置 | NAT 一定生效 |
| 网络转发 | PC 能通过上游访问互联网 | 所有 DNS 和应用访问均正常 |
例如,PC 能够从 DHCP Server 获取 IPv4 地址,说明地址分配相关链路已经能够完成通信。
但 DHCP Server 不负责配置全部 NAT 规则,也不决定设备当前的 Wi-Fi 是否能够上网。
因此,开发者必须分别验证 USB、IPv4、DHCP、路由和网络转发。
1.3 源码研究范围
本文分析以下 OpenHarmony 公共仓库:
网络共享子系统:
https://gitee.com/openharmony/communication_netmanager_ext
网络管理基础组件:
https://gitee.com/openharmony/communication_netmanager_base
DHCP 子系统:
https://gitee.com/openharmony/communication_dhcp
USB Manager:
https://gitee.com/openharmony/usb_usb_manager
重点参考 communication_netmanager_ext 公开 master 分支中 services/networksharemanager 的相关实现,源码核对时间为 2026 年 10 月。
需要说明:本文不将 master 分支直接等同于任何一个具体发布版本。不同 OpenHarmony 版本或产品配置可能存在实现差异。
文中展示的网络地址、诊断场景和预期结果均为教学示例,不涉及客户私有配置,也不代表已经在特定产品上完成实测。
2. USB 网络共享整体架构
2.1 从功能角度划分系统层次
OpenHarmony USB 网络共享可分为三个相互协作的部分。
第一部分:USB 设备功能管理
负责通过 USB Gadget 和 RNDIS 建立设备与 PC 之间的网络数据通道。
第二部分:网络共享业务控制
负责共享请求、共享类型识别、上下游接口管理、状态机切换和相关网络服务编排。
第三部分:网络数据处理
负责 DHCP 地址配置、IP 转发、NAT、路由及实际网络报文传输。
整体调用关系可以概括为:
Application / Settings
|
v
NetworkShareService
|
v
NetworkShareTracker
|
+----------------------+
| |
v v
USB Manager NetworkShare StateMachine
| |
v +---- DHCP Server
USB Gadget |
| +---- NetsysController
v | |
RNDIS Interface | +---- IP Forwarding
| | +---- NAT
v | +---- Routing
Windows PC |
v
Upstream Network
这是一张按模块职责整理的逻辑调用图,不表示每个操作都属于同一个同步函数调用。
2.2 关键源码文件
相关文件位于:
foundation/communication/netmanager_ext/services/networksharemanager/src/
| 文件 | 核心职责 |
|---|---|
networkshare_service.cpp | 服务入口、权限与策略检查 |
networkshare_tracker.cpp | 共享请求分发、接口事件和子状态机管理 |
networkshare_configuration.cpp | 网络共享配置与接口匹配规则 |
networkshare_main_statemachine.cpp | 全局转发、NAT、上游网络管理 |
networkshare_sub_statemachine.cpp | 下游接口状态、DHCP 和转发关系 |
networkshare_upstreammonitor.cpp | 上游网络监控与变化通知 |
阅读源码时,建议先找到请求入口,再沿真实调用链往下追踪,而不是一开始就研究所有状态机实现。
3. NetworkShare 启动入口及调用链
3.1 NetworkShareService:网络共享请求入口
公开源码:
networkshare_service.cpp
核心函数:
NetworkShareService::StartNetworkSharing(int32_t typeInt)
该函数不是直接执行 USB RNDIS 配置,而是先完成访问控制。
通过源码可以归纳出以下处理过程:
- 将传入参数转换为共享类型;
- 检查设备管理策略是否禁止网络共享;
- 检查调用者是否具备系统调用者身份;
- 检查内部网络连接管理权限;
- 将请求交给 NetworkShareTracker;
- 根据调用结果执行后续处理并返回。
其中,关键分发语句为:
int32_t ret = NetworkShareTracker::GetInstance().StartNetworkSharing(type);
这段代码体现了服务层与业务层分离的设计。
Service 主要负责服务入口与访问控制,而具体共享类型的处理交给 Tracker。
需要注意: StartNetworkSharing() 返回成功,不等价于 PC 已经完成 USB 枚举、DHCP 地址获取和互联网通信。
这是因为这些步骤涉及后续设备功能切换、接口事件和网络服务配置。
3.2 NetworkShareTracker:统一管理不同共享类型
核心函数:
NetworkShareTracker::EnableNetSharingInternal()
该函数根据共享类型分发不同逻辑。
| 共享类型 | 对应处理函数 |
|---|---|
| Wi-Fi | SetWifiNetworkSharing() |
| USB | SetUsbNetworkSharing() |
| Bluetooth | SetBluetoothNetworkSharing() |
对于 USB 共享,核心调用为:
result = SetUsbNetworkSharing(enable);
实际函数通过 SharingIfaceType 区分共享方式。
这说明不同网络共享业务可以共用统一的服务入口,但仍保留各自的设备侧处理逻辑。
3.3 Tracker 如何管理重复启动请求?
公开源码中,Tracker 使用 clientRequestsBitMask_ 记录不同共享类型的请求状态。
在 StartNetworkSharing() 中,若检测到对应类型已经存在共享请求,相关实现会先执行关闭操作,再重新启用该类型的共享功能。
这与简单地重复调用“开启接口”不同。
这种设计使框架能够维护不同共享类型的请求状态,并在设备功能切换之前处理已有配置。
此外,在 EnableNetSharingInternal() 中:
- 如果相关功能启用失败,会清理对应的共享请求位;
- 如果启用成功,会调用底层接口更新网络共享类型状态。
因此,Tracker 不只是一个简单的 switch 分发器,还管理着共享请求状态。
3.4 启动调用链总结
从公开源码可以得到以下核心关系:
StartNetworkSharing()
|
v
NetworkShareService
|
v
NetworkShareTracker::StartNetworkSharing()
|
v
EnableNetSharingInternal()
|
v
SetUsbNetworkSharing(true)
|
v
UsbSrvClient::SetCurrentFunctions()
|
v
请求开启 RNDIS 功能
这一阶段主要解决“系统如何请求开启 USB 网络功能”。
网络接口是否真正建立、DHCP 是否启动,还需要结合后续接口事件和状态机执行过程分析。
4. USB RNDIS 功能切换与网络接口管理
4.1 RNDIS 的作用
RNDIS 全称为 Remote Network Driver Interface Specification。
在 USB Device 与 USB Host 之间,RNDIS 提供一种通过 USB 承载网络通信的机制。
对于典型的 Windows PC 与 OpenHarmony 设备连接场景:
- Windows 是 USB Host;
- OpenHarmony 设备是 USB Device;
- 设备向主机暴露 RNDIS 功能;
- 主机在支持该功能并完成驱动绑定后,出现对应网络适配器。
此时,USB 连接具备了承载网络数据的能力。
但实际 IPv4 网络配置仍然需要上层网络服务参与。
4.2 SetUsbNetworkSharing 的关键逻辑
核心函数:
NetworkShareTracker::SetUsbNetworkSharing(bool enable)
公开实现中的 USB 功能切换逻辑受 USB_MODOULE 编译宏控制。这里的宏名称沿用所查看公开源码中的实际拼写。
启用 USB 共享时,主要执行:
- 获取
UsbSrvClient; - 保存当前 USB 功能组合;
- 请求切换为 RNDIS 功能;
- 检查 USB 接口返回值;
- 更新共享相关状态。
核心接口包括:
usbSrvClient.GetCurrentFunctions(previousFuncs_);
usbSrvClient.SetCurrentFunctions(
USB::UsbSrvSupport::FUNCTION_RNDIS);
这两次调用有不同的作用。
GetCurrentFunctions() 用于记录切换前的 USB 功能。
SetCurrentFunctions() 用于请求切换到目标功能。
关闭 USB 共享时,相关实现会尝试使用保存的 previousFuncs_ 恢复此前的功能组合。
这里的关键点是:RNDIS 功能切换和网络共享业务配置属于不同层次。
USB 功能切换成功,不能直接说明 DHCP Server 已经启动。
4.3 USB 功能切换失败会怎样?
源码明确对关键调用的返回值进行了检查。
例如:
| 失败位置 | 影响 | 排查方向 |
|---|---|---|
GetCurrentFunctions() | 无法正常取得当前功能配置 | USB 服务状态与接口响应 |
SetCurrentFunctions() | 无法完成预期功能切换 | USB Manager、Gadget 配置 |
| PC 驱动绑定 | 主机无法正常使用网络适配器 | USB 描述符、主机驱动 |
| 网络接口创建 | 后续网络共享无法获得正常下游接口 | Gadget、网络接口事件 |
这里要特别区分两类问题。
第一类:USB 功能没有成功启用。
应主要检查 USB 服务及底层 Gadget。
第二类:USB 功能已启用,但网络服务未建立。
应继续查看 NetworkShareTracker、接口事件和下游状态机。
4.4 USB 网络接口新增后的实际处理
这是理解 USB 网络共享的一个重要源码点。
在 networkshare_tracker.cpp 中,NetworkShareTracker::InterfaceAdded() 负责处理网络接口新增事件。
它并不是只记录一个接口名称,而是依次进行相关检查:
- 判断接口是否属于有效的共享接口;
- 检查网络共享配置是否可用;
- 根据接口名称识别共享类型;
- 判断当前接口事件是否需要处理;
- 如果属于 USB 共享接口,检查并配置其地址与 UP 状态;
- 异步创建或管理对应下游子状态机。
其中,CheckIfUpUsbIface() 是值得关注的函数。
在公开实现中,它通过:
InterfaceSetIpAddress()
配置 USB 网络接口 IPv4 地址,再通过:
SetInterfaceUp()
请求将网络接口置为 UP。
如果配置 IPv4 地址或将接口置 UP 失败,函数会返回失败,接口新增处理不会继续执行正常的子状态机创建步骤。
这说明:PC 已经完成 RNDIS 枚举后,设备侧还需要处理网络接口地址及接口状态。
因此,如果 PC 上能够看到 RNDIS 网卡,但无法正常获取 IPv4 地址,不能只检查 DHCP Server,还应检查这个更早的接口配置阶段。
4.5 事件与共享管理之间的关系
公开代码还包含:
OnInterfaceAdded()OnInterfaceRemoved()OnInterfaceChanged()OnInterfaceLinkStateChanged()
这些接口事件使网络共享框架能够感知网络设备的变化。
例如,USB 接口创建之后,相关回调可以驱动下游状态机建立;当接口被移除时,框架需要进入对应的停止或清理流程。
这也是网络共享采用事件驱动设计的原因之一。
5. 主子状态机设计与事件处理
5.1 为什么网络共享需要状态机?
USB 网络共享运行期间可能遇到很多异步事件:
- 用户开启共享;
- USB 接口新增;
- 网络接口断开;
- 上游 Wi-Fi 连接成功;
- 上游网络丢失;
- 用户停止共享;
- IP 转发配置失败。
如果只使用一个函数串行执行所有步骤,难以处理这些事件的不同顺序和重复发生的问题。
因此,OpenHarmony NetworkShare 使用主状态机和子状态机分别管理不同层次的网络资源。
5.2 主状态机:管理全局共享资源
核心文件:
networkshare_main_statemachine.cpp
主要状态包括:
| 状态 | 含义 |
|---|---|
MAINSTATE_INIT | 初始状态 |
MAINSTATE_ALIVE | 活动状态 |
MAINSTATE_ERROR | 错误状态 |
主状态机重点管理:
- 全局 IP 转发;
- 上游网络选择;
- NAT 配置;
- 上游变化事件;
- 全局共享错误。
例如,下游接口需要共享网络时,主状态机可能从 INIT 进入 ALIVE,并配置全局共享能力。
5.3 子状态机:管理具体下游接口
核心文件:
networkshare_sub_statemachine.cpp
主要状态包括:
| 状态 | 含义 |
|---|---|
SUBSTATE_INIT | 接口初始状态 |
SUBSTATE_SHARED | 接口共享状态 |
SUBSTATE_UNAVAILABLE | 接口不可用状态 |
在公开的 CreateInitStateTable() 和 CreateSharedStateTable() 中,可以看到事件与状态处理函数之间的对应关系。
例如:
| 当前状态 | 事件 | 处理逻辑 | 目标状态 |
|---|---|---|---|
| INIT | CMD_NETSHARE_REQUESTED | HandleInitSharingRequest | SHARED |
| INIT | CMD_INTERFACE_DOWN | HandleInitInterfaceDown | UNAVAILABLE |
| SHARED | CMD_NETSHARE_UNREQUESTED | HandleSharedUnrequest | INIT |
| SHARED | CMD_INTERFACE_DOWN | HandleSharedInterfaceDown | UNAVAILABLE |
| SHARED | CMD_NETSHARE_CONNECTION_CHANGED | HandleSharedConnectionChange | 保持或由处理逻辑决定 |
具体状态转换还可能受到处理函数内部逻辑和错误路径的影响,上表反映的是公开状态事件表中的主要关系。
5.4 主子状态机如何协作?
可以按照职责理解:
主状态机:
负责判断是否需要全局网络转发,以及当前使用哪个上游网络。
子状态机:
负责某个下游接口的地址分配、共享状态和转发关系。
例如,USB RNDIS 接口进入共享状态后,子状态机需要维护该接口相关的网络配置。
主状态机则关注 Wi-Fi 等上游网络是否可用。
这种设计有利于多个下游接口共享同一个上游网络,同时保持各自的生命周期相对独立。
5.5 上游变化时如何处理?
公开源码中:
NetworkShareMainStateMachine::HandleAliveUpstreamMonitorCallback()
会根据上游网络事件采取不同操作。
主要包括:
- 上游连接属性发生变化;
- 上游网络丢失;
- 网络能力变化;
- 默认网络发生切换。
例如,在上游丢失时,主状态机会执行关闭旧转发关系的相关处理。
在默认网络切换时,会执行旧转发清理并重新选择上游网络。
对子状态机而言,HandleSharedConnectionChange() 会处理新的上游网络信息。
当收到的上游网络信息为空时,会清理当前上游接口相关资源。
这表明网络共享框架并不是简单地把 USB 接口固定绑定到某张 Wi-Fi 网卡,而是需要根据系统网络状态进行动态管理。
6. DHCP 地址分配与错误分支分析
6.1 DHCP 在 USB 网络共享中的作用
当 Windows PC 识别到 RNDIS 网络适配器之后,如果使用自动获取 IP 地址模式,通常会通过 DHCP 获取网络参数。
典型的 DHCPv4 首次地址申请过程包括:
- Discover:客户端寻找 DHCP Server;
- Offer:服务器提供可用地址;
- Request:客户端请求使用地址;
- ACK:服务器确认地址租约。
但需要注意:续租或重新连接等场景不一定执行完整的四个阶段。
6.2 DHCP 配置入口
在公开源码中,下游状态机通过:
ConfigureShareDhcp(bool enabled)
管理 DHCP 的启动和停止。
当 enabled 为 true 时,主要逻辑为:
- 调用
RequestIpv4Address()获取配置; - 判断地址是否有效;
- 根据共享类型确定 DHCP 启动方式;
- 调用
StartDhcp()。
当 enabled 为 false 时,则通过相应逻辑停止 DHCP。
6.3 USB DHCP 地址从哪里来?
在 RequestIpv4Address() 中,代码根据共享类型选择不同配置。
例如:
| 共享类型 | 地址配置来源 |
|---|---|
| Wi-Fi | GetWifiHotspotIpv4Addr() |
| USB | GetUsbRndisIpv4Addr() |
| Bluetooth | GetBtpanIpv4Addr() |
USB 类型还会获取对应的 DHCP Server 名称。
获取配置之后,函数会检查:
- 配置对象是否有效;
- 子网掩码是否为空;
- IPv4 地址及 DHCP Server 名称是否为空;
- IPv4 地址格式是否有效。
IPv4 地址合法性检查使用了标准的 inet_pton() 机制。
这意味着即使 RNDIS 网络接口已经存在,如果 DHCP 所依赖的地址配置错误,仍然可能导致共享流程失败。
6.4 StartDhcp 如何计算地址范围?
核心函数:
NetworkShareSubStateMachine::StartDhcp()
该函数包含值得分析的地址池构建过程。
在公开实现中,函数首先取得下游设备地址、子网掩码以及 DHCP 地址范围参数。
然后,它根据接口 IPv4 地址的最后一个字节,计算地址池起始地址。
例如,假设下游接口 IPv4 为:
192.168.50.1
按照该代码中的生成思路,地址池的候选起点为:
192.168.50.2
但地址池终点仍然由网络共享配置决定,不应直接假设为 192.168.50.254。
这一实现还包含参数检查:
- IPv4 地址不能缺少最后一个分隔点;
- 最后一个地址段必须能转换为有效数字;
- 地址加一不能超过相关范围限制;
- 地址范围配置必须有效。
因此,DHCP 启动之前,除了检查接口是否存在,还要确认地址池配置是否合理。
6.5 DHCP Server 的关键调用
地址范围构建成功后,函数依次执行:
SetDhcpRange(ifaceName_.c_str(), &range);
StartDhcpServer(ifaceName_.c_str());
第一步负责配置 DHCP 地址范围。
第二步负责请求启动 DHCP Server。
公开实现还分别检查这两步的返回值。
特别需要注意:
StartDhcpServer() 返回成功,只能证明该调用成功完成了相应处理,不能单独证明 Windows PC 已经获得有效租约。
是否真正完成地址分配,需要同时检查 PC 的 IPv4 配置和 DHCP 通信行为。
6.6 DHCP 失败原因汇总
| 失败位置 | 可能影响 | 优先检查 |
|---|---|---|
| 地址配置对象不存在 | 无法获取 DHCP 参数 | NetworkShareConfiguration |
| IPv4 地址不合法 | 无法构建正确地址配置 | USB 接口 IPv4 |
| 地址范围构建失败 | DHCP 无法正常配置 | 地址池起止范围 |
SetDhcpRange() 失败 | 地址池未正确设置 | DHCP 配置接口 |
StartDhcpServer() 失败 | 服务启动失败 | DHCP Server 状态 |
| 服务已启动但 PC 无地址 | 客户端地址申请未成功 | DHCP 报文、下游链路 |
这一分析说明,DHCP 失败不等于 DHCP Server 本身一定存在缺陷。
问题可能发生在更早的下游接口配置阶段,也可能发生在地址范围构建过程中。
7. IP Forwarding、NAT 与上游网络管理
7.1 IP Forwarding 与 NAT 的区别
在 IPv4 网络共享场景中,IP Forwarding 和 NAT 经常同时出现,但它们并不是同一项功能。
IP Forwarding:
决定系统是否允许根据路由和网络策略,将非本机目标的数据包继续转发。
NAT:
负责按照配置规则转换网络报文中的地址或端口信息。
可以简单理解为:
IP Forwarding 解决“能不能继续转发”。
NAT 解决“共享网络地址如何转换”。
此外,实际数据包能否通过,还取决于路由、接口状态和底层网络策略。
7.2 主状态机如何开启 IP Forwarding?
公开源码:
networkshare_main_statemachine.cpp
核心函数:
TurnOnMainShareSettings()
其中的关键调用为:
NetsysController::GetInstance()
.IpEnableForwarding(netshareRequester_);
该函数会判断全局转发是否已配置。
如果 IpEnableForwarding() 调用失败,会执行相应错误上报,并使主状态机进入错误处理路径。
如果调用成功,则记录转发已经启用的状态。
这体现了主状态机对全局网络转发资源的统一管理。
7.3 NAT 如何配置?
在公开源码的:
ChooseUpstreamNetwork()
中,主状态机会获取当前可用的上游网络信息。
当选择到可用上游接口后,相关实现调用:
NetsysController::EnableNat()
请求配置 NAT。
因此,NAT 的启用依赖上游网络选择,而不仅仅依赖 USB RNDIS 接口是否存在。
值得注意的是,所查看源码中的 NAT 配置失败路径会记录故障信息;不能仅因为主状态机仍处于活动状态,就推断 NAT 已经成功。
7.4 下游与上游接口如何建立转发关系?
子状态机的 HandleConnection() 使用:
IpfwdAddInterfaceForward()
管理下游接口与上游接口的转发关系。
对于典型网络场景,可以理解为:
Windows RNDIS NIC
|
v
OpenHarmony USB Interface
|
v
IP Forwarding / Routing
|
v
NAT
|
v
OpenHarmony Wi-Fi Interface
|
v
Internet
公开实现中,如果 IpfwdAddInterfaceForward() 配置失败,会进入相关错误处理和资源清理逻辑。
因此,排查“PC 获取地址但不能访问外网”的问题时,需要分别确认:
- 上游网络是否可用;
- 全局 IP 转发是否开启;
- NAT 是否配置成功;
- 下游与上游的转发关系是否建立。
其中任何一步出现问题,都可能导致端到端网络通信失败。
7.5 网络切换为什么容易暴露问题?
假设设备原本通过 Wi-Fi 提供 USB 网络共享。
随后 Wi-Fi 断开,系统切换到另一条外部网络。
在这个过程中:
- USB 网络接口可能保持正常;
- PC 的 IPv4 地址可能没有变化;
- PC 仍然能够访问设备网关;
- 但原有的转发关系可能已经不适用。
因此,上游网络变化后,需要重新评估转发关系、NAT 和相关路由资源。
这也解释了为什么某些网络共享故障只在网络切换后出现,而不是每次开启共享都会出现。
8. 一次完整的网络数据包转发过程
8.1 假设网络环境
为了更直观地理解数据流,采用以下示例:
| 参数 | 示例值 |
|---|---|
| 设备 USB IPv4 | 192.168.50.1 |
| PC IPv4 | 192.168.50.2 |
| 子网掩码 | 255.255.255.0 |
| PC 默认网关 | 192.168.50.1 |
| 设备上游接口 | Wi-Fi |
| 目标服务 | https://example.com |
以上均为示例值,实际地址由网络配置决定。
8.2 第一步:客户端建立网络连接
Windows PC 识别 RNDIS 设备,并完成网络接口初始化。
随后通过 DHCP 获得地址及相关网络参数。
如果客户端没有获取有效地址,应优先检查 USB 接口和 DHCP,而不是直接定位 NAT。
8.3 第二步:客户端发送外部网络请求
当 PC 访问外部网站时,会根据本机路由表选择相应的网络出口。
在示例网络中,访问外部 IPv4 网络的数据包会发往默认网关:
192.168.50.1
数据经 RNDIS 通道到达 OpenHarmony USB 网络接口。
8.4 第三步:OpenHarmony 执行网络转发
OpenHarmony 设备根据路由、IP Forwarding 和网络策略决定是否允许该报文转发。
在典型 IPv4 NAT 共享场景中,相关源地址转换会使报文能够通过上游网络继续传输。
具体地址转换由底层网络配置执行,而不是由应用层手工修改每一个 IP 数据包。
8.5 第四步:外部响应返回客户端
外部服务器返回响应后,设备依据连接跟踪、地址转换及路由状态,将对应响应发送回下游 PC。
最终,Windows 上的应用程序能够获得网络响应。
从这个过程可以看出:
端到端网络访问不仅依赖接口是否 UP,还依赖地址、路由、转发、NAT 和上游网络共同满足条件。
9. USB 网络共享故障诊断方法
本节给出一套可复用的诊断方法,按照 USB、IPv4、DHCP、转发和 DNS 的顺序检查。
9.1 第一步:确认 Windows 是否识别 RNDIS
在 Windows PowerShell 中执行:
Get-NetAdapter
检查是否存在对应的 USB 网络适配器。
还可以执行:
Get-NetIPConfiguration
查看网络接口的 IPv4 地址、默认网关和 DNS 信息。
判断原则:
如果 Windows 未识别对应网络适配器,应首先检查 USB 枚举和驱动绑定,不应直接修改 DHCP。
9.2 第二步:检查客户端 IPv4 配置
Windows 执行:
ipconfig /all
重点关注:
- IPv4 Address;
- Subnet Mask;
- Default Gateway;
- DHCP Enabled;
- DNS Servers。
如果获得 169.254.x.x 自动配置地址,应检查 DHCP 是否真正完成,同时排除客户端静态配置、地址冲突和网络策略等因素。
9.3 第三步:检查设备 USB 网络接口
在具备相应 shell 权限和工具的设备上执行:
ifconfig -a
也可使用:
ip addr
重点检查:
- RNDIS 对应网络接口是否存在;
- 接口是否处于 UP 状态;
- 接口是否配置了预期 IPv4 地址;
- 接口地址与 DHCP 配置是否一致。
如果接口不存在,应返回 USB Gadget 和接口创建阶段。
如果接口存在但没有正确地址,应检查 CheckIfUpUsbIface()、NetworkShareConfiguration 和相关网络管理接口。
9.4 第四步:检查设备的 IP Forwarding 状态
在权限允许的设备上执行:
cat /proc/sys/net/ipv4/ip_forward
对于使用标准 Linux IPv4 转发开关的环境:
1:内核 IPv4 转发已开启;0:内核 IPv4 转发未开启。
但这里有一个重要限制:
IP Forwarding 开启不等于 NAT 已经成功。
即使读取结果为 1,仍然需要检查上游选择、路由、接口转发和 NAT 配置。
9.5 第五步:检查上游网络和路由
如果设备包含相应网络工具,可以执行:
ip route
或者:
cat /proc/net/route
重点检查:
- 是否存在正确的上游路由;
- 当前默认路由使用哪个接口;
- 上游网络是否实际连通;
- 路由是否在网络切换后更新。
不要仅通过设备显示“Wi-Fi 已连接”就判断上游网络正常,还应结合实际连接测试。
9.6 第六步:检查 DNS
Windows 执行:
nslookup example.com
如果外部 IP 通信正常,但域名解析失败,应进一步检查:
- DHCP 下发的 DNS 参数;
- PC 实际使用的 DNS 服务器;
- 设备侧 DNS 处理能力;
- 上游 DNS 是否可访问。
注意,单独使用 ping 并不能充分证明所有应用协议的连通性,因为部分网络或服务器可能限制 ICMP。
9.7 推荐的排查顺序
| 检查层次 | 目标 | 失败时优先检查 |
|---|---|---|
| USB | 主机识别到 RNDIS 功能 | USB Manager、Gadget、驱动 |
| 接口 | 设备下游接口存在且 UP | 接口事件、地址配置 |
| DHCP | PC 获取有效 IPv4 | DHCP 配置、地址池、报文 |
| 局域网 | PC 与共享网关通信 | 路由、接口地址、网络策略 |
| 上游 | 设备可访问外部网络 | 上游接口及路由 |
| 转发 | 下游流量可通过上游 | IP Forwarding、NAT、接口转发 |
| DNS | 域名正常解析 | DNS 配置与解析链路 |
10. 典型问题分析:DHCP 成功却无法联网
这一节不采用未经验证的设备运行日志,而是构造一个明确的诊断场景,展示如何根据真实可观测的信息判断问题范围。
10.1 问题现象
假设 Windows PC 已经识别 RNDIS 网卡,并获得以下网络参数:
IPv4 Address : 192.168.50.2
Subnet Mask : 255.255.255.0
Gateway : 192.168.50.1
DHCP Enabled : Yes
PC 能访问共享设备的网关地址,但无法访问外部互联网。
根据这些信息,可以初步推断:
- RNDIS 接口已经具备一定的数据通信能力;
- 客户端拥有有效的本地 IPv4 配置;
- 下游局域网链路至少部分可用;
- 问题可能位于上游网络、转发、NAT、路由或 DNS。
但这些现象不足以直接锁定某一个具体函数为根因。
10.2 排查阶段一:区分局域网与外网故障
首先检查 PC 与共享设备之间的本地通信。
ping 192.168.50.1
如果设备允许 ICMP 响应,且能够正常收到回复,可以认为当前测试的本地 IPv4 通信路径基本可用。
接着执行:
nslookup example.com
并根据环境测试外部 IP 或 HTTPS 连接。
分析目的:
把故障范围从 USB 连接和 DHCP,缩小到外部网络转发或域名解析。
10.3 排查阶段二:检查设备自身是否能联网
在 OpenHarmony 设备侧确认上游网络是否可用。
例如,检查当前默认路由和上游接口状态。
如果设备自身无法访问外部网络,首先应排查上游网络。
如果设备自身可以访问互联网,但 PC 不可以,则继续分析网络共享转发链路。
这一阶段可以避免在上游已经断网的情况下,反复修改 DHCP 配置。
10.4 排查阶段三:检查全局 IP 转发
使用:
cat /proc/sys/net/ipv4/ip_forward
如果当前环境使用标准 Linux IPv4 转发开关,并且返回 0,说明该开关未开启。
此时需要进一步检查:
NetworkShareMainStateMachine::TurnOnMainShareSettings()
以及底层 IpEnableForwarding() 的调用结果。
如果已经开启,则继续排查 NAT 和接口转发关系,不能直接认定共享正常。
10.5 排查阶段四:检查 NAT 与接口转发
主要关注两个源码位置。
主状态机:
NetworkShareMainStateMachine::ChooseUpstreamNetwork()
用于选择可用的上游接口,并请求配置 NAT。
子状态机:
NetworkShareSubStateMachine::HandleConnection()
用于处理下游与上游之间的转发关系。
相关错误路径包括:
- NAT 配置失败;
- 接口转发关系建立失败;
- 网络接口加入相关网络失败。
如果上游接口选择正确,但转发关系配置失败,就可能出现 PC 能访问设备网关,却无法正常访问外部网络的现象。
10.6 排查阶段五:检查 DNS
如果通过外部 IP 能够完成业务通信,但域名无法解析,则需要检查 DNS。
此时不应继续盲目修改 USB RNDIS 配置。
可以结合客户端 DNS 信息、设备上游 DNS 状态和相关网络服务配置进行排查。
10.7 问题分析结果如何判断?
综合前面的检查,可以得到以下判断表。
| 观察结果 | 优先判断 | 下一步 |
|---|---|---|
| Windows 没有 RNDIS 网卡 | USB 功能或驱动异常 | 检查枚举、驱动 |
| 有 RNDIS,但没有有效 IPv4 | 下游地址分配异常 | 检查接口、DHCP |
| PC 不能访问网关 | 本地链路或网络策略异常 | 检查接口、地址、路由 |
| PC 能访问网关,设备自身不能上网 | 上游网络异常 | 检查 Wi-Fi、默认路由 |
| 设备能上网,PC 不能访问外部 IP | 共享转发路径异常 | 检查 IP Forwarding、NAT、接口转发 |
| 外部 IP 可访问,域名解析失败 | DNS 方向异常 | 检查 DNS 配置与解析服务 |
| 网络切换后才异常 | 上游变化处理或路由资源问题 | 检查 UpstreamMonitor 与状态机 |
本节的结论不是“某个特定产品一定发生 NAT 故障”,而是建立一条可以逐步验证、排除其他原因的分析路径。
实际根因需要结合运行日志、接口状态和抓包结果进一步确认。
11. 工程设计特点、风险与适用边界
11.1 设计特点一:业务控制与设备功能解耦
NetworkShareService 不直接操作 USB Gadget。
Tracker 通过 USB Manager 请求配置设备功能。
这种分层方式减少了网络共享业务层对具体 USB 控制器实现的直接依赖。
11.2 设计特点二:全局资源与单接口资源分开管理
主状态机管理全局转发和上游网络。
子状态机管理具体下游接口。
这种设计更适合处理多种共享方式、接口事件和上游网络变化。
11.3 设计特点三:使用异步事件维护共享生命周期
RNDIS 网络接口可能在 USB 功能切换后才创建。
上游网络也可能在共享期间发生变化。
因此,状态机需要根据接口事件和上游网络通知维护对应资源,不能假定网络环境始终不变。
11.4 设计特点四:关键操作具有错误处理路径
从公开源码可以看到:
- USB 功能切换检查返回值;
- USB 接口地址配置检查返回值;
- DHCP 地址配置和 Server 启动检查返回值;
- IP Forwarding 失败具有错误状态处理;
- 接口转发失败会执行相关清理操作。
分析源码时,不仅需要看成功路径,也应关注错误路径以及资源是否被释放。
11.5 调试操作的适用边界
本文中的命令主要用于观察系统状态。
不同产品可能存在以下差异:
- 没有预装完整的
ip或tcpdump工具; - 普通 shell 没有读取全部网络状态的权限;
- USB 设备功能由产品配置决定;
- IPv6 共享与 IPv4 NAT 的处理机制不同;
- 主机驱动行为受到 Windows 版本影响;
- 目标 OpenHarmony 分支与公开
master分支存在代码差异。
在产品环境中,不建议为了验证而直接修改 USB 标识符、系统防火墙规则、默认路由或其他可能影响正常业务的配置。
如果确实需要进行修改性实验,应先确认测试范围、操作权限和恢复方法。
11.6 公开技术文章的源码边界
本文引用的关键函数和模块来自公开仓库。
对具体产品的私有修改、客户相关配置以及未公开的适配实现,不应直接用于公开社区文章。
如果需要结合产品调试经验进行补充,应先完成相关保密审核,并只保留允许公开的技术信息。
12. 总结
本文基于 OpenHarmony 公开源码,对 USB 网络共享从启动请求到网络数据转发的主要流程进行了分析。
整体可以归纳为五个阶段。
第一阶段:共享请求进入 NetworkShare。
NetworkShareService 执行访问控制,NetworkShareTracker 负责共享类型分发。
第二阶段:USB Manager 配置 RNDIS 功能。
设备通过 USB 功能切换建立 RNDIS 网络能力,主机识别相应网络适配器。
第三阶段:下游接口进入共享管理。
Tracker 处理接口新增事件,配置 USB 接口地址及 UP 状态,并协调子状态机。
第四阶段:DHCP 与转发资源配置。
子状态机管理下游地址分配和接口转发,主状态机管理上游选择、全局 IP 转发和 NAT。
第五阶段:客户端完成端到端网络通信。
Windows PC 获得有效网络配置后,网络数据经 OpenHarmony 设备转发到上游网络,并接收相应返回流量。
通过源码分析可以得出一个重要结论:
RNDIS 枚举成功、DHCP 地址分配成功和互联网访问成功,是三个不同层次的结果,不能相互替代。
工程排查时应按照:
USB 枚举 → 接口地址与状态 → DHCP → 本地 IPv4 → 上游网络 → IP Forwarding/NAT → DNS 和业务访问
的顺序逐层分析。
这种方法不仅适用于 USB RNDIS 网络共享,也可为其他 OpenHarmony 网络共享问题的分析提供参考。
13. 参考资料
[1] OpenHarmony 网络管理扩展组件
https://gitee.com/openharmony/communication_netmanager_ext
[2] NetworkShareService 公开源码
https://github.com/openharmony/communication_netmanager_ext/blob/master/services/networksharemanager/src/networkshare_service.cpp
[3] NetworkShareTracker 公开源码
https://github.com/openharmony/communication_netmanager_ext/blob/master/services/networksharemanager/src/networkshare_tracker.cpp
[4] NetworkShare 主状态机公开源码
https://github.com/openharmony/communication_netmanager_ext/blob/master/services/networksharemanager/src/networkshare_main_statemachine.cpp
[5] NetworkShare 子状态机公开源码
https://github.com/openharmony/communication_netmanager_ext/blob/master/services/networksharemanager/src/networkshare_sub_statemachine.cpp
[6] NetworkShare 配置管理公开源码
https://github.com/openharmony/communication_netmanager_ext/blob/master/services/networksharemanager/src/networkshare_configuration.cpp
[7] OpenHarmony DHCP 子系统
https://gitee.com/openharmony/communication_dhcp
[8] OpenHarmony USB Manager 子系统
https://gitee.com/openharmony/usb_usb_manager
[9] OpenHarmony 网络管理基础组件
https://gitee.com/openharmony/communication_netmanager_base
版权与使用说明:
本文依据 OpenHarmony 公共仓库的技术实现进行整理,源码片段仅用于技术分析。不同版本的具体行为应以对应版本的公开源码为准。
文中的 IP 地址和故障分析场景均为示例,不涉及具体客户产品的运行日志、私有代码或内部配置。
更多推荐


所有评论(0)