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_dev.h"
17 #include "nstackx_util.h"
18 #include "nstackx_error.h"
19 #include "nstackx_log.h"
20 #include "securec.h"
21
22 #define TAG "nStackXDev"
23
GetConnectionTypeByDevName(const char * devName,uint32_t devNameLen,uint16_t * connectType)24 static int32_t GetConnectionTypeByDevName(const char *devName, uint32_t devNameLen, uint16_t *connectType)
25 {
26 int32_t ret = NSTACKX_EFAILED;
27 uint32_t p2pNameLen = (uint32_t)strlen(P2P_DEV_NAME_PRE);
28 uint32_t wlanNameLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
29
30 if (devNameLen >= p2pNameLen && memcmp(devName, P2P_DEV_NAME_PRE, p2pNameLen) == 0) {
31 *connectType = CONNECT_TYPE_P2P;
32 ret = NSTACKX_EOK;
33 LOGI(TAG, "connType is P2P(%hu)", *connectType);
34 } else if (devNameLen >= wlanNameLen && memcmp(devName, WLAN_DEV_NAME_PRE, wlanNameLen) == 0) {
35 *connectType = CONNECT_TYPE_WLAN;
36 LOGI(TAG, "connType is WLAN(%hu)", *connectType);
37 ret = NSTACKX_EOK;
38 }
39 return ret;
40 }
41
GetInterfaceInfo(int32_t fd,int32_t option,struct ifreq * interface)42 static int32_t GetInterfaceInfo(int32_t fd, int32_t option, struct ifreq *interface)
43 {
44 if (interface == NULL) {
45 return NSTACKX_EINVAL;
46 }
47 if (ioctl(fd, SIOCGIFFLAGS, (char*)interface) < 0) {
48 LOGE(TAG, "ioctl fail, errno = %d", errno);
49 return NSTACKX_EFAILED;
50 }
51 if (!((uint16_t)interface->ifr_flags & IFF_UP)) {
52 LOGE(TAG, "interface is not up");
53 return NSTACKX_EINVAL;
54 }
55
56 /* get IP of this interface */
57 if (ioctl(fd, option, (char*)interface) < 0) {
58 LOGE(TAG, "ioctl fail, errno = %d", errno);
59 return NSTACKX_EFAILED;
60 }
61 return NSTACKX_EOK;
62 }
63
GetInterfaceIP(int32_t fd,struct ifreq * interface)64 int32_t GetInterfaceIP(int32_t fd, struct ifreq *interface)
65 {
66 return GetInterfaceInfo(fd, SIOCGIFADDR, interface);
67 }
68
GetInterfaceNetMask(int32_t fd,struct ifreq * interface)69 static int32_t GetInterfaceNetMask(int32_t fd, struct ifreq *interface)
70 {
71 return GetInterfaceInfo(fd, SIOCGIFNETMASK, interface);
72 }
73
GetInterfaceList(struct ifconf * ifc,struct ifreq * buf,uint32_t size)74 int32_t GetInterfaceList(struct ifconf *ifc, struct ifreq *buf, uint32_t size)
75 {
76 int32_t fd = socket(AF_INET, SOCK_DGRAM, 0);
77 if (fd < 0) {
78 return NSTACKX_EFAILED;
79 }
80 ifc->ifc_len = (int32_t)size;
81 ifc->ifc_buf = (char*)buf;
82 if (ioctl(fd, SIOCGIFCONF, (char*)ifc) < 0) {
83 LOGE(TAG, "ioctl fail, errno = %d", errno);
84 CloseSocketInner(fd);
85 return NSTACKX_EFAILED;
86 }
87 return fd;
88 }
89
GetConnectionTypeByDev(const uint32_t sourceIp,uint16_t * connectType)90 int32_t GetConnectionTypeByDev(const uint32_t sourceIp, uint16_t *connectType)
91 {
92 struct ifreq buf[INTERFACE_MAX];
93 struct ifconf ifc;
94
95 uint32_t ethNameLen = (uint32_t)strlen(ETH_DEV_NAME_PRE);
96 uint32_t wlanNameLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
97 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
98 if (fd < 0) {
99 LOGE(TAG, "get interfacelist failed");
100 return NSTACKX_EFAILED;
101 }
102
103 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
104 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
105 for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
106 LOGI(TAG, "ndevice name: %s", buf[i].ifr_name);
107 uint32_t ifrNameLen = (uint32_t)strlen(buf[i].ifr_name);
108 if (ifrNameLen < ethNameLen && ifrNameLen < wlanNameLen) {
109 continue;
110 }
111
112 /* get IP of this interface */
113 int32_t state = GetInterfaceIP(fd, &buf[i]);
114 if (state == NSTACKX_EFAILED) {
115 goto L_ERROR;
116 } else if (state == NSTACKX_EINVAL) {
117 continue;
118 }
119 if (sourceIp == ((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr.s_addr) {
120 if (GetConnectionTypeByDevName(buf[i].ifr_name, ifrNameLen, connectType) == NSTACKX_EOK) {
121 break;
122 }
123 }
124 }
125 CloseSocketInner(fd);
126 return NSTACKX_EOK;
127 L_ERROR:
128 CloseSocketInner(fd);
129 LOGE(TAG, "get connect type failed");
130 return NSTACKX_EFAILED;
131 }
132
FindDevByInterfaceIP(int32_t fd,struct ifconf ifc,struct ifreq buf[],uint32_t sourceIP)133 static int32_t FindDevByInterfaceIP(int32_t fd, struct ifconf ifc, struct ifreq buf[], uint32_t sourceIP)
134 {
135 int32_t i;
136 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
137 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
138 for (i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
139 /* get IP of this interface */
140 int32_t state = GetInterfaceIP(fd, &buf[i]);
141 if (state == NSTACKX_EFAILED) {
142 return NSTACKX_EFAILED;
143 } else if (state == NSTACKX_EINVAL) {
144 continue;
145 }
146 if (sourceIP == ((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr.s_addr) {
147 return i;
148 }
149 }
150 return NSTACKX_EFAILED;
151 }
152
GetInterfaceNameByIP(uint32_t sourceIP,char * interfaceName,size_t nameLen)153 int32_t GetInterfaceNameByIP(uint32_t sourceIP, char *interfaceName, size_t nameLen)
154 {
155 struct ifreq buf[INTERFACE_MAX];
156 struct ifconf ifc;
157 int32_t devIndex;
158 int32_t ret = NSTACKX_EOK;
159 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
160 if (fd < 0) {
161 LOGE(TAG, "can't GetInterfaceList");
162 return NSTACKX_EFAILED;
163 }
164 devIndex = FindDevByInterfaceIP(fd, ifc, buf, sourceIP);
165 CloseSocketInner(fd);
166 if (devIndex >= 0) {
167 if (strcpy_s(interfaceName, nameLen, buf[devIndex].ifr_name) != EOK) {
168 LOGE(TAG, "strcpy failed");
169 ret = NSTACKX_EFAILED;
170 }
171 }
172 return ret;
173 }
174
BindToDeviceInner(int32_t sockfd,const struct ifreq * ifBinding)175 static int32_t BindToDeviceInner(int32_t sockfd, const struct ifreq *ifBinding)
176 {
177 struct ifreq ifr;
178
179 if (ifBinding == NULL) {
180 LOGE(TAG, "no right interface for binding");
181 return NSTACKX_EFAILED;
182 }
183 if (strncpy_s(ifr.ifr_ifrn.ifrn_name, IFNAMSIZ, ifBinding->ifr_name, strlen(ifBinding->ifr_name)) != EOK) {
184 LOGE(TAG, "strncpy fail");
185 return NSTACKX_EFAILED;
186 }
187 if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr)) < 0) {
188 LOGE(TAG, "setsockopt fail, errno = %d", errno);
189 return NSTACKX_EFAILED;
190 }
191 LOGI(TAG, "binding interface %s success", ifBinding->ifr_name);
192 return NSTACKX_EOK;
193 }
194
195 /*
196 * If localAddr isn't NULL, bind to interface correspond to ip,
197 * otherwise, bind to interface which is choosed by strategy.
198 */
BindToDevice(SocketDesc sockfd,const struct sockaddr_in * localAddr)199 int32_t BindToDevice(SocketDesc sockfd, const struct sockaddr_in *localAddr)
200 {
201 struct ifreq buf[INTERFACE_MAX];
202 struct ifconf ifc;
203 struct ifreq *ifBinding = NULL;
204 uint32_t ethNameLen = (uint32_t)strlen(ETH_DEV_NAME_PRE);
205 uint32_t wlanNameLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
206 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
207 if (fd < 0) {
208 return NSTACKX_EFAILED;
209 }
210 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
211 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
212 for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
213 LOGI(TAG, "device name: %s", buf[i].ifr_name);
214 if (strlen(buf[i].ifr_name) < ethNameLen && strlen(buf[i].ifr_name) < wlanNameLen) {
215 continue;
216 }
217 /* get IP of this interface */
218 int32_t state = GetInterfaceIP(fd, &buf[i]);
219 if (state == NSTACKX_EFAILED) {
220 goto L_ERROR;
221 } else if (state == NSTACKX_EINVAL) {
222 continue;
223 }
224 if (localAddr != NULL) {
225 /* find corresponding interface by ip */
226 if (localAddr->sin_addr.s_addr == ((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr.s_addr) {
227 ifBinding = &buf[i];
228 break;
229 }
230 } else {
231 /* strategy: ethernet have higher priority */
232 if (memcmp(buf[i].ifr_name, ETH_DEV_NAME_PRE, ethNameLen) == 0) {
233 ifBinding = &buf[i];
234 break;
235 } else if (memcmp(buf[i].ifr_name, WLAN_DEV_NAME_PRE, wlanNameLen) == 0) {
236 ifBinding = &buf[i];
237 }
238 }
239 }
240 CloseSocketInner(fd);
241 return BindToDeviceInner(sockfd, ifBinding);
242 L_ERROR:
243 LOGE(TAG, "ioctl fail, errno = %d", errno);
244 CloseSocketInner(fd);
245 return NSTACKX_EFAILED;
246 }
247
GetIfBroadcastIp(const char * ifName,char * ipString,size_t ipStringLen)248 int32_t GetIfBroadcastIp(const char *ifName, char *ipString, size_t ipStringLen)
249 {
250 struct ifreq buf[INTERFACE_MAX];
251 struct ifconf ifc;
252 uint8_t foundIp = NSTACKX_FALSE;
253
254 if (ifName == NULL) {
255 return NSTACKX_EFAILED;
256 }
257
258 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
259 if (fd < 0) {
260 return NSTACKX_EFAILED;
261 }
262
263 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
264 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
265 for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
266 if (strlen(buf[i].ifr_name) < strlen(ifName)) {
267 continue;
268 }
269 if (memcmp(buf[i].ifr_name, ifName, strlen(ifName)) != 0) {
270 continue;
271 }
272 if (GetInterfaceInfo(fd, SIOCGIFBRDADDR, &buf[i]) != NSTACKX_EOK) {
273 continue;
274 }
275 if (buf[i].ifr_addr.sa_family != AF_INET) {
276 continue;
277 }
278
279 if (inet_ntop(AF_INET, &(((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr), ipString,
280 (socklen_t)ipStringLen) == NULL) {
281 continue;
282 }
283 foundIp = NSTACKX_TRUE;
284 break;
285 }
286 CloseSocketInner(fd);
287
288 if (!foundIp) {
289 return NSTACKX_EFAILED;
290 }
291
292 return NSTACKX_EOK;
293 }
294
IsValidInterface(const char * interfaceName)295 static uint8_t IsValidInterface(const char *interfaceName)
296 {
297 if (interfaceName == NULL) {
298 return NSTACKX_FALSE;
299 }
300 uint32_t targetDevLen = (uint32_t)strlen(P2P_DEV_NAME_PRE);
301 if (strlen(interfaceName) >= targetDevLen && memcmp(interfaceName, P2P_DEV_NAME_PRE, targetDevLen) == 0) {
302 return NSTACKX_TRUE;
303 }
304 targetDevLen = (uint32_t)strlen(ETH_DEV_NAME_PRE);
305 if (strlen(interfaceName) >= targetDevLen && memcmp(interfaceName, ETH_DEV_NAME_PRE, targetDevLen) == 0) {
306 return NSTACKX_TRUE;
307 }
308 targetDevLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
309 if (strlen(interfaceName) >= targetDevLen && memcmp(interfaceName, WLAN_DEV_NAME_PRE, targetDevLen) == 0) {
310 return NSTACKX_TRUE;
311 }
312 return NSTACKX_FALSE;
313 }
314
GetTargetInterface(const struct sockaddr_in * dstAddr,struct ifreq * localDev)315 int32_t GetTargetInterface(const struct sockaddr_in *dstAddr, struct ifreq *localDev)
316 {
317 struct ifreq buf[INTERFACE_MAX];
318 struct ifconf ifc;
319 uint32_t localIp;
320 uint32_t netMask;
321 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
322 if (fd < 0) {
323 return NSTACKX_EFAILED;
324 }
325 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
326 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
327 for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
328 if (!IsValidInterface(buf[i].ifr_name)) {
329 continue;
330 }
331 /* get IP of this interface */
332 int32_t state = GetInterfaceIP(fd, &buf[i]);
333 if (state == NSTACKX_EFAILED) {
334 goto L_ERROR;
335 } else if (state == NSTACKX_EINVAL) {
336 continue;
337 }
338 localIp = ((struct sockaddr_in *)(&buf[i].ifr_addr))->sin_addr.s_addr;
339 state = GetInterfaceNetMask(fd, &buf[i]);
340 if (state == NSTACKX_EFAILED) {
341 goto L_ERROR;
342 } else if (state == NSTACKX_EINVAL) {
343 continue;
344 }
345 netMask = ((struct sockaddr_in *)&(buf[i].ifr_netmask))->sin_addr.s_addr;
346 /* if localIp and dstIp are in the same LAN, fetch the interface name of thie localIp and return */
347 if ((dstAddr->sin_addr.s_addr & netMask) == (localIp & netMask)) {
348 if (strncpy_s(localDev->ifr_ifrn.ifrn_name, IFNAMSIZ, buf[i].ifr_name, strlen(buf[i].ifr_name)) != EOK) {
349 LOGE(TAG, "ifreq name copy failed");
350 goto L_ERROR;
351 }
352 CloseSocketInner(fd);
353 return NSTACKX_EOK;
354 }
355 }
356 L_ERROR:
357 CloseSocketInner(fd);
358 return NSTACKX_EFAILED;
359 }
360
BindToDevInTheSameLan(SocketDesc sockfd,const struct sockaddr_in * sockAddr)361 void BindToDevInTheSameLan(SocketDesc sockfd, const struct sockaddr_in *sockAddr)
362 {
363 struct ifreq localInterface;
364 if (sockfd < 0) {
365 return;
366 }
367 (void)memset_s(&localInterface, sizeof(localInterface), 0, sizeof(localInterface));
368 if (GetTargetInterface(sockAddr, &localInterface) != NSTACKX_EOK) {
369 LOGE(TAG, "get target interface fail");
370 return;
371 }
372 if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&localInterface, sizeof(localInterface)) < 0) {
373 LOGE(TAG, "bind to device fail, errno = %d", errno);
374 return;
375 }
376 LOGI(TAG, "bind to %s successfully", localInterface.ifr_name);
377 }
378
BindToTargetDev(SocketDesc sockfd,const char * targetInterfaceName)379 int32_t BindToTargetDev(SocketDesc sockfd, const char *targetInterfaceName)
380 {
381 struct ifreq buf[INTERFACE_MAX];
382 struct ifconf ifc;
383 int32_t ret = NSTACKX_EFAILED;
384 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
385 if (fd < 0) {
386 return NSTACKX_EFAILED;
387 }
388 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
389 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
390 for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
391 /* get IP of this interface */
392 int32_t state = GetInterfaceIP(fd, &buf[i]);
393 if (state == NSTACKX_EFAILED) {
394 break;
395 } else if (state == NSTACKX_EINVAL) {
396 continue;
397 }
398 if (strlen(buf[i].ifr_name) == strlen(targetInterfaceName) &&
399 strcmp(buf[i].ifr_name, targetInterfaceName) == 0) {
400 ret = BindToDeviceInner(sockfd, &buf[i]);
401 break;
402 }
403 }
404 CloseSocketInner(fd);
405 return ret;
406 }
407