1 /*
2  * Copyright (C) 2024 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 #include <sys/socket.h>
16 #include <sys/ioctl.h>
17 #include <net/if_arp.h>
18 #include <arpa/inet.h>
19 #include <netinet/in.h>
20 #include <securec.h>
21 
22 #include "multi_gateway.h"
23 #include "singleton.h"
24 #include "wifi_logger.h"
25 #include "wifi_config_center.h"
26 
27 namespace OHOS {
28 namespace Wifi {
29 DEFINE_WIFILOG_LABEL("MultiGateway");
30 
31 constexpr int32_t DEFAULT_ARP_TIMEOUT_MS = 1000;
32 constexpr uint32_t MULTI_GATEWAY_NUM = 2;
33 constexpr int32_t MAC_ADDRESS_LENGTH = 6;
34 constexpr int32_t MAC_INDEX_0 = 0;
35 constexpr int32_t MAC_INDEX_1 = 1;
36 constexpr int32_t MAC_INDEX_2 = 2;
37 constexpr int32_t MAC_INDEX_3 = 3;
38 constexpr int32_t MAC_INDEX_4 = 4;
39 constexpr int32_t MAC_INDEX_5 = 5;
40 
MultiGateway()41 MultiGateway::MultiGateway() : m_currentIdx(0)
42 {
43     WIFI_LOGI("MultiGateway()");
44 }
45 
~MultiGateway()46 MultiGateway::~MultiGateway()
47 {
48     WIFI_LOGI("~MultiGateway()");
49 }
50 
GetGatewayAddr(int32_t instId)51 void MultiGateway::GetGatewayAddr(int32_t instId)
52 {
53     std::string macAddress;
54     WifiConfigCenter::GetInstance().GetMacAddress(macAddress, instId);
55     IpInfo ipInfo;
56     WifiConfigCenter::GetInstance().GetIpInfo(ipInfo, instId);
57     std::string ipAddress = IpTools::ConvertIpv4Address(ipInfo.ipAddress);
58     std::string ifName = WifiConfigCenter::GetInstance().GetStaIfaceName();
59     if (ipInfo.gateway == 0) {
60         WIFI_LOGE("gateway is null");
61         return;
62     }
63     m_gwIpAddr = IpTools::ConvertIpv4Address(ipInfo.gateway);
64 
65     ArpChecker arpChecker;
66     m_currentIdx = 0;
67     arpChecker.Start(ifName, macAddress, ipAddress, m_gwIpAddr);
68     arpChecker.GetGwMacAddrList(DEFAULT_ARP_TIMEOUT_MS, true, m_gwMacLists);
69     WIFI_LOGI("get gateway num is %{public}lu", static_cast<unsigned long>(m_gwMacLists.size()));
70 }
71 
IsMultiGateway()72 bool MultiGateway::IsMultiGateway()
73 {
74     return m_gwMacLists.size() >= MULTI_GATEWAY_NUM;
75 }
76 
GetGatewayIp()77 std::string MultiGateway::GetGatewayIp()
78 {
79     return m_gwIpAddr;
80 }
81 
GetNextGatewayMac(std::string & mac)82 void MultiGateway::GetNextGatewayMac(std::string& mac)
83 {
84     WIFI_LOGE("GetNextGatewayMac m_currentIdx: %{public}u", m_currentIdx);
85     if (m_currentIdx >= m_gwMacLists.size()) {
86         WIFI_LOGE("m_currentIdx is overflow, m_currentIdx: %{public}u, size: %{public}lu",
87             m_currentIdx,  static_cast<unsigned long>(m_gwMacLists.size()));
88         return;
89     }
90     mac = m_gwMacLists[m_currentIdx];
91     m_currentIdx++;
92 }
93 
SetStaticArp(const std::string & iface,const std::string & ipAddr,const std::string & macAddr)94 int32_t MultiGateway::SetStaticArp(const std::string& iface, const std::string& ipAddr, const std::string& macAddr)
95 {
96     WIFI_LOGI("SetStaticArp enter");
97     struct arpreq req;
98     struct sockaddr_in *sin = nullptr;
99 
100     if (iface.empty() || ipAddr.empty() || macAddr.empty()) {
101         WIFI_LOGE("SetStaticArp arg is invalid");
102         return -1;
103     }
104 
105     if (memset_s(&req, sizeof(struct arpreq), 0, sizeof(struct arpreq)) != EOK) {
106         WIFI_LOGE("DelStaticArp memset_s err");
107         return -1;
108     }
109     sin = reinterpret_cast<struct sockaddr_in *>(&req.arp_pa);
110     sin->sin_family = AF_INET;
111     sin->sin_addr.s_addr = inet_addr(ipAddr.c_str());
112     if (strncpy_s(req.arp_dev, sizeof(req.arp_dev), iface.c_str(), iface.size()) != EOK) {
113         WIFI_LOGE("strncpy_s req err");
114         return -1;
115     }
116 
117     req.arp_flags = ATF_PERM | ATF_COM;
118     if (GetMacAddr(reinterpret_cast<char *>(req.arp_ha.sa_data), macAddr.c_str()) < 0) {
119         WIFI_LOGE("SetStaticArp GetMacAddr error");
120         return -1;
121     }
122     return DoArpItem(SIOCSARP, &req);
123 }
124 
DelStaticArp(const std::string & iface,const std::string & ipAddr)125 int32_t MultiGateway::DelStaticArp(const std::string& iface, const std::string& ipAddr)
126 {
127     WIFI_LOGI("DelStaticArp enter");
128     struct arpreq req;
129     if (iface.empty() || ipAddr.empty()) {
130         WIFI_LOGE("DelStaticArp arg is invalid");
131         return -1;
132     }
133 
134     if (memset_s(&req, sizeof(struct arpreq), 0, sizeof(struct arpreq)) != EOK) {
135         WIFI_LOGE("DelStaticArp memset_s err");
136         return -1;
137     }
138     struct sockaddr_in *sin = reinterpret_cast<struct sockaddr_in *>(&req.arp_pa);
139     sin->sin_family = AF_INET;
140     sin->sin_addr.s_addr = inet_addr(ipAddr.c_str());
141     if (strncpy_s(req.arp_dev, sizeof(req.arp_dev), iface.c_str(), iface.size()) != EOK) {
142         WIFI_LOGE("strncpy_s req err");
143         return -1;
144     }
145     return DoArpItem(SIOCDARP, &req);
146 }
147 
DoArpItem(int32_t cmd,struct arpreq * req)148 int32_t MultiGateway::DoArpItem(int32_t cmd, struct arpreq *req)
149 {
150     if (req == nullptr) {
151         WIFI_LOGE("DoArpItem req is nullptr");
152         return -1;
153     }
154 
155     int32_t sockFd = socket(AF_INET, SOCK_DGRAM, 0);
156     if (sockFd < 0) {
157         WIFI_LOGE("DoArpItem socket creat error");
158         return -1;
159     }
160 
161     int32_t ret = ioctl(sockFd, cmd, req);
162     if (ret < 0) {
163         WIFI_LOGE("DoArpItem ioctl error");
164     }
165     close(sockFd);
166     return ret;
167 }
168 
GetMacAddr(char * buff,const char * macAddr)169 int32_t MultiGateway::GetMacAddr(char *buff, const char *macAddr)
170 {
171     unsigned int addr[MAC_ADDRESS_LENGTH] = {0};
172     if (buff == nullptr || macAddr == nullptr) {
173         WIFI_LOGE("buff or macAddr is nullptr");
174         return -1;
175     }
176 
177     if (sscanf_s(macAddr, "%x:%x:%x:%x:%x:%x", &addr[MAC_INDEX_0], &addr[MAC_INDEX_1], &addr[MAC_INDEX_2],
178         &addr[MAC_INDEX_3], &addr[MAC_INDEX_4], &addr[MAC_INDEX_5]) < MAC_ADDRESS_LENGTH) {
179         WIFI_LOGE("sscanf_s macAddr err");
180         return -1;
181     }
182 
183     for (int32_t i = 0; i < MAC_ADDRESS_LENGTH; i++) {
184         buff[i] = addr[i];
185     }
186     return 0;
187 }
188 } // namespace Wifi
189 } // namespace OHOS
190