上一篇博客我们一起看了怎样使用wpas的命令后,接下来就利用这些命令来实现我们的代码。这些命令的实现都在wpa_cli.c文件中,以status命令为例,发生如下调用:
static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
}
wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
_wpa_ctrl_command(ctrl, cmd, 1);
char buf[2048];
wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf,
&len,wpa_cli_msg_cb);
if (print)
printf("%s", buf);
从上面可以看出,最终是调用wpa_ctrl_request函数完成命令,而最终结果是存在buf里,通过函数参数print来觉得是否输出到终端。所以我们最终需要取得的结果就是buf,只要拿到buf内容,我们就可以分析其内容实现我们需要的代码。为了实现上述目的,需要对源码进行下修改:我们把输出buf作为参数传入_wpa_ctrl_command函数,这样就可以拿到输出内容了。改写后代码如下:
static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *buf, const char *cmd)
{
return _wpa_ctrl_command(ctrl, buf, cmd, 0);
}
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *buf, const char *cmd, int print)
{
char ret_buf[2048];
int ret;
size_t ret_len;
ret_len = sizeof(ret_buf) - 1;
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), ret_buf, &ret_len,
wpa_cli_msg_cb);
if (ret == -2)
{
printf("'%s' command timed out.\n", cmd);
return -2;
}
else if (ret < 0)
{
printf("'%s' command failed.\n", cmd);
return -1;
}
ret_buf[ret_len] = '\0';
memcpy(buf, ret_buf, 2048);
if (print)
{
ret_buf[ret_len] = '\0';
printf("%s", ret_buf);
}
return 0;
}
static void wpa_cli_msg_cb(char *msg, size_t len)
{
printf("%s\n", msg);
}
对于各个命令呢,我们同样需要加入buf,还是以status为例:
static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, char *buf, int argc, char *argv[])
{
int verbose = argc > 0 && strcmp(argv[0], "verbose") == 0;
return wpa_ctrl_command(ctrl, buf, verbose ? "STATUS-VERBOSE" : "STATUS");
}
这样各个命令就达到了我们的目的。最后我们对命令进行一下封装,方便统一管理。
#define CFG_MAXARGS 10
/**
* @brief 对wpa_supplicant中处理命令进行封装
*/
class HanleCmd : public QObject
{
Q_OBJECT
public:
HanleCmd();
void printCmd();
int hanleCmd(struct wpa_ctrl *ctrl, char *buf, char *cmd);
private:
//命令封装
struct wpa_cli_cmd
{
const char *cmd; //命令名称
int (*handler)(struct wpa_ctrl *ctrl, char *buf, int argc, char *argv[]); //命令处理函数
};
QList listCmd; //命令链表
//私有函数
void addCmd();
int wpaRequest(struct wpa_ctrl *ctrl, char *buf, int argc, char *argv[]);
int parseLine (char *line, char *argv[]);
};
HanleCmd::HanleCmd()
{
qDebug("init cmd list");
addCmd();
}
void HanleCmd::addCmd()
{
struct wpa_cli_cmd cmd;
//状态命令
cmd.cmd = "status";
cmd.handler = wpa_cli_cmd_status;
listCmd.append(cmd);
//扫描命令
cmd.cmd = "scan";
cmd.handler = wpa_cli_cmd_scan;
listCmd.append(cmd);
//扫描结果命令
cmd.cmd = "scan_results";
cmd.handler = wpa_cli_cmd_scan_results;
listCmd.append(cmd);
//选择AP命令
cmd.cmd = "select_network";
cmd.handler = wpa_cli_cmd_select_network;
listCmd.append(cmd);
//增加AP命令
cmd.cmd = "add_network";
cmd.handler = wpa_cli_cmd_add_network;
listCmd.append(cmd);
//列出配置文件中已经保存的AP信息
cmd.cmd = "list_network";
cmd.handler = wpa_cli_cmd_list_networks;
listCmd.append(cmd);
//设置AP
cmd.cmd = "set_network";
cmd.handler = wpa_cli_cmd_set_network;
listCmd.append(cmd);
//移除AP
cmd.cmd = "remove_network";
cmd.handler = wpa_cli_cmd_remove_network;
listCmd.append(cmd);
//使能某个AP
cmd.cmd = "enable_network";
cmd.handler = wpa_cli_cmd_enable_network;
listCmd.append(cmd);
//关闭某个AP
cmd.cmd = "disable_network";
cmd.handler = wpa_cli_cmd_disable_network;
listCmd.append(cmd);
//保存配置
cmd.cmd = "save_config";
cmd.handler = wpa_cli_cmd_save_config;
listCmd.append(cmd);
}
int HanleCmd::parseLine (char *line, char *argv[])
{
int nargs = 0;
while (nargs < CFG_MAXARGS)
{
/* skip any white space */
while ((*line == ' ') || (*line == '\t'))
{
++line;
}
if (*line == '\0') /* end of line, no more args */
{
argv[nargs] = NULL;
return (nargs);
}
argv[nargs++] = line; /* begin of argument string */
/* find end of string */
while (*line && (*line != ' ') && (*line != '\t'))
{
++line;
}
if (*line == '\0') /* end of line, no more args */
{
argv[nargs] = NULL;
return (nargs);
}
*line++ = '\0'; /* terminate current arg */
}
return (nargs);
}
int HanleCmd::hanleCmd(struct wpa_ctrl *ctrl, char *buf, char *cmd)
{
int argc;
char bufTmp[1024];
char *argv[CFG_MAXARGS];
strncpy(bufTmp, cmd, 1024);
bufTmp[1023] = '\0';
argc = parseLine(bufTmp, argv);
return wpaRequest(ctrl, buf, argc, argv);
}
封装完毕后,只需要在执行某个命令时候调用如下代码即可:
char buf[2048];
handleCmd->hanleCmd(ctrl_conn, buf, "status");
这样buf中存入的就是status命令的结果了。
至于参数中的ctrl_conn是底层的操作接口,需要读者自己去分析下wpa_cli的源码,这里只贴一下代码:
int WifiService::initWpa()
{
qDebug()<<"initWpa";
//1.变量初始化
int conectNum = 0;
ctrl_iface = NULL;
ctrl_conn = NULL;
monitor_conn = NULL;
ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
//2.与wpa_supplicant建立连接
while(true)
{
wpa_cli_get_default_ifname();
if(ctrl_iface == NULL){
qDebug("failed to wpa_cli_get_default_ifname");
return -1;
}
wpa_cli_open_connection(ctrl_iface);
if (ctrl_conn || monitor_conn){ //ActionThread未启用情况下只用ctrl_conn就可以
qDebug("wpa_supplicant connection established");
break;
}else{
if(conectNum++ >=2){ //最多试三次
qDebug("wpa_supplicant connection established err");
return -1;
}
qDebug("wpa_supplicant connection established err, we will try agin");
usleep(10000);
continue;
}
}
return 0;
}