• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 
29 #include "nstackx_dfinder_log.h"
30 #include "nstackx_error.h"
31 #include "nstackx_util.h"
32 #include "nstackx_epoll.h"
33 #include "nstackx_device.h"
34 #include "nstackx_timer.h"
35 #include "coap_discover/coap_discover.h"
36 #include "nstackx_statistics.h"
37 
38 #define TAG "nStackXDFinder"
39 #ifdef SUPPORT_SMARTGENIUS
40 #define BUFLEN 256
41 #define NSTACKX_POSTPONE_DELAY_MS 500
42 static EpollTask g_netlinkTask;
43 static Timer *g_postponeTimer;
44 static uint8_t g_smartGeniusInit = NSTACKX_FALSE;
45 
ParseRTattr(struct rtattr ** tb,uint32_t max,struct rtattr * attr,uint32_t len)46 static void ParseRTattr(struct rtattr **tb, uint32_t max, struct rtattr *attr, uint32_t len)
47 {
48     /*
49      * Use macro RTA_OK() and RTA_NEXT() to iterate attribute list, and fill table "tb" with attribute whose type is not
50      * greater than "max".
51      */
52     for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
53         if (attr->rta_type <= max) {
54             tb[attr->rta_type] = attr;
55         }
56     }
57 }
58 
IfAddrMsgHandle(struct nlmsghdr * msgHdr)59 static void IfAddrMsgHandle(struct nlmsghdr *msgHdr)
60 {
61     struct rtattr *tb[IFA_MAX + 1] = {0}; /* Table to store rtnetlink attribute pointers */
62     struct ifaddrmsg *ifAddr = NLMSG_DATA(msgHdr); /* Get IP address information from message */
63     if (msgHdr->nlmsg_len < NLMSG_SPACE(sizeof(struct ifaddrmsg))) {
64         return;
65     }
66     uint32_t len = msgHdr->nlmsg_len - NLMSG_SPACE(sizeof(struct ifaddrmsg));
67     NetworkInterfaceInfo interfaceInfo;
68 
69     (void)memset_s(&interfaceInfo, sizeof(interfaceInfo), 0, sizeof(interfaceInfo));
70     /* Parse attribute in "ifAddr", and store attribute pointers in "tb" */
71     ParseRTattr(tb, IFA_MAX, IFA_RTA(ifAddr), len);
72     if (tb[IFA_LABEL] == NULL || tb[IFA_ADDRESS] == NULL) {
73         return;
74     }
75 
76     if (ifAddr->ifa_family != AF_INET) {
77         return;
78     }
79 
80     if (strcpy_s(interfaceInfo.name, sizeof(interfaceInfo.name), (char *)RTA_DATA(tb[IFA_LABEL])) != EOK) {
81         return;
82     }
83 
84     UpdateAllNetworkInterfaceNameIfNeed(&interfaceInfo);
85 
86     /* Use macro RTA_DATA() to get network insterface name from attribute "IFA_LABEL". */
87     if (!FilterNetworkInterface((char *)RTA_DATA(tb[IFA_LABEL]))) {
88         return;
89     }
90 
91     if (msgHdr->nlmsg_type == RTM_NEWADDR) {
92         if (memcpy_s(&interfaceInfo.ip, sizeof(interfaceInfo.ip),
93             RTA_DATA(tb[IFA_ADDRESS]), sizeof(interfaceInfo.ip)) != EOK) {
94             return;
95         }
96         /* delay 500 ms after WiFi connection avoid "Network Unreachable" error, only activate when wlan/eth online */
97         if (!(IsUsbIpAddr((char *)RTA_DATA(tb[IFA_LABEL])) || IsP2pIpAddr((char *)RTA_DATA(tb[IFA_LABEL])))) {
98             TimerSetTimeout(g_postponeTimer, NSTACKX_POSTPONE_DELAY_MS, NSTACKX_FALSE);
99         }
100         DFINDER_LOGD(TAG, "Interface %s got new address.", interfaceInfo.name);
101     } else {
102         DFINDER_LOGD(TAG, "Interface %s delete address.", interfaceInfo.name);
103     }
104 
105     if (IsP2pIpAddr((char *)RTA_DATA(tb[IFA_LABEL]))) {
106         UpdateLocalNetworkInterfaceP2pMode(&interfaceInfo, msgHdr->nlmsg_type);
107     } else if (IsUsbIpAddr((char *)RTA_DATA(tb[IFA_LABEL]))) {
108         UpdateLocalNetworkInterfaceUsbMode(&interfaceInfo, msgHdr->nlmsg_type);
109     } else {
110         UpdateLocalNetworkInterface(&interfaceInfo);
111     }
112 }
113 
SmartGeniusCallback(void * arg)114 static void SmartGeniusCallback(void *arg)
115 {
116     struct nlmsghdr *innerNlmsghdr = NULL;
117     struct nlmsgerr *nlmErr = NULL;
118     char innerBuf[BUFLEN] = {0};
119     struct sockaddr_nl peer = {AF_NETLINK, 0, 0, 0};
120     int len;
121     socklen_t socklen;
122     EpollTask *task = arg;
123 
124     socklen = sizeof(struct sockaddr_nl);
125     len = recvfrom(task->taskfd, innerBuf, BUFLEN, 0, (struct sockaddr *)&peer, &socklen);
126     if (len <= 0) {
127         IncStatistics(STATS_SOCKET_ERROR);
128         DFINDER_LOGE(TAG, "recvfrom error %d", errno);
129         return;
130     }
131 
132     innerNlmsghdr = (struct nlmsghdr *)innerBuf;
133     switch (innerNlmsghdr->nlmsg_type) {
134         case RTM_NEWADDR:
135         case RTM_DELADDR: {
136             IfAddrMsgHandle(innerNlmsghdr);
137             break;
138         }
139         case NLMSG_ERROR: {
140             nlmErr = NLMSG_DATA(innerNlmsghdr);
141             if (nlmErr->error == 0) {
142                 DFINDER_LOGD(TAG, "NLMSG_ACK");
143             } else {
144                 DFINDER_LOGE(TAG, "NLMSG_ERROR");
145             }
146             break;
147         }
148         default:
149             break;
150     }
151     return;
152 }
153 
PostponeTimerHandle(void * data)154 static void PostponeTimerHandle(void *data)
155 {
156     (void)data;
157     CoapServiceDiscoverInner(0);
158 }
159 
SmartGeniusInit(EpollDesc epollfd)160 int32_t SmartGeniusInit(EpollDesc epollfd)
161 {
162     socklen_t len;
163     struct sockaddr_nl local = {0};
164     int fd = -1;
165 
166     if (g_smartGeniusInit) {
167         return NSTACKX_EOK;
168     }
169 
170     local.nl_family = AF_NETLINK;
171     local.nl_groups = RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
172     local.nl_pid = getpid();
173     len = sizeof(local);
174 
175     fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
176     if (fd < 0) {
177         DFINDER_LOGE(TAG, "unable to create netlink socket: %d", errno);
178         return NSTACKX_EFAILED;
179     }
180 
181     if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
182         DFINDER_LOGE(TAG, "bind for netlink socket failed: %d", errno);
183         close(fd);
184         return NSTACKX_EFAILED;
185     }
186 
187     if (getsockname(fd, (struct sockaddr *)&local, &len) < 0) {
188         DFINDER_LOGE(TAG, "getsockname failed: %d", errno);
189         close(fd);
190         return NSTACKX_EFAILED;
191     }
192 
193     g_netlinkTask.taskfd = fd;
194     g_netlinkTask.epollfd = epollfd;
195     g_netlinkTask.readHandle = SmartGeniusCallback;
196     g_netlinkTask.writeHandle = NULL;
197     g_netlinkTask.errorHandle = NULL;
198     g_netlinkTask.count = 0;
199     if (RegisterEpollTask(&g_netlinkTask, EPOLLIN) != NSTACKX_EOK) {
200         close(fd);
201         DFINDER_LOGE(TAG, "RegisterEpollTask fail");
202         return NSTACKX_EFAILED;
203     }
204 
205     g_postponeTimer = TimerStart(epollfd, 0, NSTACKX_FALSE, PostponeTimerHandle, NULL);
206     if (g_postponeTimer == NULL) {
207         DeRegisterEpollTask(&g_netlinkTask);
208         close(g_netlinkTask.taskfd);
209         DFINDER_LOGE(TAG, "Create timer fail");
210         return NSTACKX_EFAILED;
211     }
212 
213     g_smartGeniusInit = NSTACKX_TRUE;
214     return NSTACKX_EOK;
215 }
216 
SmartGeniusClean(void)217 void SmartGeniusClean(void)
218 {
219     if (!g_smartGeniusInit) {
220         return;
221     }
222 
223     TimerDelete(g_postponeTimer);
224     g_postponeTimer = NULL;
225     DeRegisterEpollTask(&g_netlinkTask);
226     close(g_netlinkTask.taskfd);
227     g_smartGeniusInit = NSTACKX_FALSE;
228 }
229 
ResetSmartGeniusTaskCount(uint8_t isBusy)230 void ResetSmartGeniusTaskCount(uint8_t isBusy)
231 {
232     if (isBusy) {
233         DFINDER_LOGI(TAG, "in this busy interval: g_netlinkTask count %llu", g_netlinkTask.count);
234     }
235     g_netlinkTask.count = 0;
236 
237     if (g_postponeTimer != NULL) {
238         if (isBusy) {
239             DFINDER_LOGI(TAG, "in this busy interval: g_postponeTimer task count %llu", g_postponeTimer->task.count);
240         }
241         g_postponeTimer->task.count = 0;
242     }
243 }
244 #else
SmartGeniusInit(EpollDesc epollfd)245 int32_t SmartGeniusInit(EpollDesc epollfd)
246 {
247     (void)epollfd;
248     return NSTACKX_EOK;
249 }
250 
SmartGeniusClean(void)251 void SmartGeniusClean(void)
252 {
253 }
254 
ResetSmartGeniusTaskCount(uint8_t isBusy)255 void ResetSmartGeniusTaskCount(uint8_t isBusy)
256 {
257     (void)isBusy;
258 }
259 #endif /* SUPPORT_SMARTGENIUS */
260