196a7f077Sopenharmony_ci/*
296a7f077Sopenharmony_ci * Copyright (c) 2020 Huawei Device Co., Ltd.
396a7f077Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
496a7f077Sopenharmony_ci * you may not use this file except in compliance with the License.
596a7f077Sopenharmony_ci * You may obtain a copy of the License at
696a7f077Sopenharmony_ci *
796a7f077Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
896a7f077Sopenharmony_ci *
996a7f077Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1096a7f077Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1196a7f077Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1296a7f077Sopenharmony_ci * See the License for the specific language governing permissions and
1396a7f077Sopenharmony_ci * limitations under the License.
1496a7f077Sopenharmony_ci */
1596a7f077Sopenharmony_ci
1696a7f077Sopenharmony_ci#include "utils/includes.h"
1796a7f077Sopenharmony_ci#include "pthread.h"
1896a7f077Sopenharmony_ci#include "common/wpa_ctrl.h"
1996a7f077Sopenharmony_ci#include "securec.h"
2096a7f077Sopenharmony_ci
2196a7f077Sopenharmony_ci
2296a7f077Sopenharmony_ci#define WPA_IFACE_NAME "wlan0"
2396a7f077Sopenharmony_ci#define WIFI_AUTH_FAILED_REASON_STR "WRONG_KEY"
2496a7f077Sopenharmony_ci#define WIFI_AUTH_FAILED_REASON_CODE "reason=2"
2596a7f077Sopenharmony_ci#define WPA_CTRL_REQUEST_OK "OK"
2696a7f077Sopenharmony_ci#define WPA_CTRL_REQUEST_FAIL "FAIL"
2796a7f077Sopenharmony_ci
2896a7f077Sopenharmony_ci#define SAMPLE_INFO(format, args...) \
2996a7f077Sopenharmony_ci    do { \
3096a7f077Sopenharmony_ci        fprintf(stderr, "\033[1;32m WpaCliSample(%s:%d):\t\033[0m" format, __func__, __LINE__, ##args); \
3196a7f077Sopenharmony_ci        printf("\n"); \
3296a7f077Sopenharmony_ci    } while (0)
3396a7f077Sopenharmony_ci
3496a7f077Sopenharmony_ci#define SAMPLE_ERROR(format, args...) \
3596a7f077Sopenharmony_ci    do { \
3696a7f077Sopenharmony_ci        fprintf(stderr, "\033[1;31m WpaCliSample(%s:%d):\t\033[0m" format, __func__, __LINE__, ##args); \
3796a7f077Sopenharmony_ci        printf("\n"); \
3896a7f077Sopenharmony_ci    } while (0)
3996a7f077Sopenharmony_ci
4096a7f077Sopenharmony_ci
4196a7f077Sopenharmony_cistatic struct wpa_ctrl *g_monitorConn;
4296a7f077Sopenharmony_cistatic struct wpa_ctrl *g_ctrlConn;
4396a7f077Sopenharmony_cistatic pthread_t g_wpaThreadId;
4496a7f077Sopenharmony_cistatic int g_scanAvailable = 0;
4596a7f077Sopenharmony_ci
4696a7f077Sopenharmony_cistatic void DumpString(const char *buf, int len, const char *tag)
4796a7f077Sopenharmony_ci{
4896a7f077Sopenharmony_ci    SAMPLE_INFO("%s dump start.", tag);
4996a7f077Sopenharmony_ci    for (int i = 0; i < len; i++) {
5096a7f077Sopenharmony_ci        printf("%c", buf[i]);
5196a7f077Sopenharmony_ci    }
5296a7f077Sopenharmony_ci    printf("\n");
5396a7f077Sopenharmony_ci    SAMPLE_INFO("%s dump end.", tag);
5496a7f077Sopenharmony_ci}
5596a7f077Sopenharmony_ci
5696a7f077Sopenharmony_cistatic int StrMatch(const char *a, const char *b)
5796a7f077Sopenharmony_ci{
5896a7f077Sopenharmony_ci    return strncmp(a, b, strlen(b)) == 0;
5996a7f077Sopenharmony_ci}
6096a7f077Sopenharmony_ci
6196a7f077Sopenharmony_cistatic void WifiEventHandler(char *rawEvent, int len)
6296a7f077Sopenharmony_ci{
6396a7f077Sopenharmony_ci    char *pos = rawEvent;
6496a7f077Sopenharmony_ci    if (*pos == '<') {
6596a7f077Sopenharmony_ci        pos = strchr(pos, '>');
6696a7f077Sopenharmony_ci        if (pos) {
6796a7f077Sopenharmony_ci            pos++;
6896a7f077Sopenharmony_ci        } else {
6996a7f077Sopenharmony_ci            pos = rawEvent;
7096a7f077Sopenharmony_ci        }
7196a7f077Sopenharmony_ci    }
7296a7f077Sopenharmony_ci    if (StrMatch(pos, WPA_EVENT_CONNECTED)) {
7396a7f077Sopenharmony_ci        SAMPLE_INFO("WIFI_EVENT_CONNECTED");
7496a7f077Sopenharmony_ci        return;
7596a7f077Sopenharmony_ci    }
7696a7f077Sopenharmony_ci    if (StrMatch(pos, WPA_EVENT_SCAN_RESULTS)) {
7796a7f077Sopenharmony_ci        SAMPLE_INFO("WIFI_EVENT_SCAN_DONE");
7896a7f077Sopenharmony_ci        g_scanAvailable = 1;
7996a7f077Sopenharmony_ci        return;
8096a7f077Sopenharmony_ci    }
8196a7f077Sopenharmony_ci    if (StrMatch(pos, WPA_EVENT_TEMP_DISABLED) && strstr(pos, WIFI_AUTH_FAILED_REASON_STR)) {
8296a7f077Sopenharmony_ci        SAMPLE_INFO("WIFI_EVENT_WRONG_KEY");
8396a7f077Sopenharmony_ci        return;
8496a7f077Sopenharmony_ci    }
8596a7f077Sopenharmony_ci    if (StrMatch(pos, WPA_EVENT_DISCONNECTED) && !strstr(pos, WIFI_AUTH_FAILED_REASON_CODE)) {
8696a7f077Sopenharmony_ci        SAMPLE_INFO("WIFI_EVENT_DISCONNECTED");
8796a7f077Sopenharmony_ci        return;
8896a7f077Sopenharmony_ci    }
8996a7f077Sopenharmony_ci}
9096a7f077Sopenharmony_ci
9196a7f077Sopenharmony_cistatic void CliRecvPending(void)
9296a7f077Sopenharmony_ci{
9396a7f077Sopenharmony_ci    while (wpa_ctrl_pending(g_monitorConn)) {
9496a7f077Sopenharmony_ci        char buf[4096];
9596a7f077Sopenharmony_ci        size_t len = sizeof(buf) - 1;
9696a7f077Sopenharmony_ci        if (wpa_ctrl_recv(g_monitorConn, buf, &len) == 0) {
9796a7f077Sopenharmony_ci            buf[len] = '\0';
9896a7f077Sopenharmony_ci            SAMPLE_INFO("event received %s", buf);
9996a7f077Sopenharmony_ci            WifiEventHandler(buf, len);
10096a7f077Sopenharmony_ci        } else {
10196a7f077Sopenharmony_ci            SAMPLE_INFO("could not read pending message.");
10296a7f077Sopenharmony_ci            break;
10396a7f077Sopenharmony_ci        }
10496a7f077Sopenharmony_ci    }
10596a7f077Sopenharmony_ci}
10696a7f077Sopenharmony_ci
10796a7f077Sopenharmony_cistatic void* MonitorTask(void *args)
10896a7f077Sopenharmony_ci{
10996a7f077Sopenharmony_ci    (void)args;
11096a7f077Sopenharmony_ci    int fd, ret;
11196a7f077Sopenharmony_ci    fd_set rfd;
11296a7f077Sopenharmony_ci    while (1) {
11396a7f077Sopenharmony_ci        fd = wpa_ctrl_get_fd(g_monitorConn);
11496a7f077Sopenharmony_ci        FD_ZERO(&rfd);
11596a7f077Sopenharmony_ci        FD_SET(fd, &rfd);
11696a7f077Sopenharmony_ci        ret = select(fd + 1, &rfd, NULL, NULL, NULL);
11796a7f077Sopenharmony_ci        if (ret <= 0) {
11896a7f077Sopenharmony_ci            SAMPLE_INFO("select failed ret = %d\n", ret);
11996a7f077Sopenharmony_ci            break;
12096a7f077Sopenharmony_ci        }
12196a7f077Sopenharmony_ci        CliRecvPending();
12296a7f077Sopenharmony_ci        sleep(1);
12396a7f077Sopenharmony_ci    }
12496a7f077Sopenharmony_ci    return NULL;
12596a7f077Sopenharmony_ci}
12696a7f077Sopenharmony_ci
12796a7f077Sopenharmony_cistatic int SendCtrlCommand(const char *cmd, char *reply, size_t *replyLen)
12896a7f077Sopenharmony_ci{
12996a7f077Sopenharmony_ci    size_t len = *replyLen - 1;
13096a7f077Sopenharmony_ci    wpa_ctrl_request(g_ctrlConn, cmd, strlen(cmd), reply, &len, 0);
13196a7f077Sopenharmony_ci    DumpString(reply, len, "SendCtrlCommand raw return");
13296a7f077Sopenharmony_ci    if (len != 0 && !StrMatch(reply, WPA_CTRL_REQUEST_FAIL)) {
13396a7f077Sopenharmony_ci        *replyLen = len;
13496a7f077Sopenharmony_ci        return 0;
13596a7f077Sopenharmony_ci    }
13696a7f077Sopenharmony_ci    SAMPLE_ERROR("send ctrl request [%s] failed.", cmd);
13796a7f077Sopenharmony_ci    return -1;
13896a7f077Sopenharmony_ci}
13996a7f077Sopenharmony_ci
14096a7f077Sopenharmony_cistatic void TestNetworkConfig(void)
14196a7f077Sopenharmony_ci{
14296a7f077Sopenharmony_ci    char networkId[20] = {0};
14396a7f077Sopenharmony_ci    size_t networkIdLen = sizeof(networkId);
14496a7f077Sopenharmony_ci    int ret = SendCtrlCommand("DISCONNECT", networkId, &networkIdLen);
14596a7f077Sopenharmony_ci    ret += SendCtrlCommand("ADD_NETWORK", networkId, &networkIdLen);
14696a7f077Sopenharmony_ci    if (ret != 0) {
14796a7f077Sopenharmony_ci        SAMPLE_ERROR("add network failed.");
14896a7f077Sopenharmony_ci        return;
14996a7f077Sopenharmony_ci    }
15096a7f077Sopenharmony_ci    SAMPLE_INFO("add network success, network id [%.*s]", networkIdLen, networkId);
15196a7f077Sopenharmony_ci    char reply[100] = {0};
15296a7f077Sopenharmony_ci    size_t replyLen = sizeof(reply);
15396a7f077Sopenharmony_ci    char cmd[200] = {0};
15496a7f077Sopenharmony_ci    int temp = 0;
15596a7f077Sopenharmony_ci    temp = sprintf_s(cmd, sizeof(cmd), "SET_NETWORK %.*s ssid \"example\"", networkIdLen, networkId);
15696a7f077Sopenharmony_ci    if (temp != 0) {
15796a7f077Sopenharmony_ci        printf("result is %d\n", temp);
15896a7f077Sopenharmony_ci    };
15996a7f077Sopenharmony_ci    ret += SendCtrlCommand(cmd, reply, &replyLen);
16096a7f077Sopenharmony_ci    replyLen = sizeof(reply);
16196a7f077Sopenharmony_ci    temp = sprintf_s(cmd, sizeof(cmd), "SET_NETWORK %.*s psk \"012345678\"", networkIdLen, networkId);
16296a7f077Sopenharmony_ci    if (temp != 0) {
16396a7f077Sopenharmony_ci        printf("result is %d\n", temp);
16496a7f077Sopenharmony_ci    };
16596a7f077Sopenharmony_ci    ret += SendCtrlCommand(cmd, reply, &replyLen);
16696a7f077Sopenharmony_ci    replyLen = sizeof(reply);
16796a7f077Sopenharmony_ci    temp = sprintf_s(cmd, sizeof(cmd), "ENABLE_NETWORK %.*s", networkIdLen, networkId);
16896a7f077Sopenharmony_ci    if (temp != 0) {
16996a7f077Sopenharmony_ci        printf("result is %d\n", temp);
17096a7f077Sopenharmony_ci    };
17196a7f077Sopenharmony_ci    ret += SendCtrlCommand(cmd, reply, &replyLen);
17296a7f077Sopenharmony_ci    replyLen = sizeof(reply);
17396a7f077Sopenharmony_ci    ret += SendCtrlCommand("RECONNECT", reply, &replyLen);
17496a7f077Sopenharmony_ci    replyLen = sizeof(reply);
17596a7f077Sopenharmony_ci    if (ret == 0) {
17696a7f077Sopenharmony_ci        SAMPLE_INFO("network config success.");
17796a7f077Sopenharmony_ci        return;
17896a7f077Sopenharmony_ci    }
17996a7f077Sopenharmony_ci    temp = sprintf_s(cmd, sizeof(cmd), "REMOVE_NETWORK %.*s", networkIdLen, networkId);
18096a7f077Sopenharmony_ci    if (temp != 0) {
18196a7f077Sopenharmony_ci        printf("result is %d\n", temp);
18296a7f077Sopenharmony_ci    };
18396a7f077Sopenharmony_ci    SendCtrlCommand(cmd, reply, &replyLen);
18496a7f077Sopenharmony_ci    SAMPLE_ERROR("network config failed remove network [%.*s].", networkIdLen, networkId);
18596a7f077Sopenharmony_ci}
18696a7f077Sopenharmony_ci
18796a7f077Sopenharmony_cistatic void TestCliConnection(void)
18896a7f077Sopenharmony_ci{
18996a7f077Sopenharmony_ci    char reply[100] = {0};
19096a7f077Sopenharmony_ci    size_t replyLen = sizeof(reply);
19196a7f077Sopenharmony_ci    int ret = SendCtrlCommand("PING", reply, &replyLen);
19296a7f077Sopenharmony_ci    if (ret == 0 && StrMatch(reply, "PONG")) {
19396a7f077Sopenharmony_ci        SAMPLE_INFO("connect to wpa success.");
19496a7f077Sopenharmony_ci        return;
19596a7f077Sopenharmony_ci    }
19696a7f077Sopenharmony_ci    SAMPLE_INFO("connect to wpa failed, err = %s.", reply);
19796a7f077Sopenharmony_ci}
19896a7f077Sopenharmony_ci
19996a7f077Sopenharmony_cistatic void TestScan()
20096a7f077Sopenharmony_ci{
20196a7f077Sopenharmony_ci    char reply[100] = {0};
20296a7f077Sopenharmony_ci    size_t replyLen = sizeof(reply);
20396a7f077Sopenharmony_ci    g_scanAvailable = 0;
20496a7f077Sopenharmony_ci    SendCtrlCommand("SCAN", reply, &replyLen);
20596a7f077Sopenharmony_ci    while (1) {
20696a7f077Sopenharmony_ci        sleep(1);
20796a7f077Sopenharmony_ci        if (g_scanAvailable == 1) {
20896a7f077Sopenharmony_ci            SAMPLE_INFO("scan result received.");
20996a7f077Sopenharmony_ci            break;
21096a7f077Sopenharmony_ci        }
21196a7f077Sopenharmony_ci        SAMPLE_INFO("waiting scan result.");
21296a7f077Sopenharmony_ci    }
21396a7f077Sopenharmony_ci    char scanResult[4096] = {0};
21496a7f077Sopenharmony_ci    size_t scanLen = sizeof(scanResult);
21596a7f077Sopenharmony_ci    int ret = SendCtrlCommand("SCAN_RESULTS", scanResult, &scanLen);
21696a7f077Sopenharmony_ci    if (ret != 0) {
21796a7f077Sopenharmony_ci        SAMPLE_ERROR("request scan results failed.");
21896a7f077Sopenharmony_ci        return;
21996a7f077Sopenharmony_ci    }
22096a7f077Sopenharmony_ci    DumpString(scanResult, scanLen, "scan results");
22196a7f077Sopenharmony_ci}
22296a7f077Sopenharmony_ci
22396a7f077Sopenharmony_cistatic void StartTest()
22496a7f077Sopenharmony_ci{
22596a7f077Sopenharmony_ci    TestCliConnection(); // test if wpa control interface connected successfully
22696a7f077Sopenharmony_ci    TestScan(); // test scan and get scan results
22796a7f077Sopenharmony_ci    TestNetworkConfig(); // test config network and connect
22896a7f077Sopenharmony_ci}
22996a7f077Sopenharmony_ci
23096a7f077Sopenharmony_ciint InitControlInterface()
23196a7f077Sopenharmony_ci{
23296a7f077Sopenharmony_ci    g_ctrlConn = wpa_ctrl_open(WPA_IFACE_NAME); // create control interface for send cmd
23396a7f077Sopenharmony_ci    g_monitorConn = wpa_ctrl_open(WPA_IFACE_NAME); // create control interface for event monitor
23496a7f077Sopenharmony_ci    if (!g_ctrlConn || !g_monitorConn) {
23596a7f077Sopenharmony_ci        SAMPLE_ERROR("open wpa control interface failed.");
23696a7f077Sopenharmony_ci        return -1;
23796a7f077Sopenharmony_ci    }
23896a7f077Sopenharmony_ci    if (wpa_ctrl_attach(g_monitorConn) == 0) { // start monitor
23996a7f077Sopenharmony_ci        pthread_create(&g_wpaThreadId, NULL, MonitorTask, NULL); // create thread for read event
24096a7f077Sopenharmony_ci        return 0;
24196a7f077Sopenharmony_ci    }
24296a7f077Sopenharmony_ci    return -1;
24396a7f077Sopenharmony_ci}
24496a7f077Sopenharmony_ci
24596a7f077Sopenharmony_ciint main()
24696a7f077Sopenharmony_ci{
24796a7f077Sopenharmony_ci    if (InitControlInterface() != 0) {
24896a7f077Sopenharmony_ci        SAMPLE_ERROR("control interface init failed, exit client.");
24996a7f077Sopenharmony_ci        return -1;
25096a7f077Sopenharmony_ci    }
25196a7f077Sopenharmony_ci    SAMPLE_INFO("control interface init success.");
25296a7f077Sopenharmony_ci    StartTest();
25396a7f077Sopenharmony_ci    pthread_join(g_wpaThreadId, NULL);
25496a7f077Sopenharmony_ci    SAMPLE_INFO("test finished, exit client.");
25596a7f077Sopenharmony_ci}
256