1 /*
2 * Copyright (C) 2021-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 "nstackx_smartgenius.h"
17 #include <errno.h>
18 #include <string.h>
19 #include <securec.h>
20 #include <sys/types.h>
21 #ifdef SUPPORT_SMARTGENIUS
22 #include <sys/socket.h>
23 #include <unistd.h>
24 #include <linux/netlink.h>
25 #include <linux/rtnetlink.h>
26 #include <arpa/inet.h>
27 #endif /* SUPPORT_SMARTGENIUS */
28 #include <time.h>
29
30 #include "nstackx_dfinder_log.h"
31 #include "nstackx_error.h"
32 #include "nstackx_util.h"
33 #include "nstackx_epoll.h"
34 #include "nstackx_device.h"
35 #include "nstackx_timer.h"
36 #include "coap_discover/coap_discover.h"
37 #include "nstackx_statistics.h"
38 #include "nstackx_device_local.h"
39 #include "nstackx_device_remote.h"
40
41 #define TAG "nStackXDFinder"
42 #ifdef SUPPORT_SMARTGENIUS
43 #define BUFLEN 256
44 #define NSTACKX_POSTPONE_DELAY_MS 500
45 #define NSTACKX_NETLINK_RECOVER_MS 300000 // 5min
46 #define NSTACKX_ERROR_INTERVAL_S 5 // 5s
47
48 typedef enum {
49 NETLINK_SOCKET_READ_EVENT = 0,
50 NETLINK_SOCKET_WRITE_EVENT,
51 NETLINK_SOCKET_ERROR_EVENT,
52 NETLINK_SOCKET_EVENT
53 } NetLinkSocketEventType;
54 static uint64_t g_netlinkSocketEventNum[NETLINK_SOCKET_EVENT];
55
56 static EpollTask g_netlinkTask;
57 static uint8_t g_smartGeniusInit = NSTACKX_FALSE;
58 static Timer *g_recoverTimer;
59 static long g_lastErrorTimeS = -1;
60
ParseRTattr(struct rtattr ** tb,uint32_t max,struct rtattr * attr,uint32_t len)61 static void ParseRTattr(struct rtattr **tb, uint32_t max, struct rtattr *attr, uint32_t len)
62 {
63 /*
64 * Use macro RTA_OK() and RTA_NEXT() to iterate attribute list, and fill table "tb" with attribute whose type is not
65 * greater than "max".
66 */
67 for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
68 if (attr->rta_type <= max) {
69 tb[attr->rta_type] = attr;
70 }
71 }
72 }
73
CreateNetLinkSocketFd()74 static int CreateNetLinkSocketFd()
75 {
76 struct sockaddr_nl local = {0};
77 local.nl_family = AF_NETLINK;
78 local.nl_groups = RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
79 local.nl_pid = getpid();
80 socklen_t len = sizeof(local);
81
82 int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
83 if (fd < 0) {
84 DFINDER_LOGE(TAG, "unable to create netlink socket: %d", errno);
85 return NSTACKX_EFAILED;
86 }
87 if (bind(fd, (struct sockaddr *)&local, len) < 0) {
88 DFINDER_LOGE(TAG, "bind for netlink socket failed: %d", errno);
89 close(fd);
90 return NSTACKX_EFAILED;
91 }
92 if (getsockname(fd, (struct sockaddr *)&local, &len)) {
93 DFINDER_LOGE(TAG, "getsockname failed: %d", errno);
94 close(fd);
95 return NSTACKX_EFAILED;
96 }
97 return fd;
98 }
99
IfAddrMsgHandle(struct nlmsghdr * msgHdr)100 static void IfAddrMsgHandle(struct nlmsghdr *msgHdr)
101 {
102 struct rtattr *tb[IFA_MAX + 1] = {0}; /* Table to store rtnetlink attribute pointers */
103 struct ifaddrmsg *ifAddr = NLMSG_DATA(msgHdr); /* Get IP address information from message */
104 if (msgHdr->nlmsg_len < NLMSG_SPACE(sizeof(struct ifaddrmsg))) {
105 return;
106 }
107 uint32_t len = msgHdr->nlmsg_len - NLMSG_SPACE(sizeof(struct ifaddrmsg));
108 NetworkInterfaceInfo interfaceInfo;
109
110 (void)memset_s(&interfaceInfo, sizeof(interfaceInfo), 0, sizeof(interfaceInfo));
111 /* Parse attribute in "ifAddr", and store attribute pointers in "tb" */
112 ParseRTattr(tb, IFA_MAX, IFA_RTA(ifAddr), len);
113 if (tb[IFA_LABEL] == NULL || tb[IFA_ADDRESS] == NULL) {
114 return;
115 }
116
117 if (ifAddr->ifa_family != AF_INET) {
118 return;
119 }
120
121 if (strcpy_s(interfaceInfo.name, sizeof(interfaceInfo.name), (char *)RTA_DATA(tb[IFA_LABEL])) != EOK) {
122 return;
123 }
124
125 UpdateAllNetworkInterfaceNameIfNeed(&interfaceInfo);
126
127 /* Use macro RTA_DATA() to get network insterface name from attribute "IFA_LABEL". */
128 uint8_t ifaceType = GetIfaceType((char *)RTA_DATA(tb[IFA_LABEL]));
129 if (ifaceType >= IFACE_TYPE_UNKNOWN) {
130 DFINDER_LOGE(TAG, "unknown iface type %s", (char *)RTA_DATA(tb[IFA_LABEL]));
131 return;
132 }
133
134 if (msgHdr->nlmsg_type == RTM_NEWADDR) {
135 if (memcpy_s(&interfaceInfo.ip, sizeof(interfaceInfo.ip),
136 RTA_DATA(tb[IFA_ADDRESS]), sizeof(interfaceInfo.ip)) != EOK) {
137 return;
138 }
139 DFINDER_LOGD(TAG, "Interface %s got new address.", interfaceInfo.name);
140 AddLocalIface(interfaceInfo.name, &interfaceInfo.ip);
141 } else {
142 DFINDER_LOGD(TAG, "Interface %s delete address.", interfaceInfo.name);
143 RemoveLocalIface(interfaceInfo.name);
144 }
145 }
146
SmartGeniusCallback(void * arg)147 static void SmartGeniusCallback(void *arg)
148 {
149 g_netlinkSocketEventNum[NETLINK_SOCKET_READ_EVENT]++;
150 struct nlmsghdr *innerNlmsghdr = NULL;
151 struct nlmsgerr *nlmErr = NULL;
152 char innerBuf[BUFLEN] = {0};
153 struct sockaddr_nl peer = {AF_NETLINK, 0, 0, 0};
154 int len;
155 socklen_t socklen;
156 EpollTask *task = arg;
157
158 socklen = sizeof(struct sockaddr_nl);
159 len = recvfrom(task->taskfd, innerBuf, BUFLEN, 0, (struct sockaddr *)&peer, &socklen);
160 if (len <= 0) {
161 IncStatistics(STATS_SOCKET_ERROR);
162 DFINDER_LOGE(TAG, "recvfrom error %d", errno);
163 return;
164 }
165
166 innerNlmsghdr = (struct nlmsghdr *)innerBuf;
167 switch (innerNlmsghdr->nlmsg_type) {
168 case RTM_NEWADDR:
169 case RTM_DELADDR: {
170 IfAddrMsgHandle(innerNlmsghdr);
171 break;
172 }
173 case NLMSG_ERROR: {
174 nlmErr = NLMSG_DATA(innerNlmsghdr);
175 if (nlmErr->error == 0) {
176 DFINDER_LOGD(TAG, "NLMSG_ACK");
177 } else {
178 DFINDER_LOGE(TAG, "NLMSG_ERROR");
179 }
180 break;
181 }
182 default:
183 break;
184 }
185 return;
186 }
187
NetlinkWriteHandle(void * data)188 static void NetlinkWriteHandle(void *data)
189 {
190 (void)data;
191 g_netlinkSocketEventNum[NETLINK_SOCKET_WRITE_EVENT]++;
192 }
193
NetlinkErrorHandle(void * data UNUSED)194 static void NetlinkErrorHandle(void *data UNUSED)
195 {
196 g_netlinkSocketEventNum[NETLINK_SOCKET_ERROR_EVENT]++;
197 DFINDER_LOGE(TAG, "Netlink Socket ErrorHandle");
198 struct timespec errorTime;
199 if (clock_gettime(CLOCK_MONOTONIC, &errorTime) != 0) {
200 DFINDER_LOGE(TAG, "Get current time fail");
201 NotifyDFinderMsgRecver(DFINDER_ON_INNER_ERROR);
202 return;
203 }
204 long currErrorTimeS = errorTime.tv_sec;
205 if (g_lastErrorTimeS > 0 && (currErrorTimeS - g_lastErrorTimeS < NSTACKX_ERROR_INTERVAL_S)) {
206 // if exception triggered more than twice within 5s: close socket and restart it after 5min
207 (void)DeRegisterEpollTask(&g_netlinkTask);
208 close(g_netlinkTask.taskfd);
209 g_netlinkTask.taskfd = -1;
210 if (TimerSetTimeout(g_recoverTimer, NSTACKX_NETLINK_RECOVER_MS, NSTACKX_FALSE) != NSTACKX_EOK) {
211 DFINDER_LOGE(TAG, "Timer setting timer fail");
212 g_lastErrorTimeS = currErrorTimeS;
213 NotifyDFinderMsgRecver(DFINDER_ON_INNER_ERROR);
214 return;
215 }
216 g_lastErrorTimeS = -1;
217 return;
218 }
219 g_lastErrorTimeS = currErrorTimeS;
220 }
221
RecoverNetLinkTask()222 static void RecoverNetLinkTask()
223 {
224 if (!g_smartGeniusInit) {
225 return;
226 }
227 g_netlinkTask.taskfd = CreateNetLinkSocketFd();
228 if (g_netlinkTask.taskfd < 0) {
229 DFINDER_LOGE(TAG, "unable to create netlink socket: %d", errno);
230 NotifyDFinderMsgRecver(DFINDER_ON_INNER_ERROR);
231 return;
232 }
233 if (RegisterEpollTask(&g_netlinkTask, EPOLLIN) != NSTACKX_EOK) {
234 DFINDER_LOGE(TAG, "RegisterEpollTask fail");
235 close(g_netlinkTask.taskfd);
236 g_netlinkTask.taskfd = -1;
237 NotifyDFinderMsgRecver(DFINDER_ON_INNER_ERROR);
238 return;
239 }
240 DFINDER_LOGI(TAG, "Recover netlink task success");
241 }
242
SmartGeniusInit(EpollDesc epollfd)243 int32_t SmartGeniusInit(EpollDesc epollfd)
244 {
245 if (g_smartGeniusInit) {
246 return NSTACKX_EOK;
247 }
248 int fd = CreateNetLinkSocketFd();
249 if (fd < 0) {
250 DFINDER_LOGE(TAG, "unable to create netlink socket");
251 return NSTACKX_EFAILED;
252 }
253 g_netlinkTask.taskfd = fd;
254 g_netlinkTask.epollfd = epollfd;
255 g_netlinkTask.readHandle = SmartGeniusCallback;
256 g_netlinkTask.writeHandle = NetlinkWriteHandle;
257 g_netlinkTask.errorHandle = NetlinkErrorHandle;
258 g_netlinkTask.count = 0;
259 if (RegisterEpollTask(&g_netlinkTask, EPOLLIN) != NSTACKX_EOK) {
260 DFINDER_LOGE(TAG, "RegisterEpollTask fail");
261 goto L_CLOSE;
262 }
263 g_recoverTimer = TimerStart(epollfd, 0, NSTACKX_FALSE, RecoverNetLinkTask, NULL);
264 if (g_recoverTimer == NULL) {
265 DFINDER_LOGE(TAG, "Create recover timer fail");
266 goto L_ERR;
267 }
268 g_lastErrorTimeS = -1;
269 g_smartGeniusInit = NSTACKX_TRUE;
270 return NSTACKX_EOK;
271 L_ERR:
272 (void)DeRegisterEpollTask(&g_netlinkTask);
273 L_CLOSE:
274 close(g_netlinkTask.taskfd);
275 g_netlinkTask.taskfd = -1;
276 return NSTACKX_EFAILED;
277 }
278
SmartGeniusClean(void)279 void SmartGeniusClean(void)
280 {
281 if (!g_smartGeniusInit) {
282 return;
283 }
284
285 TimerDelete(g_recoverTimer);
286 g_recoverTimer = NULL;
287 g_lastErrorTimeS = -1;
288 if (g_netlinkTask.taskfd != -1) {
289 (void)DeRegisterEpollTask(&g_netlinkTask);
290 close(g_netlinkTask.taskfd);
291 g_netlinkTask.taskfd = -1;
292 }
293 g_smartGeniusInit = NSTACKX_FALSE;
294 }
295
ResetSmartGeniusTaskCount(uint8_t isBusy)296 void ResetSmartGeniusTaskCount(uint8_t isBusy)
297 {
298 if (isBusy) {
299 DFINDER_LOGI(TAG, "in this busy interval: g_netlinkTask count %llu", g_netlinkTask.count);
300 }
301 g_netlinkTask.count = 0;
302
303 if (isBusy) {
304 DFINDER_LOGI(TAG, "SmartGeniusCallback has been called %lu times",
305 g_netlinkSocketEventNum[NETLINK_SOCKET_READ_EVENT]);
306 DFINDER_LOGI(TAG, "NetlinkWriteHandle has been called %lu times",
307 g_netlinkSocketEventNum[NETLINK_SOCKET_WRITE_EVENT]);
308 DFINDER_LOGI(TAG, "NetlinkErrorHandle has benn called %lu times",
309 g_netlinkSocketEventNum[NETLINK_SOCKET_ERROR_EVENT]);
310 }
311 (void)memset_s(g_netlinkSocketEventNum, sizeof(g_netlinkSocketEventNum), 0, sizeof(g_netlinkSocketEventNum));
312 }
313 #else
SmartGeniusInit(EpollDesc epollfd)314 int32_t SmartGeniusInit(EpollDesc epollfd)
315 {
316 (void)epollfd;
317 return NSTACKX_EOK;
318 }
319
SmartGeniusClean(void)320 void SmartGeniusClean(void)
321 {
322 }
323
ResetSmartGeniusTaskCount(uint8_t isBusy)324 void ResetSmartGeniusTaskCount(uint8_t isBusy)
325 {
326 (void)isBusy;
327 }
328 #endif /* SUPPORT_SMARTGENIUS */
329