mirror of
https://github.com/openharmony/communication_t2stack.git
synced 2026-08-26 18:46:36 -04:00
9f56148dfc
Signed-off-by: Agrant <luojuheng@huawei.com>
407 lines
13 KiB
C
407 lines
13 KiB
C
/*
|
|
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "nstackx_dev.h"
|
|
#include "nstackx_util.h"
|
|
#include "nstackx_error.h"
|
|
#include "nstackx_log.h"
|
|
#include "securec.h"
|
|
|
|
#define TAG "nStackXDev"
|
|
|
|
static int32_t GetConnectionTypeByDevName(const char *devName, uint32_t devNameLen, uint16_t *connectType)
|
|
{
|
|
int32_t ret = NSTACKX_EFAILED;
|
|
uint32_t p2pNameLen = (uint32_t)strlen(P2P_DEV_NAME_PRE);
|
|
uint32_t wlanNameLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
|
|
|
|
if (devNameLen >= p2pNameLen && memcmp(devName, P2P_DEV_NAME_PRE, p2pNameLen) == 0) {
|
|
*connectType = CONNECT_TYPE_P2P;
|
|
ret = NSTACKX_EOK;
|
|
LOGI(TAG, "connType is P2P(%hu)", *connectType);
|
|
} else if (devNameLen >= wlanNameLen && memcmp(devName, WLAN_DEV_NAME_PRE, wlanNameLen) == 0) {
|
|
*connectType = CONNECT_TYPE_WLAN;
|
|
LOGI(TAG, "connType is WLAN(%hu)", *connectType);
|
|
ret = NSTACKX_EOK;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int32_t GetInterfaceInfo(int32_t fd, int32_t option, struct ifreq *interface)
|
|
{
|
|
if (interface == NULL) {
|
|
return NSTACKX_EINVAL;
|
|
}
|
|
if (ioctl(fd, SIOCGIFFLAGS, (char*)interface) < 0) {
|
|
LOGE(TAG, "ioctl fail, errno = %d", errno);
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
if (!((uint16_t)interface->ifr_flags & IFF_UP)) {
|
|
LOGE(TAG, "interface is not up");
|
|
return NSTACKX_EINVAL;
|
|
}
|
|
|
|
/* get IP of this interface */
|
|
if (ioctl(fd, option, (char*)interface) < 0) {
|
|
LOGE(TAG, "ioctl fail, errno = %d", errno);
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
return NSTACKX_EOK;
|
|
}
|
|
|
|
int32_t GetInterfaceIP(int32_t fd, struct ifreq *interface)
|
|
{
|
|
return GetInterfaceInfo(fd, SIOCGIFADDR, interface);
|
|
}
|
|
|
|
static int32_t GetInterfaceNetMask(int32_t fd, struct ifreq *interface)
|
|
{
|
|
return GetInterfaceInfo(fd, SIOCGIFNETMASK, interface);
|
|
}
|
|
|
|
int32_t GetInterfaceList(struct ifconf *ifc, struct ifreq *buf, uint32_t size)
|
|
{
|
|
int32_t fd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (fd < 0) {
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
ifc->ifc_len = (int32_t)size;
|
|
ifc->ifc_buf = (char*)buf;
|
|
if (ioctl(fd, SIOCGIFCONF, (char*)ifc) < 0) {
|
|
LOGE(TAG, "ioctl fail, errno = %d", errno);
|
|
CloseSocketInner(fd);
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
int32_t GetConnectionTypeByDev(const uint32_t sourceIp, uint16_t *connectType)
|
|
{
|
|
struct ifreq buf[INTERFACE_MAX];
|
|
struct ifconf ifc;
|
|
|
|
uint32_t ethNameLen = (uint32_t)strlen(ETH_DEV_NAME_PRE);
|
|
uint32_t wlanNameLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
|
|
int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
|
|
if (fd < 0) {
|
|
LOGE(TAG, "get interfacelist failed");
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
|
|
int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
|
|
int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
|
|
for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
|
|
LOGI(TAG, "ndevice name: %s", buf[i].ifr_name);
|
|
uint32_t ifrNameLen = (uint32_t)strlen(buf[i].ifr_name);
|
|
if (ifrNameLen < ethNameLen && ifrNameLen < wlanNameLen) {
|
|
continue;
|
|
}
|
|
|
|
/* get IP of this interface */
|
|
int32_t state = GetInterfaceIP(fd, &buf[i]);
|
|
if (state == NSTACKX_EFAILED) {
|
|
goto L_ERROR;
|
|
} else if (state == NSTACKX_EINVAL) {
|
|
continue;
|
|
}
|
|
if (sourceIp == ((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr.s_addr) {
|
|
if (GetConnectionTypeByDevName(buf[i].ifr_name, ifrNameLen, connectType) == NSTACKX_EOK) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CloseSocketInner(fd);
|
|
return NSTACKX_EOK;
|
|
L_ERROR:
|
|
CloseSocketInner(fd);
|
|
LOGE(TAG, "get connect type failed");
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
|
|
static int32_t FindDevByInterfaceIP(int32_t fd, struct ifconf ifc, struct ifreq buf[], uint32_t sourceIP)
|
|
{
|
|
int32_t i;
|
|
int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
|
|
int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
|
|
for (i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
|
|
/* get IP of this interface */
|
|
int32_t state = GetInterfaceIP(fd, &buf[i]);
|
|
if (state == NSTACKX_EFAILED) {
|
|
return NSTACKX_EFAILED;
|
|
} else if (state == NSTACKX_EINVAL) {
|
|
continue;
|
|
}
|
|
if (sourceIP == ((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr.s_addr) {
|
|
return i;
|
|
}
|
|
}
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
|
|
int32_t GetInterfaceNameByIP(uint32_t sourceIP, char *interfaceName, size_t nameLen)
|
|
{
|
|
struct ifreq buf[INTERFACE_MAX];
|
|
struct ifconf ifc;
|
|
int32_t devIndex;
|
|
int32_t ret = NSTACKX_EOK;
|
|
int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
|
|
if (fd < 0) {
|
|
LOGE(TAG, "can't GetInterfaceList");
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
devIndex = FindDevByInterfaceIP(fd, ifc, buf, sourceIP);
|
|
CloseSocketInner(fd);
|
|
if (devIndex >= 0) {
|
|
if (strcpy_s(interfaceName, nameLen, buf[devIndex].ifr_name) != EOK) {
|
|
LOGE(TAG, "strcpy failed");
|
|
ret = NSTACKX_EFAILED;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int32_t BindToDeviceInner(int32_t sockfd, const struct ifreq *ifBinding)
|
|
{
|
|
struct ifreq ifr;
|
|
|
|
if (ifBinding == NULL) {
|
|
LOGE(TAG, "no right interface for binding");
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
if (strncpy_s(ifr.ifr_ifrn.ifrn_name, IFNAMSIZ, ifBinding->ifr_name, strlen(ifBinding->ifr_name)) != EOK) {
|
|
LOGE(TAG, "strncpy fail");
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr)) < 0) {
|
|
LOGE(TAG, "setsockopt fail, errno = %d", errno);
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
LOGI(TAG, "binding interface %s success", ifBinding->ifr_name);
|
|
return NSTACKX_EOK;
|
|
}
|
|
|
|
/*
|
|
* If localAddr isn't NULL, bind to interface correspond to ip,
|
|
* otherwise, bind to interface which is choosed by strategy.
|
|
*/
|
|
int32_t BindToDevice(SocketDesc sockfd, const struct sockaddr_in *localAddr)
|
|
{
|
|
struct ifreq buf[INTERFACE_MAX];
|
|
struct ifconf ifc;
|
|
struct ifreq *ifBinding = NULL;
|
|
uint32_t ethNameLen = (uint32_t)strlen(ETH_DEV_NAME_PRE);
|
|
uint32_t wlanNameLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
|
|
int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
|
|
if (fd < 0) {
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
|
|
int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
|
|
for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
|
|
LOGI(TAG, "device name: %s", buf[i].ifr_name);
|
|
if (strlen(buf[i].ifr_name) < ethNameLen && strlen(buf[i].ifr_name) < wlanNameLen) {
|
|
continue;
|
|
}
|
|
/* get IP of this interface */
|
|
int32_t state = GetInterfaceIP(fd, &buf[i]);
|
|
if (state == NSTACKX_EFAILED) {
|
|
goto L_ERROR;
|
|
} else if (state == NSTACKX_EINVAL) {
|
|
continue;
|
|
}
|
|
if (localAddr != NULL) {
|
|
/* find corresponding interface by ip */
|
|
if (localAddr->sin_addr.s_addr == ((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr.s_addr) {
|
|
ifBinding = &buf[i];
|
|
break;
|
|
}
|
|
} else {
|
|
/* strategy: ethernet have higher priority */
|
|
if (memcmp(buf[i].ifr_name, ETH_DEV_NAME_PRE, ethNameLen) == 0) {
|
|
ifBinding = &buf[i];
|
|
break;
|
|
} else if (memcmp(buf[i].ifr_name, WLAN_DEV_NAME_PRE, wlanNameLen) == 0) {
|
|
ifBinding = &buf[i];
|
|
}
|
|
}
|
|
}
|
|
CloseSocketInner(fd);
|
|
return BindToDeviceInner(sockfd, ifBinding);
|
|
L_ERROR:
|
|
LOGE(TAG, "ioctl fail, errno = %d", errno);
|
|
CloseSocketInner(fd);
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
|
|
int32_t GetIfBroadcastIp(const char *ifName, char *ipString, size_t ipStringLen)
|
|
{
|
|
struct ifreq buf[INTERFACE_MAX];
|
|
struct ifconf ifc;
|
|
uint8_t foundIp = NSTACKX_FALSE;
|
|
|
|
if (ifName == NULL) {
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
|
|
int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
|
|
if (fd < 0) {
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
|
|
int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
|
|
int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
|
|
for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
|
|
if (strlen(buf[i].ifr_name) < strlen(ifName)) {
|
|
continue;
|
|
}
|
|
if (memcmp(buf[i].ifr_name, ifName, strlen(ifName)) != 0) {
|
|
continue;
|
|
}
|
|
if (GetInterfaceInfo(fd, SIOCGIFBRDADDR, &buf[i]) != NSTACKX_EOK) {
|
|
continue;
|
|
}
|
|
if (buf[i].ifr_addr.sa_family != AF_INET) {
|
|
continue;
|
|
}
|
|
|
|
if (inet_ntop(AF_INET, &(((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr), ipString,
|
|
(socklen_t)ipStringLen) == NULL) {
|
|
continue;
|
|
}
|
|
foundIp = NSTACKX_TRUE;
|
|
break;
|
|
}
|
|
CloseSocketInner(fd);
|
|
|
|
if (!foundIp) {
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
|
|
return NSTACKX_EOK;
|
|
}
|
|
|
|
static uint8_t IsValidInterface(const char *interfaceName)
|
|
{
|
|
if (interfaceName == NULL) {
|
|
return NSTACKX_FALSE;
|
|
}
|
|
uint32_t targetDevLen = (uint32_t)strlen(P2P_DEV_NAME_PRE);
|
|
if (strlen(interfaceName) >= targetDevLen && memcmp(interfaceName, P2P_DEV_NAME_PRE, targetDevLen) == 0) {
|
|
return NSTACKX_TRUE;
|
|
}
|
|
targetDevLen = (uint32_t)strlen(ETH_DEV_NAME_PRE);
|
|
if (strlen(interfaceName) >= targetDevLen && memcmp(interfaceName, ETH_DEV_NAME_PRE, targetDevLen) == 0) {
|
|
return NSTACKX_TRUE;
|
|
}
|
|
targetDevLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
|
|
if (strlen(interfaceName) >= targetDevLen && memcmp(interfaceName, WLAN_DEV_NAME_PRE, targetDevLen) == 0) {
|
|
return NSTACKX_TRUE;
|
|
}
|
|
return NSTACKX_FALSE;
|
|
}
|
|
|
|
int32_t GetTargetInterface(const struct sockaddr_in *dstAddr, struct ifreq *localDev)
|
|
{
|
|
struct ifreq buf[INTERFACE_MAX];
|
|
struct ifconf ifc;
|
|
uint32_t localIp;
|
|
uint32_t netMask;
|
|
int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
|
|
if (fd < 0) {
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
|
|
int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
|
|
for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
|
|
if (!IsValidInterface(buf[i].ifr_name)) {
|
|
continue;
|
|
}
|
|
/* get IP of this interface */
|
|
int32_t state = GetInterfaceIP(fd, &buf[i]);
|
|
if (state == NSTACKX_EFAILED) {
|
|
goto L_ERROR;
|
|
} else if (state == NSTACKX_EINVAL) {
|
|
continue;
|
|
}
|
|
localIp = ((struct sockaddr_in *)(&buf[i].ifr_addr))->sin_addr.s_addr;
|
|
state = GetInterfaceNetMask(fd, &buf[i]);
|
|
if (state == NSTACKX_EFAILED) {
|
|
goto L_ERROR;
|
|
} else if (state == NSTACKX_EINVAL) {
|
|
continue;
|
|
}
|
|
netMask = ((struct sockaddr_in *)&(buf[i].ifr_netmask))->sin_addr.s_addr;
|
|
/* if localIp and dstIp are in the same LAN, fetch the interface name of thie localIp and return */
|
|
if ((dstAddr->sin_addr.s_addr & netMask) == (localIp & netMask)) {
|
|
if (strncpy_s(localDev->ifr_ifrn.ifrn_name, IFNAMSIZ, buf[i].ifr_name, strlen(buf[i].ifr_name)) != EOK) {
|
|
LOGE(TAG, "ifreq name copy failed");
|
|
goto L_ERROR;
|
|
}
|
|
CloseSocketInner(fd);
|
|
return NSTACKX_EOK;
|
|
}
|
|
}
|
|
L_ERROR:
|
|
CloseSocketInner(fd);
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
|
|
void BindToDevInTheSameLan(SocketDesc sockfd, const struct sockaddr_in *sockAddr)
|
|
{
|
|
struct ifreq localInterface;
|
|
if (sockfd < 0) {
|
|
return;
|
|
}
|
|
(void)memset_s(&localInterface, sizeof(localInterface), 0, sizeof(localInterface));
|
|
if (GetTargetInterface(sockAddr, &localInterface) != NSTACKX_EOK) {
|
|
LOGE(TAG, "get target interface fail");
|
|
return;
|
|
}
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&localInterface, sizeof(localInterface)) < 0) {
|
|
LOGE(TAG, "bind to device fail, errno = %d", errno);
|
|
return;
|
|
}
|
|
LOGI(TAG, "bind to %s successfully", localInterface.ifr_name);
|
|
}
|
|
|
|
int32_t BindToTargetDev(SocketDesc sockfd, const char *targetInterfaceName)
|
|
{
|
|
struct ifreq buf[INTERFACE_MAX];
|
|
struct ifconf ifc;
|
|
int32_t ret = NSTACKX_EFAILED;
|
|
int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
|
|
if (fd < 0) {
|
|
return NSTACKX_EFAILED;
|
|
}
|
|
int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
|
|
int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
|
|
for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
|
|
/* get IP of this interface */
|
|
int32_t state = GetInterfaceIP(fd, &buf[i]);
|
|
if (state == NSTACKX_EFAILED) {
|
|
break;
|
|
} else if (state == NSTACKX_EINVAL) {
|
|
continue;
|
|
}
|
|
if (strlen(buf[i].ifr_name) == strlen(targetInterfaceName) &&
|
|
strcmp(buf[i].ifr_name, targetInterfaceName) == 0) {
|
|
ret = BindToDeviceInner(sockfd, &buf[i]);
|
|
break;
|
|
}
|
|
}
|
|
CloseSocketInner(fd);
|
|
return ret;
|
|
}
|