• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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