1 /*
2  * Copyright (c) 2020 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "utils/includes.h"
17 #include "pthread.h"
18 #include "common/wpa_ctrl.h"
19 #include "securec.h"
20 
21 
22 #define WPA_IFACE_NAME "wlan0"
23 #define WIFI_AUTH_FAILED_REASON_STR "WRONG_KEY"
24 #define WIFI_AUTH_FAILED_REASON_CODE "reason=2"
25 #define WPA_CTRL_REQUEST_OK "OK"
26 #define WPA_CTRL_REQUEST_FAIL "FAIL"
27 
28 #define SAMPLE_INFO(format, args...) \
29     do { \
30         fprintf(stderr, "\033[1;32m WpaCliSample(%s:%d):\t\033[0m" format, __func__, __LINE__, ##args); \
31         printf("\n"); \
32     } while (0)
33 
34 #define SAMPLE_ERROR(format, args...) \
35     do { \
36         fprintf(stderr, "\033[1;31m WpaCliSample(%s:%d):\t\033[0m" format, __func__, __LINE__, ##args); \
37         printf("\n"); \
38     } while (0)
39 
40 
41 static struct wpa_ctrl *g_monitorConn;
42 static struct wpa_ctrl *g_ctrlConn;
43 static pthread_t g_wpaThreadId;
44 static int g_scanAvailable = 0;
45 
DumpString(const char *buf, int len, const char *tag)46 static void DumpString(const char *buf, int len, const char *tag)
47 {
48     SAMPLE_INFO("%s dump start.", tag);
49     for (int i = 0; i < len; i++) {
50         printf("%c", buf[i]);
51     }
52     printf("\n");
53     SAMPLE_INFO("%s dump end.", tag);
54 }
55 
StrMatch(const char *a, const char *b)56 static int StrMatch(const char *a, const char *b)
57 {
58     return strncmp(a, b, strlen(b)) == 0;
59 }
60 
WifiEventHandler(char *rawEvent, int len)61 static void WifiEventHandler(char *rawEvent, int len)
62 {
63     char *pos = rawEvent;
64     if (*pos == '<') {
65         pos = strchr(pos, '>');
66         if (pos) {
67             pos++;
68         } else {
69             pos = rawEvent;
70         }
71     }
72     if (StrMatch(pos, WPA_EVENT_CONNECTED)) {
73         SAMPLE_INFO("WIFI_EVENT_CONNECTED");
74         return;
75     }
76     if (StrMatch(pos, WPA_EVENT_SCAN_RESULTS)) {
77         SAMPLE_INFO("WIFI_EVENT_SCAN_DONE");
78         g_scanAvailable = 1;
79         return;
80     }
81     if (StrMatch(pos, WPA_EVENT_TEMP_DISABLED) && strstr(pos, WIFI_AUTH_FAILED_REASON_STR)) {
82         SAMPLE_INFO("WIFI_EVENT_WRONG_KEY");
83         return;
84     }
85     if (StrMatch(pos, WPA_EVENT_DISCONNECTED) && !strstr(pos, WIFI_AUTH_FAILED_REASON_CODE)) {
86         SAMPLE_INFO("WIFI_EVENT_DISCONNECTED");
87         return;
88     }
89 }
90 
CliRecvPending(void)91 static void CliRecvPending(void)
92 {
93     while (wpa_ctrl_pending(g_monitorConn)) {
94         char buf[4096];
95         size_t len = sizeof(buf) - 1;
96         if (wpa_ctrl_recv(g_monitorConn, buf, &len) == 0) {
97             buf[len] = '\0';
98             SAMPLE_INFO("event received %s", buf);
99             WifiEventHandler(buf, len);
100         } else {
101             SAMPLE_INFO("could not read pending message.");
102             break;
103         }
104     }
105 }
106 
MonitorTask(void *args)107 static void* MonitorTask(void *args)
108 {
109     (void)args;
110     int fd, ret;
111     fd_set rfd;
112     while (1) {
113         fd = wpa_ctrl_get_fd(g_monitorConn);
114         FD_ZERO(&rfd);
115         FD_SET(fd, &rfd);
116         ret = select(fd + 1, &rfd, NULL, NULL, NULL);
117         if (ret <= 0) {
118             SAMPLE_INFO("select failed ret = %d\n", ret);
119             break;
120         }
121         CliRecvPending();
122         sleep(1);
123     }
124     return NULL;
125 }
126 
SendCtrlCommand(const char *cmd, char *reply, size_t *replyLen)127 static int SendCtrlCommand(const char *cmd, char *reply, size_t *replyLen)
128 {
129     size_t len = *replyLen - 1;
130     wpa_ctrl_request(g_ctrlConn, cmd, strlen(cmd), reply, &len, 0);
131     DumpString(reply, len, "SendCtrlCommand raw return");
132     if (len != 0 && !StrMatch(reply, WPA_CTRL_REQUEST_FAIL)) {
133         *replyLen = len;
134         return 0;
135     }
136     SAMPLE_ERROR("send ctrl request [%s] failed.", cmd);
137     return -1;
138 }
139 
TestNetworkConfig(void)140 static void TestNetworkConfig(void)
141 {
142     char networkId[20] = {0};
143     size_t networkIdLen = sizeof(networkId);
144     int ret = SendCtrlCommand("DISCONNECT", networkId, &networkIdLen);
145     ret += SendCtrlCommand("ADD_NETWORK", networkId, &networkIdLen);
146     if (ret != 0) {
147         SAMPLE_ERROR("add network failed.");
148         return;
149     }
150     SAMPLE_INFO("add network success, network id [%.*s]", networkIdLen, networkId);
151     char reply[100] = {0};
152     size_t replyLen = sizeof(reply);
153     char cmd[200] = {0};
154     int temp = 0;
155     temp = sprintf_s(cmd, sizeof(cmd), "SET_NETWORK %.*s ssid \"example\"", networkIdLen, networkId);
156     if (temp != 0) {
157         printf("result is %d\n", temp);
158     };
159     ret += SendCtrlCommand(cmd, reply, &replyLen);
160     replyLen = sizeof(reply);
161     temp = sprintf_s(cmd, sizeof(cmd), "SET_NETWORK %.*s psk \"012345678\"", networkIdLen, networkId);
162     if (temp != 0) {
163         printf("result is %d\n", temp);
164     };
165     ret += SendCtrlCommand(cmd, reply, &replyLen);
166     replyLen = sizeof(reply);
167     temp = sprintf_s(cmd, sizeof(cmd), "ENABLE_NETWORK %.*s", networkIdLen, networkId);
168     if (temp != 0) {
169         printf("result is %d\n", temp);
170     };
171     ret += SendCtrlCommand(cmd, reply, &replyLen);
172     replyLen = sizeof(reply);
173     ret += SendCtrlCommand("RECONNECT", reply, &replyLen);
174     replyLen = sizeof(reply);
175     if (ret == 0) {
176         SAMPLE_INFO("network config success.");
177         return;
178     }
179     temp = sprintf_s(cmd, sizeof(cmd), "REMOVE_NETWORK %.*s", networkIdLen, networkId);
180     if (temp != 0) {
181         printf("result is %d\n", temp);
182     };
183     SendCtrlCommand(cmd, reply, &replyLen);
184     SAMPLE_ERROR("network config failed remove network [%.*s].", networkIdLen, networkId);
185 }
186 
TestCliConnection(void)187 static void TestCliConnection(void)
188 {
189     char reply[100] = {0};
190     size_t replyLen = sizeof(reply);
191     int ret = SendCtrlCommand("PING", reply, &replyLen);
192     if (ret == 0 && StrMatch(reply, "PONG")) {
193         SAMPLE_INFO("connect to wpa success.");
194         return;
195     }
196     SAMPLE_INFO("connect to wpa failed, err = %s.", reply);
197 }
198 
TestScannull199 static void TestScan()
200 {
201     char reply[100] = {0};
202     size_t replyLen = sizeof(reply);
203     g_scanAvailable = 0;
204     SendCtrlCommand("SCAN", reply, &replyLen);
205     while (1) {
206         sleep(1);
207         if (g_scanAvailable == 1) {
208             SAMPLE_INFO("scan result received.");
209             break;
210         }
211         SAMPLE_INFO("waiting scan result.");
212     }
213     char scanResult[4096] = {0};
214     size_t scanLen = sizeof(scanResult);
215     int ret = SendCtrlCommand("SCAN_RESULTS", scanResult, &scanLen);
216     if (ret != 0) {
217         SAMPLE_ERROR("request scan results failed.");
218         return;
219     }
220     DumpString(scanResult, scanLen, "scan results");
221 }
222 
StartTestnull223 static void StartTest()
224 {
225     TestCliConnection(); // test if wpa control interface connected successfully
226     TestScan(); // test scan and get scan results
227     TestNetworkConfig(); // test config network and connect
228 }
229 
InitControlInterfacenull230 int InitControlInterface()
231 {
232     g_ctrlConn = wpa_ctrl_open(WPA_IFACE_NAME); // create control interface for send cmd
233     g_monitorConn = wpa_ctrl_open(WPA_IFACE_NAME); // create control interface for event monitor
234     if (!g_ctrlConn || !g_monitorConn) {
235         SAMPLE_ERROR("open wpa control interface failed.");
236         return -1;
237     }
238     if (wpa_ctrl_attach(g_monitorConn) == 0) { // start monitor
239         pthread_create(&g_wpaThreadId, NULL, MonitorTask, NULL); // create thread for read event
240         return 0;
241     }
242     return -1;
243 }
244 
mainnull245 int main()
246 {
247     if (InitControlInterface() != 0) {
248         SAMPLE_ERROR("control interface init failed, exit client.");
249         return -1;
250     }
251     SAMPLE_INFO("control interface init success.");
252     StartTest();
253     pthread_join(g_wpaThreadId, NULL);
254     SAMPLE_INFO("test finished, exit client.");
255 }
256