1b1b8bc3fSopenharmony_ci/*
2b1b8bc3fSopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3b1b8bc3fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b1b8bc3fSopenharmony_ci * you may not use this file except in compliance with the License.
5b1b8bc3fSopenharmony_ci * You may obtain a copy of the License at
6b1b8bc3fSopenharmony_ci *
7b1b8bc3fSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8b1b8bc3fSopenharmony_ci *
9b1b8bc3fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b1b8bc3fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b1b8bc3fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b1b8bc3fSopenharmony_ci * See the License for the specific language governing permissions and
13b1b8bc3fSopenharmony_ci * limitations under the License.
14b1b8bc3fSopenharmony_ci */
15b1b8bc3fSopenharmony_ci
16b1b8bc3fSopenharmony_ci#include "clatd.h"
17b1b8bc3fSopenharmony_ci
18b1b8bc3fSopenharmony_ci#include <arpa/inet.h>
19b1b8bc3fSopenharmony_ci#include <cerrno>
20b1b8bc3fSopenharmony_ci#include <climits>
21b1b8bc3fSopenharmony_ci#include <cstdlib>
22b1b8bc3fSopenharmony_ci#include <linux/if_packet.h>
23b1b8bc3fSopenharmony_ci#include <net/if.h>
24b1b8bc3fSopenharmony_ci#include <netinet/icmp6.h>
25b1b8bc3fSopenharmony_ci#include <netinet/in.h>
26b1b8bc3fSopenharmony_ci#include <netinet/ip6.h>
27b1b8bc3fSopenharmony_ci#include <poll.h>
28b1b8bc3fSopenharmony_ci#include <string>
29b1b8bc3fSopenharmony_ci#include <sys/eventfd.h>
30b1b8bc3fSopenharmony_ci#include <sys/socket.h>
31b1b8bc3fSopenharmony_ci#include <thread>
32b1b8bc3fSopenharmony_ci#include <unistd.h>
33b1b8bc3fSopenharmony_ci#include <vector>
34b1b8bc3fSopenharmony_ci
35b1b8bc3fSopenharmony_ci#include "clat_constants.h"
36b1b8bc3fSopenharmony_ci#include "clat_utils.h"
37b1b8bc3fSopenharmony_ci#include "clatd_packet_converter.h"
38b1b8bc3fSopenharmony_ci#include "ffrt.h"
39b1b8bc3fSopenharmony_ci#include "ffrt_inner.h"
40b1b8bc3fSopenharmony_ci#include "ffrt_timer.h"
41b1b8bc3fSopenharmony_ci#include "net_manager_constants.h"
42b1b8bc3fSopenharmony_ci#include "netnative_log_wrapper.h"
43b1b8bc3fSopenharmony_ci
44b1b8bc3fSopenharmony_cinamespace OHOS {
45b1b8bc3fSopenharmony_cinamespace nmd {
46b1b8bc3fSopenharmony_ciusing namespace OHOS::NetManagerStandard;
47b1b8bc3fSopenharmony_ciClatd::Clatd(int tunFd, int readSock6, int writeSock6, const std::string &v6Iface, const std::string &prefixAddrStr,
48b1b8bc3fSopenharmony_ci             const std::string &v4AddrStr, const std::string &v6AddrStr)
49b1b8bc3fSopenharmony_ci    : tunFd_(tunFd), readSock6_(readSock6), writeSock6_(writeSock6), v6Iface_(v6Iface)
50b1b8bc3fSopenharmony_ci{
51b1b8bc3fSopenharmony_ci    stopFd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
52b1b8bc3fSopenharmony_ci    tunIface_ = std::string(CLAT_PREFIX) + v6Iface;
53b1b8bc3fSopenharmony_ci    inet_pton(AF_INET6, v6AddrStr.c_str(), &v6Addr_);
54b1b8bc3fSopenharmony_ci    inet_pton(AF_INET, v4AddrStr.c_str(), &v4Addr_.s_addr);
55b1b8bc3fSopenharmony_ci    inet_pton(AF_INET6, prefixAddrStr.c_str(), &prefixAddr_);
56b1b8bc3fSopenharmony_ci    isSocketClosed_ = false;
57b1b8bc3fSopenharmony_ci    stopStatus_ = true;
58b1b8bc3fSopenharmony_ci}
59b1b8bc3fSopenharmony_ci
60b1b8bc3fSopenharmony_ciClatd::~Clatd()
61b1b8bc3fSopenharmony_ci{
62b1b8bc3fSopenharmony_ci    close(stopFd_);
63b1b8bc3fSopenharmony_ci}
64b1b8bc3fSopenharmony_ci
65b1b8bc3fSopenharmony_civoid Clatd::Start()
66b1b8bc3fSopenharmony_ci{
67b1b8bc3fSopenharmony_ci    if (!stopStatus_) {
68b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("fail to start clatd, clatd for %{public}s is already running", v6Iface_.c_str());
69b1b8bc3fSopenharmony_ci        return;
70b1b8bc3fSopenharmony_ci    }
71b1b8bc3fSopenharmony_ci    SendDadPacket();
72b1b8bc3fSopenharmony_ci    stopStatus_ = false;
73b1b8bc3fSopenharmony_ci    std::thread([this]() { RunLoop(); }).detach();
74b1b8bc3fSopenharmony_ci}
75b1b8bc3fSopenharmony_ci
76b1b8bc3fSopenharmony_civoid Clatd::Stop()
77b1b8bc3fSopenharmony_ci{
78b1b8bc3fSopenharmony_ci    if (stopStatus_) {
79b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("fail to stop clatd, clatd for %{public}s is not running", v6Iface_.c_str());
80b1b8bc3fSopenharmony_ci        return;
81b1b8bc3fSopenharmony_ci    }
82b1b8bc3fSopenharmony_ci    uint64_t one = 1;
83b1b8bc3fSopenharmony_ci    write(stopFd_, &one, sizeof(one));
84b1b8bc3fSopenharmony_ci
85b1b8bc3fSopenharmony_ci    std::unique_lock<ffrt::mutex> lck(mutex_);
86b1b8bc3fSopenharmony_ci    cv_.wait(lck, [this] { return stopStatus_ == true; });
87b1b8bc3fSopenharmony_ci};
88b1b8bc3fSopenharmony_ci
89b1b8bc3fSopenharmony_civoid Clatd::SendDadPacket()
90b1b8bc3fSopenharmony_ci{
91b1b8bc3fSopenharmony_ci    ClatdDadPacket dadPacket;
92b1b8bc3fSopenharmony_ci
93b1b8bc3fSopenharmony_ci    dadPacket.v6Header.ip6_vfc = IPV6_VERSION_FLAG;
94b1b8bc3fSopenharmony_ci    dadPacket.v6Header.ip6_plen = htons(sizeof(ClatdDadPacket) - sizeof(ip6_hdr));
95b1b8bc3fSopenharmony_ci    dadPacket.v6Header.ip6_nxt = IPPROTO_ICMPV6;
96b1b8bc3fSopenharmony_ci    dadPacket.v6Header.ip6_hlim = 0xff;
97b1b8bc3fSopenharmony_ci    inet_pton(AF_INET6, "::", &dadPacket.v6Header.ip6_src);
98b1b8bc3fSopenharmony_ci    inet_pton(AF_INET6, SOLICITED_NODE_PREFIX, &dadPacket.v6Header.ip6_dst);
99b1b8bc3fSopenharmony_ci    size_t v6AddrByteLen = V6ADDR_BIT_LEN / CHAR_BIT;
100b1b8bc3fSopenharmony_ci    for (size_t i = SOLICITED_NODE_SUFFIX_OFFSET; i < v6AddrByteLen; i++) {
101b1b8bc3fSopenharmony_ci        dadPacket.v6Header.ip6_dst.s6_addr[i] = v6Addr_.s6_addr[i];
102b1b8bc3fSopenharmony_ci    }
103b1b8bc3fSopenharmony_ci
104b1b8bc3fSopenharmony_ci    dadPacket.ns.nd_ns_type = ND_NEIGHBOR_SOLICIT;
105b1b8bc3fSopenharmony_ci    dadPacket.ns.nd_ns_code = 0;
106b1b8bc3fSopenharmony_ci    dadPacket.ns.nd_ns_reserved = 0;
107b1b8bc3fSopenharmony_ci    dadPacket.ns.nd_ns_target = v6Addr_;
108b1b8bc3fSopenharmony_ci    uint32_t checkSum = dadPacket.v6Header.ip6_plen + htons(dadPacket.v6Header.ip6_nxt);
109b1b8bc3fSopenharmony_ci    checkSum = AddChecksum(checkSum, &dadPacket.v6Header.ip6_src, sizeof(dadPacket) - IPV6_SRC_OFFSET);
110b1b8bc3fSopenharmony_ci    dadPacket.ns.nd_ns_cksum = ~Checksum32To16(checkSum);
111b1b8bc3fSopenharmony_ci
112b1b8bc3fSopenharmony_ci    dadPacket.nonceOptType = NDP_NOUNCE_OPT;
113b1b8bc3fSopenharmony_ci    dadPacket.nonceOptLen = 1;
114b1b8bc3fSopenharmony_ci    arc4random_buf(&dadPacket.nonce, sizeof(dadPacket.nonce));
115b1b8bc3fSopenharmony_ci
116b1b8bc3fSopenharmony_ci    sockaddr_in6 dstAddr;
117b1b8bc3fSopenharmony_ci    dstAddr.sin6_family = AF_INET6;
118b1b8bc3fSopenharmony_ci    dstAddr.sin6_addr = dadPacket.v6Header.ip6_dst;
119b1b8bc3fSopenharmony_ci    dstAddr.sin6_scope_id = if_nametoindex(v6Iface_.c_str());
120b1b8bc3fSopenharmony_ci
121b1b8bc3fSopenharmony_ci    sendto(writeSock6_, &dadPacket, sizeof(dadPacket), 0, reinterpret_cast<const sockaddr *>(&dstAddr),
122b1b8bc3fSopenharmony_ci           sizeof(dstAddr));
123b1b8bc3fSopenharmony_ci}
124b1b8bc3fSopenharmony_ci
125b1b8bc3fSopenharmony_civoid Clatd::RunLoop()
126b1b8bc3fSopenharmony_ci{
127b1b8bc3fSopenharmony_ci    pollfd fds[] = {
128b1b8bc3fSopenharmony_ci        {stopFd_, POLLIN, 0},
129b1b8bc3fSopenharmony_ci        {readSock6_, POLLIN, 0},
130b1b8bc3fSopenharmony_ci        {tunFd_, POLLIN, 0},
131b1b8bc3fSopenharmony_ci    };
132b1b8bc3fSopenharmony_ci    enum clatdFds {
133b1b8bc3fSopenharmony_ci        EVENT_STOP,
134b1b8bc3fSopenharmony_ci        READ_V6,
135b1b8bc3fSopenharmony_ci        READ_V4,
136b1b8bc3fSopenharmony_ci    };
137b1b8bc3fSopenharmony_ci    FfrtTimer timerClatdRunning;
138b1b8bc3fSopenharmony_ci    timerClatdRunning.Start(CLATD_TIMER_CYCLE_MS, []() { NETNATIVE_LOGI("Clatd is running loop"); });
139b1b8bc3fSopenharmony_ci    while (!isSocketClosed_) {
140b1b8bc3fSopenharmony_ci        if (poll(fds, sizeof(fds) / sizeof((fds)[0]), -1) == -1) {
141b1b8bc3fSopenharmony_ci            if (errno != EINTR) {
142b1b8bc3fSopenharmony_ci                NETNATIVE_LOGW("event_loop/poll returned an error, errno: %{public}d", errno);
143b1b8bc3fSopenharmony_ci            }
144b1b8bc3fSopenharmony_ci        } else {
145b1b8bc3fSopenharmony_ci            if (fds[EVENT_STOP].revents) {
146b1b8bc3fSopenharmony_ci                uint64_t one = 1;
147b1b8bc3fSopenharmony_ci                read(stopFd_, &one, sizeof one);
148b1b8bc3fSopenharmony_ci                std::unique_lock<ffrt::mutex> lck(mutex_);
149b1b8bc3fSopenharmony_ci                stopStatus_ = true;
150b1b8bc3fSopenharmony_ci                cv_.notify_one();
151b1b8bc3fSopenharmony_ci                break;
152b1b8bc3fSopenharmony_ci            }
153b1b8bc3fSopenharmony_ci            if (fds[READ_V6].revents) {
154b1b8bc3fSopenharmony_ci                ProcessV6Packet();
155b1b8bc3fSopenharmony_ci            }
156b1b8bc3fSopenharmony_ci            if (fds[READ_V4].revents) {
157b1b8bc3fSopenharmony_ci                ProcessV4Packet();
158b1b8bc3fSopenharmony_ci            }
159b1b8bc3fSopenharmony_ci        }
160b1b8bc3fSopenharmony_ci    }
161b1b8bc3fSopenharmony_ci    timerClatdRunning.Stop();
162b1b8bc3fSopenharmony_ci}
163b1b8bc3fSopenharmony_ci
164b1b8bc3fSopenharmony_ciint32_t Clatd::MaybeCalculateL4Checksum(int packetLen, ClatdReadV6Buf &readBuf)
165b1b8bc3fSopenharmony_ci{
166b1b8bc3fSopenharmony_ci    const int csumStart = readBuf.vnet.csumStart;
167b1b8bc3fSopenharmony_ci    const int csumOffset = csumStart + readBuf.vnet.csumOffset;
168b1b8bc3fSopenharmony_ci    if (csumOffset > packetLen) {
169b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("csum offset %{public}d larger than packet length %{public}d", csumOffset, packetLen);
170b1b8bc3fSopenharmony_ci        return NETMANAGER_ERR_INVALID_PARAMETER;
171b1b8bc3fSopenharmony_ci    }
172b1b8bc3fSopenharmony_ci    uint16_t csum = CalChecksum(readBuf.payload, packetLen); // L4 checksum calculation required
173b1b8bc3fSopenharmony_ci    if (csum == 0) {
174b1b8bc3fSopenharmony_ci        csum = 0xFFFF;
175b1b8bc3fSopenharmony_ci    }
176b1b8bc3fSopenharmony_ci    readBuf.payload[csumOffset] = csum & 0xFF;
177b1b8bc3fSopenharmony_ci    readBuf.payload[csumOffset + 1] = csum >> CHAR_BIT;
178b1b8bc3fSopenharmony_ci    return NETMANAGER_SUCCESS;
179b1b8bc3fSopenharmony_ci}
180b1b8bc3fSopenharmony_ci
181b1b8bc3fSopenharmony_civoid Clatd::ProcessV6Packet()
182b1b8bc3fSopenharmony_ci{
183b1b8bc3fSopenharmony_ci    ClatdReadV6Buf readBuf;
184b1b8bc3fSopenharmony_ci    iovec iov;
185b1b8bc3fSopenharmony_ci    iov.iov_base = &readBuf;
186b1b8bc3fSopenharmony_ci    iov.iov_len = sizeof(readBuf);
187b1b8bc3fSopenharmony_ci
188b1b8bc3fSopenharmony_ci    char cmsgBuf[CMSG_SPACE(sizeof(tpacket_auxdata))];
189b1b8bc3fSopenharmony_ci    msghdr msgHdr;
190b1b8bc3fSopenharmony_ci    msgHdr.msg_iov = &iov;
191b1b8bc3fSopenharmony_ci    msgHdr.msg_iovlen = 1;
192b1b8bc3fSopenharmony_ci    msgHdr.msg_control = cmsgBuf;
193b1b8bc3fSopenharmony_ci    msgHdr.msg_controllen = sizeof(cmsgBuf);
194b1b8bc3fSopenharmony_ci
195b1b8bc3fSopenharmony_ci    ssize_t readLen;
196b1b8bc3fSopenharmony_ci    if (ReadV6Packet(msgHdr, readLen) != NETMANAGER_SUCCESS) {
197b1b8bc3fSopenharmony_ci        return;
198b1b8bc3fSopenharmony_ci    }
199b1b8bc3fSopenharmony_ci
200b1b8bc3fSopenharmony_ci    uint32_t tpStatus = 0;
201b1b8bc3fSopenharmony_ci    uint16_t tpNet = 0;
202b1b8bc3fSopenharmony_ci    for (cmsghdr *cmsgHdr = CMSG_FIRSTHDR(&msgHdr); cmsgHdr != NULL; cmsgHdr = CMSG_NXTHDR(&msgHdr, cmsgHdr)) {
203b1b8bc3fSopenharmony_ci        if (cmsgHdr->cmsg_level == SOL_PACKET && cmsgHdr->cmsg_type == PACKET_AUXDATA) {
204b1b8bc3fSopenharmony_ci            tpacket_auxdata *auxData = reinterpret_cast<tpacket_auxdata *>(CMSG_DATA(cmsgHdr));
205b1b8bc3fSopenharmony_ci            tpStatus = auxData->tp_status;
206b1b8bc3fSopenharmony_ci            tpNet = auxData->tp_net;
207b1b8bc3fSopenharmony_ci            break;
208b1b8bc3fSopenharmony_ci        }
209b1b8bc3fSopenharmony_ci    }
210b1b8bc3fSopenharmony_ci
211b1b8bc3fSopenharmony_ci    if (static_cast<size_t>(readLen) < offsetof(ClatdReadV6Buf, payload) + tpNet) {
212b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("%{public}zd read packet len shorter than %{public}u L2 header", readLen, tpNet);
213b1b8bc3fSopenharmony_ci        return;
214b1b8bc3fSopenharmony_ci    }
215b1b8bc3fSopenharmony_ci
216b1b8bc3fSopenharmony_ci    int packetLen = readLen - offsetof(ClatdReadV6Buf, payload);
217b1b8bc3fSopenharmony_ci    bool skip_csum = false;
218b1b8bc3fSopenharmony_ci    if ((tpStatus & TP_STATUS_CSUMNOTREADY) || (tpStatus & TP_STATUS_CSUM_VALID)) {
219b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("skip csum for packet which length is %{public}zd", readLen);
220b1b8bc3fSopenharmony_ci        skip_csum = true;
221b1b8bc3fSopenharmony_ci    }
222b1b8bc3fSopenharmony_ci
223b1b8bc3fSopenharmony_ci    ClatdPacketConverter converter = ClatdPacketConverter(readBuf.payload + tpNet, packetLen - tpNet,
224b1b8bc3fSopenharmony_ci                                                          CONVERT_FROM_V6_TO_V4, v4Addr_, v6Addr_, prefixAddr_);
225b1b8bc3fSopenharmony_ci    if (converter.ConvertPacket(skip_csum) != NETMANAGER_SUCCESS) {
226b1b8bc3fSopenharmony_ci        return;
227b1b8bc3fSopenharmony_ci    }
228b1b8bc3fSopenharmony_ci    std::vector<iovec> iovPackets(CLATD_MAX);
229b1b8bc3fSopenharmony_ci    int effectivePos = 0;
230b1b8bc3fSopenharmony_ci    converter.GetConvertedPacket(iovPackets, effectivePos);
231b1b8bc3fSopenharmony_ci    if (effectivePos > 0) {
232b1b8bc3fSopenharmony_ci        writev(tunFd_, &iovPackets[0], effectivePos);
233b1b8bc3fSopenharmony_ci    }
234b1b8bc3fSopenharmony_ci}
235b1b8bc3fSopenharmony_ci
236b1b8bc3fSopenharmony_civoid Clatd::ProcessV4Packet()
237b1b8bc3fSopenharmony_ci{
238b1b8bc3fSopenharmony_ci    ClatdReadTunBuf readBuf;
239b1b8bc3fSopenharmony_ci    ssize_t readLen;
240b1b8bc3fSopenharmony_ci    if (ReadV4Packet(readBuf, readLen) != NETMANAGER_SUCCESS) {
241b1b8bc3fSopenharmony_ci        return;
242b1b8bc3fSopenharmony_ci    }
243b1b8bc3fSopenharmony_ci
244b1b8bc3fSopenharmony_ci    const int payloadOffset = offsetof(ClatdReadTunBuf, payload);
245b1b8bc3fSopenharmony_ci    if (readLen < payloadOffset) {
246b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("%{public}zd read packet len shorter than %{public}d payload offset", readLen, payloadOffset);
247b1b8bc3fSopenharmony_ci        return;
248b1b8bc3fSopenharmony_ci    }
249b1b8bc3fSopenharmony_ci
250b1b8bc3fSopenharmony_ci    const int packetLen = readLen - payloadOffset;
251b1b8bc3fSopenharmony_ci
252b1b8bc3fSopenharmony_ci    uint16_t tunProtocol = ntohs(readBuf.tunProtocolInfo.proto);
253b1b8bc3fSopenharmony_ci    if (tunProtocol != ETH_P_IP) {
254b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("unknown packet type = 0x%{public}x", tunProtocol);
255b1b8bc3fSopenharmony_ci        return;
256b1b8bc3fSopenharmony_ci    }
257b1b8bc3fSopenharmony_ci
258b1b8bc3fSopenharmony_ci    if (readBuf.tunProtocolInfo.flags != 0) {
259b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("unexpected flags = %{public}d", readBuf.tunProtocolInfo.flags);
260b1b8bc3fSopenharmony_ci    }
261b1b8bc3fSopenharmony_ci
262b1b8bc3fSopenharmony_ci    ClatdPacketConverter converter =
263b1b8bc3fSopenharmony_ci        ClatdPacketConverter(readBuf.payload, packetLen, CONVERT_FROM_V4_TO_V6, v4Addr_, v6Addr_, prefixAddr_);
264b1b8bc3fSopenharmony_ci    bool skip_csum = false;
265b1b8bc3fSopenharmony_ci    if (converter.ConvertPacket(skip_csum) != NETMANAGER_SUCCESS) {
266b1b8bc3fSopenharmony_ci        return;
267b1b8bc3fSopenharmony_ci    }
268b1b8bc3fSopenharmony_ci    std::vector<iovec> iovPackets(CLATD_MAX);
269b1b8bc3fSopenharmony_ci    int effectivePos = 0;
270b1b8bc3fSopenharmony_ci    converter.GetConvertedPacket(iovPackets, effectivePos);
271b1b8bc3fSopenharmony_ci    if (effectivePos > 0) {
272b1b8bc3fSopenharmony_ci        SendV6OnRawSocket(writeSock6_, iovPackets, effectivePos);
273b1b8bc3fSopenharmony_ci    }
274b1b8bc3fSopenharmony_ci}
275b1b8bc3fSopenharmony_ci
276b1b8bc3fSopenharmony_ciint32_t Clatd::ReadV6Packet(msghdr &msgHdr, ssize_t &readLen)
277b1b8bc3fSopenharmony_ci{
278b1b8bc3fSopenharmony_ci    readLen = recvmsg(readSock6_, &msgHdr, 0);
279b1b8bc3fSopenharmony_ci    if (readLen < 0) {
280b1b8bc3fSopenharmony_ci        if (errno != EAGAIN) {
281b1b8bc3fSopenharmony_ci            NETNATIVE_LOGW("recvmsg failed: %{public}s", strerror(errno));
282b1b8bc3fSopenharmony_ci        }
283b1b8bc3fSopenharmony_ci        return NETMANAGER_ERR_OPERATION_FAILED;
284b1b8bc3fSopenharmony_ci    } else if (readLen == 0) {
285b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("recvmsg failed: socket closed");
286b1b8bc3fSopenharmony_ci        isSocketClosed_ = true;
287b1b8bc3fSopenharmony_ci        return NETMANAGER_ERR_OPERATION_FAILED;
288b1b8bc3fSopenharmony_ci    } else if (static_cast<size_t>(readLen) >= sizeof(ClatdReadV6Buf)) {
289b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("recvmsg failed: packet oversize, readLen: %{public}zu, sizeof(ClatdReadV6Buf): %{public}zu", static_cast<size_t>(readLen), sizeof(ClatdReadV6Buf));
290b1b8bc3fSopenharmony_ci        return NETMANAGER_ERR_OPERATION_FAILED;
291b1b8bc3fSopenharmony_ci    }
292b1b8bc3fSopenharmony_ci    return NETMANAGER_SUCCESS;
293b1b8bc3fSopenharmony_ci}
294b1b8bc3fSopenharmony_ci
295b1b8bc3fSopenharmony_ciint32_t Clatd::ReadV4Packet(ClatdReadTunBuf &readBuf, ssize_t &readLen)
296b1b8bc3fSopenharmony_ci{
297b1b8bc3fSopenharmony_ci    readLen = read(tunFd_, reinterpret_cast<iovec *>(&readBuf), sizeof(readBuf));
298b1b8bc3fSopenharmony_ci    if (readLen < 0) {
299b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("read failed: %{public}s", strerror(errno));
300b1b8bc3fSopenharmony_ci        return NETMANAGER_ERR_OPERATION_FAILED;
301b1b8bc3fSopenharmony_ci    } else if (readLen == 0) {
302b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("read failed: socket closed");
303b1b8bc3fSopenharmony_ci        isSocketClosed_ = true;
304b1b8bc3fSopenharmony_ci        return NETMANAGER_ERR_OPERATION_FAILED;
305b1b8bc3fSopenharmony_ci    } else if (static_cast<size_t>(readLen) >= sizeof(readBuf)) {
306b1b8bc3fSopenharmony_ci        NETNATIVE_LOGW("read failed: packet oversize");
307b1b8bc3fSopenharmony_ci        return NETMANAGER_ERR_OPERATION_FAILED;
308b1b8bc3fSopenharmony_ci    }
309b1b8bc3fSopenharmony_ci    return NETMANAGER_SUCCESS;
310b1b8bc3fSopenharmony_ci}
311b1b8bc3fSopenharmony_ci
312b1b8bc3fSopenharmony_civoid Clatd::SendV6OnRawSocket(int fd, std::vector<iovec> &iovPackets, int effectivePos)
313b1b8bc3fSopenharmony_ci{
314b1b8bc3fSopenharmony_ci    static sockaddr_in6 sin6 = {AF_INET6, 0, 0, {{{0, 0, 0, 0}}}, 0};
315b1b8bc3fSopenharmony_ci    static msghdr msgHeader;
316b1b8bc3fSopenharmony_ci    msgHeader.msg_name = &sin6;
317b1b8bc3fSopenharmony_ci    msgHeader.msg_namelen = sizeof(sin6);
318b1b8bc3fSopenharmony_ci
319b1b8bc3fSopenharmony_ci    msgHeader.msg_iov = &iovPackets[0];
320b1b8bc3fSopenharmony_ci    msgHeader.msg_iovlen = effectivePos;
321b1b8bc3fSopenharmony_ci    sin6.sin6_addr = reinterpret_cast<struct ip6_hdr *>(iovPackets[CLATD_TPHDR].iov_base)->ip6_dst;
322b1b8bc3fSopenharmony_ci    sendmsg(fd, &msgHeader, 0);
323b1b8bc3fSopenharmony_ci}
324b1b8bc3fSopenharmony_ci
325b1b8bc3fSopenharmony_ci} // namespace nmd
326b1b8bc3fSopenharmony_ci} // namespace OHOS