暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

wpa_supplicant的控制接口简单说明

ta是一个搬运工 2021-07-29
3968

1 说明

本文旨在用wpa_supplicant提供的API控制wifi模块以STA工作模式连接热点。wpa_supplicant程序一般运行在后台(./wpa_supplicant -B -cwpa_0_8.conf -iwlan0),用户通过它提供的接口让它做各种连接操作。

2 参考

http://w1.fi/wpa_supplicant/devel/wpa__ctrl_8h.html#a4e48c0a662d9150ea603e75365748b0b

wpa_supplicant-devel.pdf

https://www.kancloud.cn/alex_wsc/android-wifi-nfc-gps/414067

2.1 函数基本说明

struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);

打开wpa_supplicant的一个控制接口,参数ctrl_path一般为/var/run/wpa_supplicant/wlan0wlan0为对应的网络节点。成功时返回控制结构体指针,后续的一系列函数都以该指针为参数。失败时返回NULL

 

int wpa_ctrl_attach(struct wpa_ctrl *ctrl);

注册一个事件通知监视器。成功时返回。失败时返回-1。超时则返回-2。该函数成功之后,可以通过wpa_ctrl_pendingwpa_ctrl_recv处理事件通知。

 

int wpa_ctrl_pending(struct wpa_ctrl *ctrl);

检查是否有待处理的事件通知,如果有返回1,没有返回0,出错返回-1

 

int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);

接收一条待处理的事件通知,将内容保存在reply指向的空间,内容的长度保存在reply_len指向的空间。

 

int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,

     char *reply, size_t *reply_len,

     void (*msg_cb)(char *msg, size_t len));

发送一条命令给wpa_supplicantcmdcmd_len描述该条命令。replyreply_len用于保存本次命令的响应。msg_cb一般为NULL即可。成功时返回0,出错(发送或接收失败)返回-1,超时则返回-2

 

int wpa_ctrl_detach(struct wpa_ctrl *ctrl);

注销事件通知监视器。成功时返回0,出错返回-1,超时则返回-2

 

void wpa_ctrl_close(struct wpa_ctrl *ctrl);

关闭控制接口。

2.2 逻辑说明

wpa_supplicant处理命令的结果分成两种:状态信息和事件通知。状态信息可以理解成命令的响应很快,可以立即拿到结果,比如"PING""LIST_NETWORKS""STATUS""ADD_NETWORK"

"SET_NETWORK""ENABLE_NETWORK""SAVE_CONFIG"等,成功时能立即返回并将结果保存在相应的函数参数中。事件通知可以理解成异步事件,比如发送了"ENABLE_NETWORK"该命令能成功且立即返回,但连接热点的过程比较复杂且耗时较长,连接是否成功则通过事件通知告诉用户。

3 应用程序的处理

找出跟wpa_cli相关的文件,将这些文件做成库文件

通过查看编译过程信息,结合makefile,找到了wpa_cli相关的源文件,将这些源文件编译成库文件。在makefile中的wpa_cli: $(OBJS_c)下面添加一行

AR -crv wpa_cli.a $(OBJS_c)AR的值由开发环境决定,如arm-himix100-linux-ar,即可得到想要的库文件。

应用程序使用上述生成的wpa_cli.awpa_supplicant包中的wpa_ctrl.h即可控制各种连接操作。

3.1 事件通知消息说明

热点连接成功或者失败的响应消息依赖于驱动程序的实现,比如用户给出错误的SSID或密码不能连接时的打印:

WPA: 4-Way Handshake failed - pre-shared key may be incorrect

CTRL-EVENT-DISCONNECTED bssid=ec:41:18:45:06:5a reason=0

连接成功时的打印:

CTRL-EVENT-CONNECTED

 

发送命令太频繁会导致消息紊乱,可能导致wpa_0_8.conf内容不完整,

所以建议不要自动发送命令,等待用户通过GUI调用API发送命令或者需要某个功能时才发送命令。

3.2 代码示例

通过函数user_wifiConnectAP_func连接指定的wifi热点(pu8EncryptType可以为NULL),通过线程user_wifiHdlEvent_thread不断地监听事件通知。

    int user_wifiConnectAP_func(char *pu8SSID, char *pu8Secret, char *pu8EncryptType)
    {
    char au8ReplyBuf[2048] = {"\0"};
    size_t reply_len;
    int ret;
    int i;
    int s32NetId = -1;
    char au8Path[128] = {"\0"};

    /* wpa_ctrl_open */
    sprintf(au8Path, "/var/run/wpa_supplicant/wlan0");
    g_pstWpaCtrl = wpa_ctrl_open(au8Path);
    if(g_pstWpaCtrl == NULL)
    {
    printf("\x1b[31m""%s %d, wpa_ctrl_open failed:%s!\n""\x1b[0m", __FILE__, __LINE__, strerror(errno));
    return -1;
    }


    /* wpa_ctrl_request ADD_NETWORK */
    memset(au8ReplyBuf, '\0', sizeof(au8ReplyBuf));
    reply_len = sizeof(au8ReplyBuf)-1;
    ret = wpa_ctrl_request(g_pstWpaCtrl, "ADD_NETWORK", strlen("ADD_NETWORK"), au8ReplyBuf, &reply_len, user_msgCb_func);
    if(ret == 0)
    {
    au8ReplyBuf[reply_len] = '\0';
    }


    s32NetId = atoi(au8ReplyBuf);


    /* wpa_ctrl_request SET_NETWORK */
    char au8SsidBuf[128] = {"\0"};
    snprintf(au8SsidBuf, sizeof(au8SsidBuf)-1, "SET_NETWORK %d ssid \"%s\"", s32NetId, pu8SSID);
    memset(au8ReplyBuf, '\0', sizeof(au8ReplyBuf));
    reply_len = sizeof(au8ReplyBuf)-1;
    ret = wpa_ctrl_request(g_pstWpaCtrl, au8SsidBuf, strlen(au8SsidBuf), au8ReplyBuf, &reply_len, user_msgCb_func);
    if(ret == 0)
    {
    au8ReplyBuf[reply_len] = '\0';
    printf("\x1b[32m""%s %d, reply_len:%d, au8ReplyBuf:%s\n""\x1b[0m", __FILE__, __LINE__, reply_len, au8ReplyBuf);
    }
    else
    {
    return -1;
    }


    /* wpa_ctrl_request SET_NETWORK */
    char au8PskBuf[128] = {"\0"};
    snprintf(au8PskBuf, sizeof(au8PskBuf)-1, "SET_NETWORK %d psk \"%s\"", s32NetId, pu8Secret);
    memset(au8ReplyBuf, '\0', sizeof(au8ReplyBuf));
    reply_len = sizeof(au8ReplyBuf)-1;
    ret = wpa_ctrl_request(g_pstWpaCtrl, au8PskBuf, strlen(au8PskBuf), au8ReplyBuf, &reply_len, user_msgCb_func);
    if(ret == 0)
    {
    au8ReplyBuf[reply_len] = '\0';
    printf("\x1b[32m""%s %d, reply_len:%d, au8ReplyBuf:%s\n""\x1b[0m", __FILE__, __LINE__, reply_len, au8ReplyBuf);
    }
    else
    {
    return -1;
    }


    /* wpa_ctrl_request ENABLE_NETWORK */
    char au8EnableBuf[64] = {"\0"};
    snprintf(au8EnableBuf, sizeof(au8EnableBuf)-1, "ENABLE_NETWORK %d", s32NetId);
    memset(au8ReplyBuf, '\0', sizeof(au8ReplyBuf));
    reply_len = sizeof(au8ReplyBuf)-1;
    ret = wpa_ctrl_request(g_pstWpaCtrl, au8EnableBuf, strlen(au8EnableBuf), au8ReplyBuf, &reply_len, user_msgCb_func);
    if(ret == 0)
    {
    au8ReplyBuf[reply_len] = '\0';
    printf("\x1b[32m""%s %d, reply_len:%d, au8ReplyBuf:%s\n""\x1b[0m", __FILE__, __LINE__, reply_len, au8ReplyBuf);
    }
    else
    {
    return -1;
    }


    return ret;
    }


    void *user_wifiHdlEvent_thread(void *arg)
    {
    char au8ReplyBuf[2048] = {"\0"};
    size_t reply_len;
    int ret;
    char au8Cmdline[64] = {"\0"};


    while(1)
    {
    if(wpa_ctrl_pending(g_pstWpaCtrl) > 0)
    {
    char buf[2048];
    size_t len = sizeof(buf) - 1;
    if(wpa_ctrl_recv(g_pstWpaCtrl, buf, &len) == 0)
    {
    buf[len] = '\0';
    if(strstr(buf, "CTRL-EVENT-CONNECTED") != NULL)
    {
    sprintf(au8Cmdline, "udhcpc -i wlan0 -t 5 -T 2 -A 5 -q");
    system(au8Cmdline);
    /* wpa_ctrl_request SAVE_CONFIG */
    wpa_ctrl_request(g_pstWpaCtrl, "SAVE_CONFIG", strlen("SAVE_CONFIG"), au8ReplyBuf, &reply_len, user_msgCb_func);
    }
    }
    else
    {
              usleep(100000);
    }
    }
    }

    pthread_exit(NULL);
    }
    复制


    文章转载自ta是一个搬运工,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论