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