WPA_Supplicant使用及配置
来源:互联网 发布:qq分享组件js代码 编辑:程序博客网 时间:2024/05/03 13:23
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">WPA_Supplicant这个工具的下载和移植都很简单。一般来说,移植后能得到wpa_supplicant和wpa_cli这两个工具</span>
wpa_supplicant运行在后台,使用socket与前台进行数据通信
wpa_cli可以用来进行调试和查看wpa_supplicant的运行,能够帮助我们学习它的命令用法,以及了解返回数据的格式。
不过,我们最终的目的实际上是需要集成wpa_cli的发送接受功能,同时能够处理接收数据的程序。 可以参考里面的参考程序wpa_gui-qt4。
我的项目中对wifi的管理需要以下功能:
1、扫描wifi热点,每个热点需要显示名字和信号强度,必要时可显示加密方法
2、连接指定热点,支持WPA/WPA2/WEP常用加密方法,连接成功后分配IP
3、定期获取并更新wifi信号强度
4、支持wifi开启和关闭
将这些功能封装成wpa_controller的类:
class wpa_controller: public QObject{ Q_OBJECT enum{ WPA_STARTED, WPA_STOP };public: static wpa_controller * Instance() { static wpa_controller* _instance=NULL; if(_instance==NULL) { _instance=new wpa_controller(); JYZ_ASSERT(_instance); } return _instance; } static void ParseFlags(const QString& flag,int& auth,bool &encr); bool IsInited() {return mInited;} bool ImportConfigureFromFile(const char* filename); //从配置文件中导入网络配置参数 QString GetWIFIStatus(); //查询网卡状态 QString GetConnectedSSID(){return mCurrentSSID;} //当前的SSID void Scan(); //发送扫描命令 bool AddNetWork(int auth,int enc,int& ,const char* ssid,const char* key); //添加网络参数 void SelectNetwork(int id=-1); //选择热点 bool RemoveNetWork(QString ssid); //删除网络参数 bool BSS(int,QString&,QString&,QString&,QString&,QString&); //查询热点具体信息 void EnableNetworkInCfg(void); bool Disconnect(); //断开连接 //重启 void Reset(); //开启 bool Start(); //停止 void Stop();signals: //wifi 扫描结果 void wifiScanResultUpdate(); //wifi 链接信息 void wifiConnected(bool connected,int reason,QString bssid); //信号强度信息 void signallevelupdate(quint32 level); private: bool StopWpaSupplicant(); bool StartWpaSupplicant(); bool InstallDriver(); //初始化 bool UninstallDriver(); void timerEvent(QTimerEvent *); bool Ping(); //测试连接,需要定时调用 void Reconfigure(); //重新配置 void updateStatus(); //更新链接状态 void updateNetworks(); //更新连接列表 ~wpa_controller(); wpa_controller(); void EnableNetwork(int id=-1); //使能网络 int ctrlRequest(const QString& cmd, QString&); int setNetworkParam(int id, const char *field,const char *value, bool quote); void processMsg(char *msg); int openCtrlConnection(); private slots: void receiveMsgs(); void resetWifi(); void startWifi(); void stopWifi(); public: QMap<QString,int> WifiHotPotSavedList; private: QString mRequestReply; QSocketNotifier *msgNotifier; struct wpa_ctrl *ctrl_conn; struct wpa_ctrl *monitor_conn; bool mWPSCapable; //是否支持WPS QString mWIFIStatus; //WIFI当前状态 QString mIPAddress; //当前IP地址 QString mBSSID; //BSSID QString mCurrentSSID; //当前连接SSID quint32 mSignalLevel; QMutex m_lock; int mTimerHandle; bool mDriverInstalled; unsigned int mWifiFailCount; bool mInited;};
1、加载好驱动并且开启了网卡
2、建立/var/run/文件夹
3、建立一个或者使用原有的配置文件
这个文件的前两行如下:
ctrl_interface=/var/run/wpa_supplicantupdate_config=1
ctrl_interface指向的是一个目录,在这个目录中默认会生成一个文件/var/run/wpa_supplicant/wlan0,这是local socket address,用于我们的程序和后台程序wpa_supplicant进行通信(我们必须知道wpa_supplicant作为后台服务程序是通过本地socket和客户端进行通信的)
update_config为1时会在特定时候(客户端发送SAVE_CONFIG命令)更新这个配置文件。
B、启动
1、wpa_supplicant后台服务程序
我的项目使用的是wpa_supplicant -Dwext -iwlan0 -c./wpa.conf -qq&
2、openCtrlConnection()
这个接口是演示程序自己封装的,它执行的主要过程是使用wpa_ctrl_open打开两次,获得两个wpa_ctrl变量。这些变量代表着后台服务程序wpa_supplicant,通过这两个变量可以和wpa_supplicant进行通信。不过他们的分工有点不同,一个变量用于客户端主动给服务程序发起命令,另外一个变量用于监控wpa_supplicant的是否有数据发给客户端程序。
wpa_ctrl定义
struct wpa_ctrl {#ifdef CONFIG_CTRL_IFACE_UDPint s;struct sockaddr_in local;struct sockaddr_in dest;char *cookie;char *remote_ifname;char *remote_ip;#endif /* CONFIG_CTRL_IFACE_UDP */#ifdef CONFIG_CTRL_IFACE_UNIXint s;struct sockaddr_un local;struct sockaddr_un dest;#endif /* CONFIG_CTRL_IFACE_UNIX */#ifdef CONFIG_CTRL_IFACE_NAMED_PIPEHANDLE pipe;#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */};
wpa_ctrl_open函数接口
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path){struct wpa_ctrl *ctrl;static int counter = 0;int ret;size_t res;int tries = 0;int flags;ctrl = os_malloc(sizeof(*ctrl));if (ctrl == NULL)return NULL;os_memset(ctrl, 0, sizeof(*ctrl));ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);if (ctrl->s < 0) {os_free(ctrl);return NULL;}ctrl->local.sun_family = AF_UNIX;counter++;try_again:ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), CONFIG_CTRL_IFACE_CLIENT_DIR "/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", (int) getpid(), counter);if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {close(ctrl->s);os_free(ctrl);return NULL;}tries++;if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, sizeof(ctrl->local)) < 0) {if (errno == EADDRINUSE && tries < 2) {/* * getpid() returns unique identifier for this instance * of wpa_ctrl, so the existing socket file must have * been left by unclean termination of an earlier run. * Remove the file and try again. */unlink(ctrl->local.sun_path);goto try_again;}close(ctrl->s);os_free(ctrl);return NULL;}#ifdef ANDROIDchmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);/* * If the ctrl_path isn't an absolute pathname, assume that * it's the name of a socket in the Android reserved namespace. * Otherwise, it's a normal UNIX domain socket appearing in the * filesystem. */if (ctrl_path != NULL && *ctrl_path != '/') {char buf[21];os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);if (socket_local_client_connect( ctrl->s, buf, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM) < 0) {close(ctrl->s);unlink(ctrl->local.sun_path);os_free(ctrl);return NULL;}return ctrl;}#endif /* ANDROID */ctrl->dest.sun_family = AF_UNIX;res = os_strlcpy(ctrl->dest.sun_path, ctrl_path, sizeof(ctrl->dest.sun_path));if (res >= sizeof(ctrl->dest.sun_path)) {close(ctrl->s);os_free(ctrl);return NULL;}if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, sizeof(ctrl->dest)) < 0) {close(ctrl->s);unlink(ctrl->local.sun_path);os_free(ctrl);return NULL;}/* * Make socket non-blocking so that we don't hang forever if * target dies unexpectedly. */flags = fcntl(ctrl->s, F_GETFL);if (flags >= 0) {flags |= O_NONBLOCK;if (fcntl(ctrl->s, F_SETFL, flags) < 0) {perror("fcntl(ctrl->s, O_NONBLOCK)");/* Not fatal, continue on.*/}}return ctrl;}
从上面可以看出打开的操作实际上就是给wpa_ctrl这个结构体赋值的过程,这个结构体最重要的元素s就是以后客户端程序和服务程序进行通讯的接口了。
3、客户端发送命令
为了获取wifi设备的一些信息,客户端程序需要给服务程序发送命令。我的项目中使用到的命令包括:
scan:发起扫描热点请求
status:查询wifi设备状态。主要用于获得wifi信号强度以及链接指定热点时查看连接是否成功("wpa_state")
list_networks:查询已经保存的热点信息,同时查看当前连接的热点名称
ping:用于查看后台服务程序是否异常退出
BSS %d:查看指定热点信息,如加密信息等
ADD_NETWORK:添加热点,需要配合SET_NETWORK使用
SAVE_CONFIG:保存热点信息更新到配置文件中(若update_config=1)
RECONFIG:重新加载配置文件
项目中,定时发送的命令包括PING和STATUS。 STATUS获得信号强度并显示,同时获取wifi设备状态(当状态从非Completed状态到Completed状态表明设备非连接状态变为连接状态)
4、侦听服务程序主动发送的数据
openCtrlConnection时总共打开了两个wpa_ctrl,第一个用于客户端发送命令,第二个用于侦听服务程序主动发送给客户端程序的命令。如何侦听?使用QSocketNotifier。
msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),QSocketNotifier::Read, this); if(connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()))==false)或者新建一个线程使用select进行侦听。
不管怎样,当发现有数据能读取时,读取socket并处理。
为什么还需要侦听服务程序? 有些命令的回复是异步的,例如scan,扫描的结果并不是马上能得到。 也有一些wifi状态信息wifi设备连接或者断开变化。
扫描网络时:
1、发送SCAN命令
wpa_supplicant异步返回SCAN_RESULT事件
2、发送SCAN_RESULT命令得到扫描结果。(注意,必须等到SCAN_RESULT异步事件接受到后,SCAN_RESULT命令才能拿到正确的结果)
(SCAN_RESULT一次能得到所有的扫描结果,若想一次获得一个热点,可以使用BSS命令)
添加热点时:
1、通过扫描网络(BSS命令)能够得到指定热点的一些信息(SSID,安全策略,加密方式等)
2、根据安全策略和加密方式信息,设置加密密码
3、使用ADD_NETWORK添加这些信息到wpa_supplicant的配置文件中
此过程比较难理解的是第二步,不同的安全策略对于不同的加密方式对密码的要求不一样
ADD_NETWORK步骤
1、得到Network ID(若不知ID,可以发送ADD_NETWORK不带参数,将会得到ID)
设置 ssid、 auth_alg、proto、key_mgmt、
若支持WPA_PSK获知WPA2_PSK需要设置pairwise、 group、 psk
若支持WEP需要设置wep_keyx和wep_txt_keyidx
若支持EAP,需要设置eap、pcsc、phase1、pac_file、phase2(EAP挺复杂的,我的产品里没有支持他)
ENABLE_NETWORK
SAVE_CONFIG
SELECT_NETWORK
查询当前网卡的信息
1、通过STATUS命令能够得到当前链接状态(是否连接或断开,信号强度等)
查询当前网卡连接热点的信息
1、通过LIST_NETWORK,能够列出wpa_supplicant配置文件中所有保存热点的信息。
2、解析热点列表可以得到当前链接到的热点SSID(有current后缀)
不过例外情况是:
A 当使用错误密码连接一个热点时,LIST_NETWORK会将此热点当成已连接热点。
B 当使用正确密码连接热点,但分配不到IP时,LIST_NETWORK得到的信息也是有问题的。
所以,一般来说,还是STATUS命令更加有效,它能得到当前的网卡的状态是否为COMPLETED(代表密码正确,且连接成功),能得到IP_address(代表分配地址成功)
最后说说网络安全策略和加密方式的一些摘抄:
身份校验算法(WEP没有身份校验)两种:
802.1x + EAP
Pre-shared Key
数据加密两种(类似WEP的RC4加密算法):
TKIP
AES
数据完整性编码校验两种(类似WEP的CRC32校验算法):
MIC
CCMP
- WPA_Supplicant使用及配置
- wpa_supplicant网络配置与使用
- wpa_supplicant 配置
- 使用 wpa_supplicant
- 使用 wpa_supplicant
- TQ2440移植之--USB无线网卡及配置wpa_supplicant:
- wpa_supplicant及openssl移植
- wpa_supplicant用法及分析
- wpa_supplicant无线网络配置
- wpa_supplicant无线网络配置
- wpa_supplicant无线网络配置
- wpa_supplicant文件配置
- wpa_supplicant无线网络配置
- wpa_supplicant无线网络配置
- 6wpa_supplicant无线网络配置
- wpa_supplicant无线网络配置
- wpa_supplicant无线网络配置
- wpa_supplicant无线网络配置
- hdu 1875 畅通工程再续(图论:最小生成树)
- JAVA/ANDROID 将文件安全写入到磁盘
- 接口隔离原则
- 1004Let the Balloon Rise
- Going Home
- WPA_Supplicant使用及配置
- UVa242Stamps and Envelope Size
- poj 1258 Agri-Net
- K-12教育在印度
- 关于Datatable删除行和删除列
- Drush commands reference
- WIN8.1配置JDK
- mysql 四舍五入
- IOS研究之打开照相机与本地相册选择图片