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