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