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、状态机、源码分析


目录

  1. 研究背景与源码范围
  2. USB 网络共享整体架构
  3. NetworkShare 启动入口及调用链
  4. USB RNDIS 功能切换与网络接口管理
  5. 主子状态机设计与事件处理
  6. DHCP 地址分配与错误分支分析
  7. IP Forwarding、NAT 与上游网络管理
  8. 一次完整的网络数据包转发过程
  9. USB 网络共享故障诊断方法
  10. 典型问题分析:DHCP 成功却无法联网
  11. 工程设计特点、风险与适用边界
  12. 总结
  13. 参考资料

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 接口可用并配置了 IPPC 已经获得地址
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 配置,而是先完成访问控制。

通过源码可以归纳出以下处理过程:

  1. 将传入参数转换为共享类型;
  2. 检查设备管理策略是否禁止网络共享;
  3. 检查调用者是否具备系统调用者身份;
  4. 检查内部网络连接管理权限;
  5. 将请求交给 NetworkShareTracker;
  6. 根据调用结果执行后续处理并返回。

其中,关键分发语句为:

int32_t ret = NetworkShareTracker::GetInstance().StartNetworkSharing(type);

这段代码体现了服务层与业务层分离的设计。

Service 主要负责服务入口与访问控制,而具体共享类型的处理交给 Tracker。

需要注意: StartNetworkSharing() 返回成功,不等价于 PC 已经完成 USB 枚举、DHCP 地址获取和互联网通信。

这是因为这些步骤涉及后续设备功能切换、接口事件和网络服务配置。

3.2 NetworkShareTracker:统一管理不同共享类型

核心函数:

NetworkShareTracker::EnableNetSharingInternal()

该函数根据共享类型分发不同逻辑。

共享类型对应处理函数
Wi-FiSetWifiNetworkSharing()
USBSetUsbNetworkSharing()
BluetoothSetBluetoothNetworkSharing()

对于 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 共享时,主要执行:

  1. 获取 UsbSrvClient;
  2. 保存当前 USB 功能组合;
  3. 请求切换为 RNDIS 功能;
  4. 检查 USB 接口返回值;
  5. 更新共享相关状态。

核心接口包括:

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() 负责处理网络接口新增事件。

它并不是只记录一个接口名称,而是依次进行相关检查:

  1. 判断接口是否属于有效的共享接口;
  2. 检查网络共享配置是否可用;
  3. 根据接口名称识别共享类型;
  4. 判断当前接口事件是否需要处理;
  5. 如果属于 USB 共享接口,检查并配置其地址与 UP 状态;
  6. 异步创建或管理对应下游子状态机。

其中,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() 中,可以看到事件与状态处理函数之间的对应关系。

例如:

当前状态事件处理逻辑目标状态
INITCMD_NETSHARE_REQUESTEDHandleInitSharingRequestSHARED
INITCMD_INTERFACE_DOWNHandleInitInterfaceDownUNAVAILABLE
SHAREDCMD_NETSHARE_UNREQUESTEDHandleSharedUnrequestINIT
SHAREDCMD_INTERFACE_DOWNHandleSharedInterfaceDownUNAVAILABLE
SHAREDCMD_NETSHARE_CONNECTION_CHANGEDHandleSharedConnectionChange保持或由处理逻辑决定

具体状态转换还可能受到处理函数内部逻辑和错误路径的影响,上表反映的是公开状态事件表中的主要关系。

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 首次地址申请过程包括:

  1. Discover:客户端寻找 DHCP Server;
  2. Offer:服务器提供可用地址;
  3. Request:客户端请求使用地址;
  4. ACK:服务器确认地址租约。

但需要注意:续租或重新连接等场景不一定执行完整的四个阶段。

6.2 DHCP 配置入口

在公开源码中,下游状态机通过:

ConfigureShareDhcp(bool enabled)

管理 DHCP 的启动和停止。

当 enabled 为 true 时,主要逻辑为:

  1. 调用 RequestIpv4Address() 获取配置;
  2. 判断地址是否有效;
  3. 根据共享类型确定 DHCP 启动方式;
  4. 调用 StartDhcp()。

当 enabled 为 false 时,则通过相应逻辑停止 DHCP。

6.3 USB DHCP 地址从哪里来?

在 RequestIpv4Address() 中,代码根据共享类型选择不同配置。

例如:

共享类型地址配置来源
Wi-FiGetWifiHotspotIpv4Addr()
USBGetUsbRndisIpv4Addr()
BluetoothGetBtpanIpv4Addr()

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 IPv4192.168.50.1
PC IPv4192.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

重点检查:

  1. RNDIS 对应网络接口是否存在;
  2. 接口是否处于 UP 状态;
  3. 接口是否配置了预期 IPv4 地址;
  4. 接口地址与 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接口事件、地址配置
DHCPPC 获取有效 IPv4DHCP 配置、地址池、报文
局域网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 地址和故障分析场景均为示例,不涉及具体客户产品的运行日志、私有代码或内部配置。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐