• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# WLAN
2
3
4## 概述
5
6### 功能简介
7
8WLAN(Wireless Local Area Network)作为网络设备的一个重要特性,其驱动的开发也是设备开发过程中不可忽略的一部分。
9在OpenHarmony架构中,基于HDF(Hardware Driver Foundation)驱动框架开发的WLAN驱动模块,具备跨操作系统迁移、自适应器件差异、模块化拼装编译等特性。
10
11### 运作机制
12
13各WLAN设备厂商的驱动开发人员可根据WLAN模块提供的向下、向上的统一接口适配各自的驱动代码:
14
15- 向下统一接口实现的能力包括:建立/关闭WLAN热点、扫描、关联WLAN热点等。
16- 对HDI层向上提供能力包括:设置MAC地址、设置发射功率、获取设备的MAC地址等。
17
18WLAN框架如图1所示,其中WLAN Driver模块主要提供启动加载、配置文件解析、提供总线抽象接口等能力,WLAN Chip Driver模块主要提供MAC子层管理实体等。
19
20  **图1** WLAN框架
21
22  ![image](figures/WLAN框架.png "WLAN框架")
23
24  WLAN Driver框架如图2所示。
25
26  **图2** WLAN Driver框架
27
28  ![zh-cn_image_0000001300092359](figures/zh-cn_image_0000001300092359.png)
29
30WLAN Driver框架主要由如下模块组成:
31
321. WLAN Message:该部件为每个服务单独提供业务接口,每个服务也可依赖其他服务形成组合业务接口,此模块支持在用户态、内核态和MCU环境运行,实现部件间的充分解耦。
33
342. WLAN Configuration Core:WLAN相关的配置文件进行解析。
35
363. AP:AP(Access Point)为WLAN终端提供外部接入入口的设备。
37
384. STA:STA(Station)为接入WLAN系统的终端。
39
405. Mac80211:定义底层驱动相关的MAC层接口。
41
426. Bus:该驱动模块向上提供统一的总线抽象接口。通过向下调用Platform层提供的SDIO接口和封装适配USB、PCIE接口,屏蔽不同内核的差异;通过对不同类型的总线操作进行统一封装,屏蔽不同芯片差异,能够对不同芯片厂商提供完备的总线驱动能力,不同厂商共用此模块接口,从而使厂商的开发更为便捷和统一。
43
447. NetDevice:用于建立专属网络设备,屏蔽不同OS的差异,对WiFi驱动提供统一接口,提供统一的HDF NetDevice数据结构,及其统一管理、注册、去注册能力;对接轻设备及富设备上的Linux的网络设备层。
45
468. NetBuf:该部件为WLAN驱动提供Linux或者LiteOS原生的网络数据缓冲的统一数据结构的封装以及对网络数据的操作接口的封装。
47
489. FlowCtl:流控模块,当数据量过大时按照优先级策略处理数据。
49
5010. HCC-CFG:WLAN相关参数配置其中包括板级配置、驱动配置、Module配置。
51
52其中主要模块关系如下:
53
541. WLAN Driver通过HCC-CFG模块和WLAN Configuration Core模块进行配置文件的解析与加载。
55
562. WLAN Message将用户态的消息按组件分发至AP、STA等模块。
57
583. 对于命令字段则下发至Mac80211,再通过Bus模块发送到WLAN芯片固件侧。
59
604. 协议栈与NetDevice模块、NetBuf模块、FlowCtl模块共同协同完成数据流交互。
61
62## 开发指导
63
64### 接口说明
65
66WLAN模块有三部分对外开放的API接口,如下图所示:
67
681. 对上层服务提供HDI以及HAL能力接口。
69
702. 提供给各厂商实现的能力接口。
71
723. 驱动直接调用WLAN模块能力接口。
73
74  **图3** WLAN驱动接口框架图
75
76  ![image](figures/WLAN驱动接口框架图.png "WLAN驱动接口框架图")
77
78
79- WLAN驱动模块对上层服务提供的HAL能力接口(适用于小型系统及轻量系统),主要功能有:创建/销毁 IWiFi对象、设置MAC地址等。提供的部分接口说明如表2、表3所示:
80
81    **表1** wifi_hal.h
82
83  | 接口名称 | 功能描述 |
84  | -------- | -------- |
85  | int32_t WifiConstruct(struct IWiFi \*\*wifiInstance) | 创建IWiFi对象,提供IWiFi基本能力。 |
86  | int32_t WifiDestruct(struct IWiFi \*\*wifiInstance) | 销毁IWiFi对象。 |
87  | int32_t (\*start)(struct IWiFi \*) | 创建HAL和驱动之间的通道及获取驱动支持的网卡信息。 |
88  | int32_t (\*stop)(struct IWiFi \*) | 销毁通道。 |
89
90    **表2** wifi_hal_base_feature.h
91
92  | 接口名称 | 功能描述 |
93  | -------- | -------- |
94  | int32_t (\*getFeatureType)(const struct IWiFiBaseFeature \*) | 获取特性的类型。 |
95  | int32_t (\*setMacAddress)(const struct IWiFiBaseFeature \*, unsigned char \*, uint8_t) | 设置MAC地址。 |
96  | int32_t (\*getDeviceMacAddress)(const struct IWiFiBaseFeature \*, unsigned char \*, uint8_t) | 获取设备持久化的MAC地址。 |
97  | int32_t (\*setTxPower)(const struct IWiFiBaseFeature \*, int32_t) | 设置发射功率。 |
98
99- WLAN驱动模块也提供了需要驱动开发人员自行去填充具体实现内容的能力接口,主要功能有:初始化/注销NetDevice、打开/关闭NetDevice、获取NetDevice的状态等。提供的部分接口说明如表4所示:
100
101    **表3** net_device.h
102
103  | 接口名称 | 功能描述 |
104  | -------- | -------- |
105  | int32_t (\*init)(struct NetDevice \*netDev) | 初始化NetDevice。 |
106  | struct NetDevStats \*(\*getStats)(struct NetDevice \*netDev) | 获取NetDevice的状态。 |
107  | int32_t (\*setMacAddr)(struct NetDevice \*netDev, void \*addr) | 设置Mac地址。 |
108  | void (\*deInit)(struct NetDevice \*netDev) | 注销NetDevice。 |
109  | int32_t (\*open)(struct NetDevice \*netDev) | 打开NetDevice。 |
110  | int32_t (\*stop)(struct NetDevice \*netDev) | 关闭NetDevice。 |
111
112- WLAN驱动模块提供给驱动开发人员可直接调用的能力接口,主要功能有:创建/释放WifiModule、关联/取消关联、申请/释放NetBuf、lwip的pbuf和NetBuf的相互转换等。
113
114  可直接调用的接口如表5、表6和表7所示。
115
116    **表4** wifi_module.h
117
118  | 接口名称 | 功能描述 |
119  | -------- | -------- |
120  | struct WifiModule \*WifiModuleCreate(const struct HdfConfigWifiModuleConfig \*config) | 基于HDF开发WLAN驱动时,创建一个WifiModule。 |
121  | void WifiModuleDelete(struct WifiModule \*module) | 基于HDF开发WLAN驱动时,删除并释放WifiModule所有数据。 |
122  | int32_t DelFeature(struct WifiModule \*module, uint16_t featureType) | 基于HDF开发WLAN驱动时,从WifiModule删除一个功能组件。 |
123  | int32_t&nbsp;AddFeature(struct&nbsp;WifiModule&nbsp;\*module,&nbsp;uint16_t&nbsp;featureType,<br>&nbsp;struct&nbsp;WifiFeature&nbsp;\*featureData) | 基于HDF开发WLAN驱动时,注册一个功能组件到WifiModule。 |
124
125    **表5** wifi_mac80211_ops.h
126
127  | 接口名称 | 功能描述 |
128  | -------- | -------- |
129  | int32_t&nbsp;(\*startAp)(NetDevice&nbsp;\*netDev) | 启动AP。 |
130  | int32_t&nbsp;(\*stopAp)(NetDevice&nbsp;\*netDev) | 停止AP。 |
131  | int32_t&nbsp;(\*connect)(NetDevice&nbsp;\*netDev,&nbsp;WifiConnectParams&nbsp;\*param) | 开始关联。 |
132  | int32_t&nbsp;(\*disconnect)(NetDevice&nbsp;\*netDev,&nbsp;uint16_t&nbsp;reasonCode) | 取消关联。 |
133
134    **表6** hdf_netbuf.h
135
136  | 接口名称 | 功能描述 |
137  | -------- | -------- |
138  | static&nbsp;inline&nbsp;void&nbsp;NetBufQueueInit(struct&nbsp;NetBufQueue&nbsp;\*q) | 初始化NetBuf队列。 |
139  | struct&nbsp;NetBuf&nbsp;\*NetBufAlloc(uint32_t&nbsp;size) | 申请NetBuf。 |
140  | void&nbsp;NetBufFree(struct&nbsp;NetBuf&nbsp;\*nb) | 释放NetBuf。 |
141  | struct&nbsp;NetBuf&nbsp;\*Pbuf2NetBuf(const&nbsp;struct&nbsp;NetDevice&nbsp;\*netdev,&nbsp;struct&nbsp;pbuf&nbsp;\*lwipBuf) | lwip的pbuf转换为NetBuf。 |
142  | struct&nbsp;pbuf&nbsp;\*NetBuf2Pbuf(const&nbsp;struct&nbsp;NetBuf&nbsp;\*nb) | NetBuf转换为lwip的pbuf。 |
143
144### 开发步骤
145#### 厂商适配WLAN框架
146
147WLAN驱动基于HDF框架和Platform框架开发,不区分OS和芯片平台,为不同厂商的WLAN模组提供统一的驱动模型,各WLAN模组厂商根据如下开发流程适配WLAN驱动框架。
148
149**开发流程**
150
1511. 配置硬件(例如module、芯片等)相关的参数。wlan_platform.hcs文件中对参数进行配置后,HDF框架会对该文件进行解析,并生成全量配置的结构体对象。
152
1532. 初始化和去初始化WLAN模块相关适配(如WLAN芯片初始化和去初始化、WLAN芯片驱动初始化和去初始化)。
154
1553. 控制流命令下发的适配。
156
1574. 事件上报的调用。
158
159**开发实例**
160
161本例程提供WLAN模块初始化过程的完整使用流程。示例如下(以Hi3881WLAN芯片为例):
162
1631. Driver的HCS配置。
164
165   HCS文件配置包括:device相关配置和组件配置。
166
167   - device相关配置
168
169     配置文件内容包括:电源配置、复位配置和总线配置。
170
171     配置文件路径:vendor/<厂商名>/<设备名>/hdf_config/khdf/wifi172
173     根据硬件具体情况,在wlan_platform.hcs中配置相关参数,以下是WLAN平台配置的示例:
174        ```text
175        hisi :& deviceList {
176            device0 :: deviceInst {
177                deviceInstId = 0;
178                powers {
179                    power0 {
180                        powerSeqDelay = 0;  /* 电源序列延时 */
181                        powerType = 1;      /* 电源类型,0表示总是打开;1表示GPIO */
182                        gpioId = 1;         /* GPIO管脚号 */
183                        activeLevel=1;      /* 有效电平,0表示低电平有效;1表示高电平有效 */
184                    }
185                    power1 {
186                        powerSeqDelay = 0;  /* 电源序列延时 */
187                        powerType = 0;      /* 电源类型,0表示总是打开;1表示GPIO */
188                    }
189                }
190                reset {
191                    resetType = 0;         /* 复位类型,0表示不管理;1表示GPIO */
192                    gpioId = 2;            /* GPIO管脚号 */
193                    activeLevel=1;         /* 有效电平,0表示低电平有效;1表示高电平有效 */
194                    resetHoldTime = 30;    /* 复位配置后的等待时间(ms) */
195                }
196                bootUpTimeout = 30;  /* 启动超时时间(ms) */
197                bus {
198                    busEnable = 1;   /* bus总线是否初始化,0-表示不初始化; 1表示初始化 */
199                    busType = 0;     /* 总线类型,0表示sdio */
200                    busId = 2;       /* 总线号 */
201                    funcNum = [1];   /* SDIO功能号 */
202                    timeout = 1000;  /* 读/写数据的超时时间 */
203                    blockSize = 512; /* 读/写数据的块大小 */
204                }
205            }
206        }
207        ```
208   - 组件配置
209
210     每一块芯片添加配置文件wlan_chip_<芯片名>.hcs(如:wlan_chip_hi3881.hcs),配置相关参数。以下是hi3881的配置示例:
211        ```text
212        root {
213            wlan_config {
214                hi3881 :& chipList {
215                    chipHi3881 :: chipInst {
216                        match_attr = "hdf_wlan_chips_hi3881";  /* 配置匹配标识 */
217                        chipName = "hi3881";                   /* WLAN芯片的名称 */
218                        bus {
219                            vendorId = 0x0296;    /* 厂商ID */
220                            deviceId = [0x5347];  /* 设备ID */
221                        }
222                    }
223                }
224            }
225        }
226        ```
227
2282. 驱动适配挂接WLAN芯片的初始化和去初始化、WLAN芯片驱动的初始化和去初始化。
229   - 驱动适配入口函数实现
230
231     根据各自的芯片定义一个HdfDriverEntry类型的变量,主要实现Bind、Init、Release接口的函数挂接。调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源。
232     ```c
233     struct HdfDriverEntry g_hdfHisiChipEntry = {
234        .moduleVersion = 1,
235        .Bind = HdfWlanHisiDriverBind,
236        .Init = HdfWlanHisiChipDriverInit,
237        .Release = HdfWlanHisiChipRelease,
238        .moduleName = "HDF_WLAN_CHIPS"
239     };
240
241     HDF_INIT(g_hdfHisiChipEntry);
242     ```
243
244   - 芯片初始化,芯片驱动初始化函数的注册
245
246     InitChip/DeinitChip接口挂接芯片初始化、去初始化的函数实现。
247
248     Build/Release接口挂接芯片驱动的初始化、去初始化函数实现。
249
250     ```c
251     /* WLAN芯片相关函数的注册 */
252     static int32_t HDFWlanRegHisiDriverFactory(void)
253     {
254         static struct HdfChipDriverFactory tmpFactory = { 0 };
255         struct HdfChipDriverManager *driverMgr = NULL;
256         driverMgr = HdfWlanGetChipDriverMgr();
257         if (driverMgr == NULL) {
258             HDF_LOGE("%s fail: driverMgr is NULL!", __func__);
259             return HDF_FAILURE;
260         }
261         tmpFactory.driverName = HI3881_DRIVER_NAME;
262         tmpFactory.GetMaxIFCount = GetHi3881GetMaxIFCount;
263         tmpFactory.InitChip = InitHi3881Chip;
264         tmpFactory.DeinitChip = DeinitHi3881Chip;
265         tmpFactory.Build = BuildHi3881Driver;
266         tmpFactory.Release = ReleaseHi3881Driver;
267         tmpFactory.ReleaseFactory = NULL;
268         if (driverMgr->RegChipDriver(&tmpFactory) != HDF_SUCCESS) {
269             HDF_LOGE("%s fail: driverMgr is NULL!", __func__);
270             return HDF_FAILURE;
271         }
272
273         return HDF_SUCCESS;
274     }
275
276     static int32_t HdfWlanHisiChipDriverInit(struct HdfDeviceObject *device)
277     {
278         (void)device;
279         return HDFWlanRegHisiDriverFactory();
280     }
281     ```
282
283   - 芯片的初始化和去初始化
284     ```c
285     /* WLAN芯片的初始化函数 */
286     int32_t InitHi3881Chip(struct HdfWlanDevice *device)
287     {
288         uint8_t maxPortCount = 3;
289         int32_t ret = HI_SUCCESS;
290         uint8_t maxRetryCount = 3;
291         if (device == NULL || device->bus == NULL) {
292             HDF_LOGE("%s:NULL ptr!", __func__);
293             return HI_FAIL;
294         }
295
296         do {
297             if (ret != HI_SUCCESS) {
298                 if (device->reset != NULL && device->reset->Reset != NULL) {
299                     device->reset->Reset(device->reset);
300                 }
301                 HDF_LOGE("%s:Retry init hi3881!last ret=%d", __func__, ret);
302             }
303             ret = hi_wifi_init(maxPortCount, device->bus);
304         } while (ret != 0 && --maxRetryCount > 0);
305
306         if (ret != 0) {
307             HDF_LOGE("%s:Init hi3881 driver failed!", __func__);
308             return ret;
309         }
310         return HI_SUCCESS;
311     }
312
313     /* WLAN芯片的去初始化函数 */
314     int32_t DeinitHi3881Chip(struct HdfWlanDevice *device)
315     {
316         (void)device;
317         int32_t ret = hi_wifi_deinit();
318         if (ret != 0) {
319             HDF_LOGE("%s:Deinit failed!ret=%d", __func__, ret);
320         }
321         return ret;
322     }
323     ```
324   - 芯片驱动的初始化和去初始化
325     ```c
326     /* WLAN芯片驱动挂接以及Mac80211与芯片侧的函数挂接 */
327     static struct HdfChipDriver *BuildHi3881Driver(struct HdfWlanDevice *device, uint8_t ifIndex)
328     {
329         struct HdfChipDriver *specificDriver = NULL;
330         if (device == NULL) {
331             HDF_LOGE("%s fail: channel is NULL!", __func__);
332             return NULL;
333         }
334         (void)ifIndex;
335         specificDriver = (struct HdfChipDriver *)OsalMemCalloc(sizeof(struct HdfChipDriver));
336         if (specificDriver == NULL) {
337             HDF_LOGE("%s fail: OsalMemCalloc fail!", __func__);
338             return NULL;
339         }
340         if (memset_s(specificDriver, sizeof(struct HdfChipDriver), 0, sizeof(struct HdfChipDriver)) != EOK) {
341             HDF_LOGE("%s fail: memset_s fail!", __func__);
342             OsalMemFree(specificDriver);
343             return NULL;
344         }
345
346         if (strcpy_s(specificDriver->name, MAX_WIFI_COMPONENT_NAME_LEN, HI3881_DRIVER_NAME) != EOK) {
347             HDF_LOGE("%s fail: strcpy_s fail!", __func__);
348             OsalMemFree(specificDriver);
349             return NULL;
350         }
351         specificDriver->init = Hi3881Init;
352         specificDriver->deinit = Hi3881Deinit;
353
354         HiMac80211Init(specificDriver);
355
356         return specificDriver;
357     }
358
359     /* 释放WLAN芯片驱动 */
360     static void ReleaseHi3881Driver(struct HdfChipDriver *chipDriver)
361     {
362         if (chipDriver == NULL) {
363             return;
364         }
365         if (strcmp(chipDriver->name, HI3881_DRIVER_NAME) != 0) {
366             HDF_LOGE("%s:Not my driver!", __func__);
367             return;
368         }
369         OsalMemFree(chipDriver);
370     }
371
372     /* WLAN芯片驱动的初始化函数 */
373     int32_t Hi3881Init(struct HdfChipDriver *chipDriver, struct NetDevice *netDevice)
374     {
375         hi_u16 mode;
376         int32_t ret;
377         nl80211_iftype_uint8 type;
378         (void)chipDriver;
379         HDF_LOGI("%s: start...", __func__);
380         mode = wal_get_vap_mode();
381         if (mode >= WAL_WIFI_MODE_BUTT) {
382             oam_error_log1(0, 0, "wal_init_drv_netdev:: invalid mode[%d]", mode);
383             return HI_FAIL;
384         }
385         if (mode == WAL_WIFI_MODE_STA) {
386             type = NL80211_IFTYPE_STATION;
387     #ifdef _PRE_WLAN_FEATURE_P2P
388             if (InitNetdev(netDevice, NL80211_IFTYPE_P2P_DEVICE) != HI_SUCCESS) {
389                 return HI_FAIL;
390             }
391     #endif
392         } else if (mode == WAL_WIFI_MODE_AP) {
393             type = NL80211_IFTYPE_AP;
394         } else {
395             oam_error_log1(0, 0, "wal_init_drv_netdev:: invalid mode[%d]", mode);
396             return HI_FAIL;
397         }
398         ret = wal_init_drv_wlan_netdev(type, WAL_PHY_MODE_11N, netDevice);
399         if (ret != HI_SUCCESS) {
400             oam_error_log2(0, OAM_SF_ANY, "wal_init_drv_netdev %s failed.l_return:%d\n", netDevice->name, ret);
401         }
402         return ret;
403     }
404
405     /* WLAN芯片驱动的去初始化函数 */
406     int32_t Hi3881Deinit(struct HdfChipDriver *chipDriver, struct NetDevice *netDevice)
407     {
408         int32_t ret;
409         (void)chipDriver;
410         ret = DeinitNetdev(NL80211_IFTYPE_P2P_DEVICE);
411         if (ret != HI_SUCCESS) {
412             oam_error_log1(0, OAM_SF_ANY, "Hi3881Deinit: DeinitNetdev p2p device fail, ret = %d\n",  ret);
413             return ret;
414         }
415         return wal_deinit_drv_wlan_netdev(netDevice);
416     }
417
418     ```
419
420     在芯片驱动初始化过程中调用netdev的init和add接口进行初始化netdev,并挂接netdev的一些函数指针。
421
422     ```c
423     hi_s32 wal_init_drv_wlan_netdev(nl80211_iftype_uint8 type, wal_phy_mode mode, oal_net_device_stru *netdev)
424     {
425         hi_char *ac_mode_str = NULL;
426         hi_s32 ret;
427         if (oal_unlikely(netdev == HI_NULL)) {
428             oam_error_log0(0, OAM_SF_ANY, "{netdev is null!}");
429             return HI_ERR_CODE_PTR_NULL;
430         }
431
432         do {
433             /* 初始化网络设备。 */
434             ret = wal_init_netdev(type, netdev);
435             if (ret != HI_SUCCESS) {
436                 break;
437             }
438
439             ret = wal_init_netif(type, netdev);
440             if (ret != HI_SUCCESS) {
441                 break;
442             }
443             ac_mode_str = "11bgn";
444             if (mode == WAL_PHY_MODE_11G) {
445                 ac_mode_str = "11bg";
446             } else if (mode == WAL_PHY_MODE_11B) {
447                 ac_mode_str = "11b";
448             }
449
450             ret = wal_ioctl_set_mode(netdev, ac_mode_str);
451         } while (false);
452
453         if (ret != HI_SUCCESS) {
454             wal_deinit_wlan_vap(netdev);
455             oal_net_unregister_netdev(netdev);
456             oal_net_clear_netdev(netdev);
457             return HI_FAIL;
458         }
459
460         return HI_SUCCESS;
461     }
462
463     /* 挂接netdev的一些函数指针,详细挂接函数请参考NetDeviceInterFace */
464     oal_net_device_ops_stru g_wal_net_dev_ops =
465     {
466        .getStats          = wal_netdev_get_stats,
467        .open               = wal_netdev_open,
468        .stop               = wal_netdev_stop,
469        .xmit         = hmac_bridge_vap_xmit,
470        .ioctl           = wal_net_device_ioctl,
471        .changeMtu         = oal_net_device_change_mtu,
472        .init              = oal_net_device_init,
473        .deInit            = oal_net_free_netdev,
474
475        ......
476
477     };
478
479     hi_s32 wal_init_netif(nl80211_iftype_uint8 type, oal_net_device_stru *netdev, const oal_wireless_dev *wdev)
480     {
481         /* 添加网络设备到协议栈 */
482         hi_u32 ret = NetDeviceAdd(netdev, (Protocol80211IfType)type);
483
484         ......
485
486         return HI_SUCCESS;
487     }
488     ```
489
4903. 命令下发绑定,包括具有公共能力的设置MAC地址、设置发射功率等;STA相关的连接、扫描等;AP相关的启动AP、设置国家码等。
491
492    ```c
493    /* 驱动需要实现的MAC层基本能力的控制接口 */
494    static struct HdfMac80211BaseOps g_baseOps = {
495        .SetMode = WalSetMode,
496        .AddKey = WalAddKey,
497        .DelKey = WalDelKey,
498        .SetDefaultKey = WalSetDefaultKey,
499        .GetDeviceMacAddr = WalGetDeviceMacAddr,
500        .SetMacAddr = WalSetMacAddr,
501        .SetTxPower = WalSetTxPower,
502        .GetValidFreqsWithBand = WalGetValidFreqsWithBand,
503        .GetHwCapability = WalGetHwCapability
504    };
505
506    /* 驱动需要实现的MAC层STA能力的控制接口 */
507    static struct HdfMac80211STAOps g_staOps = {
508        .Connect = WalConnect,
509        .Disconnect = WalDisconnect,
510        .StartScan = WalStartScan,
511        .AbortScan = WalAbortScan,
512        .SetScanningMacAddress = WalSetScanningMacAddress,
513    };
514
515    /* 驱动需要实现的MAC层AP能力的控制接口 */
516    static struct HdfMac80211APOps g_apOps = {
517        .ConfigAp = WalConfigAp,
518        .StartAp = WalStartAp,
519        .StopAp = WalStopAp,
520        .ConfigBeacon = WalChangeBeacon,
521        .DelStation = WalDelStation,
522        .SetCountryCode = WalSetCountryCode,
523        .GetAssociatedStasCount = WalGetAssociatedStasCount,
524        .GetAssociatedStasInfo = WalGetAssociatedStasInfo
525    };
526
527    static struct HdfMac80211P2POps g_p2pOps = {
528        .RemainOnChannel = WalRemainOnChannel,
529        .CancelRemainOnChannel = WalCancelRemainOnChannel,
530        .ProbeReqReport = WalProbeReqReport,
531        .AddIf = WalAddIf,
532        .RemoveIf = WalRemoveIf,
533        .SetApWpsP2pIe = WalSetApWpsP2pIe,
534        .GetDriverFlag = WalGetDriverFlag
535    };
536
537    /* 初始化Mac80211与芯片侧的函数挂接 */
538    void HiMac80211Init(struct HdfChipDriver *chipDriver)
539    {
540        if (chipDriver == NULL) {
541            HDF_LOGE("%s:input is NULL!", __func__);
542            return;
543        }
544        chipDriver->ops = &g_baseOps;
545        chipDriver->staOps = &g_staOps;
546        chipDriver->apOps = &g_apOps;
547        chipDriver->p2pOps = &g_p2pOps;
548    }
549    ```
550
5514. 事件上报接口调用,WLAN框架提供了event事件的上报接口,详情见hdf_wifi_event.c,例:调用HdfWiFiEventNewSta AP上报新关联的某个STA的情况。
552
553    ```c
554    hi_u32 oal_cfg80211_new_sta(oal_net_device_stru *net_device, const hi_u8 *mac_addr, hi_u8 addr_len,
555        oal_station_info_stru *station_info, oal_gfp_enum_uint8 en_gfp)
556    {
557    #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION) && !defined(_PRE_HDF_LINUX)
558        cfg80211_new_sta(net_device, mac_addr, station_info, en_gfp);
559        hi_unref_param(addr_len);
560    #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION) || defined(_PRE_HDF_LINUX)
561        struct StationInfo info = { 0 };
562        info.assocReqIes = station_info->assoc_req_ies;
563        info.assocReqIesLen = station_info->assoc_req_ies_len;
564        HdfWifiEventNewSta(net_device, mac_addr, WLAN_MAC_ADDR_LEN, &info);
565        hi_unref_param(en_gfp);
566        hi_unref_param(addr_len);
567    #endif
568
569        return HI_SUCCESS;
570    }
571    ```
572**调测验证**
573
574驱动开发完成后,在WLAN模块单元测试里面开发自测试用例以及验证WLAN模块基本功能。测试环境采用开发者自测试平台(这里以Hi3516DV300标准系统为例)。
575
5761. 测试验证环境准备。
577
578   - 新建hostapd.conf文件(启动AP配置文件)并将以下内容复制到该文件中。
579
580        ```text
581        interface=wlan0
582        driver=hdf wifi
583        ctrl_interface=udp
584        #WiFi名称
585        ssid=test
586        hw_mode=g
587        channel=1
588        ignore_broadcast_ssid=0
589        wpa=2
590        rsn_pairwise=CCMP
591        # WiFi密码
592        wpa_passphrase=12345678
593        ```
594
595    - 新建wpa_supplicant.conf文件(启动STA配置文件)并将以下内容复制到该文件中。
596
597        ```text
598        country=GB
599
600        network={
601            #热点名称
602            ssid="test"
603            #热点密码
604            psk="12345678"
605        }
606        ```
607
608    - 新建dhcpc.sh文件(将UDHCPC分配的IP地址等写入到设备中)并将以下内容复制到该文件中。
609
610        ```shell
611        #!/system/bin/sh
612        [ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
613
614        RESOLV_CONF="/etc/resolv.conf"
615        [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
616        [ -n "$subnet" ] && NETMASK="netmask $subnet"
617
618        case "$1" in
619            deconfig)
620            /system/bin/ifconfig $interface 0.0.0.0
621            ;;
622
623            renew|bound)
624            /system/bin/ifconfig $interface $ip $BROADCAST $NETMASK
625
626            if [ -n "$router" ] ; then
627                echo "deleting routers"
628                while busybox route del default gw 0.0.0.0 dev $interface ; do
629                :
630                done
631
632                for i in $router ; do
633                busybox route add default gw $i dev $interface
634                done
635            fi
636
637            echo -n > $RESOLV_CONF
638            [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
639            for i in $dns ; do
640                echo adding dns $i
641                echo nameserver $i >> $RESOLV_CONF
642            done
643            ;;
644        esac
645
646        exit 0
647        ```
648
649    - 新建udhcpd.conf文件(启动UDHCPD配置文件)并将以下内容(其中opt dns x.x.x.x x.x.x.x配置了两个DNS服务器地址,开发者可按照实际情况自行配置)复制到该文件中。
650
651        ```text
652        start 192.168.12.2
653        end 192.168.12.100
654        interface wlan0 #default: eth0
655        max_leases 20 #default: 254
656        remaining yes #default: yes
657        auto_time 7200 #default: 7200 (2 hours)
658        decline_time 3600 #default: 3600 (1 hour)
659        conflict_time 3600 #default: 3600 (1 hour)
660        offer_time 60 #default: 60 (1 minute)
661        min_lease 60 #defult: 60
662        lease_file /vendor/etc/udhcpd.leases
663        opt dns x.x.x.x x.x.x.x
664        option subnet 255.255.255.0
665        opt router 192.168.12.1
666        ```
667
668    - 执行下列命令将测试所需文件推送到开发板。
669
670        ```shell
671        hdc shell "mount -o rw,remount /"
672        timeout /T 1
673        hdc file send dhcpc.sh /system/lib/
674        hdc shell "chmod 777 /system/lib/dhcpc.sh"
675        hdc file send wpa_supplicant.conf /
676        hdc shell "mount -o rw,remount /vendor"
677        hdc file send hostapd.conf /
678        hdc file send udhcpd.conf /vendor/etc
679        hdc shell "touch /vendor/etc/udhcpd.leases"
680        hdc shell "chmod 777 /vendor/etc/udhcpd.leases"
681        ```
682
6832. 验证WiFi基本功能。
684
685   - 验证AP基本功能
686
687     1. 开发板启动AP,测试终端(例如手机)打开WiFi开关(设置 -> WLAN -> 打开WiFi开关)。
688
689     2. 使用cmd窗口输入如下命令。
690        ```shell
691        hdc shell
692        hostapd ./hostapd.conf
693        ```
694
695     3. 使用另一个cmd窗口执行下列命令。
696
697        ```shell
698        hdc shell
699        ifconfig wlan0 192.168.12.1 netmask 255.255.255.0
700        busybox udhcpd /vendor/etc/udhcpd.conf
701        ```
702
703     4. 在手机的WiFi列表中找到对应名称为test的网络,并输入密码(网络名称及密码均在在hostapd.conf中进行配置,成功连接后,手机上可看到已连接)。
704
705     5. 使用开发板ping测试终端。
706
707        ```shell
708        busybox ping xxx.xxx.xxx.xxx
709        ```
710
711        上述xxx.xxx.xxx.xxx为当前测试终端的IP地址,若测试能够ping通测试终端则表示,WLAN驱动基本功能正常。
712
713   - 验证STA基本功能
714
715     1. 开发板启动STA,测试终端(例如手机)打开热点(网络名称及密码均在在hostapd.conf中进行配置,热点名称为test,密码为12345678)。
716
717     2. 使用cmd窗口输入如下命令。
718
719        ```shell
720        hdc shell
721        wpa_supplicant -i wlan0 -d -c wpa_supplicant.conf
722        ```
723
724     3. 使用另一个cmd窗口执行下列命令。
725
726        ```shell
727        hdc shell
728        mount -o rw,remount /
729        mount -o rw,remount /vendor
730        busybox udhcpc -i wlan0 -s system/lib/dhcpc.sh
731        ```
732        上述命令执行成功后,回显信息中可以看到单板及测试终端IP地址。
733
734     4. 使用开发板ping测试终端。
735
736        ```shell
737        busybox ping xxx.xxx.xxx.xxx
738        ```
739
740        上述xxx.xxx.xxx.xxx为当前测试终端的IP地址,若测试能够ping通测试终端则表示,WLAN驱动基本功能正常。
741
742#### 接口调用
743WLAN驱动模块向上层提供两种能力接口:HDI接口和HAL接口。
744- HDI接口调用
745
746   HDI接口调用开发步骤(以GetSupportFeature为例):
747
748   1. 使用WlanInterfaceGetInstance获取WLAN服务对象。
749
750   2. 使用Start创建HAL和驱动之间的通道及获取驱动网卡信息。
751
752   3. 通过GetSupportFeature获取该设备支持的WLAN特性。
753
754   4. 调用Stop,销毁HAL和驱动之间的通道。
755
756   5. 执行WlanInterfaceRelease销毁WLAN服务对象。
757
758   HDI接口调用开发实例:
759   ```c
760   #include "v1_0/iwlan_interface.h"
761   #include "wlan_callback_impl.h"
762   #include "wlan_impl.h"
763
764   #define PROTOCOL_80211_IFTYPE_NUM 11
765   #define HDF_SUCCESS 0
766   #define HDF_FAILURE (-1)
767
768   static int32_t hdi_main()
769   {
770       int32_t rc;
771       const char *WLAN_SERVICE_NAME = "wlan_hal_c_service";
772       static struct IWlanInterface *g_wlanObj = NULL;
773       uint8_t supType[PROTOCOL_80211_IFTYPE_NUM + 1] = {0};
774       uint32_t supTypeLen = PROTOCOL_80211_IFTYPE_NUM + 1;
775
776        /* 获取WLAN服务对象。*/
777        g_wlanObj = WlanInterfaceGetInstance(WLAN_SERVICE_NAME);
778        if (g_wlanObj == NULL)
779        {
780            return HDF_FAILURE;
781        }
782
783        /* 创建HAL和驱动之间的通道及获取驱动网卡信息。 */
784        rc = g_wlanObj->Start(g_wlanObj);
785        if (rc != HDF_SUCCESS)
786        {
787            return HDF_FAILURE;
788        }
789
790        /* 获取该设备支持的WLAN特性(不考虑当前的使用状态)。 */
791        rc = g_wlanObj->GetSupportFeature(g_wlanObj, supType, &supTypeLen);
792        if (rc != HDF_SUCCESS)
793        {
794            return HDF_FAILURE;
795        }
796
797        /* 销毁HAL和驱动之间的通道。 */
798        rc = g_wlanObj->Stop(g_wlanObj);
799        if (rc != HDF_SUCCESS)
800        {
801            return HDF_FAILURE;
802        }
803
804        /* 销毁WLAN服务对象。 */
805        rc = WlanInterfaceRelease(g_wlanObj);
806        if (rc != HDF_SUCCESS)
807        {
808            return HDF_FAILURE;
809        }
810        return rc;
811    }
812
813   ```
814
815   HDI接口调用编译:
816
817   1. 编译脚本中添加依赖的库文件:
818
819      ```text
820      deps = [
821        "//drivers/peripheral/wlan/hdi_service:hdi_wlan_service",
822      ]
823      ```
824   2. 编译脚本中添加依赖的头文件:
825      ```text
826      include_dirs = [
827        "//drivers/peripheral/wlan/interfaces/include",
828        "//drivers/peripheral/wlan/hdi_service",
829        "//drivers/peripheral/wlan/client/include",
830        "//drivers/peripheral/wlan/hal/include",
831      ]
832      ```
833   3. 执行编译脚本,确认是否编译OK。
834
835- HAL接口调用
836
837   HAL接口调用开发步骤(需要测试HAL模块指定接口时,可采用下列步骤):
838
839   1. 使用WifiConstruct创建一个WiFi实体。
840
841   2. 用创建的WiFi实体调用start开启HAL和驱动之间的通道,获得驱动网卡的信息。
842
843   3. 通过createFeature创建一个apFeature或者staFeature。后面可通过这些Feature去调用具体的实现接口,下面基于创建的apFeature为例进行介绍。
844
845   4. 调用和使用相关接口:如setMacAddress设置MAC地址、getDeviceMacAddress获取设备的MAC地址等。
846
847   5. 调用destroyFeature,销毁掉创建的apFeature。
848
849   6. 调用stop销毁创建的通道。
850
851   7. 执行WifiDestruct销毁创建的WiFi实体。
852
853   HAL接口调用开发实例:
854
855   ```c
856    #include "wifi_hal.h"
857    #include "wifi_hal_sta_feature.h"
858    #include "wifi_hal_ap_feature.h"
859    #include "wifi_hal_cmd.h"
860
861    #define MAC_LEN 6
862    #define HDF_SUCCESS 0
863    #define HDF_FAILURE (-1)
864
865    static int32_t hal_main()
866    {
867        int32_t ret;
868        struct IWiFi *wifi;
869        struct IWiFiAp *apFeature;
870
871        /* 创建一个wifi实体。 */
872        ret = WifiConstruct(&wifi);
873        if (ret != HDF_SUCCESS || wifi == NULL) {
874            return HDF_FAILURE;
875        }
876
877        /* 开启HAL和驱动之间的通道,获得驱动网卡的信息。 */
878        ret = wifi->start(wifi);
879        if (ret != HDF_SUCCESS) {
880            return HDF_FAILURE;
881        }
882
883        /* 创建apFeature。 */
884        ret = wifi->createFeature(PROTOCOL_80211_IFTYPE_AP, (struct IWiFiBaseFeature **)&apFeature);
885        if (ret != HDF_SUCCESS) {
886            return HDF_FAILURE;
887        }
888
889        /* 获取设备MAC地址。 */
890        unsigned char mac[MAC_LEN] = {0};
891        ret = apFeature->baseFeature.getDeviceMacAddress((struct IWiFiBaseFeature *)apFeature, mac, MAC_LEN);
892        if (ret != HDF_SUCCESS) {
893            return HDF_FAILURE;
894        }
895
896        /* 销毁创建的apFeature。 */
897        ret = wifi->destroyFeature((struct IWiFiBaseFeature *)apFeature);
898        if (ret != HDF_SUCCESS) {
899            return HDF_FAILURE;
900        }
901
902        /* 销毁HAL和驱动之间的通道。 */
903        ret = wifi->stop(wifi);
904        if (ret != HDF_SUCCESS) {
905            return HDF_FAILURE;
906        }
907
908        /* 销毁创建的WiFi实体。 */
909        ret = WifiDestruct(&wifi);
910        if (ret != HDF_SUCCESS) {
911            return HDF_FAILURE;
912        }
913        return ret;
914    }
915   ```
916   HAL接口调用编译:
917   1. 编译脚本中添加依赖的库文件:
918
919      ```text
920      deps = [
921        "//drivers/peripheral/wlan/client:wifi_driver_client",
922        "//drivers/peripheral/wlan/hal:wifi_hal",
923      ]
924      ```
925
926   2. 编译脚本中添加依赖的头文件:
927      ```text
928      include_dirs = [
929        "//drivers/peripheral/wlan/interfaces/include",
930        "//drivers/peripheral/wlan/hdi_service",
931        "//drivers/peripheral/wlan/client/include",
932        "//drivers/peripheral/wlan/hal/include",
933      ]
934      ```
935   3. 执行编译脚本,确认是否编译OK。
936
937
938
939
940## 参考
941
942- 代码仓库如下:
943
944  **[drivers\_hdf\_core](https://gitee.com/openharmony/drivers_hdf_core)**
945
946  [drivers\_peripheral](https://gitee.com/openharmony/drivers_peripheral)
947
948  [drivers\_interface](https://gitee.com/openharmony/drivers_interface)
949
950- 代码路径如下:
951
952  WLAN模块流控组件liteos适配://drivers/hdf_core/adapter/khdf/liteos/model/network/wifi
953
954  HDF网络模型liteos适配://drivers/hdf_core/adapter/khdf/liteos/model/network
955
956  WLAN模块流控组件Linux适配、HDF WLAN模型、VENDOR WLAN驱动编译:
957
958  //drivers/hdf_core/adapter/khdf/linux/model/network/wifi
959
960  WLAN模块实现核心代码://drivers/hdf_core/framework/model/network/wifi
961
962  WLAN模块对外接口://drivers/hdf_core/framework/include/wifi
963
964  HDF网络模型接口://drivers/hdf_core/framework/include/net
965
966  WLAN HDI服务端实现://drivers/peripheral/wlan
967
968