
WPA是WiFi Protected Access的缩写,中文含义为“WiFi网络安全存取”。WPA是一种基于标准的可互操作的WLAN安全性增强解决方案,可大大增强现有以及未来无线局域网络的数据保护和访问控制水平。
wpa_supplicant是开源项目源码,支持Linux,Windows以及很多嵌入式系统。它是WPA的应用层认证客户端,负责完成认证相关的登录、加密等工作。wpa_supplicant是一个 独立运行的 守护进程,其核心是一个消息循环,在消息循环中处理WPA状态机、控制命令、驱动事件、配置信息等。
经过编译后 的 wpa_supplicant源程序可以看到两个主要的可执行工具:wpa_supplicant 和 wpa_cli。wpa_supplicant是核心程序,它和wpa_cli的关系就是服务和客户端的关系:后台运行wpa_supplicant,使用 wpa_cli来搜索、设置、和连接网络。wpa_supplicant与上层还是wpa_supplicant与驱动都采用socket通讯, 与驱动交互上报数据给用户,而用户可以通过socket发送命令给wpa_supplicant调动驱动来对WiFi芯片操作,如图1所示:

图 1 wpa_supplicant框架
Wpa_supplicant支持AF_INET和AF_UNIX socket两种通信方式:AF_INET socket、AF_UNIX socket。
AF_INET socket通信方式类似于网络socket通信,发送方、接收方依赖IP:Port来标识,即将本地的socket绑定到对应的IP端口上,发送数据时,指定对方的IP端口,经过Internet,可以根据此IP端口最终找到接收方;接收数据时,可以从数据包中获取到发送方的IP端口。发送方通过系统调用send()将原始数据发送到操作系统内核缓冲区中。内核缓冲区从上到下依次经过TCP层、IP层、链路层的编码,分别添加对应的头部信息,经过网卡将一个数据包发送到网络中。经过网络路由到接收方的网卡。网卡通过系统中断将数据包通知到接收方的操作系统,再沿着发送方编码的反方向进行解码,即依次经过链路层、IP层、TCP层去除头部、检查校验等,最终将原始数据上报到接收方进程,通信过程如下图所示:

图 2 AF_INET socket通信过程
AF_UNIX socket通信是典型的本地IPC,类似于管道,依赖路径名标识发送方和接收方。即发送数据时,指定接收方绑定的路径名,操作系统根据该路径名可以直接找到对应的接收方,并将原始数据直接拷贝到接收方的内核缓冲区中,并上报给接收方进程进行处理。同样的接收方可以从收到的数据包中获取到发送方的路径名,并通过此路径名向其发送数据。

图 3 AF_UNIX socket通信过程
他们的相同点:操作系统提供的接口socket(),bind(),connect(),accept(),send(),recv(),以及用来对其进行多路复用事件检测的select(),poll(),epoll()都是完全相同的。收发数据的过程中,上层应用感知不到底层的差别。
不同点:
OpenHarmony的WIFI子系统使用WPA_supplicant实现调动驱动操作WIFI芯片,驱动数据上报给框架层的功能,WPA_supplicant在WIFI子系统的位置如下图的WIFI架构图所示:

图 4 WIFI子系统架构图
WPA Supplicant包含libwpa、libwpa_client库和wpa_cli、wpa_supplicant、hostapd可执行程序。
Wifi HAL层作为硬件适配层,承上启下,对上层框架屏蔽底层硬件差别,为上层提供一致的接口。对下则负责拉起WPAS,即fork进程wifi_hal_service的子进程,在子进程中加载libwpa库,执行wpa_supplicant或hostapd的入口函数, 作为unix socket通信的服务端. Wifi HAL的wifi_hal_service进程是unix socket通信的客户端,通过命令消息下发给wpa_supplicant或hostapd。
Wifi HAL拉起wpa_supplicant或hostapd并建立unix socket连接过程如下图所示:

图 5 Wifi HAL与wpa_supplicant unix socket建立过程
其中HAL拉起wpas的主要实现函数为StartModuleInternal,代码主干如下
int StartModuleInternal(const char *moduleName, const char *startCmd, pid_t *pProcessId)
{
...
pid_t pid = fork(); // fork子进程
if (pid < 0) {
LOGE("Create wpa process failed!");
return HAL_FAILURE;
}
if (pid == 0) { /* sub process */
prctl(PR_SET_PDEATHSIG, SIGKILL);
pthread_t tid;
int ret = pthread_create(&tid, NULL, WpaThreadMain, (void *)startCmd); // 子进程中创建主线程,线程入口函数WpaThreadMain
...
} else {
...
}
return HAL_SUCCESS;
}子进程的主线程入口函数WpaThreadMain中,加载libwpa动态库,执行主函数wpa_main或ap_main,参数由创建线程时传入的startcmd解析而来。对于Sta和P2p业务,有两个参数分别是配置文件路径、全局控制路径;对于hostapd业务,传入一个参数,即hostapd配置文件路径。
static void *WpaThreadMain(void *p)
{
...
// 加载动态库libwpa
#ifdef OHOS_ARCH_LITE
void *handleLibWpa = dlopen("libwpa.so", RTLD_NOW | RTLD_LOCAL);
#else
#ifdef __aarch64__
void *handleLibWpa = dlopen("/system/lib64/libwpa.z.so", RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE);
#else
void *handleLibWpa = dlopen("/system/lib/libwpa.z.so", RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE);
#endif
#endif
...
if (strcmp(param.argv[0], "wpa_supplicant") == 0) {
func = (int (*)(int, char **))dlsym(handleLibWpa, "wpa_main");
} else {
func = (int (*)(int, char **))dlsym(handleLibWpa, "ap_main");
}
...
// 执行主函数
int ret = func(param.argc, tmpArgv);
LOGD("run wpa_main ret:%{public}d.\n", ret);
if (dlclose(handleLibWpa) != 0) {
LOGE("dlclose libwpa failed.");
return NULL;
}
return NULL;
}Wifi HAL作为客户端建立unix socket连接的主要实现函数WpaCliConnect,通过调用wpa client的函数wpa_ctrl_open建立socket连接,其参数ifname为“/data/service/el1/public/wifi/sockets/wpa/wlan0”。
static int WpaCliConnect(WifiWpaInterface *p)
{
...
int count = WPA_TRY_CONNECT_TIMES;
while (count-- > 0) {
int ret = InitWpaCtrl(&p->wpaCtrl, WPA_CTRL_OPEN_IFNAME);
if (ret == 0) {
LOGI("Global wpa interface connect successfully!");
break;
} else {
LOGE("Init wpaCtrl failed: %{public}d", ret);
}
usleep(WPA_TRY_CONNECT_SLEEP_TIME);
}
if (count <= 0) {
return -1;
}
p->threadRunFlag = 1;
if (pthread_create(&p->tid, NULL, WpaReceiveCallback, p) != 0) {
p->threadRunFlag = 0;
ReleaseWpaCtrl(&p->wpaCtrl);
LOGE("Create monitor thread failed!");
return -1;
}
LOGI("Wpa connect finish.");
return 0;
}
int InitWpaCtrl(WpaCtrl *pCtrl, const char *ifname)
{
...
do {
#ifdef WPA_CTRL_IFACE_UNIX
pCtrl->pRecv = wpa_ctrl_open(ifname);
#else
pCtrl->pRecv = wpa_ctrl_open("global");
#endif
if (pCtrl->pRecv == NULL) {
LOGE("open wpa control recv interface failed!");
break;
}
if (wpa_ctrl_attach(pCtrl->pRecv) != 0) {
LOGE("attach monitor interface failed!");
break;
}
#ifdef WPA_CTRL_IFACE_UNIX
pCtrl->pSend = wpa_ctrl_open(ifname);
#else
pCtrl->pSend = wpa_ctrl_open("global");
#endif
if (pCtrl->pSend == NULL) {
LOGE("open wpa control send interface failed!");
break;
}
flag += 1;
} while (0);
...
return 0;
}本文主要介绍了WPA_supplicant基础及其在分布式软总线子系统WIFI模块的应用 ,着重分析了HAL层与WPA_supplicant之间的unix socket通信机制并贴出主要入口代码,为开发人员维护和扩展功能提供参考。
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub
我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle
一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame
我正在尝试将一个资源属性的默认值设置为另一个属性的值。我正在为我正在构建的tomcat说明书定义一个资源,其中包含以下定义。我想要可以独立设置的“名称”和“服务名称”属性。当未设置服务名称时,我希望它默认为为“名称”提供的任何内容。以下不符合我的预期:attribute:name,:kind_of=>String,:required=>true,:name_attribute=>trueattribute:service_name,:kind_of=>String,:default=>:name注意第二行末尾的“:default=>:name”。当我在Recipe的新block中引用我
目录0专栏介绍1平面2R机器人概述2运动学建模2.1正运动学模型2.2逆运动学模型2.3机器人运动学仿真3动力学建模3.1计算动能3.2势能计算与动力学方程3.3动力学仿真0专栏介绍?附C++/Python/Matlab全套代码?课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);曲线优化(贝塞尔曲线、B样条曲线等)。?详情:图解自动驾驶中的运动规划(MotionPlanning),附几十种规划算法1平面2R机器人概述如图1所示为本文的研究本体——平面2R机器人。对参数进行如下定义:机器人广义坐标
网站的日志分析,是seo优化不可忽视的一门功课,但网站越大,每天产生的日志就越大,大站一天都可以产生几个G的网站日志,如果光靠肉眼去分析,那可能看到猴年马月都看不完,因此借助网站日志分析工具去分析网站日志,那将会使网站日志分析工作变得更简单。下面推荐两款网站日志分析软件。第一款:逆火网站日志分析器逆火网站日志分析器是一款功能全面的网站服务器日志分析软件。通过分析网站的日志文件,不仅能够精准的知道网站的访问量、网站的访问来源,网站的广告点击,访客的地区统计,搜索引擎关键字查询等,还能够一次性分析多个网站的日志文件,让你轻松管理网站。逆火网站日志分析器下载地址:https://pan.baidu.
1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>
文章目录1.自动驾驶实战:基于Paddle3D的点云障碍物检测1.1环境信息1.2准备点云数据1.3安装Paddle3D1.4模型训练1.5模型评估1.6模型导出1.7模型部署效果附录show_lidar_pred_on_image.py1.自动驾驶实战:基于Paddle3D的点云障碍物检测项目地址——自动驾驶实战:基于Paddle3D的点云障碍物检测课程地址——自动驾驶感知系统揭秘1.1环境信息硬件信息CPU:2核AI加速卡:v100总显存:16GB总内存:16GB总硬盘:100GB环境配置Python:3.7.4框架信息框架版本:PaddlePaddle2.4.0(项目默认框架版本为2.3
参考文章搭建文章gitte源码在线体验可以注册两个号来测试演示图:一.整体介绍 介绍SignalR一种通讯模型Hub(中心模型,或者叫集线器模型),调用这个模型写好的方法,去发送消息。 内容有: ①:Hub模型的方法介绍 ②:服务器端代码介绍 ③:前端vue3安装并调用后端方法 ④:聊天室样例整体流程:1、进入网站->调用连接SignalR的方法2、与好友发送消息->调用SignalR的自定义方法 前端通过,signalR内置方法.invoke() 去请求接口3、监听接受方法(渲染消息)通过new signalR.HubConnectionBuilder().on
一、机器人介绍 此处是基于MATLABRVC工具箱,对ABB-IRB-1200型号的微型机械臂进行正逆向运动学分析,并利Simulink工具实现对机械臂进行具有动力学参数的末端轨迹规划仿真,最后根据机械模型设计Simulink-Adams联合仿真。 图1.ABBIRB 1200尺寸参数示意图ABBIRB 1200提供的两种型号广泛适用于各作业,且两者间零部件通用,两种型号的工作范围分别为700 mm 和 900 mm,大有效负载分别为 7 kg 和5 kg。 IRB 1200 能够在狭小空间内能发挥其工作范围与性能优势,具有全新的设计、小型化的体积、高效的性能、易于集成、便捷的接