基于wpa_supplicant库的WIFI连接功能实现--wpa_cli命令代码改写

来源:互联网 发布:考研英语时间分配知乎 编辑:程序博客网 时间:2024/06/03 19:34

上一篇博客我们一起看了怎样使用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_OBJECTpublic:    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<wpa_cli_cmd> 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;}
0 0
原创粉丝点击