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 
16 #include "net_manager_constants.h"
17 #include "router_advertisement_daemon.h"
18 #include <csignal>
19 #include <net/if.h>
20 #include <sys/time.h>
21 
22 namespace OHOS {
23 namespace NetManagerStandard {
24 namespace {
25 /** https://www.rfc-editor.org/rfc/rfc4861#section-6.2.1
26  * MaxRtrAdvInterval: MUST be no less than 4 seconds and no greater than 1800 seconds.
27  *                 Default: 600 seconds
28  * MinRtrAdvInterval: MUST be no less than 3seconds and no greater than 0.75 * MaxRtrAdvInterval.
29  *                 Default: 0.33 * MaxRtrAdvInterval If
30  *                 MaxRtrAdvInterval >= 9 seconds; otherwise, the
31  *                 Default is MaxRtrAdvInterval.
32  */
33 constexpr uint32_t MAX_URGENT_RTR_ADVERTISEMENTS = 10;
34 constexpr uint32_t RECV_RS_TIMEOUT = 1;
35 constexpr uint32_t SEND_RA_INTERVAL = 3;
36 constexpr uint32_t SEND_RA_DELAY = 1;
37 constexpr size_t RA_HEADER_SIZE = 16;
38 
39 /**
40  * https://www.rfc-editor.org/rfc/rfc4861.html#section-6.1.2-4.2
41  * Note: If neither M nor O flags are set, this indicates that no
42  * information is available via DHCPv6.
43  */
44 constexpr uint8_t DEFAULT_ROUTER_PRE = 0x08;
45 constexpr uint8_t PREFIX_INFO_FLAGS = 0xc0;
46 constexpr uint32_t DEFAULT_HOP_LIMIT = 255;
47 
48 /**
49  * https://tools.ietf.org/html/rfc4861#section-2.3
50  * all-nodes multicast address
51  *          - the link-local scope address to reach all nodes,
52  *            FF02::1.
53  */
54 constexpr const char *DST_IPV6 = "ff02::1";
55 } // namespace
56 
57 RouterAdvertisementDaemon *RouterAdvertisementDaemon::pThis = nullptr;
RouterAdvertisementDaemon()58 RouterAdvertisementDaemon::RouterAdvertisementDaemon()
59 {
60     raParams_ = std::make_shared<RaParams>();
61 }
62 
IsSocketValid()63 bool RouterAdvertisementDaemon::IsSocketValid()
64 {
65     return socket_ > 0;
66 }
67 
HupRaThread()68 void RouterAdvertisementDaemon::HupRaThread()
69 {
70     stopRaThread_ = true;
71 }
72 
Init(const std::string & ifaceName)73 int32_t RouterAdvertisementDaemon::Init(const std::string &ifaceName)
74 {
75     sendRaTimes_ = 0;
76     raParams_->name_ = ifaceName;
77     raParams_->index_ = if_nametoindex(ifaceName.c_str());
78     if (memset_s(&dstIpv6Addr_, sizeof(dstIpv6Addr_), 0, sizeof(dstIpv6Addr_)) != EOK) {
79         return NETMANAGER_EXT_ERR_MEMSET_FAIL;
80     }
81     dstIpv6Addr_.sin6_port = 0;
82     dstIpv6Addr_.sin6_family = AF_INET6;
83     dstIpv6Addr_.sin6_scope_id = 0;
84     inet_pton(AF_INET6, DST_IPV6, &dstIpv6Addr_.sin6_addr);
85     return NETMANAGER_EXT_SUCCESS;
86 }
87 
StartRa()88 int32_t RouterAdvertisementDaemon::StartRa()
89 {
90     NETMGR_EXT_LOG_I("StartRa");
91     if (!CreateRASocket()) {
92         NETMGR_EXT_LOG_E("StartRa fail due to socket");
93         return NETMANAGER_EXT_ERR_PARAMETER_ERROR;
94     }
95     pThis = this;
96     stopRaThread_ = false;
97     recvRsThread_ = std::thread([this]() { this->RunRecvRsThread(); });
98     pthread_setname_np(recvRsThread_.native_handle(), "OH_Net_RecvRs");
99     recvRsThread_.detach();
100     return NETMANAGER_EXT_SUCCESS;
101 }
102 
StopRa()103 void RouterAdvertisementDaemon::StopRa()
104 {
105     NETMGR_EXT_LOG_I("StopRa");
106     HupRaThread();
107     CloseRaSocket();
108     raParams_ = nullptr;
109 
110     // close timer
111     itimerval value = {};
112     setitimer(ITIMER_REAL, &value, nullptr);
113 }
114 
CreateRASocket()115 bool RouterAdvertisementDaemon::CreateRASocket()
116 {
117     NETMGR_EXT_LOG_I("CreateRASocket Start");
118     socket_ = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
119     if (socket_ < 0) {
120         NETMGR_EXT_LOG_E("CreateRASocket fail, errno[%{public}d]", errno);
121         return false;
122     }
123     timeval timeout = {};
124     timeout.tv_sec = RECV_RS_TIMEOUT;
125     if (setsockopt(socket_, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
126         NETMGR_EXT_LOG_E("CreateRASocket setsockopt SO_RCVTIMEO fail");
127         close(socket_);
128         return false;
129     }
130     ifreq ifr = {};
131     if (strncpy_s(ifr.ifr_name, IFNAMSIZ - 1, raParams_->name_.c_str(), raParams_->name_.size()) != EOK) {
132         NETMGR_EXT_LOG_E("CreateRASocket strncopy fail");
133         close(socket_);
134         return false;
135     }
136     if (setsockopt(socket_, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
137         NETMGR_EXT_LOG_E("CreateRASocket setsockopt SO_BINDTODEVICE fail");
138         close(socket_);
139         return false;
140     }
141     uint32_t hoplimitNew = DEFAULT_HOP_LIMIT;
142     if (setsockopt(socket_, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (void *)&hoplimitNew, sizeof(hoplimitNew)) == -1) {
143         NETMGR_EXT_LOG_E(" setsockopt IPV6_UNICAST_HOPS fail");
144     }
145     return true;
146 }
147 
CloseRaSocket()148 void RouterAdvertisementDaemon::CloseRaSocket()
149 {
150     NETMGR_EXT_LOG_I("CloseRaSocket Start");
151     if (socket_ > 0) {
152         close(socket_);
153     }
154     socket_ = -1;
155 }
156 
MaybeSendRa(sockaddr_in6 & dest)157 bool RouterAdvertisementDaemon::MaybeSendRa(sockaddr_in6 &dest)
158 {
159     NETMGR_EXT_LOG_D("Send Ra Enter, socket_[%{public}d], raPacketLength_[%{public}hu]", socket_, raPacketLength_);
160     if (raPacketLength_ < RA_HEADER_SIZE) {
161         NETMGR_EXT_LOG_E("Send Ra failed due to Ra packet length less than RA header size");
162         return false;
163     }
164     if (!IsSocketValid()) {
165         NETMGR_EXT_LOG_E("Send Ra failed due to socket invalid");
166         return false;
167     }
168     int ret = sendto(socket_, raPacket_, raPacketLength_, 0, (sockaddr *)&dest, sizeof(dest));
169     if (ret < 0) {
170         NETMGR_EXT_LOG_E("Send Ra error, ret[%{public}d], errno[%{public}d]", ret, errno);
171         return false;
172     }
173     return true;
174 }
175 
ProcessSendRaPacket(int inputSignal)176 void RouterAdvertisementDaemon::ProcessSendRaPacket(int inputSignal)
177 {
178     if (pThis == nullptr) {
179         NETMGR_EXT_LOG_E("pThis is nullptr!");
180         return;
181     }
182     if (!pThis->IsSocketValid() || pThis->stopRaThread_) {
183         NETMGR_EXT_LOG_E("socket closed or stopRaThread!");
184         return;
185     }
186     if (pThis->AssembleRaLocked()) {
187         pThis->MaybeSendRa(pThis->dstIpv6Addr_);
188     }
189     pThis->ResetRaRetryInterval();
190 }
191 
RunRecvRsThread()192 void RouterAdvertisementDaemon::RunRecvRsThread()
193 {
194     NETMGR_EXT_LOG_I("Start to receive Rs thread, socket[%{public}d]", socket_);
195     if (signal(SIGALRM, ProcessSendRaPacket) == SIG_ERR) {
196         NETMGR_EXT_LOG_E("signal error!");
197         CloseRaSocket();
198         return;
199     }
200     itimerval setvalue = {};
201     setvalue.it_interval.tv_sec = SEND_RA_INTERVAL;
202     setvalue.it_value.tv_sec = SEND_RA_DELAY;
203     setitimer(ITIMER_REAL, &setvalue, nullptr);
204 
205     sockaddr_in6 solicitor = {};
206     uint8_t solicitation[IPV6_MIN_MTU] = {};
207     socklen_t sendLen = sizeof(solicitation);
208     while (IsSocketValid() && !stopRaThread_) {
209         if (memset_s(solicitation, sizeof(solicitation), 0, sizeof(solicitation)) != EOK) {
210             break;
211         }
212         auto rval =
213             recvfrom(socket_, solicitation, IPV6_MIN_MTU, 0, reinterpret_cast<sockaddr *>(&solicitor), &sendLen);
214         if (rval <= 0 && errno != EAGAIN && errno != EINTR) {
215             NETMGR_EXT_LOG_E("recvfrom failed, rval[%{public}zd], errno[%{public}d]", rval, errno);
216             break;
217         }
218         if (solicitation[0] != ICMPV6_ND_ROUTER_SOLICIT_TYPE) {
219             continue;
220         }
221         if (AssembleRaLocked()) {
222             MaybeSendRa(solicitor);
223         }
224     }
225     CloseRaSocket();
226 }
227 
GetDeprecatedRaParams(RaParams & oldRa,RaParams & newRa)228 RaParams RouterAdvertisementDaemon::GetDeprecatedRaParams(RaParams &oldRa, RaParams &newRa)
229 {
230     RaParams deprecateRa = {};
231     for (auto ipp : newRa.prefixes_) {
232         if (oldRa.ContainsPrefix(ipp)) {
233             deprecateRa.prefixes_.emplace_back(ipp);
234         }
235     }
236     for (auto dns : newRa.dnses_) {
237         if (oldRa.ContainsDns(dns)) {
238             deprecateRa.dnses_.emplace_back(dns);
239         }
240     }
241     return deprecateRa;
242 }
243 
BuildNewRa(const RaParams & newRa)244 void RouterAdvertisementDaemon::BuildNewRa(const RaParams &newRa)
245 {
246     raParams_->Set(newRa);
247 }
248 
ResetRaRetryInterval()249 void RouterAdvertisementDaemon::ResetRaRetryInterval()
250 {
251     if (sendRaTimes_ < MAX_URGENT_RTR_ADVERTISEMENTS) {
252         sendRaTimes_++;
253         return;
254     }
255     if (sendRaTimes_ == MAX_URGENT_RTR_ADVERTISEMENTS) {
256         itimerval setvalue = {};
257         itimerval oldvalue = {};
258         setvalue.it_interval.tv_sec = DEFAULT_RTR_INTERVAL_SEC;
259         setvalue.it_value.tv_sec = 1;
260         setitimer(ITIMER_REAL, &setvalue, &oldvalue);
261         sendRaTimes_++;
262         return;
263     }
264 }
265 
AssembleRaLocked()266 bool RouterAdvertisementDaemon::AssembleRaLocked()
267 {
268     NETMGR_EXT_LOG_D("Generate Ra package start");
269     uint8_t raBuf[IPV6_MIN_MTU] = {};
270     uint8_t *ptr = raBuf;
271     uint16_t raHeadLen = PutRaHeader(ptr);
272     ptr += raHeadLen;
273     uint16_t raSllLen = PutRaSlla(ptr, raParams_->macAddr_);
274     ptr += raSllLen;
275     uint16_t raMtuLen = PutRaMtu(ptr, raParams_->mtu_);
276     ptr += raMtuLen;
277     uint16_t raPrefixLens = 0;
278     for (IpPrefix ipp : raParams_->prefixes_) {
279         uint16_t raPrefixLen = PutRaPio(ptr, ipp);
280         ptr += raPrefixLen;
281         raPrefixLens += raPrefixLen;
282     }
283     uint16_t raRdnsLen = PutRaRdnss(ptr);
284     ptr += raRdnsLen;
285     raPacketLength_ = raHeadLen + raSllLen + raMtuLen + raPrefixLens + raRdnsLen;
286     if (memset_s(&raPacket_, sizeof(raPacket_), 0, sizeof(raPacket_)) != EOK) {
287         return false;
288     }
289     if (memcpy_s(raPacket_, sizeof(raPacket_), raBuf, raPacketLength_) != EOK) {
290         return false;
291     }
292     NETMGR_EXT_LOG_D("Generate Ra package end, raPacketLength_: %{public}hu", raPacketLength_);
293     return true;
294 }
295 
PutRaHeader(uint8_t * raBuf)296 uint16_t RouterAdvertisementDaemon::PutRaHeader(uint8_t *raBuf)
297 {
298     NETMGR_EXT_LOG_D("Append Ra header");
299     // https://datatracker.ietf.org/doc/html/rfc4861#section-4.2
300     // 0                   1                   2                   3
301     // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
302     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
303     // |     Type      |     Code      |          Checksum             |
304     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
305     // | Cur Hop Limit |M|O|  Reserved |       Router Lifetime         |
306     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
307     // |                         Reachable Time                        |
308     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
309     // |                          Retrans Timer                        |
310     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
311     // |   Options ...
312     // +-+-+-+-+-+-+-+-+-+-+-+-
313     Icmpv6HeadSt raHeadSt;
314     raHeadSt.type = ICMPV6_ND_ROUTER_ADVERT_TYPE;
315     raHeadSt.curHopLimit = DEFAULT_HOPLIMIT;
316     raHeadSt.flags = DEFAULT_ROUTER_PRE;
317     raHeadSt.routerLifetime = htons(DEFAULT_LIFETIME);
318     if (memcpy_s(raBuf, sizeof(Icmpv6HeadSt), &raHeadSt, sizeof(Icmpv6HeadSt)) != EOK) {
319         return 0;
320     }
321     return static_cast<uint16_t>(sizeof(Icmpv6HeadSt));
322 }
323 
PutRaSlla(uint8_t * raBuf,const std::string & mac)324 uint16_t RouterAdvertisementDaemon::PutRaSlla(uint8_t *raBuf, const std::string &mac)
325 {
326     NETMGR_EXT_LOG_D("Append Ra source link lay address");
327     if (mac.size() < HW_MAC_STR_LENGTH) {
328         return 0;
329     }
330     // https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.1
331     //  0                   1                   2                   3
332     // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
333     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
334     // |     Type      |    Length     |    Link-Layer Address ...
335     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
336     Icmpv6SllOpt srcLinkAddrSt;
337     srcLinkAddrSt.type = ND_OPTION_SLLA_TYPE;
338     srcLinkAddrSt.len = sizeof(Icmpv6SllOpt) / UNITS_OF_OCTETS;
339     std::istringstream iss(mac);
340     int value = 0;
341     for (uint32_t i = 0; i < HW_MAC_LENGTH; i++) {
342         iss >> std::hex >> value;
343         srcLinkAddrSt.linkAddress[i] = static_cast<uint8_t>(value);
344         iss.ignore(1, ':');
345     }
346     if (memcpy_s(raBuf, sizeof(Icmpv6SllOpt), &srcLinkAddrSt, sizeof(Icmpv6SllOpt)) != EOK) {
347         return 0;
348     }
349     return static_cast<uint16_t>(sizeof(Icmpv6SllOpt));
350 }
351 
PutRaMtu(uint8_t * raBuf,int32_t mtu)352 uint16_t RouterAdvertisementDaemon::PutRaMtu(uint8_t *raBuf, int32_t mtu)
353 {
354     NETMGR_EXT_LOG_D("Append Ra Mtu option");
355     // https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.4
356     //    0                   1                   2                   3
357     // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
358     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
359     // |     Type      |    Length     |           Reserved            |
360     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
361     // |                              MTU                              |
362     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
363     Icmpv6MtuOpt mtuSt;
364     mtuSt.type = ND_OPTION_MTU_TYPE;
365     mtuSt.len = sizeof(Icmpv6MtuOpt) / UNITS_OF_OCTETS;
366     mtuSt.mtu = static_cast<uint32_t>(htonl(mtu));
367     if (memcpy_s(raBuf, sizeof(Icmpv6MtuOpt), &mtuSt, sizeof(Icmpv6MtuOpt)) != EOK) {
368         return 0;
369     }
370     return static_cast<uint16_t>(sizeof(Icmpv6MtuOpt));
371 }
372 
PutRaPio(uint8_t * raBuf,IpPrefix & ipp)373 uint16_t RouterAdvertisementDaemon::PutRaPio(uint8_t *raBuf, IpPrefix &ipp)
374 {
375     NETMGR_EXT_LOG_D("Append Ra prefix information option");
376     // refer to https://tools.ietf.org/html/rfc4861#section-4.6.2
377     //    0                   1                   2                   3
378     // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
379     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
380     // |     Type      |    Length     | Prefix Length |L|A| Reserved1 |
381     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
382     // |                         Valid Lifetime                        |
383     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
384     // |                       Preferred Lifetime                      |
385     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
386     // |                           Reserved2                           |
387     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
388     // |                                                               |
389     // +                                                               +
390     // |                                                               |
391     // +                            Prefix                             +
392     // |                                                               |
393     // +                                                               +
394     // |                                                               |
395     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
396     Icmpv6PrefixInfoOpt prefixInfoSt;
397     prefixInfoSt.type = ND_OPTION_PIO_TYPE;
398     prefixInfoSt.len = sizeof(Icmpv6PrefixInfoOpt) / UNITS_OF_OCTETS;
399     prefixInfoSt.prefixLen = ipp.prefixesLength;
400     prefixInfoSt.flag = PREFIX_INFO_FLAGS;
401     prefixInfoSt.validLifetime = htonl(DEFAULT_LIFETIME);
402     prefixInfoSt.prefLifetime = htonl(DEFAULT_LIFETIME);
403     prefixInfoSt.type = ND_OPTION_PIO_TYPE;
404     if (memcpy_s(prefixInfoSt.prefix, IPV6_ADDR_LEN, ipp.prefix.s6_addr, IPV6_ADDR_LEN) != EOK) {
405         return 0;
406     }
407     if (memcpy_s(raBuf, sizeof(Icmpv6PrefixInfoOpt), &prefixInfoSt, sizeof(Icmpv6PrefixInfoOpt)) != EOK) {
408         return 0;
409     }
410     return static_cast<uint16_t>(sizeof(Icmpv6PrefixInfoOpt));
411 }
412 
PutRaRdnss(uint8_t * raBuf)413 uint16_t RouterAdvertisementDaemon::PutRaRdnss(uint8_t *raBuf)
414 {
415     NETMGR_EXT_LOG_D("Make RA DNS server option");
416     // https://datatracker.ietf.org/doc/rfc8106/
417     //   0                   1                   2                   3
418     //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
419     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
420     //  |     Type      |     Length    |           Reserved            |
421     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
422     //  |                           Lifetime                            |
423     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
424     //  |                                                               |
425     //  :            Addresses of IPv6 Recursive DNS Servers            :
426     //  |                                                               |
427     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
428     Icmpv6RdnsOpt rdnsInfoSt;
429     size_t raRdnsNum = raParams_->prefixes_.size();
430     rdnsInfoSt.type = ND_OPTION_RDNSS_TYPE;
431     rdnsInfoSt.len = (sizeof(Icmpv6RdnsOpt) + raRdnsNum * IPV6_ADDR_LEN) / UNITS_OF_OCTETS;
432     rdnsInfoSt.lifetime = htonl(DEFAULT_LIFETIME);
433     if (memcpy_s(raBuf, sizeof(Icmpv6RdnsOpt), &rdnsInfoSt, sizeof(Icmpv6RdnsOpt)) != EOK) {
434         return 0;
435     }
436     raBuf += sizeof(Icmpv6RdnsOpt);
437     uint32_t index = 0;
438     for (IpPrefix ipp : raParams_->prefixes_) {
439         if (memcpy_s(raBuf + index * IPV6_ADDR_LEN, IPV6_ADDR_LEN, ipp.address.s6_addr, IPV6_ADDR_LEN) != EOK) {
440             return 0;
441         }
442         index++;
443     }
444     return static_cast<uint16_t>(sizeof(Icmpv6RdnsOpt) + raRdnsNum * IPV6_ADDR_LEN);
445 }
446 } // namespace NetManagerStandard
447 } // namespace OHOS
448