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

上一篇博客我们一起看了怎样使用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<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;
}
  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: wpa_supplicant是一个用于连接WiFi的开源软件,它支持WPAWPA2加密协议,可以在Linux、Unix、Windows等操作系统上运行。使用wpa_supplicant连接WiFi需要先配置wpa_supplicant.conf文件,然后启动wpa_supplicant服务,最后使用命令行工具或者图形界面工具连接WiFi。具体步骤如下: 1. 配置wpa_supplicant.conf文件 在Linux系统中,wpa_supplicant.conf文件通常位于/etc/wpa_supplicant/目录下。可以使用文本编辑器打开该文件,添加以下内容: network={ ssid="WiFi名称" psk="WiFi密码" } 其中,ssid是WiFi的名称,psk是WiFi的密码。如果WiFi使用的是其他加密方式,可以根据需要修改配置文件。 2. 启动wpa_supplicant服务 在Linux系统中,可以使用以下命令启动wpa_supplicant服务: sudo wpa_supplicant -i wlan -c /etc/wpa_supplicant/wpa_supplicant.conf 其中,wlan是无线网卡的接口名称,可以根据需要修改。启动服务后,wpa_supplicant会自动搜索附近的WiFi网络。 3. 连接WiFi 使用命令行工具连接WiFi,可以使用以下命令: sudo dhclient wlan 其中,wlan是无线网卡的接口名称,可以根据需要修改。该命令会自动获取IP地址,并连接WiFi。 使用图形界面工具连接WiFi,可以在系统设置中找到网络设置,选择WiFi网络并输入密码即可。 ### 回答2: wpa_supplicant是一个用于连接无线网络的软件,它支持多种不同的身份验证方式,比如WPAWPA2、PEAP等。除了无线连接外,它还可以用于其他网络协议的管理,比如Ethernet、PPP等。在Linux系统中,wpa_supplicant通常在命令行下使用。 要连接wifi,首先需要运行wpa_supplicant,并指定使用哪个无线网卡。命令的格式为: sudo wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf 其中,-B表示在后台运行,-i后面跟着无线网卡的名称(这里是wlan0),-c后面指定wpa_supplicant的配置文件位置。如果要在命令行中输入wifi密码,则在配置文件中设置密码明文会更方便。 wpa_supplicant的配置文件是一个文本文件,其中包含了要连接wifi网络的信息,比如SSID、密码、身份验证方式等。配置文件的格式如下: network={ ssid="wifi_ssid" key_mgmt=WPA-PSK psk="wifi_password" } 其中,ssid表示wifi的名称,key_mgmt表示身份验证方式,psk表示wifi密码。如果需要使用其他身份验证方式,比如EAP-PEAP或者wpa_supplicant内置的其他方法,则需要在配置文件中设置其他参数。 一旦启动wpa_supplicant成功,并且连接wifi成功,就可以使用ifconfig命令查看无线网卡的IP地址,或者使用ping命令测试网络是否正常。需要注意的是,wpa_supplicant的日志会输出到/var/log/wpa_supplicant.log文件中,可用于排查故障。 ### 回答3: wpa_supplicant是一个常用的Wi-Fi连接工具,它可以让设备与Wi-Fi网络建立稳定的连接。下面来介绍一下如何使用wpa_supplicant连接Wi-Fi。 首先,使用wpa_supplicant连接Wi-Fi需要用到两个文件:wpa_supplicant.conf和ifconfig.sh。wpa_supplicant.conf是配置文件,里面存放着连接Wi-Fi的相关信息,如Wi-Fi的名称、密码等。ifconfig.sh是一个脚本文件,用于设置IP地址和网络掩码。 接下来,先来介绍一下如何配置wpa_supplicant.conf。以连接“Test_WiFi”为例,打开wpa_supplicant.conf文件,输入以下内容: network={ ssid="Test_WiFi" key_mgmt=WPA-PSK psk="123456" } 其中,ssid表示Wi-Fi的名称,key_mgmt表示Wi-Fi的加密方式,这里用的是WPA-PSK,psk表示Wi-Fi的密码。可以根据实际情况更换参数。 接下来,保存wpa_supplicant.conf文件,将文件上传到设备上,并给予文件可执行权限。 然后,打开ifconfig.sh文件,输入以下代码: ifconfig wlan0 up wpa_supplicant -B -i wlan0 -c /path/to/wpa_supplicant.conf udhcpc -i wlan0 其中,第二行代码连接Wi-Fi命令。将path/to/wpa_supplicant.conf替换为实际的wpa_supplicant.conf文件路径,保存ifconfig.sh文件,并给予文件可执行权限。 最后,运行ifconfig.sh文件,设备便可以自动连接Wi-Fi网络了。如果需要修改Wi-Fi名称和密码等信息,只需要修改wpa_supplicant.conf文件即可。 综上所述,使用wpa_supplicant连接Wi-Fi需要进行一系列操作,包括配置wpa_supplicant.conf文件、ifconfig.sh文件的编写和执行。但是,一旦配置成功,设备就可以轻松地自动连接Wi-Fi网络,方便实用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浓咖啡jy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值