1 /*
2 * Copyright (c) 2022 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
27 #include "hilog/log.h"
28 #include "../wifi_common_cmd.h"
29 #include "netlink_adapter.h"
30
31 #define OUI_QCA 0x001374
32
33 #define LISTEN_FD_NUMS 2
34 #define EVENT_SOCKET_INDEX 0
35 #define CTRL_SOCKET_INDEX 1
36 #define CTRL_SOCKET_WRITE_SIDE 0
37 #define CTRL_SOCKET_READ_SIDE 1
38
39 #define BUFSIZE 1024
40 #define POLLTIMEOUT 1000
41 #define SIGNALLEVELCONFFICIENT 100
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 static int g_familyId = 0;
62
HandleCtrlEvent(int fd)63 static int HandleCtrlEvent(int fd)
64 {
65 int ret;
66 char buf[BUFSIZE];
67
68 ret = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)));
69 if (ret < 0) {
70 HILOG_ERROR(LOG_DOMAIN, "%s: Read after POLL returned %zd, error no = %d (%s)",
71 __FUNCTION__, ret, errno, strerror(errno));
72 }
73
74 return ret;
75 }
76
NoSeqCheck(struct nl_msg * msg,void * arg)77 static int NoSeqCheck(struct nl_msg *msg, void *arg)
78 {
79 return NL_OK;
80 }
81
QcaWifiEventScanDoneProcess(const char * ifName,struct nlattr * data,size_t len)82 static void QcaWifiEventScanDoneProcess(const char *ifName, struct nlattr *data, size_t len)
83 {
84 struct nlattr *attr[WLAN_ATTR_SCAN_MAX + 1];
85 uint32_t status;
86
87 if (nla_parse(attr, WLAN_ATTR_SCAN_MAX, data, len, NULL) ||
88 attr[WLAN_ATTR_SCAN_STATUS] ||
89 !attr[WLAN_ATTR_SCAN_COOKIE]) {
90 return;
91 }
92
93 status = nla_get_u8(attr[WLAN_ATTR_SCAN_STATUS]);
94 if (status >= SCAN_STATUS_MAX) {
95 HILOG_ERROR(LOG_DOMAIN, "%s: invalid status", __func__);
96 return;
97 }
98
99 WifiEventReport(ifName, WIFI_EVENT_SCAN_DONE, &status);
100 }
101
WifiEventVendorProcess(const char * ifName,struct nlattr ** attr)102 static void WifiEventVendorProcess(const char *ifName, struct nlattr **attr)
103 {
104 uint32_t vendor_id;
105 uint32_t subcmd;
106 uint8_t *data = NULL;
107 size_t len;
108
109 if (attr[NL80211_ATTR_VENDOR_ID] == NULL) {
110 HILOG_ERROR(LOG_DOMAIN, "%s: failed to get vendor id", __FUNCTION__);
111 return;
112 }
113 if (attr[NL80211_ATTR_VENDOR_SUBCMD] == NULL) {
114 HILOG_ERROR(LOG_DOMAIN, "%s: failed to get vendor subcmd", __FUNCTION__);
115 return;
116 }
117
118 vendor_id = nla_get_u32(attr[NL80211_ATTR_VENDOR_ID]);
119 subcmd = nla_get_u32(attr[NL80211_ATTR_VENDOR_SUBCMD]);
120 if (vendor_id != OUI_QCA || subcmd != NL80211_SCAN_DONE) {
121 HILOG_ERROR(LOG_DOMAIN, "%s: unsupported vendor event", __FUNCTION__);
122 return;
123 }
124
125 if (attr[NL80211_ATTR_VENDOR_DATA] == NULL) {
126 HILOG_ERROR(LOG_DOMAIN, "%s: get vendor data fail", __FUNCTION__);
127 return;
128 }
129 data = nla_data(attr[NL80211_ATTR_VENDOR_DATA]);
130 len = nla_len(attr[NL80211_ATTR_VENDOR_DATA]);
131
132 QcaWifiEventScanDoneProcess(ifName, (struct nlattr *)data, len);
133 }
134
DoGetScanResult(struct nlattr * attr[],int len,WifiScanResult * scanResult)135 static void DoGetScanResult(struct nlattr *attr[], int len, WifiScanResult *scanResult)
136 {
137 if (attr[NL80211_BSS_INFORMATION_ELEMENTS]) {
138 scanResult->ie = nla_data(attr[NL80211_BSS_INFORMATION_ELEMENTS]);
139 scanResult->ieLen = nla_len(attr[NL80211_BSS_INFORMATION_ELEMENTS]);
140 }
141 if (attr[NL80211_BSS_BEACON_IES]) {
142 scanResult->beaconIe = nla_data(attr[NL80211_BSS_BEACON_IES]);
143 scanResult->beaconIeLen = nla_len(attr[NL80211_BSS_BEACON_IES]);
144 }
145 if (attr[NL80211_BSS_BSSID]) {
146 scanResult->bssid = nla_data(attr[NL80211_BSS_BSSID]);
147 }
148 if (attr[NL80211_BSS_FREQUENCY]) {
149 scanResult->freq = nla_get_u32(attr[NL80211_BSS_FREQUENCY]);
150 }
151 if (attr[NL80211_BSS_BEACON_INTERVAL]) {
152 scanResult->beaconInt = nla_get_u16(attr[NL80211_BSS_BEACON_INTERVAL]);
153 }
154 if (attr[NL80211_BSS_CAPABILITY]) {
155 scanResult->caps = nla_get_u16(attr[NL80211_BSS_CAPABILITY]);
156 }
157 if (attr[NL80211_BSS_SIGNAL_MBM]) {
158 scanResult->level = nla_get_u32(attr[NL80211_BSS_SIGNAL_MBM]) / SIGNALLEVELCONFFICIENT; /* mBm to dBm */
159 scanResult->flags |= SCAN_LEVEL_DBM | SCAN_QUAL_INVALID;
160 } else if (attr[NL80211_BSS_SIGNAL_UNSPEC]) {
161 scanResult->level = nla_get_u8(attr[NL80211_BSS_SIGNAL_UNSPEC]);
162 scanResult->flags |= SCAN_QUAL_INVALID;
163 } else {
164 scanResult->flags |= SCAN_LEVEL_INVALID | SCAN_QUAL_INVALID;
165 }
166 if (attr[NL80211_BSS_SEEN_MS_AGO]) {
167 scanResult->age = nla_get_u32(attr[NL80211_BSS_SEEN_MS_AGO]);
168 }
169 }
170
WifiGetScanResultHandler(struct nl_msg * msg,void * arg)171 static int32_t WifiGetScanResultHandler(struct nl_msg *msg, void *arg)
172 {
173 WifiScanResult scanResult;
174 struct genlmsghdr *hdr = nlmsg_data(nlmsg_hdr(msg));
175 const char *ifName = (const char *)arg;
176 struct nlattr *attr[NL80211_ATTR_MAX + 1], *bssAttr[NL80211_BSS_MAX + 1];
177 static struct nla_policy bssPolicy[NL80211_BSS_MAX + 1];
178 memset_s(bssPolicy, sizeof(bssPolicy), 0, sizeof(bssPolicy));
179 bssPolicy[NL80211_BSS_FREQUENCY].type = NLA_U32;
180 bssPolicy[NL80211_BSS_TSF].type = NLA_U64;
181 bssPolicy[NL80211_BSS_BEACON_INTERVAL].type = NLA_U16;
182 bssPolicy[NL80211_BSS_CAPABILITY].type = NLA_U16;
183 bssPolicy[NL80211_BSS_SIGNAL_MBM].type = NLA_U32;
184 bssPolicy[NL80211_BSS_SIGNAL_UNSPEC].type = NLA_U8;
185 bssPolicy[NL80211_BSS_STATUS].type = NLA_U32;
186 bssPolicy[NL80211_BSS_SEEN_MS_AGO].type = NLA_U32;
187
188 if (ifName == NULL) {
189 HILOG_ERROR(LOG_DOMAIN, "%s: ifName is null", __func__);
190 return NL_SKIP;
191 }
192
193 nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(hdr, 0), genlmsg_attrlen(hdr, 0), NULL);
194 if (!attr[NL80211_ATTR_BSS]) {
195 HILOG_ERROR(LOG_DOMAIN, "%s: bss info missing", __func__);
196 return NL_SKIP;
197 }
198 if (nla_parse_nested(bssAttr, NL80211_BSS_MAX, attr[NL80211_ATTR_BSS], bssPolicy)) {
199 HILOG_ERROR(LOG_DOMAIN, "%s: failed to parse nested attributes", __func__);
200 return NL_SKIP;
201 }
202
203 DoGetScanResult(bssAttr, NL80211_BSS_MAX + 1, &scanResult);
204
205 WifiEventReport(ifName, WIFI_EVENT_SCAN_RESULT, &scanResult);
206 return NL_SKIP;
207 }
208
WifiEventScanResultProcess(const char * ifName)209 static void WifiEventScanResultProcess(const char *ifName)
210 {
211 int32_t ret;
212 uint32_t ifaceId = if_nametoindex(ifName);
213 struct nl_msg *msg = nlmsg_alloc();
214
215 genlmsg_put(msg, 0, 0, g_familyId, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0);
216 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifaceId);
217 ret = SendCmdSync(msg, WifiGetScanResultHandler, (void *)ifName);
218 if (ret != RET_CODE_SUCCESS) {
219 HILOG_ERROR(LOG_DOMAIN, "%s: send cmd failed", __func__);
220 }
221
222 nlmsg_free(msg);
223 }
224
DoProcessEvent(const char * ifName,int cmd,struct nlattr ** attr)225 static void DoProcessEvent(const char *ifName, int cmd, struct nlattr **attr)
226 {
227 switch (cmd) {
228 case NL80211_CMD_VENDOR:
229 WifiEventVendorProcess(ifName, attr);
230 break;
231 case NL80211_CMD_NEW_SCAN_RESULTS:
232 WifiEventScanResultProcess(ifName);
233 break;
234 default:
235 HILOG_INFO(LOG_DOMAIN, "%s: not supported cmd, cmd = %d\n", __FUNCTION__, cmd);
236 break;
237 }
238 }
239
ProcessEvent(struct nl_msg * msg,void * arg)240 static int32_t ProcessEvent(struct nl_msg *msg, void *arg)
241 {
242 struct genlmsghdr *hdr = nlmsg_data(nlmsg_hdr(msg));
243 struct nlattr *attr[NL80211_ATTR_MAX + 1];
244 struct NetworkInfoResult networkInfo;
245 uint32_t ifidx = -1;
246 uint32_t i;
247 int ret;
248
249 nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(hdr, 0),
250 genlmsg_attrlen(hdr, 0), NULL);
251
252 if (attr[NL80211_ATTR_IFINDEX]) {
253 ifidx = nla_get_u32(attr[NL80211_ATTR_IFINDEX]);
254 }
255
256 ret = GetUsableNetworkInfo(&networkInfo);
257 if (ret != RET_CODE_SUCCESS) {
258 HILOG_ERROR(LOG_DOMAIN, "%s: get usable network information failed", __FUNCTION__);
259 return NL_SKIP;
260 }
261
262 for (i = 0; i < networkInfo.nums; i++) {
263 if (ifidx == if_nametoindex(networkInfo.infos[i].name)) {
264 DoProcessEvent(networkInfo.infos[i].name, hdr->cmd, attr);
265 return NL_SKIP;
266 }
267 }
268
269 return NL_SKIP;
270 }
271
CreateCb(void)272 static struct nl_cb *CreateCb(void)
273 {
274 struct nl_cb *cb;
275
276 cb = nl_cb_alloc(NL_CB_DEFAULT);
277 if (cb == NULL) {
278 HILOG_ERROR(LOG_DOMAIN, "%s: alloc cb failed", __FUNCTION__);
279 return NULL;
280 }
281
282 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, NoSeqCheck, NULL);
283 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, ProcessEvent, NULL);
284
285 return cb;
286 }
287
HandleEvent(struct nl_sock * sock)288 static int HandleEvent(struct nl_sock *sock)
289 {
290 int ret;
291 struct nl_cb *cb = CreateCb();
292 if (cb == NULL) {
293 HILOG_ERROR(LOG_DOMAIN, "%s: Ceate cb failed", __FUNCTION__);
294 return RET_CODE_FAILURE;
295 }
296
297 ret = nl_recvmsgs(sock, cb);
298
299 nl_cb_put(cb);
300 cb = NULL;
301 return ret;
302 }
303
EventThread(void * para)304 void *EventThread(void *para)
305 {
306 struct nl_sock *eventSock = NULL;
307 struct pollfd pollFds[LISTEN_FD_NUMS] = {0};
308 struct WifiThreadParam *threadParam = NULL;
309 int ctrlSocks[2];
310 int ret;
311 enum ThreadStatus *status = NULL;
312
313 if (para == NULL) {
314 HILOG_ERROR(LOG_DOMAIN, "%s: para is null", __FUNCTION__);
315 return NULL;
316 } else {
317 threadParam = (struct WifiThreadParam *)para;
318 eventSock = threadParam->eventSock;
319 g_familyId = threadParam->familyId;
320 status = threadParam->status;
321 *status = THREAD_RUN;
322 }
323
324 pollFds[EVENT_SOCKET_INDEX].fd = nl_socket_get_fd(eventSock);
325 pollFds[EVENT_SOCKET_INDEX].events = POLLIN | POLLERR;
326
327 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, ctrlSocks);
328 if (ret != 0) {
329 HILOG_ERROR(LOG_DOMAIN, "%s: fail socketpair", __FUNCTION__);
330 *status = THREAD_STOP;
331 return NULL;
332 }
333 pollFds[CTRL_SOCKET_INDEX].fd = ctrlSocks[CTRL_SOCKET_READ_SIDE];
334 pollFds[CTRL_SOCKET_INDEX].events = POLLIN | POLLERR;
335
336 while (*status == THREAD_RUN) {
337 ret = TEMP_FAILURE_RETRY(poll(pollFds, LISTEN_FD_NUMS, POLLTIMEOUT));
338 if (ret < 0) {
339 HILOG_ERROR(LOG_DOMAIN, "%s: fail poll", __FUNCTION__);
340 break;
341 } else if (pollFds[EVENT_SOCKET_INDEX].revents & POLLERR) {
342 HILOG_ERROR(LOG_DOMAIN, "%s: event socket get POLLERR event", __FUNCTION__);
343 break;
344 } else if (pollFds[EVENT_SOCKET_INDEX].revents & POLLIN) {
345 if (HandleEvent(eventSock) != RET_CODE_SUCCESS) {
346 break;
347 }
348 } else if (pollFds[CTRL_SOCKET_INDEX].revents & POLLERR) {
349 HILOG_ERROR(LOG_DOMAIN, "%s: ctrl socket get POLLERR event", __FUNCTION__);
350 break;
351 } else if (pollFds[CTRL_SOCKET_INDEX].revents & POLLIN) {
352 if (HandleCtrlEvent(pollFds[CTRL_SOCKET_INDEX].fd) != RET_CODE_SUCCESS) {
353 break;
354 }
355 }
356 }
357
358 close(pollFds[CTRL_SOCKET_INDEX].fd);
359 *status = THREAD_STOP;
360 return NULL;
361 }
362