1 /*
2 * Copyright (c) 2022-2023 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 <poll.h>
17 #include <sys/types.h>
18 #include <securec.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <net/if.h>
22 #include <linux/nl80211.h>
23 #include <netlink/genl/ctrl.h>
24 #include <netlink/genl/genl.h>
25 #include <netlink/handlers.h>
26 #include <osal_mem.h>
27
28 #include "hilog/log.h"
29 #include "../wifi_common_cmd.h"
30 #include "netlink_adapter.h"
31
32 #define OUI_QCA 0x001374
33
34 #define LISTEN_FD_NUMS 2
35 #define EVENT_SOCKET_INDEX 0
36 #define CTRL_SOCKET_INDEX 1
37 #define CTRL_SOCKET_WRITE_SIDE 0
38 #define CTRL_SOCKET_READ_SIDE 1
39
40 #define BUFSIZE 1024
41 #define POLLTIMEOUT 1000
42
BitLeftShift(uint8_t x)43 static inline uint32_t BitLeftShift(uint8_t x)
44 {
45 return 1U << x;
46 }
47
48 #define SCAN_QUAL_INVALID BitLeftShift(0)
49 #define SCAN_NOISE_INVALID BitLeftShift(1)
50 #define SCAN_LEVEL_INVALID BitLeftShift(2)
51 #define SCAN_LEVEL_DBM BitLeftShift(3)
52 #define SCAN_ASSOCIATED BitLeftShift(5)
53
54 #define SUCCESS_STATUS 0
55 #define WLAN_ATTR_SCAN_COOKIE 7
56 #define WLAN_ATTR_SCAN_STATUS 8
57 #define WLAN_ATTR_SCAN_MAX 11
58 #define SCAN_STATUS_MAX 2
59 #define NL80211_SCAN_DONE 107
60
61 typedef struct {
62 WifiScanResults *scanResults;
63 const char *ifName;
64 } WifiScanResultArg;
65
66 static int g_familyId = 0;
67
HandleCtrlEvent(int fd)68 static int HandleCtrlEvent(int fd)
69 {
70 int ret;
71 char buf[BUFSIZE];
72
73 ret = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)));
74 if (ret < 0) {
75 HILOG_ERROR(LOG_CORE, "%s: Read after POLL returned %d, error no = %d (%s)",
76 __FUNCTION__, ret, errno, strerror(errno));
77 }
78
79 return ret;
80 }
81
NoSeqCheck(struct nl_msg * msg,void * arg)82 static int NoSeqCheck(struct nl_msg *msg, void *arg)
83 {
84 (void)msg;
85 return NL_OK;
86 }
87
QcaWifiEventScanDoneProcess(const char * ifName,struct nlattr * data,size_t len)88 static void QcaWifiEventScanDoneProcess(const char *ifName, struct nlattr *data, size_t len)
89 {
90 struct nlattr *attr[WLAN_ATTR_SCAN_MAX + 1];
91 uint32_t status;
92
93 if (nla_parse(attr, WLAN_ATTR_SCAN_MAX, data, len, NULL) ||
94 attr[WLAN_ATTR_SCAN_STATUS] ||
95 !attr[WLAN_ATTR_SCAN_COOKIE]) {
96 return;
97 }
98
99 status = nla_get_u8(attr[WLAN_ATTR_SCAN_STATUS]);
100 if (status >= SCAN_STATUS_MAX) {
101 HILOG_ERROR(LOG_CORE, "%s: invalid status", __func__);
102 return;
103 }
104
105 WifiEventReport(ifName, WIFI_EVENT_SCAN_DONE, &status);
106 }
107
WifiEventVendorProcess(const char * ifName,struct nlattr ** attr)108 static void WifiEventVendorProcess(const char *ifName, struct nlattr **attr)
109 {
110 uint32_t vendorId;
111 uint32_t subCmd;
112 uint8_t *data = NULL;
113 uint32_t len;
114
115 if (attr[NL80211_ATTR_VENDOR_ID] == NULL) {
116 HILOG_ERROR(LOG_CORE, "%s: failed to get vendor id", __FUNCTION__);
117 return;
118 }
119 if (attr[NL80211_ATTR_VENDOR_SUBCMD] == NULL) {
120 HILOG_ERROR(LOG_CORE, "%s: failed to get vendor subcmd", __FUNCTION__);
121 return;
122 }
123
124 vendorId = nla_get_u32(attr[NL80211_ATTR_VENDOR_ID]);
125 subCmd = nla_get_u32(attr[NL80211_ATTR_VENDOR_SUBCMD]);
126 if (vendorId != OUI_QCA || subCmd != NL80211_SCAN_DONE) {
127 HILOG_ERROR(LOG_CORE, "%s: unsupported vendor event", __FUNCTION__);
128 return;
129 }
130
131 if (attr[NL80211_ATTR_VENDOR_DATA] == NULL) {
132 HILOG_ERROR(LOG_CORE, "%s: get vendor data fail", __FUNCTION__);
133 return;
134 }
135 data = nla_data(attr[NL80211_ATTR_VENDOR_DATA]);
136 len = nla_len(attr[NL80211_ATTR_VENDOR_DATA]);
137
138 QcaWifiEventScanDoneProcess(ifName, (struct nlattr *)data, len);
139 }
140
GetNlaDataScanResult(struct nlattr * attr[],int len,WifiScanResult * scanResult)141 static int32_t GetNlaDataScanResult(struct nlattr *attr[], int len, WifiScanResult *scanResult)
142 {
143 uint8_t *ie;
144 uint8_t *beaconIe;
145 uint8_t *bssid;
146
147 (void)len;
148 if (attr[NL80211_BSS_INFORMATION_ELEMENTS]) {
149 ie = nla_data(attr[NL80211_BSS_INFORMATION_ELEMENTS]);
150 scanResult->ieLen = (uint32_t)nla_len(attr[NL80211_BSS_INFORMATION_ELEMENTS]);
151 if (ie != NULL && scanResult->ieLen != 0) {
152 scanResult->ie = OsalMemCalloc(scanResult->ieLen);
153 if (scanResult->ie == NULL || memcpy_s(scanResult->ie, scanResult->ieLen, ie, scanResult->ieLen) != EOK) {
154 HILOG_ERROR(LOG_CORE, "%s: fill ie data fail", __FUNCTION__);
155 return RET_CODE_FAILURE;
156 }
157 }
158 }
159 if (attr[NL80211_BSS_BEACON_IES]) {
160 beaconIe = nla_data(attr[NL80211_BSS_INFORMATION_ELEMENTS]);
161 scanResult->beaconIeLen = (uint32_t)nla_len(attr[NL80211_BSS_INFORMATION_ELEMENTS]);
162 if (beaconIe != NULL && scanResult->beaconIeLen != 0) {
163 scanResult->beaconIe = OsalMemCalloc(scanResult->beaconIeLen);
164 if (scanResult->beaconIe == NULL ||
165 memcpy_s(scanResult->beaconIe, scanResult->beaconIeLen, beaconIe, scanResult->beaconIeLen) != EOK) {
166 HILOG_ERROR(LOG_CORE, "%s: fill beacon ie data fail", __FUNCTION__);
167 return RET_CODE_FAILURE;
168 }
169 }
170 }
171 if (attr[NL80211_BSS_BSSID]) {
172 bssid = nla_data(attr[NL80211_BSS_BSSID]);
173 if (bssid != NULL) {
174 scanResult->bssid = OsalMemCalloc(ETH_ADDR_LEN);
175 if (scanResult->bssid == NULL || memcpy_s(scanResult->bssid, ETH_ADDR_LEN, bssid, ETH_ADDR_LEN) != EOK) {
176 HILOG_ERROR(LOG_CORE, "%s: fill bssid fail", __FUNCTION__);
177 return RET_CODE_FAILURE;
178 }
179 }
180 }
181 return RET_CODE_SUCCESS;
182 }
183
DoGetScanResult(struct nlattr * attr[],int len,WifiScanResult * scanResult)184 static int32_t DoGetScanResult(struct nlattr *attr[], int len, WifiScanResult *scanResult)
185 {
186 if (GetNlaDataScanResult(attr, len, scanResult) != RET_CODE_SUCCESS) {
187 return RET_CODE_FAILURE;
188 }
189 if (attr[NL80211_BSS_FREQUENCY]) {
190 scanResult->freq = nla_get_u32(attr[NL80211_BSS_FREQUENCY]);
191 }
192 if (attr[NL80211_BSS_BEACON_INTERVAL]) {
193 scanResult->beaconInt = nla_get_u16(attr[NL80211_BSS_BEACON_INTERVAL]);
194 }
195 if (attr[NL80211_BSS_CAPABILITY]) {
196 scanResult->caps = nla_get_u16(attr[NL80211_BSS_CAPABILITY]);
197 }
198 if (attr[NL80211_BSS_SIGNAL_MBM]) {
199 /* mBm to dBm */
200 scanResult->level = (int32_t)nla_get_u32(attr[NL80211_BSS_SIGNAL_MBM]) / SIGNAL_LEVEL_CONFFICIENT;
201 scanResult->flags |= SCAN_LEVEL_DBM | SCAN_QUAL_INVALID;
202 } else if (attr[NL80211_BSS_SIGNAL_UNSPEC]) {
203 scanResult->level = (int32_t)nla_get_u8(attr[NL80211_BSS_SIGNAL_UNSPEC]);
204 scanResult->flags |= SCAN_QUAL_INVALID;
205 } else {
206 scanResult->flags |= SCAN_LEVEL_INVALID | SCAN_QUAL_INVALID;
207 }
208 if (attr[NL80211_BSS_TSF]) {
209 scanResult->tsf = nla_get_u64(attr[NL80211_BSS_TSF]);
210 }
211 if (attr[NL80211_BSS_BEACON_TSF]) {
212 uint64_t tsf = nla_get_u64(attr[NL80211_BSS_BEACON_TSF]);
213 if (tsf > scanResult->tsf) {
214 scanResult->tsf = tsf;
215 }
216 }
217 if (attr[NL80211_BSS_SEEN_MS_AGO]) {
218 scanResult->age = nla_get_u32(attr[NL80211_BSS_SEEN_MS_AGO]);
219 }
220 return RET_CODE_SUCCESS;
221 }
222
WifiGetScanResultHandler(struct nl_msg * msg,void * arg)223 static int32_t WifiGetScanResultHandler(struct nl_msg *msg, void *arg)
224 {
225 WifiScanResult *scanResult = NULL;
226 WifiScanResults *scanResults = NULL;
227 struct genlmsghdr *hdr = nlmsg_data(nlmsg_hdr(msg));
228 WifiScanResultArg *handlerArg = (WifiScanResultArg *)arg;
229 struct nlattr *attr[NL80211_ATTR_MAX + 1], *bssAttr[NL80211_BSS_MAX + 1];
230 static struct nla_policy bssPolicy[NL80211_BSS_MAX + 1];
231 memset_s(bssPolicy, sizeof(bssPolicy), 0, sizeof(bssPolicy));
232 bssPolicy[NL80211_BSS_FREQUENCY].type = NLA_U32;
233 bssPolicy[NL80211_BSS_TSF].type = NLA_U64;
234 bssPolicy[NL80211_BSS_BEACON_INTERVAL].type = NLA_U16;
235 bssPolicy[NL80211_BSS_CAPABILITY].type = NLA_U16;
236 bssPolicy[NL80211_BSS_SIGNAL_MBM].type = NLA_U32;
237 bssPolicy[NL80211_BSS_SIGNAL_UNSPEC].type = NLA_U8;
238 bssPolicy[NL80211_BSS_STATUS].type = NLA_U32;
239 bssPolicy[NL80211_BSS_SEEN_MS_AGO].type = NLA_U32;
240
241 if (handlerArg == NULL || handlerArg->scanResults == NULL ||
242 handlerArg->scanResults->num >= MAX_SCAN_RES_NUM || handlerArg->ifName == NULL) {
243 HILOG_ERROR(LOG_CORE, "%s: Invalid param", __func__);
244 return NL_SKIP;
245 }
246 scanResults = handlerArg->scanResults;
247 scanResult = &scanResults->scanResult[scanResults->num];
248 nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(hdr, 0), genlmsg_attrlen(hdr, 0), NULL);
249 if (!attr[NL80211_ATTR_BSS]) {
250 HILOG_ERROR(LOG_CORE, "%s: bss info missing", __func__);
251 return NL_SKIP;
252 }
253 if (nla_parse_nested(bssAttr, NL80211_BSS_MAX, attr[NL80211_ATTR_BSS], bssPolicy)) {
254 HILOG_ERROR(LOG_CORE, "%s: failed to parse nested attributes", __func__);
255 return NL_SKIP;
256 }
257 if (DoGetScanResult(bssAttr, NL80211_BSS_MAX + 1, scanResult) != RET_CODE_SUCCESS) {
258 HILOG_ERROR(LOG_CORE, "%s: DoGetScanResult fail", __func__);
259 FreeScanResult(scanResult);
260 return NL_SKIP;
261 }
262 WifiEventReport(handlerArg->ifName, WIFI_EVENT_SCAN_RESULT, scanResult);
263 scanResults->num++;
264 if (scanResults->num == MAX_SCAN_RES_NUM) {
265 WifiEventReport(handlerArg->ifName, WIFI_EVENT_SCAN_RESULTS, scanResults);
266 FreeScanResults(scanResults);
267 (void)memset_s(scanResults, sizeof(WifiScanResults), 0, sizeof(WifiScanResults));
268 }
269 return NL_SKIP;
270 }
271
WifiEventScanResultProcess(const char * ifName)272 static void WifiEventScanResultProcess(const char *ifName)
273 {
274 int32_t ret;
275 WifiScanResults scanResults = {0};
276 WifiScanResultArg arg;
277 uint32_t ifaceId = if_nametoindex(ifName);
278 struct nl_msg *msg = nlmsg_alloc();
279
280 arg.scanResults = &scanResults;
281 arg.ifName = ifName;
282 genlmsg_put(msg, 0, 0, g_familyId, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0);
283 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifaceId);
284 ret = NetlinkSendCmdSync(msg, WifiGetScanResultHandler, (void *)&arg);
285 if (ret != RET_CODE_SUCCESS) {
286 HILOG_ERROR(LOG_CORE, "%s: send cmd failed", __func__);
287 }
288 if (scanResults.num != 0) {
289 WifiEventReport(ifName, WIFI_EVENT_SCAN_RESULTS, &scanResults);
290 }
291 FreeScanResults(&scanResults);
292 nlmsg_free(msg);
293 }
294
WifiEventScanAbortedProcess(const char * ifName)295 static void WifiEventScanAbortedProcess(const char *ifName)
296 {
297 WifiScanResults scanResults = {0};
298
299 if (ifName == NULL) {
300 HILOG_ERROR(LOG_CORE, "%s: ifName is NULL.", __func__);
301 return;
302 }
303 WifiEventReport(ifName, WIFI_EVENT_SCAN_ABORTED, &scanResults);
304 }
305
DoProcessEvent(const char * ifName,int cmd,struct nlattr ** attr)306 static void DoProcessEvent(const char *ifName, int cmd, struct nlattr **attr)
307 {
308 switch (cmd) {
309 case NL80211_CMD_VENDOR:
310 WifiEventVendorProcess(ifName, attr);
311 break;
312 case NL80211_CMD_START_SCHED_SCAN:
313 HILOG_INFO(LOG_CORE, "%s: receive cmd NL80211_CMD_START_SCHED_SCAN, cmd = %d", __FUNCTION__, cmd);
314 break;
315 case NL80211_CMD_SCHED_SCAN_RESULTS:
316 HILOG_INFO(LOG_CORE, "%s: receive cmd NL80211_CMD_SCHED_SCAN_RESULTS, cmd = %d", __FUNCTION__, cmd);
317 WifiEventScanResultProcess(ifName);
318 break;
319 case NL80211_CMD_SCHED_SCAN_STOPPED:
320 HILOG_INFO(LOG_CORE, "%s: receive cmd NL80211_CMD_SCHED_SCAN_STOPPED, cmd = %d", __FUNCTION__, cmd);
321 break;
322 case NL80211_CMD_NEW_SCAN_RESULTS:
323 HILOG_INFO(LOG_CORE, "%s: receive cmd NL80211_CMD_NEW_SCAN_RESULTS, cmd = %d", __FUNCTION__, cmd);
324 WifiEventScanResultProcess(ifName);
325 break;
326 case NL80211_CMD_SCAN_ABORTED:
327 HILOG_INFO(LOG_CORE, "%s: receive cmd NL80211_CMD_SCAN_ABORTED, cmd = %d", __FUNCTION__, cmd);
328 WifiEventScanAbortedProcess(ifName);
329 break;
330 case NL80211_CMD_TRIGGER_SCAN:
331 HILOG_INFO(LOG_CORE, "%s: receive cmd NL80211_CMD_TRIGGER_SCAN, cmd = %d", __FUNCTION__, cmd);
332 break;
333 default:
334 HILOG_INFO(LOG_CORE, "%s: not supported cmd, cmd = %d", __FUNCTION__, cmd);
335 break;
336 }
337 }
338
ProcessEvent(struct nl_msg * msg,void * arg)339 static int32_t ProcessEvent(struct nl_msg *msg, void *arg)
340 {
341 struct genlmsghdr *hdr = nlmsg_data(nlmsg_hdr(msg));
342 struct nlattr *attr[NL80211_ATTR_MAX + 1];
343 struct NetworkInfoResult networkInfo;
344 uint32_t ifidx = -1;
345 uint32_t i;
346 int ret;
347
348 nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(hdr, 0),
349 genlmsg_attrlen(hdr, 0), NULL);
350
351 if (attr[NL80211_ATTR_IFINDEX]) {
352 ifidx = nla_get_u32(attr[NL80211_ATTR_IFINDEX]);
353 }
354
355 ret = GetUsableNetworkInfo(&networkInfo);
356 if (ret != RET_CODE_SUCCESS) {
357 HILOG_ERROR(LOG_CORE, "%s: get usable network information failed", __FUNCTION__);
358 return NL_SKIP;
359 }
360
361 for (i = 0; i < networkInfo.nums; i++) {
362 if (ifidx == if_nametoindex(networkInfo.infos[i].name)) {
363 DoProcessEvent(networkInfo.infos[i].name, hdr->cmd, attr);
364 return NL_SKIP;
365 }
366 }
367
368 return NL_SKIP;
369 }
370
CreateCb(void)371 static struct nl_cb *CreateCb(void)
372 {
373 struct nl_cb *cb;
374
375 cb = nl_cb_alloc(NL_CB_DEFAULT);
376 if (cb == NULL) {
377 HILOG_ERROR(LOG_CORE, "%s: alloc cb failed", __FUNCTION__);
378 return NULL;
379 }
380
381 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, NoSeqCheck, NULL);
382 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, ProcessEvent, NULL);
383
384 return cb;
385 }
386
HandleEvent(struct nl_sock * sock)387 static int HandleEvent(struct nl_sock *sock)
388 {
389 int ret;
390 struct nl_cb *cb = CreateCb();
391 if (cb == NULL) {
392 HILOG_ERROR(LOG_CORE, "%s: Create cb failed", __FUNCTION__);
393 return RET_CODE_FAILURE;
394 }
395
396 ret = nl_recvmsgs(sock, cb);
397
398 nl_cb_put(cb);
399 cb = NULL;
400 return ret;
401 }
402
EventThread(void * para)403 void *EventThread(void *para)
404 {
405 struct nl_sock *eventSock = NULL;
406 struct pollfd pollFds[LISTEN_FD_NUMS] = {0};
407 struct WifiThreadParam *threadParam = NULL;
408 int ctrlSocks[2];
409 int ret;
410 enum ThreadStatus *status = NULL;
411
412 if (para == NULL) {
413 HILOG_ERROR(LOG_CORE, "%s: para is null", __FUNCTION__);
414 return NULL;
415 } else {
416 threadParam = (struct WifiThreadParam *)para;
417 eventSock = threadParam->eventSock;
418 g_familyId = threadParam->familyId;
419 status = threadParam->status;
420 *status = THREAD_RUN;
421 }
422
423 pollFds[EVENT_SOCKET_INDEX].fd = nl_socket_get_fd(eventSock);
424 pollFds[EVENT_SOCKET_INDEX].events = POLLIN | POLLERR;
425
426 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, ctrlSocks);
427 if (ret != 0) {
428 HILOG_ERROR(LOG_CORE, "%s: fail socketpair", __FUNCTION__);
429 *status = THREAD_STOP;
430 return NULL;
431 }
432 pollFds[CTRL_SOCKET_INDEX].fd = ctrlSocks[CTRL_SOCKET_READ_SIDE];
433 pollFds[CTRL_SOCKET_INDEX].events = POLLIN | POLLERR;
434
435 while (*status == THREAD_RUN) {
436 ret = TEMP_FAILURE_RETRY(poll(pollFds, LISTEN_FD_NUMS, POLLTIMEOUT));
437 if (ret < 0) {
438 HILOG_ERROR(LOG_CORE, "%s: fail poll", __FUNCTION__);
439 break;
440 } else if (pollFds[EVENT_SOCKET_INDEX].revents & POLLERR) {
441 HILOG_ERROR(LOG_CORE, "%s: event socket get POLLERR event", __FUNCTION__);
442 break;
443 } else if (pollFds[EVENT_SOCKET_INDEX].revents & POLLIN) {
444 if (HandleEvent(eventSock) != RET_CODE_SUCCESS) {
445 break;
446 }
447 } else if (pollFds[CTRL_SOCKET_INDEX].revents & POLLERR) {
448 HILOG_ERROR(LOG_CORE, "%s: ctrl socket get POLLERR event", __FUNCTION__);
449 break;
450 } else if (pollFds[CTRL_SOCKET_INDEX].revents & POLLIN) {
451 if (HandleCtrlEvent(pollFds[CTRL_SOCKET_INDEX].fd) != RET_CODE_SUCCESS) {
452 break;
453 }
454 }
455 }
456
457 close(pollFds[CTRL_SOCKET_INDEX].fd);
458 *status = THREAD_STOP;
459 return NULL;
460 }
461