# USBNET功能
***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.***
---
# 功能概述
USBNET是基于USB接口实现网络共享的技术统称,在Linux内核中对应USBNET驱动框架,支持ECM、NCM、RNDIS、MBIM等多种协议。其核心机制是在USB通信中模拟标准网络设备:主机的网络协议栈通过虚拟USB网络适配器与设备相连,设备作为网关将流量转发至移动网络,从而使主机能够通过设备的移动网络访问互联网。
## 基本要素
1. **USB设备:** 蜂窝模块或内置模块的终端设备。作为USB从设备,需实现特定的USB接口类型,向主机声明自身为网络适配器。
2. **主机驱动:** 运行在主机操作系统上的软件,用于识别USB设备并驱动其呈现的网络接口。不同的USBNET协议对应不同的驱动。
3. **网络接口:** 主机操作系统中呈现的虚拟网卡,操作系统通过此接口进行IP配置、路由配置和网络通信。
4. **数据通道:** USB设备与主机之间用于传输网络数据包的逻辑通道,通常通过USB批量传输端点交换数据。
## 流程概述
USBNET流程是指将设备的移动数据连接通过USB桥接并共享给主机的端到端过程,通常包含以下操作步骤:
1. **设备枚举与识别**:设备连接到主机后,主机查询其USB描述符,识别设备所属的设备类(通信设备类或特定厂商类),并加载对应驱动,完成网络适配器的注册。
2. **接口初始化与连接**:驱动与设备进行初始化握手,配置USB端点和通信参数。设备端USBNET服务激活后,开始从移动数据连接读取数据;主机端虚拟网络接口状态变为"已连接"。
3. **IP配置**:主机通过DHCP向设备请求IP配置。设备内嵌的DHCP服务器为主机分配私有IP地址并下发网关地址,主机完成IP和路由配置。
4. **数据包转发**:
**下行**:设备从移动网络接收IP数据包,通过USB通道发送至主机驱动,驱动解包后提交至主机网络协议栈。
**上行**:主机产生的IP数据包经虚拟网络接口和驱动,通过USB发送至设备,再由设备转发至移动网络。
5. **连接断开**:停止USBNET服务时,设备通知主机驱动,驱动将网络接口标记为断开,随后关闭数据通道并释放资源。
**主机接收网络数据:**
```{image} images/image_SMJvbHKvEotuPAxSiPQcVK6PnLc.webp
:width: 2960px
:height: 4628px
:align: center
```
**主机发送数据到网络:**
```{image} images/image_HJp2belklolqlSxBiuKcGOCJnOh.webp
:width: 2960px
:height: 5492px
:align: center
```
## 主要协议对比
| **协议** | **全称** | **性质与描述** | **优点** | **缺点** | **主要适用系统** |
| --- | --- | --- | --- | --- | --- |
| RNDIS | Remote Network Driver Interface Specification | 微软制定的私有协议,通过在USB上封装以太网帧实现通信,已成为Windows事实标准。 | Windows兼容性最佳,即插即用,无需额外安装驱动。 | 协议复杂冗余;在Linux/macOS上需额外驱动或兼容层。 | Windows |
| ECM | Ethernet Control Model | USB-IF官方标准。直接在USB上传输原始以太网帧,协议简洁。 | 跨平台标准,在Linux、macOS和现代Windows上支持良好、稳定。 | 在旧版本Windows上可能需要手动安装驱动。 | Linux,macOS,现代Windows |
| NCM | Network Control Model | CDC ECM的增强版标准。核心改进是支持数据包聚合,将多个IP数据包聚合到一个USB传输中,提升效率。 | 高性能,在大带宽场景下吞吐量和效率显著高于ECM/RNDIS;跨平台兼容性好。 | 协议实现稍复杂,需驱动和设备端同时支持。 | Linux,macOS,现代Windows(尤其适合4G/5G高速场景) |
| MBIM | Mobile Broadband Interface Model | 微软与行业联合制定的现代标准。专为移动宽带设计,在USB上传输原始的、未封装的IP数据包,控制与数据分离。 | 架构现代高效,直接处理IP数据包,开销低;支持丰富的移动网络功能管理;是Windows 8+及5G时代的推荐标准。 | 协议相对复杂;在旧系统或非Windows平台上支持可能有限。 | 现代Windows (8+),5G设备 |
## 数据结构
USBNET的实现依赖以下核心数据结构层次:
- USB描述符层:
设备通过此层向主机声明身份。关键描述符包括设备描述符、配置描述符、接口描述符和端点描述符,它们共同定义了"通信接口类"和"数据接口",后者关联的批量传输端点用于传输网络数据。
- 协议控制消息层(以RNDIS/MBIM为例):
该层提供连接管理和参数协商功能,通过USB控制传输或中断传输端点交换带外控制消息。
**RNDIS:** 使用 *RNDIS_INITIALIZE_MSG*、*RNDIS_QUERY_MSG* 等控制消息。
**MBIM:** 使用 *MBIM_COMMAND_MSG*、*MBIM_COMMAND_DONE* 等结构化消息管理网络功能。
- 网络数据帧层:
传输实际用户网络数据的带内数据通道,封装格式因协议而异:
**RNDIS:** 以太网帧包裹在 *RNDIS_PACKET_MSG* 结构中传输。
**ECM:** 在USB端点上直接传输完整的以太网帧。
**NCM:** 传输NCM传输块,其中聚合了多个IP数据包,效率更高。
**MBIM:** 在USB端点上直接传输原始的IP数据包,无需额外的链路层封装,协议开销较低。
## 网络激活管理
参照:[DataCall拨号](../../%E8%9C%82%E7%AA%9D%E6%97%A0%E7%BA%BF%E7%BD%91%E5%8D%A1/DataCall%E6%8B%A8%E5%8F%B7/DataCall%E6%8B%A8%E5%8F%B7.md)
# USBNET API
## 头文件
*qosa_usbnet.h*
## 函数概览
| **函数** | **说明** |
| --- | --- |
| *qosa_usbnet_get_type()* | 获取USBNET应用协议类型 |
| *qosa_usbnet_set_type()* | 设置USBNET应用协议类型 |
| *qosa_usbnet_set_config()* | 设置USBNET连接配置项 |
| *qosa_usbnet_get_config()* | 获取USBNET连接配置项 |
| *qosa_usbnet_start()* | 启动USBNET连接 |
| *qosa_usbnet_stop()* | 停止USBNET连接 |
## 函数详解
### qosa_usbnet_get_type
- **功能描述**
获取USBNET应用协议类型。
- **函数原型**
```c
qosa_usbnet_err_e qosa_usbnet_get_type(qosa_uint8_t simid, qosa_usbnet_type_e *type)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *simid* | 输入 | qosa_uint8_t | SIM卡ID;范围:0~1
*0*:卡槽1
*1*:卡槽2 |
| *type* | 输出 | *qosa_usbnet_type_e** | 协议类型;详见 [*qosa_usbnet_type_e*](#qosausbnettype_e) |
- **返回值说明**
*QOSA_USBNET_ERR_OK*:函数执行成功
其他值(详见 [*qosa_usbnet_err_e*](#qosausbneterr_e)):函数执行失败
### qosa_usbnet_set_type
- **功能描述**
设置USBNET应用协议类型。
- **函数原型**
```c
qosa_usbnet_err_e qosa_usbnet_set_type(qosa_uint8_t simid, qosa_usbnet_type_e type)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *simid* | 输入 | qosa_uint8_t | SIM卡ID;范围:0~1
*0*:卡槽1
*1*:卡槽2 |
| *type* | 输入 | *qosa_usbnet_type_e* | 协议类型;详见 [*qosa_usbnet_type_e*](#qosausbnettype_e) |
- **返回值说明**
*QOSA_USBNET_ERR_OK*:函数执行成功
其他值(详见 [*qosa_usbnet_err_e*](#qosausbneterr_e)):函数执行失败
```{note}
设置的USBNET应用协议类型在设备重启后生效。
```
### qosa_usbnet_set_config
- **功能描述**
设置USBNET连接配置项。
- **函数原型**
```c
qosa_usbnet_err_e qosa_usbnet_set_config(qosa_uint8_t simid, qosa_usbnet_config_t *config)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *simid* | 输入 | qosa_uint8_t | SIM卡ID;范围:0~1
*0*:卡槽1
*1*:卡槽2 |
| *config* | 输入 | *qosa_usbnet_config_t** | 连接配置项;详见 [*qosa_usbnet_config_t*](#qosausbnetconfig_t) |
- **返回值说明**
*QOSA_USBNET_ERR_OK*:函数执行成功
其他值(详见 [*qosa_usbnet_err_e*](#qosausbneterr_e)):函数执行失败
### qosa_usbnet_get_config
- **功能描述**
获取USBNET连接配置项。
- **函数原型**
```c
qosa_usbnet_err_e qosa_usbnet_get_config(qosa_uint8_t simid, qosa_usbnet_config_t *config)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *simid* | 输入 | qosa_uint8_t | SIM卡ID;范围:0~1
*0*:卡槽1
*1*:卡槽2 |
| *config* | 输出 | *qosa_usbnet_config_t** | 连接配置项;详见 [*qosa_usbnet_config_t*](#qosausbnetconfig_t) |
- **返回值说明**
*QOSA_USBNET_ERR_OK*:函数执行成功
其他值(详见 [*qosa_usbnet_err_e*](#qosausbneterr_e)):函数执行失败
### qosa_usbnet_start
- **功能描述**
启动USBNET连接,进行网络共享。
- **函数原型**
```c
qosa_usbnet_err_e qosa_usbnet_start(qosa_uint8_t simid, usbnet_callback_t cb, void *ctx)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *simid* | 输入 | qosa_uint8_t | SIM卡ID;范围:0~1
*0*:卡槽1
*1*:卡槽2 |
| *cb* | 输入 | *usbnet_callback_t* | 启动USBNET连接,返回状态的回调函数 |
| *ctx* | 输入 | void * | 回调函数上下文 |
- **返回值说明**
*QOSA_USBNET_ERR_OK*:函数执行成功
其他值(详见 [*qosa_usbnet_err_e*](#qosausbneterr_e)):函数执行失败
### qosa_usbnet_stop
- **功能描述**
停止USBNET连接,断开网络共享。
- **函数原型**
```c
qosa_usbnet_err_e qosa_usbnet_stop(qosa_uint8_t simid, usbnet_callback_t cb, void *ctx)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *simid* | 输入 | qosa_uint8_t | SIM卡ID;范围:0~1
*0*:卡槽1
*1*:卡槽2 |
| *cb* | 输入 | *usbnet_callback_t* | 停止USBNET连接,返回状态的回调函数 |
| *ctx* | 输入 | void * | 回调函数上下文 |
- **返回值说明**
*QOSA_USBNET_ERR_OK*:函数执行成功
其他值(详见 [*qosa_usbnet_err_e*](#qosausbneterr_e)):函数执行失败
#### usbnet_callback_t
- **函数原型**
```c
typedef void (*usbnet_callback_t)(void *ctx, void *argv);
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *ctx* | 输入 | void * | 用户上下文指针 |
| *argv* | 输入 | void * | 回调参数指针 |
## 结构体定义
### qosa_usbnet_config_t
配置USBNET连接参数的结构体定义如下:
```c
typedef struct
{
qosa_uint8_t simid;
qosa_uint8_t pdpid;
qosa_usbnet_method_e method;
} qosa_usbnet_config_t;
```
| **参数** | **类型** | **说明** |
| --- | --- | --- |
| *simid* | qosa_uint8_t | SIM卡ID;范围:0~1
*0*:卡槽1
*1*:卡槽2 |
| *pdpid* | qosa_uint8_t | PDP ID;范围:1~15 |
| *method* | *qosa_usbnet_method_e* | 连接方式;详见 [*qosa_usbnet_method_e*](#qosausbnetmethod_e) |
```{note}
仅当连接方式(*method*)为 *0* 时,配置文件ID(*pdpid*)才允许设置为 *0*。
```
## 枚举定义
### qosa_usbnet_type_e
协议类型枚举定义如下:
```c
typedef enum
{
QOSA_USBNET_TYPE_ECM = 1,
QOSA_USBNET_TYPE_MBIM = 2,
QOSA_USBNET_TYPE_RNDIS = 3,
QOSA_USBNET_TYPE_NCM = 5,
} qosa_usbnet_type_e;
```
| **成员** | **说明** |
| --- | --- |
| *QOSA_USBNET_TYPE_ECM* | ECM协议 |
| *QOSA_USBNET_TYPE_MBIM* | MBIM协议 |
| *QOSA_USBNET_TYPE_RNDIS* | RNDIS协议 |
| *QOSA_USBNET_TYPE_NCM* | NCM协议 |
### qosa_usbnet_method_e
连接方式枚举定义如下:
```c
typedef enum
{
QOSA_USBNET_METHOD_DISABLE = 0,
QOSA_USBNET_METHOD_ONE_SHOT = 1,
QOSA_USBNET_METHOD_AUTO_CONNECT
= 3,
} qosa_usbnet_method_e;
```
| **成员** | **说明** |
| --- | --- |
| *QOSA_USBNET_METHOD_DISABLE* | 禁用 |
| *QOSA_USBNET_METHOD_ONE_SHOT* | 单次连接 |
| *QOSA_USBNET_METHOD_AUTO_CONNECT* | PDP连接断开或上电等情况下USBNET将自动重新连接,重连间隔逐渐增大 |
### qosa_usbnet_err_e
USBNET模块的结果码枚举定义如下:
```c
typedef enum usbnet_err
{
QOSA_USBNET_ERR_OK = 0,
QOSA_USBNET_ERR_OPERATION_NOT_ALLOWED = 3 | QOSA_ERRCODE_USBNET_BASE,
QOSA_USBNET_ERR_OPERATION_NOT_SUPPORTED = 4 | QOSA_ERRCODE_USBNET_BASE,
QOSA_USBNET_ERR_MEMORY_FULL = 20 | QOSA_ERRCODE_USBNET_BASE,
QOSA_USBNET_ERR_MEMORY_FAILURE = 23 | QOSA_ERRCODE_USBNET_BASE,
QOSA_USBNET_ERR_INVALID_PARAM = 53 | QOSA_ERRCODE_USBNET_BASE,
QOSA_USBNET_ERR_EXECUTE = 1 | (QOSA_ERRCODE_USBNET_BASE + QOSA_AT_ERR_OFS),
QOSA_USBNET_ERR_BUSY = 2 | (QOSA_ERRCODE_USBNET_BASE + QOSA_AT_ERR_OFS),
QOSA_USBNET_ERR_ALREADY_CONNECTED = 3 | (QOSA_ERRCODE_USBNET_BASE + QOSA_AT_ERR_OFS),
} qosa_usbnet_err_e;
```
| **成员** | **说明** |
| --- | --- |
| *QOSA_USBNET_ERR_OK* | 操作成功 |
| *QOSA_USBNET_ERR_OPERATION_NOT_ALLOWED* | 操作不被允许 |
| *QOSA_USBNET_ERR_OPERATION_NOT_SUPPORTED* | 操作不被支持 |
| *QOSA_USBNET_ERR_MEMORY_FULL* | 内存已满 |
| *QOSA_USBNET_ERR_MEMORY_FAILURE* | 内存故障 |
| *QOSA_USBNET_ERR_INVALID_PARAM* | 无效参数 |
| *QOSA_USBNET_ERR_EXECUTE* | 操作执行 |
| *QOSA_USBNET_ERR_BUSY* | 模块忙 |
| *QOSA_USBNET_ERR_ALREADY_CONNECTED* | 已连接 |
# 应用逻辑流程图
```{image} images/board_QinCw2MxyhuoQobsmRkcRh6Unbb.jpg
:width: 789px
:height: 1471px
:align: center
```
# 示例代码
完整示例代码请查看https://github.com/UniRTOS/UniRTOS-Doc-Examples/blob/main/network/nic/usbnet/usbnet_demo.c