• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2018, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file implements the platform network on Linux.
32  */
33 
34 #include "openthread-posix-config.h"
35 #include "platform-posix.h"
36 
37 #if defined(__APPLE__)
38 
39 //	NOTE: on mac OS, the utun driver is present on the system and "works" --
40 //	but in a limited way.  In particular, the mac OS "utun" driver is marked IFF_POINTTOPOINT,
41 //	and you cannot clear that flag with SIOCSIFFLAGS (it's part of the IFF_CANTCHANGE definition
42 //	in xnu's net/if.h [but removed from the mac OS SDK net/if.h]).  And unfortunately, mac OS's
43 //	build of mDNSResponder won't allow for mDNS over an interface marked IFF_POINTTOPOINT
44 //	(see comments near definition of MulticastInterface in mDNSMacOSX.c for the bogus reasoning).
45 //
46 //	There is an alternative.  An open-source tuntap kernel extension is available here:
47 //
48 //		<http://tuntaposx.sourceforge.net>
49 //		<https://sourceforge.net/p/tuntaposx/code/ci/master/tree/>
50 //
51 //	and can be installed via homebrew here:
52 //
53 //		<https://formulae.brew.sh/cask/tuntap>
54 //
55 //	Building from source and installing isn't trivial, and it's
56 //	not getting easier (https://forums.developer.apple.com/thread/79590).
57 //
58 //	If you want mDNS support, then you can't use Apple utun.  I use the non-Apple driver
59 //	pretty much exclusively, because mDNS is a requirement.
60 
61 #if !(defined(OPENTHREAD_POSIX_CONFIG_MACOS_TUN_OPTION) &&                         \
62       ((OPENTHREAD_POSIX_CONFIG_MACOS_TUN_OPTION == OT_POSIX_CONFIG_MACOS_UTUN) || \
63        (OPENTHREAD_POSIX_CONFIG_MACOS_TUN_OPTION == OT_POSIX_CONFIG_MACOS_TUN)))
64 #error "Unexpected tunnel driver selection"
65 #endif
66 
67 #endif // defined(__APPLE__)
68 
69 #include <arpa/inet.h>
70 #include <assert.h>
71 #include <errno.h>
72 #include <fcntl.h>
73 #include <ifaddrs.h>
74 #ifdef __linux__
75 #include <linux/if_tun.h>
76 #include <linux/netlink.h>
77 #include <linux/rtnetlink.h>
78 #endif // __linux__
79 #include <net/if.h>
80 #include <net/if_arp.h>
81 #include <stdio.h>
82 #include <string.h>
83 #include <sys/ioctl.h>
84 #include <sys/select.h>
85 #include <sys/socket.h>
86 #include <sys/stat.h>
87 #include <sys/types.h>
88 #include <unistd.h>
89 
90 #if defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
91 #include <netinet/in.h>
92 #if defined(__APPLE__) || defined(__FreeBSD__)
93 #include <net/if_var.h>
94 #endif // defined(__APPLE__) || defined(__FreeBSD__)
95 #include <net/route.h>
96 #include <netinet6/in6_var.h>
97 #if defined(__APPLE__) || defined(__FreeBSD__)
98 // the prf_ra structure is defined inside another structure (in6_prflags), and C++
99 //   treats that as out of scope if another structure tries to use it -- this (slightly gross)
100 //   workaround makes us dependent on our definition remaining in sync (at least the size of it),
101 //   so we add a compile-time check that will fail if the SDK ever changes
102 //
103 // our definition of the struct:
104 struct prf_ra
105 {
106     u_char onlink : 1;
107     u_char autonomous : 1;
108     u_char reserved : 6;
109 } prf_ra;
110 // object that contains the SDK's version of the structure:
111 struct in6_prflags compile_time_check_prflags;
112 // compile time check to make sure they're the same size:
113 extern int
114     compile_time_check_struct_prf_ra[(sizeof(struct prf_ra) == sizeof(compile_time_check_prflags.prf_ra)) ? 1 : -1];
115 #endif
116 #include <net/if_dl.h>    // struct sockaddr_dl
117 #include <netinet6/nd6.h> // ND6_INFINITE_LIFETIME
118 
119 #ifdef __APPLE__
120 #if OPENTHREAD_POSIX_CONFIG_MACOS_TUN_OPTION == OT_POSIX_CONFIG_MACOS_UTUN
121 #include <net/if_utun.h>
122 #endif
123 
124 #if OPENTHREAD_POSIX_CONFIG_MACOS_TUN_OPTION == OT_POSIX_CONFIG_MACOS_TUN
125 #include <sys/ioccom.h>
126 // FIX ME: include the tun_ioctl.h file (challenging, as it's location depends on where the developer puts it)
127 #define TUNSIFHEAD _IOW('t', 96, int)
128 #define TUNGIFHEAD _IOR('t', 97, int)
129 #endif
130 
131 #include <sys/kern_control.h>
132 #endif // defined(__APPLE__)
133 
134 #if defined(__NetBSD__) || defined(__FreeBSD__)
135 #include <net/if_tun.h>
136 #endif // defined(__NetBSD__) || defined(__FreeBSD__)
137 
138 #endif // defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
139 
140 #include <openthread/border_router.h>
141 #include <openthread/icmp6.h>
142 #include <openthread/instance.h>
143 #include <openthread/ip6.h>
144 #include <openthread/logging.h>
145 #include <openthread/message.h>
146 #include <openthread/netdata.h>
147 #include <openthread/platform/misc.h>
148 
149 #include "common/code_utils.hpp"
150 #include "common/debug.hpp"
151 #include "net/ip6_address.hpp"
152 
153 unsigned int gNetifIndex = 0;
154 char         gNetifName[IFNAMSIZ];
155 
otSysGetThreadNetifName(void)156 const char *otSysGetThreadNetifName(void)
157 {
158     return gNetifName;
159 }
160 
otSysGetThreadNetifIndex(void)161 unsigned int otSysGetThreadNetifIndex(void)
162 {
163     return gNetifIndex;
164 }
165 
166 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
167 #if OPENTHREAD_POSIX_CONFIG_FIREWALL_ENABLE
168 #include "firewall.hpp"
169 #endif
170 #include "posix/platform/ip6_utils.hpp"
171 
172 using namespace ot::Posix::Ip6Utils;
173 
174 #ifndef OPENTHREAD_POSIX_TUN_DEVICE
175 
176 #ifdef __linux__
177 #define OPENTHREAD_POSIX_TUN_DEVICE "/dev/net/tun"
178 #elif defined(__NetBSD__) || defined(__FreeBSD__)
179 #define OPENTHREAD_POSIX_TUN_DEVICE "/dev/tun0"
180 #elif defined(__APPLE__)
181 #if OPENTHREAD_POSIX_CONFIG_MACOS_TUN_OPTION == OT_POSIX_CONFIG_MACOS_UTUN
182 #define OPENTHREAD_POSIX_TUN_DEVICE // not used - calculated dynamically
183 #elif OPENTHREAD_POSIX_CONFIG_MACOS_TUN_OPTION == OT_POSIX_CONFIG_MACOS_TUN
184 #define OPENTHREAD_POSIX_TUN_DEVICE "/dev/tun0"
185 #endif
186 #else
187 // good luck -- untested platform...
188 #define OPENTHREAD_POSIX_TUN_DEVICE "/dev/net/tun"
189 #endif
190 
191 #endif // OPENTHREAD_TUN_DEVICE
192 
193 #if defined(__linux__)
194 static uint32_t sNetlinkSequence = 0; ///< Netlink message sequence.
195 #endif
196 
197 #if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && __linux__
198 static constexpr uint32_t kOmrRoutesPriority = OPENTHREAD_POSIX_CONFIG_OMR_ROUTES_PRIORITY;
199 static constexpr uint8_t  kMaxOmrRoutesNum   = OPENTHREAD_POSIX_CONFIG_MAX_OMR_ROUTES_NUM;
200 static uint8_t            sAddedOmrRoutesNum = 0;
201 static otIp6Prefix        sAddedOmrRoutes[kMaxOmrRoutesNum];
202 #endif
203 
204 #if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__
205 static constexpr uint32_t kExternalRoutePriority  = OPENTHREAD_POSIX_CONFIG_EXTERNAL_ROUTE_PRIORITY;
206 static constexpr uint8_t  kMaxExternalRoutesNum   = OPENTHREAD_POSIX_CONFIG_MAX_EXTERNAL_ROUTE_NUM;
207 static uint8_t            sAddedExternalRoutesNum = 0;
208 static otIp6Prefix        sAddedExternalRoutes[kMaxExternalRoutesNum];
209 #endif
210 
211 #if defined(RTM_NEWMADDR) || defined(__NetBSD__)
212 // on some BSDs (mac OS, FreeBSD), we get RTM_NEWMADDR/RTM_DELMADDR messages, so we don't need to monitor using MLD
213 // on NetBSD, MLD monitoring simply doesn't work
214 #define OPENTHREAD_POSIX_USE_MLD_MONITOR 0
215 #else
216 // on some platforms (Linux, but others might be made to work), we do not get information about multicast
217 // group joining via AF_NETLINK or AF_ROUTE sockets.  on those platform, we must listen for IPv6 ICMP
218 // MLDv2 messages to know when mulicast memberships change
219 // 		https://stackoverflow.com/questions/37346289/using-netlink-is-it-possible-to-listen-whenever-multicast-group-membership-is-ch
220 #define OPENTHREAD_POSIX_USE_MLD_MONITOR 1
221 #endif // defined(RTM_NEWMADDR) || defined(__NetBSD__)
222 
223 // some platforms (like NetBSD) do not have RTM_NEWMADDR/RTM_DELMADDR messages, and they ALSO lack
224 // working MLDv2 support.  for those platforms, we must tell the OpenThread interface to
225 // pass ALL multicast packets up; the kernel's IPv6 will filter and drop those that have no listeners
226 #define OPENTHREAD_POSIX_MULTICAST_PROMISCUOUS_REQUIRED 0
227 #if !OPENTHREAD_POSIX_USE_MLD_MONITOR
228 #if defined(__NetBSD__)
229 #undef OPENTHREAD_POSIX_MULTICAST_PROMISCUOUS_REQUIRED
230 #define OPENTHREAD_POSIX_MULTICAST_PROMISCUOUS_REQUIRED 1
231 #endif
232 #endif
233 
234 #if defined(__NetBSD__) || defined(__FreeBSD__)
235 static otError destroyTunnel(void);
236 #endif
237 
238 static int sTunFd     = -1; ///< Used to exchange IPv6 packets.
239 static int sIpFd      = -1; ///< Used to manage IPv6 stack on Thread interface.
240 static int sNetlinkFd = -1; ///< Used to receive netlink events.
241 #if OPENTHREAD_POSIX_USE_MLD_MONITOR
242 static int sMLDMonitorFd = -1; ///< Used to receive MLD events.
243 #endif
244 #if OPENTHREAD_POSIX_USE_MLD_MONITOR
245 // ff02::16
246 static const otIp6Address kMLDv2MulticastAddress = {
247     {{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16}}};
248 
249 OT_TOOL_PACKED_BEGIN
250 struct MLDv2Header
251 {
252     uint8_t  mType;
253     uint8_t  _rsv0;
254     uint16_t mChecksum;
255     uint16_t _rsv1;
256     uint16_t mNumRecords;
257 } OT_TOOL_PACKED_END;
258 
259 OT_TOOL_PACKED_BEGIN
260 struct MLDv2Record
261 {
262     uint8_t         mRecordType;
263     uint8_t         mAuxDataLen;
264     uint16_t        mNumSources;
265     struct in6_addr mMulticastAddress;
266 } OT_TOOL_PACKED_END;
267 
268 enum
269 {
270     kICMPv6MLDv2Type                      = 143,
271     kICMPv6MLDv2RecordChangeToExcludeType = 3,
272     kICMPv6MLDv2RecordChangeToIncludeType = 4,
273 };
274 #endif
275 
276 static constexpr size_t kMaxIp6Size = OPENTHREAD_CONFIG_IP6_MAX_DATAGRAM_LENGTH;
277 #if defined(RTM_NEWLINK) && defined(RTM_DELLINK)
278 static bool sIsSyncingState = false;
279 #endif
280 
281 #define OPENTHREAD_POSIX_LOG_TUN_PACKETS 0
282 
283 #if !defined(__linux__)
UnicastAddressIsSubscribed(otInstance * aInstance,const otNetifAddress * netAddr)284 static bool UnicastAddressIsSubscribed(otInstance *aInstance, const otNetifAddress *netAddr)
285 {
286     const otNetifAddress *address = otIp6GetUnicastAddresses(aInstance);
287 
288     while (address != nullptr)
289     {
290         if (memcmp(address->mAddress.mFields.m8, netAddr->mAddress.mFields.m8, sizeof(address->mAddress.mFields.m8)) ==
291             0)
292         {
293             return true;
294         }
295 
296         address = address->mNext;
297     }
298 
299     return false;
300 }
301 #endif
302 
303 #if defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
304 static const uint8_t allOnes[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
305                                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
306 
InitNetaskWithPrefixLength(struct in6_addr * address,uint8_t prefixLen)307 static void InitNetaskWithPrefixLength(struct in6_addr *address, uint8_t prefixLen)
308 {
309 #define MAX_PREFIX_LENGTH (OT_IP6_ADDRESS_SIZE * CHAR_BIT)
310     if (prefixLen > MAX_PREFIX_LENGTH)
311     {
312         prefixLen = MAX_PREFIX_LENGTH;
313     }
314 
315     ot::Ip6::Address addr;
316 
317     addr.Clear();
318     addr.SetPrefix(allOnes, prefixLen);
319     memcpy(address, addr.mFields.m8, sizeof(addr.mFields.m8));
320 }
321 
NetmaskToPrefixLength(const struct sockaddr_in6 * netmask)322 static uint8_t NetmaskToPrefixLength(const struct sockaddr_in6 *netmask)
323 {
324     return otIp6PrefixMatch(reinterpret_cast<const otIp6Address *>(netmask->sin6_addr.s6_addr),
325                             reinterpret_cast<const otIp6Address *>(allOnes));
326 }
327 #endif
328 
329 #if defined(__linux__)
330 #pragma GCC diagnostic push
331 #pragma GCC diagnostic ignored "-Wcast-align"
332 
AddRtAttr(struct nlmsghdr * aHeader,uint32_t aMaxLen,uint8_t aType,const void * aData,uint8_t aLen)333 void AddRtAttr(struct nlmsghdr *aHeader, uint32_t aMaxLen, uint8_t aType, const void *aData, uint8_t aLen)
334 {
335     uint8_t        len = RTA_LENGTH(aLen);
336     struct rtattr *rta;
337 
338     assert(NLMSG_ALIGN(aHeader->nlmsg_len) + RTA_ALIGN(len) <= aMaxLen);
339     OT_UNUSED_VARIABLE(aMaxLen);
340 
341     rta           = (struct rtattr *)((char *)(aHeader) + NLMSG_ALIGN((aHeader)->nlmsg_len));
342     rta->rta_type = aType;
343     rta->rta_len  = len;
344     if (aLen)
345     {
346         memcpy(RTA_DATA(rta), aData, aLen);
347     }
348     aHeader->nlmsg_len = NLMSG_ALIGN(aHeader->nlmsg_len) + RTA_ALIGN(len);
349 }
350 
AddRtAttrUint32(struct nlmsghdr * aHeader,uint32_t aMaxLen,uint8_t aType,uint32_t aData)351 void AddRtAttrUint32(struct nlmsghdr *aHeader, uint32_t aMaxLen, uint8_t aType, uint32_t aData)
352 {
353     AddRtAttr(aHeader, aMaxLen, aType, &aData, sizeof(aData));
354 }
355 
356 #if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE
IsOmrAddress(otInstance * aInstance,const otIp6AddressInfo & aAddressInfo)357 static bool IsOmrAddress(otInstance *aInstance, const otIp6AddressInfo &aAddressInfo)
358 {
359     otIp6Prefix addressPrefix{*aAddressInfo.mAddress, aAddressInfo.mPrefixLength};
360 
361     return otNetDataContainsOmrPrefix(aInstance, &addressPrefix);
362 }
363 #endif
364 
UpdateUnicastLinux(otInstance * aInstance,const otIp6AddressInfo & aAddressInfo,bool aIsAdded)365 static void UpdateUnicastLinux(otInstance *aInstance, const otIp6AddressInfo &aAddressInfo, bool aIsAdded)
366 {
367     OT_UNUSED_VARIABLE(aInstance);
368 
369     struct
370     {
371         struct nlmsghdr  nh;
372         struct ifaddrmsg ifa;
373         char             buf[512];
374     } req;
375 
376     memset(&req, 0, sizeof(req));
377 
378     req.nh.nlmsg_len   = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
379     req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
380     req.nh.nlmsg_type  = aIsAdded ? RTM_NEWADDR : RTM_DELADDR;
381     req.nh.nlmsg_pid   = 0;
382     req.nh.nlmsg_seq   = ++sNetlinkSequence;
383 
384     req.ifa.ifa_family    = AF_INET6;
385     req.ifa.ifa_prefixlen = aAddressInfo.mPrefixLength;
386     req.ifa.ifa_flags     = IFA_F_NODAD;
387     req.ifa.ifa_scope     = aAddressInfo.mScope;
388     req.ifa.ifa_index     = gNetifIndex;
389 
390     AddRtAttr(&req.nh, sizeof(req), IFA_LOCAL, aAddressInfo.mAddress, sizeof(*aAddressInfo.mAddress));
391 
392     if (!aAddressInfo.mPreferred)
393     {
394         struct ifa_cacheinfo cacheinfo;
395 
396         memset(&cacheinfo, 0, sizeof(cacheinfo));
397         cacheinfo.ifa_valid = UINT32_MAX;
398 
399         AddRtAttr(&req.nh, sizeof(req), IFA_CACHEINFO, &cacheinfo, sizeof(cacheinfo));
400     }
401 
402 #if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE
403     if (IsOmrAddress(aInstance, aAddressInfo))
404     {
405         // Remove prefix route for OMR address if `OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE` is enabled to
406         // avoid having two routes.
407         if (aIsAdded)
408         {
409             AddRtAttrUint32(&req.nh, sizeof(req), IFA_FLAGS, IFA_F_NOPREFIXROUTE);
410         }
411     }
412     else
413 #endif
414     {
415 #if OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC > 0
416         if (aAddressInfo.mScope > ot::Ip6::Address::kLinkLocalScope)
417         {
418             AddRtAttrUint32(&req.nh, sizeof(req), IFA_RT_PRIORITY, OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC);
419         }
420 #endif
421     }
422 
423     if (send(sNetlinkFd, &req, req.nh.nlmsg_len, 0) != -1)
424     {
425         otLogInfoPlat("[netif] Sent request#%u to %s %s/%u", sNetlinkSequence, (aIsAdded ? "add" : "remove"),
426                       Ip6AddressString(aAddressInfo.mAddress).AsCString(), aAddressInfo.mPrefixLength);
427     }
428     else
429     {
430         otLogWarnPlat("[netif] Failed to send request#%u to %s %s/%u", sNetlinkSequence, (aIsAdded ? "add" : "remove"),
431                       Ip6AddressString(aAddressInfo.mAddress).AsCString(), aAddressInfo.mPrefixLength);
432     }
433 }
434 
435 #pragma GCC diagnostic pop
436 #endif // defined(__linux__)
437 
UpdateUnicast(otInstance * aInstance,const otIp6AddressInfo & aAddressInfo,bool aIsAdded)438 static void UpdateUnicast(otInstance *aInstance, const otIp6AddressInfo &aAddressInfo, bool aIsAdded)
439 {
440     OT_UNUSED_VARIABLE(aInstance);
441 
442     assert(gInstance == aInstance);
443     assert(sIpFd >= 0);
444 
445 #if defined(__linux__)
446     UpdateUnicastLinux(aInstance, aAddressInfo, aIsAdded);
447 #elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
448     {
449         int                 rval;
450         struct in6_aliasreq ifr6;
451 
452         memset(&ifr6, 0, sizeof(ifr6));
453         strlcpy(ifr6.ifra_name, gNetifName, sizeof(ifr6.ifra_name));
454         ifr6.ifra_addr.sin6_family = AF_INET6;
455         ifr6.ifra_addr.sin6_len    = sizeof(ifr6.ifra_addr);
456         memcpy(&ifr6.ifra_addr.sin6_addr, aAddressInfo.mAddress, sizeof(struct in6_addr));
457         ifr6.ifra_prefixmask.sin6_family = AF_INET6;
458         ifr6.ifra_prefixmask.sin6_len    = sizeof(ifr6.ifra_prefixmask);
459         InitNetaskWithPrefixLength(&ifr6.ifra_prefixmask.sin6_addr, aAddressInfo.mPrefixLength);
460         ifr6.ifra_lifetime.ia6t_vltime    = ND6_INFINITE_LIFETIME;
461         ifr6.ifra_lifetime.ia6t_pltime    = ND6_INFINITE_LIFETIME;
462 
463 #if defined(__APPLE__)
464         ifr6.ifra_lifetime.ia6t_expire    = ND6_INFINITE_LIFETIME;
465         ifr6.ifra_lifetime.ia6t_preferred = (aAddressInfo.mPreferred ? ND6_INFINITE_LIFETIME : 0);
466 #endif
467 
468         rval = ioctl(sIpFd, aIsAdded ? SIOCAIFADDR_IN6 : SIOCDIFADDR_IN6, &ifr6);
469         if (rval == 0)
470         {
471             otLogInfoPlat("[netif] %s %s/%u", (aIsAdded ? "Added" : "Removed"),
472                           Ip6AddressString(aAddressInfo.mAddress).AsCString(), aAddressInfo.mPrefixLength);
473         }
474         else if (errno != EALREADY)
475         {
476             otLogWarnPlat("[netif] Failed to %s %s/%u: %s", (aIsAdded ? "add" : "remove"),
477                           Ip6AddressString(aAddressInfo.mAddress).AsCString(), aAddressInfo.mPrefixLength,
478                           strerror(errno));
479         }
480     }
481 #endif
482 }
483 
UpdateMulticast(otInstance * aInstance,const otIp6Address & aAddress,bool aIsAdded)484 static void UpdateMulticast(otInstance *aInstance, const otIp6Address &aAddress, bool aIsAdded)
485 {
486     OT_UNUSED_VARIABLE(aInstance);
487 
488     struct ipv6_mreq mreq;
489     otError          error = OT_ERROR_NONE;
490     int              err;
491 
492     assert(gInstance == aInstance);
493 
494     VerifyOrExit(sIpFd >= 0);
495     memcpy(&mreq.ipv6mr_multiaddr, &aAddress, sizeof(mreq.ipv6mr_multiaddr));
496     mreq.ipv6mr_interface = gNetifIndex;
497 
498     err = setsockopt(sIpFd, IPPROTO_IPV6, (aIsAdded ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP), &mreq, sizeof(mreq));
499 
500 #if defined(__APPLE__) || defined(__FreeBSD__)
501     if ((err != 0) && (errno == EINVAL) && (IN6_IS_ADDR_MC_LINKLOCAL(&mreq.ipv6mr_multiaddr)))
502     {
503         // FIX ME
504         // on mac OS (and FreeBSD), the first time we run (but not subsequently), we get a failure on this
505         // particular join. do we need to bring up the interface at least once prior to joining? we need to figure
506         // out why so we can get rid of this workaround
507         char addressString[INET6_ADDRSTRLEN + 1];
508 
509         inet_ntop(AF_INET6, mreq.ipv6mr_multiaddr.s6_addr, addressString, sizeof(addressString));
510         otLogWarnPlat("[netif] Ignoring %s failure (EINVAL) for MC LINKLOCAL address (%s)",
511                       aIsAdded ? "IPV6_JOIN_GROUP" : "IPV6_LEAVE_GROUP", addressString);
512         err = 0;
513     }
514 #endif
515 
516     if (err != 0)
517     {
518         otLogWarnPlat("[netif] %s failure (%d)", aIsAdded ? "IPV6_JOIN_GROUP" : "IPV6_LEAVE_GROUP", errno);
519         error = OT_ERROR_FAILED;
520         ExitNow();
521     }
522 
523     otLogInfoPlat("[netif] %s multicast address %s", aIsAdded ? "Added" : "Removed",
524                   Ip6AddressString(&aAddress).AsCString());
525 
526 exit:
527     SuccessOrDie(error);
528 }
529 
UpdateLink(otInstance * aInstance)530 static void UpdateLink(otInstance *aInstance)
531 {
532     otError      error = OT_ERROR_NONE;
533     struct ifreq ifr;
534     bool         ifState = false;
535     bool         otState = false;
536 
537     assert(gInstance == aInstance);
538 
539     VerifyOrExit(sIpFd >= 0);
540     memset(&ifr, 0, sizeof(ifr));
541     strncpy(ifr.ifr_name, gNetifName, sizeof(ifr.ifr_name));
542     VerifyOrExit(ioctl(sIpFd, SIOCGIFFLAGS, &ifr) == 0, perror("ioctl"); error = OT_ERROR_FAILED);
543 
544     ifState = ((ifr.ifr_flags & IFF_UP) == IFF_UP) ? true : false;
545     otState = otIp6IsEnabled(aInstance);
546 
547     otLogNotePlat("[netif] Changing interface state to %s%s.", otState ? "up" : "down",
548                   (ifState == otState) ? " (already done, ignoring)" : "");
549 
550     if (ifState != otState)
551     {
552         ifr.ifr_flags = otState ? (ifr.ifr_flags | IFF_UP) : (ifr.ifr_flags & ~IFF_UP);
553         VerifyOrExit(ioctl(sIpFd, SIOCSIFFLAGS, &ifr) == 0, perror("ioctl"); error = OT_ERROR_FAILED);
554 #if defined(RTM_NEWLINK) && defined(RTM_DELLINK)
555         // wait for RTM_NEWLINK event before processing notification from kernel to avoid infinite loop
556         sIsSyncingState = true;
557 #endif
558     }
559 
560 exit:
561     if (error != OT_ERROR_NONE)
562     {
563         otLogWarnPlat("[netif] Failed to update state %s", otThreadErrorToString(error));
564     }
565 }
566 
567 #if __linux__ && \
568     (OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE || OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE)
569 
AddRoute(const otIp6Prefix & aPrefix,uint32_t aPriority)570 static otError AddRoute(const otIp6Prefix &aPrefix, uint32_t aPriority)
571 {
572     constexpr unsigned int kBufSize = 128;
573     struct
574     {
575         struct nlmsghdr header;
576         struct rtmsg    msg;
577         char            buf[kBufSize];
578     } req{};
579     unsigned char data[sizeof(in6_addr)];
580     char          addrBuf[OT_IP6_ADDRESS_STRING_SIZE];
581     unsigned int  netifIdx = otSysGetThreadNetifIndex();
582     otError       error    = OT_ERROR_NONE;
583 
584     VerifyOrExit(netifIdx > 0, error = OT_ERROR_INVALID_STATE);
585     VerifyOrExit(sNetlinkFd >= 0, error = OT_ERROR_INVALID_STATE);
586 
587     req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
588 
589     req.header.nlmsg_len  = NLMSG_LENGTH(sizeof(rtmsg));
590     req.header.nlmsg_type = RTM_NEWROUTE;
591     req.header.nlmsg_pid  = 0;
592     req.header.nlmsg_seq  = ++sNetlinkSequence;
593 
594     req.msg.rtm_family   = AF_INET6;
595     req.msg.rtm_src_len  = 0;
596     req.msg.rtm_dst_len  = aPrefix.mLength;
597     req.msg.rtm_tos      = 0;
598     req.msg.rtm_scope    = RT_SCOPE_UNIVERSE;
599     req.msg.rtm_type     = RTN_UNICAST;
600     req.msg.rtm_table    = RT_TABLE_MAIN;
601     req.msg.rtm_protocol = RTPROT_BOOT;
602     req.msg.rtm_flags    = 0;
603 
604     otIp6AddressToString(&aPrefix.mPrefix, addrBuf, OT_IP6_ADDRESS_STRING_SIZE);
605     inet_pton(AF_INET6, addrBuf, data);
606     AddRtAttr(reinterpret_cast<nlmsghdr *>(&req), sizeof(req), RTA_DST, data, sizeof(data));
607     AddRtAttrUint32(&req.header, sizeof(req), RTA_PRIORITY, aPriority);
608     AddRtAttrUint32(&req.header, sizeof(req), RTA_OIF, netifIdx);
609 
610     if (send(sNetlinkFd, &req, sizeof(req), 0) < 0)
611     {
612         VerifyOrExit(errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK, error = OT_ERROR_BUSY);
613         DieNow(OT_EXIT_ERROR_ERRNO);
614     }
615 exit:
616     return error;
617 }
618 
DeleteRoute(const otIp6Prefix & aPrefix)619 static otError DeleteRoute(const otIp6Prefix &aPrefix)
620 {
621     constexpr unsigned int kBufSize = 512;
622     struct
623     {
624         struct nlmsghdr header;
625         struct rtmsg    msg;
626         char            buf[kBufSize];
627     } req{};
628     unsigned char data[sizeof(in6_addr)];
629     char          addrBuf[OT_IP6_ADDRESS_STRING_SIZE];
630     unsigned int  netifIdx = otSysGetThreadNetifIndex();
631     otError       error    = OT_ERROR_NONE;
632 
633     VerifyOrExit(netifIdx > 0, error = OT_ERROR_INVALID_STATE);
634     VerifyOrExit(sNetlinkFd >= 0, error = OT_ERROR_INVALID_STATE);
635 
636     req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_NONREC;
637 
638     req.header.nlmsg_len  = NLMSG_LENGTH(sizeof(rtmsg));
639     req.header.nlmsg_type = RTM_DELROUTE;
640     req.header.nlmsg_pid  = 0;
641     req.header.nlmsg_seq  = ++sNetlinkSequence;
642 
643     req.msg.rtm_family   = AF_INET6;
644     req.msg.rtm_src_len  = 0;
645     req.msg.rtm_dst_len  = aPrefix.mLength;
646     req.msg.rtm_tos      = 0;
647     req.msg.rtm_scope    = RT_SCOPE_UNIVERSE;
648     req.msg.rtm_type     = RTN_UNICAST;
649     req.msg.rtm_table    = RT_TABLE_MAIN;
650     req.msg.rtm_protocol = RTPROT_BOOT;
651     req.msg.rtm_flags    = 0;
652 
653     otIp6AddressToString(&aPrefix.mPrefix, addrBuf, OT_IP6_ADDRESS_STRING_SIZE);
654     inet_pton(AF_INET6, addrBuf, data);
655     AddRtAttr(reinterpret_cast<nlmsghdr *>(&req), sizeof(req), RTA_DST, data, sizeof(data));
656     AddRtAttrUint32(&req.header, sizeof(req), RTA_OIF, netifIdx);
657 
658     if (send(sNetlinkFd, &req, sizeof(req), 0) < 0)
659     {
660         VerifyOrExit(errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK, error = OT_ERROR_BUSY);
661         DieNow(OT_EXIT_ERROR_ERRNO);
662     }
663 
664 exit:
665     return error;
666 }
667 
668 #endif // __linux__ && (OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE ||
669        // OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE)
670 
671 #if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && __linux__
672 
HasAddedOmrRoute(const otIp6Prefix & aOmrPrefix)673 static bool HasAddedOmrRoute(const otIp6Prefix &aOmrPrefix)
674 {
675     bool found = false;
676 
677     for (uint8_t i = 0; i < sAddedOmrRoutesNum; ++i)
678     {
679         if (otIp6ArePrefixesEqual(&sAddedOmrRoutes[i], &aOmrPrefix))
680         {
681             found = true;
682             break;
683         }
684     }
685 
686     return found;
687 }
688 
AddOmrRoute(const otIp6Prefix & aPrefix)689 static otError AddOmrRoute(const otIp6Prefix &aPrefix)
690 {
691     otError error;
692 
693     VerifyOrExit(sAddedOmrRoutesNum < kMaxOmrRoutesNum, error = OT_ERROR_NO_BUFS);
694 
695     error = AddRoute(aPrefix, kOmrRoutesPriority);
696 exit:
697     return error;
698 }
699 
UpdateOmrRoutes(otInstance * aInstance)700 static void UpdateOmrRoutes(otInstance *aInstance)
701 {
702     otError               error;
703     otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
704     otBorderRouterConfig  config;
705     char                  prefixString[OT_IP6_PREFIX_STRING_SIZE];
706 
707     // Remove kernel routes if the OMR prefix is removed
708     for (int i = 0; i < static_cast<int>(sAddedOmrRoutesNum); ++i)
709     {
710         if (otNetDataContainsOmrPrefix(aInstance, &sAddedOmrRoutes[i]))
711         {
712             continue;
713         }
714 
715         otIp6PrefixToString(&sAddedOmrRoutes[i], prefixString, sizeof(prefixString));
716         if ((error = DeleteRoute(sAddedOmrRoutes[i])) != OT_ERROR_NONE)
717         {
718             otLogWarnPlat("[netif] Failed to delete an OMR route %s in kernel: %s", prefixString,
719                           otThreadErrorToString(error));
720         }
721         else
722         {
723             sAddedOmrRoutes[i] = sAddedOmrRoutes[sAddedOmrRoutesNum - 1];
724             --sAddedOmrRoutesNum;
725             --i;
726             otLogInfoPlat("[netif] Successfully deleted an OMR route %s in kernel", prefixString);
727         }
728     }
729 
730     // Add kernel routes for OMR prefixes in Network Data
731     while (otNetDataGetNextOnMeshPrefix(aInstance, &iterator, &config) == OT_ERROR_NONE)
732     {
733         if (HasAddedOmrRoute(config.mPrefix))
734         {
735             continue;
736         }
737 
738         otIp6PrefixToString(&config.mPrefix, prefixString, sizeof(prefixString));
739         if ((error = AddOmrRoute(config.mPrefix)) != OT_ERROR_NONE)
740         {
741             otLogWarnPlat("[netif] Failed to add an OMR route %s in kernel: %s", prefixString,
742                           otThreadErrorToString(error));
743         }
744         else
745         {
746             sAddedOmrRoutes[sAddedOmrRoutesNum++] = config.mPrefix;
747             otLogInfoPlat("[netif] Successfully added an OMR route %s in kernel: %s", prefixString);
748         }
749     }
750 }
751 
752 #endif // OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && __linux__
753 
754 #if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__
755 
AddExternalRoute(const otIp6Prefix & aPrefix)756 static otError AddExternalRoute(const otIp6Prefix &aPrefix)
757 {
758     otError error;
759 
760     VerifyOrExit(sAddedExternalRoutesNum < kMaxExternalRoutesNum, error = OT_ERROR_NO_BUFS);
761 
762     error = AddRoute(aPrefix, kExternalRoutePriority);
763 exit:
764     return error;
765 }
766 
HasExternalRouteInNetData(otInstance * aInstance,const otIp6Prefix & aExternalRoute)767 bool HasExternalRouteInNetData(otInstance *aInstance, const otIp6Prefix &aExternalRoute)
768 {
769     otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
770     otExternalRouteConfig config;
771     bool                  found = false;
772 
773     while (otNetDataGetNextRoute(aInstance, &iterator, &config) == OT_ERROR_NONE)
774     {
775         if (otIp6ArePrefixesEqual(&config.mPrefix, &aExternalRoute))
776         {
777             found = true;
778             break;
779         }
780     }
781     return found;
782 }
783 
HasAddedExternalRoute(const otIp6Prefix & aExternalRoute)784 bool HasAddedExternalRoute(const otIp6Prefix &aExternalRoute)
785 {
786     bool found = false;
787 
788     for (uint8_t i = 0; i < sAddedExternalRoutesNum; ++i)
789     {
790         if (otIp6ArePrefixesEqual(&sAddedExternalRoutes[i], &aExternalRoute))
791         {
792             found = true;
793             break;
794         }
795     }
796     return found;
797 }
798 
UpdateExternalRoutes(otInstance * aInstance)799 static void UpdateExternalRoutes(otInstance *aInstance)
800 {
801     otError               error;
802     otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
803     otExternalRouteConfig config;
804     char                  prefixString[OT_IP6_PREFIX_STRING_SIZE];
805 
806     for (int i = 0; i < static_cast<int>(sAddedExternalRoutesNum); ++i)
807     {
808         if (HasExternalRouteInNetData(aInstance, sAddedExternalRoutes[i]))
809         {
810             continue;
811         }
812 
813         otIp6PrefixToString(&sAddedExternalRoutes[i], prefixString, sizeof(prefixString));
814         if ((error = DeleteRoute(sAddedExternalRoutes[i])) != OT_ERROR_NONE)
815         {
816             otLogWarnPlat("[netif] Failed to delete an external route %s in kernel: %s", prefixString,
817                           otThreadErrorToString(error));
818         }
819         else
820         {
821             sAddedExternalRoutes[i] = sAddedExternalRoutes[sAddedExternalRoutesNum - 1];
822             --sAddedExternalRoutesNum;
823             --i;
824             otLogWarnPlat("[netif] Successfully deleted an external route %s in kernel", prefixString);
825         }
826     }
827 
828     while (otNetDataGetNextRoute(aInstance, &iterator, &config) == OT_ERROR_NONE)
829     {
830         if (config.mRloc16 == otThreadGetRloc16(aInstance) || HasAddedExternalRoute(config.mPrefix))
831         {
832             continue;
833         }
834         VerifyOrExit(sAddedExternalRoutesNum < kMaxExternalRoutesNum,
835                      otLogWarnPlat("[netif] No buffer to add more external routes in kernel"));
836 
837         otIp6PrefixToString(&config.mPrefix, prefixString, sizeof(prefixString));
838         if ((error = AddExternalRoute(config.mPrefix)) != OT_ERROR_NONE)
839         {
840             otLogWarnPlat("[netif] Failed to add an external route %s in kernel: %s", prefixString,
841                           otThreadErrorToString(error));
842         }
843         else
844         {
845             sAddedExternalRoutes[sAddedExternalRoutesNum++] = config.mPrefix;
846             otLogWarnPlat("[netif] Successfully added an external route %s in kernel: %s", prefixString);
847         }
848     }
849 exit:
850     return;
851 }
852 #endif // OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__
853 
processAddressChange(const otIp6AddressInfo * aAddressInfo,bool aIsAdded,void * aContext)854 static void processAddressChange(const otIp6AddressInfo *aAddressInfo, bool aIsAdded, void *aContext)
855 {
856     if (aAddressInfo->mAddress->mFields.m8[0] == 0xff)
857     {
858         UpdateMulticast(static_cast<otInstance *>(aContext), *aAddressInfo->mAddress, aIsAdded);
859     }
860     else
861     {
862         UpdateUnicast(static_cast<otInstance *>(aContext), *aAddressInfo, aIsAdded);
863     }
864 }
865 
platformNetifStateChange(otInstance * aInstance,otChangedFlags aFlags)866 void platformNetifStateChange(otInstance *aInstance, otChangedFlags aFlags)
867 {
868     if (OT_CHANGED_THREAD_NETIF_STATE & aFlags)
869     {
870         UpdateLink(aInstance);
871     }
872     if (OT_CHANGED_THREAD_NETDATA & aFlags)
873     {
874 #if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && __linux__
875         UpdateOmrRoutes(aInstance);
876 #endif
877 #if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__
878         UpdateExternalRoutes(aInstance);
879 #endif
880 #if OPENTHREAD_POSIX_CONFIG_FIREWALL_ENABLE
881         ot::Posix::UpdateIpSets(aInstance);
882 #endif
883     }
884 }
885 
processReceive(otMessage * aMessage,void * aContext)886 static void processReceive(otMessage *aMessage, void *aContext)
887 {
888     OT_UNUSED_VARIABLE(aContext);
889 
890     char     packet[kMaxIp6Size + 4];
891     otError  error     = OT_ERROR_NONE;
892     uint16_t length    = otMessageGetLength(aMessage);
893     size_t   offset    = 0;
894     uint16_t maxLength = sizeof(packet) - 4;
895 #if defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
896     // BSD tunnel drivers use (for legacy reasons) a 4-byte header to determine the address family of the packet
897     offset += 4;
898 #endif
899 
900     assert(gInstance == aContext);
901     assert(length <= kMaxIp6Size);
902 
903     VerifyOrExit(sTunFd > 0);
904 
905     VerifyOrExit(otMessageRead(aMessage, 0, &packet[offset], maxLength) == length, error = OT_ERROR_NO_BUFS);
906 
907 #if OPENTHREAD_POSIX_LOG_TUN_PACKETS
908     otLogInfoPlat("[netif] Packet from NCP (%u bytes)", static_cast<uint16_t>(length));
909     otDumpInfoPlat("", &packet[offset], length);
910 #endif
911 
912 #if defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
913     packet[0] = 0;
914     packet[1] = 0;
915     packet[2] = (PF_INET6 << 8) & 0xFF;
916     packet[3] = (PF_INET6 << 0) & 0xFF;
917     length += 4;
918 #endif
919 
920     VerifyOrExit(write(sTunFd, packet, length) == length, perror("write"); error = OT_ERROR_FAILED);
921 
922 exit:
923     otMessageFree(aMessage);
924 
925     if (error != OT_ERROR_NONE)
926     {
927         otLogWarnPlat("[netif] Failed to receive, error:%s", otThreadErrorToString(error));
928     }
929 }
930 
processTransmit(otInstance * aInstance)931 static void processTransmit(otInstance *aInstance)
932 {
933     otMessage *message = nullptr;
934     ssize_t    rval;
935     char       packet[kMaxIp6Size];
936     otError    error  = OT_ERROR_NONE;
937     size_t     offset = 0;
938 
939     assert(gInstance == aInstance);
940 
941     rval = read(sTunFd, packet, sizeof(packet));
942     VerifyOrExit(rval > 0, error = OT_ERROR_FAILED);
943 
944     {
945         otMessageSettings settings;
946 
947         settings.mLinkSecurityEnabled = (otThreadGetDeviceRole(aInstance) != OT_DEVICE_ROLE_DISABLED);
948         settings.mPriority            = OT_MESSAGE_PRIORITY_LOW;
949         message                       = otIp6NewMessage(aInstance, &settings);
950         VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS);
951     }
952 
953 #if defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
954     // BSD tunnel drivers have (for legacy reasons), may have a 4-byte header on them
955     if ((rval >= 4) && (packet[0] == 0) && (packet[1] == 0))
956     {
957         rval -= 4;
958         offset = 4;
959     }
960 #endif
961 
962 #if OPENTHREAD_POSIX_LOG_TUN_PACKETS
963     otLogInfoPlat("[netif] Packet to NCP (%hu bytes)", static_cast<uint16_t>(rval));
964     otDumpInfoPlat("", &packet[offset], static_cast<size_t>(rval));
965 #endif
966 
967     SuccessOrExit(error = otMessageAppend(message, &packet[offset], static_cast<uint16_t>(rval)));
968 
969     error   = otIp6Send(aInstance, message);
970     message = nullptr;
971 
972 exit:
973     if (message != nullptr)
974     {
975         otMessageFree(message);
976     }
977 
978     if (error != OT_ERROR_NONE)
979     {
980         if (error == OT_ERROR_DROP)
981         {
982             otLogInfoPlat("[netif] Message dropped by Thread", otThreadErrorToString(error));
983         }
984         else
985         {
986             otLogWarnPlat("[netif] Failed to transmit, error:%s", otThreadErrorToString(error));
987         }
988     }
989 }
990 
logAddrEvent(bool isAdd,const ot::Ip6::Address & aAddress,otError error)991 static void logAddrEvent(bool isAdd, const ot::Ip6::Address &aAddress, otError error)
992 {
993     OT_UNUSED_VARIABLE(aAddress);
994 
995     if ((error == OT_ERROR_NONE) || ((isAdd) && (error == OT_ERROR_ALREADY || error == OT_ERROR_REJECTED)) ||
996         ((!isAdd) && (error == OT_ERROR_NOT_FOUND || error == OT_ERROR_REJECTED)))
997     {
998         otLogInfoPlat("[netif] %s [%s] %s%s", isAdd ? "ADD" : "DEL", aAddress.IsMulticast() ? "M" : "U",
999                       aAddress.ToString().AsCString(),
1000                       error == OT_ERROR_ALREADY
1001                           ? " (already subscribed, ignored)"
1002                           : error == OT_ERROR_REJECTED ? " (rejected)"
1003                                                        : error == OT_ERROR_NOT_FOUND ? " (not found, ignored)" : "");
1004     }
1005     else
1006     {
1007         otLogWarnPlat("[netif] %s [%s] %s failed (%s)", isAdd ? "ADD" : "DEL", aAddress.IsMulticast() ? "M" : "U",
1008                       aAddress.ToString().AsCString(), otThreadErrorToString(error));
1009     }
1010 }
1011 
1012 #if defined(__linux__)
1013 
processNetifAddrEvent(otInstance * aInstance,struct nlmsghdr * aNetlinkMessage)1014 static void processNetifAddrEvent(otInstance *aInstance, struct nlmsghdr *aNetlinkMessage)
1015 {
1016     struct ifaddrmsg *  ifaddr = reinterpret_cast<struct ifaddrmsg *>(NLMSG_DATA(aNetlinkMessage));
1017     size_t              rtaLength;
1018     otError             error = OT_ERROR_NONE;
1019     struct sockaddr_in6 addr6;
1020 
1021     VerifyOrExit(ifaddr->ifa_index == static_cast<unsigned int>(gNetifIndex) && ifaddr->ifa_family == AF_INET6);
1022 
1023     rtaLength = IFA_PAYLOAD(aNetlinkMessage);
1024 
1025     for (struct rtattr *rta = reinterpret_cast<struct rtattr *>(IFA_RTA(ifaddr)); RTA_OK(rta, rtaLength);
1026          rta                = RTA_NEXT(rta, rtaLength))
1027     {
1028         switch (rta->rta_type)
1029         {
1030         case IFA_ADDRESS:
1031         case IFA_LOCAL:
1032         case IFA_BROADCAST:
1033         case IFA_ANYCAST:
1034         case IFA_MULTICAST:
1035         {
1036             ot::Ip6::Address addr;
1037             memcpy(&addr, RTA_DATA(rta), sizeof(addr));
1038 
1039             memset(&addr6, 0, sizeof(addr6));
1040             addr6.sin6_family = AF_INET6;
1041             memcpy(&addr6.sin6_addr, RTA_DATA(rta), sizeof(addr6.sin6_addr));
1042 
1043             if (aNetlinkMessage->nlmsg_type == RTM_NEWADDR)
1044             {
1045                 if (!addr.IsMulticast())
1046                 {
1047                     otNetifAddress netAddr;
1048 
1049                     netAddr.mAddress      = addr;
1050                     netAddr.mPrefixLength = ifaddr->ifa_prefixlen;
1051 
1052                     error = otIp6AddUnicastAddress(aInstance, &netAddr);
1053                 }
1054                 else
1055                 {
1056                     otNetifMulticastAddress netAddr;
1057 
1058                     netAddr.mAddress = addr;
1059 
1060                     error = otIp6SubscribeMulticastAddress(aInstance, &addr);
1061                 }
1062 
1063                 logAddrEvent(/* isAdd */ true, addr, error);
1064                 if (error == OT_ERROR_ALREADY || error == OT_ERROR_REJECTED)
1065                 {
1066                     error = OT_ERROR_NONE;
1067                 }
1068 
1069                 SuccessOrExit(error);
1070             }
1071             else if (aNetlinkMessage->nlmsg_type == RTM_DELADDR)
1072             {
1073                 if (!addr.IsMulticast())
1074                 {
1075                     error = otIp6RemoveUnicastAddress(aInstance, &addr);
1076                 }
1077                 else
1078                 {
1079                     error = otIp6UnsubscribeMulticastAddress(aInstance, &addr);
1080                 }
1081 
1082                 logAddrEvent(/* isAdd */ false, addr, error);
1083                 if (error == OT_ERROR_NOT_FOUND || error == OT_ERROR_REJECTED)
1084                 {
1085                     error = OT_ERROR_NONE;
1086                 }
1087 
1088                 SuccessOrExit(error);
1089             }
1090             else
1091             {
1092                 continue;
1093             }
1094             break;
1095         }
1096 
1097         default:
1098             otLogDebgPlat("[netif] Unexpected address type (%d).", (int)rta->rta_type);
1099             break;
1100         }
1101     }
1102 
1103 exit:
1104     if (error != OT_ERROR_NONE)
1105     {
1106         otLogWarnPlat("[netif] Failed to process event, error:%s", otThreadErrorToString(error));
1107     }
1108 }
1109 
processNetifLinkEvent(otInstance * aInstance,struct nlmsghdr * aNetlinkMessage)1110 static void processNetifLinkEvent(otInstance *aInstance, struct nlmsghdr *aNetlinkMessage)
1111 {
1112     struct ifinfomsg *ifinfo = reinterpret_cast<struct ifinfomsg *>(NLMSG_DATA(aNetlinkMessage));
1113     otError           error  = OT_ERROR_NONE;
1114     bool              isUp;
1115 
1116     VerifyOrExit(ifinfo->ifi_index == static_cast<int>(gNetifIndex) && (ifinfo->ifi_change & IFF_UP));
1117 
1118     isUp = ((ifinfo->ifi_flags & IFF_UP) != 0);
1119 
1120     otLogInfoPlat("[netif] Host netif is %s", isUp ? "up" : "down");
1121 
1122 #if defined(RTM_NEWLINK) && defined(RTM_DELLINK)
1123     if (sIsSyncingState)
1124     {
1125         VerifyOrExit(isUp == otIp6IsEnabled(aInstance),
1126                      otLogWarnPlat("[netif] Host netif state notification is unexpected (ignore)"));
1127         sIsSyncingState = false;
1128     }
1129     else
1130 #endif
1131         if (isUp != otIp6IsEnabled(aInstance))
1132     {
1133         SuccessOrExit(error = otIp6SetEnabled(aInstance, isUp));
1134         otLogInfoPlat("[netif] Succeeded to sync netif state with host");
1135     }
1136 
1137 exit:
1138     if (error != OT_ERROR_NONE)
1139     {
1140         otLogWarnPlat("[netif] Failed to sync netif state with host: %s", otThreadErrorToString(error));
1141     }
1142 }
1143 #endif
1144 
1145 #if defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
1146 
1147 #if defined(__FreeBSD__)
1148 #define ROUNDUP(a) ((a) > 0 ? (1 + (((a)-1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
1149 #endif
1150 
1151 #if defined(__APPLE__)
1152 #define ROUNDUP(a) ((a) > 0 ? (1 + (((a)-1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
1153 #define DARWIN_SA_SIZE(sa) ROUNDUP(sa->sa_len)
1154 #define SA_SIZE(sa) DARWIN_SA_SIZE(sa)
1155 #endif
1156 
1157 #if defined(__NetBSD__)
1158 #define RT_ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a)-1U) | ((n)-1))) : (n))
1159 #define RT_ROUNDUP(a) RT_ROUNDUP2((a), sizeof(uint64_t))
1160 #define SA_SIZE(sa) RT_ROUNDUP(sa->sa_len)
1161 #endif
1162 
processNetifAddrEvent(otInstance * aInstance,struct rt_msghdr * rtm)1163 static void processNetifAddrEvent(otInstance *aInstance, struct rt_msghdr *rtm)
1164 {
1165     otError            error;
1166     struct ifa_msghdr *ifam;
1167 #ifdef RTM_NEWMADDR
1168     struct ifma_msghdr *ifmam;
1169 #endif
1170     struct sockaddr_in6 addr6;
1171     struct sockaddr_in6 netmask;
1172     uint8_t *           addrbuf;
1173     unsigned int        addrmask = 0;
1174     unsigned int        i;
1175     struct sockaddr *   sa;
1176     bool                is_link_local;
1177 
1178     addr6.sin6_family   = 0;
1179     netmask.sin6_family = 0;
1180 
1181     if ((rtm->rtm_type == RTM_NEWADDR) || (rtm->rtm_type == RTM_DELADDR))
1182     {
1183         ifam = reinterpret_cast<struct ifa_msghdr *>(rtm);
1184 
1185         VerifyOrExit(ifam->ifam_index == static_cast<unsigned int>(gNetifIndex));
1186 
1187         addrbuf  = (uint8_t *)&ifam[1];
1188         addrmask = (unsigned int)ifam->ifam_addrs;
1189     }
1190 #ifdef RTM_NEWMADDR
1191     else if ((rtm->rtm_type == RTM_NEWMADDR) || (rtm->rtm_type == RTM_DELMADDR))
1192     {
1193         ifmam = reinterpret_cast<struct ifma_msghdr *>(rtm);
1194 
1195         VerifyOrExit(ifmam->ifmam_index == static_cast<unsigned int>(gNetifIndex));
1196 
1197         addrbuf  = (uint8_t *)&ifmam[1];
1198         addrmask = (unsigned int)ifmam->ifmam_addrs;
1199     }
1200 #endif
1201 
1202     if (addrmask != 0)
1203     {
1204         for (i = 0; i < RTAX_MAX; i++)
1205         {
1206             unsigned int mask = (addrmask & (1 << i));
1207             if (mask)
1208             {
1209                 sa = (struct sockaddr *)addrbuf;
1210 
1211                 if (sa->sa_family == AF_INET6)
1212                 {
1213                     if (i == RTAX_IFA)
1214                         memcpy(&addr6, sa, sizeof(sockaddr_in6));
1215                     if (i == RTAX_NETMASK)
1216                         memcpy(&netmask, sa, sizeof(sockaddr_in6));
1217                 }
1218                 addrbuf += SA_SIZE(sa);
1219             }
1220         }
1221     }
1222 
1223     if (addr6.sin6_family == AF_INET6)
1224     {
1225         is_link_local = false;
1226         if (IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr))
1227         {
1228             is_link_local = true;
1229             // clear the scope -- Mac OS X sends this to us (bozos!)
1230             addr6.sin6_addr.s6_addr[3] = 0;
1231         }
1232         else if (IN6_IS_ADDR_MC_LINKLOCAL(&addr6.sin6_addr))
1233         {
1234             addr6.sin6_addr.s6_addr[3] = 0;
1235         }
1236 
1237         ot::Ip6::Address addr;
1238         memcpy(&addr, &addr6.sin6_addr, sizeof(addr));
1239 
1240         if (rtm->rtm_type == RTM_NEWADDR
1241 #ifdef RTM_NEWMADDR
1242             || rtm->rtm_type == RTM_NEWMADDR
1243 #endif
1244         )
1245         {
1246             if (!addr.IsMulticast())
1247             {
1248                 otNetifAddress netAddr;
1249                 bool           subscribed;
1250 
1251                 netAddr.mAddress      = addr;
1252                 netAddr.mPrefixLength = NetmaskToPrefixLength(&netmask);
1253 
1254                 subscribed = UnicastAddressIsSubscribed(aInstance, &netAddr);
1255 
1256                 if (subscribed)
1257                 {
1258                     logAddrEvent(/* isAdd */ true, addr, OT_ERROR_ALREADY);
1259                     error = OT_ERROR_NONE;
1260                 }
1261                 else
1262                 {
1263                     if (is_link_local)
1264                     {
1265                         // remove the stack-added link-local address
1266 
1267                         int                 err;
1268                         struct in6_aliasreq ifr6;
1269                         char                addressString[INET6_ADDRSTRLEN + 1];
1270 
1271                         OT_UNUSED_VARIABLE(addressString); // if otLog*Plat is disabled, we'll get a warning
1272 
1273                         memset(&ifr6, 0, sizeof(ifr6));
1274                         strlcpy(ifr6.ifra_name, gNetifName, sizeof(ifr6.ifra_name));
1275                         ifr6.ifra_addr.sin6_family = AF_INET6;
1276                         ifr6.ifra_addr.sin6_len    = sizeof(ifr6.ifra_addr);
1277                         memcpy(&ifr6.ifra_addr.sin6_addr, &addr6.sin6_addr, sizeof(struct in6_addr));
1278                         ifr6.ifra_prefixmask.sin6_family = AF_INET6;
1279                         ifr6.ifra_prefixmask.sin6_len    = sizeof(ifr6.ifra_prefixmask);
1280                         InitNetaskWithPrefixLength(&ifr6.ifra_prefixmask.sin6_addr, netAddr.mPrefixLength);
1281                         ifr6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
1282                         ifr6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
1283 
1284 #if defined(__APPLE__)
1285                         ifr6.ifra_lifetime.ia6t_expire    = ND6_INFINITE_LIFETIME;
1286                         ifr6.ifra_lifetime.ia6t_preferred = ND6_INFINITE_LIFETIME;
1287 #endif
1288 
1289                         err = ioctl(sIpFd, SIOCDIFADDR_IN6, &ifr6);
1290                         if (err != 0)
1291                         {
1292                             otLogWarnPlat(
1293                                 "[netif] Error (%d) removing stack-addded link-local address %s", errno,
1294                                 inet_ntop(AF_INET6, addr6.sin6_addr.s6_addr, addressString, sizeof(addressString)));
1295                             error = OT_ERROR_FAILED;
1296                         }
1297                         else
1298                         {
1299                             otLogNotePlat(
1300                                 "[netif]        %s (removed stack-added link-local)",
1301                                 inet_ntop(AF_INET6, addr6.sin6_addr.s6_addr, addressString, sizeof(addressString)));
1302                             error = OT_ERROR_NONE;
1303                         }
1304                     }
1305                     else
1306                     {
1307                         error = otIp6AddUnicastAddress(aInstance, &netAddr);
1308                         logAddrEvent(/* isAdd */ true, addr, error);
1309                         if (error == OT_ERROR_ALREADY)
1310                         {
1311                             error = OT_ERROR_NONE;
1312                         }
1313                     }
1314                 }
1315                 SuccessOrExit(error);
1316             }
1317             else
1318             {
1319                 otNetifMulticastAddress netAddr;
1320                 netAddr.mAddress = addr;
1321 
1322                 error = otIp6SubscribeMulticastAddress(aInstance, &addr);
1323                 logAddrEvent(/* isAdd */ true, addr, error);
1324                 if (error == OT_ERROR_ALREADY || error == OT_ERROR_REJECTED)
1325                 {
1326                     error = OT_ERROR_NONE;
1327                 }
1328                 SuccessOrExit(error);
1329             }
1330         }
1331         else if (rtm->rtm_type == RTM_DELADDR
1332 #ifdef RTM_DELMADDR
1333                  || rtm->rtm_type == RTM_DELMADDR
1334 #endif
1335         )
1336         {
1337             if (!addr.IsMulticast())
1338             {
1339                 error = otIp6RemoveUnicastAddress(aInstance, &addr);
1340                 logAddrEvent(/* isAdd */ false, addr, error);
1341                 if (error == OT_ERROR_NOT_FOUND)
1342                 {
1343                     error = OT_ERROR_NONE;
1344                 }
1345             }
1346             else
1347             {
1348                 error = otIp6UnsubscribeMulticastAddress(aInstance, &addr);
1349                 logAddrEvent(/* isAdd */ false, addr, error);
1350                 if (error == OT_ERROR_NOT_FOUND)
1351                 {
1352                     error = OT_ERROR_NONE;
1353                 }
1354             }
1355             SuccessOrExit(error);
1356         }
1357     }
1358 
1359 exit:;
1360 }
1361 
processNetifInfoEvent(otInstance * aInstance,struct rt_msghdr * rtm)1362 static void processNetifInfoEvent(otInstance *aInstance, struct rt_msghdr *rtm)
1363 {
1364     struct if_msghdr *ifm   = reinterpret_cast<struct if_msghdr *>(rtm);
1365     otError           error = OT_ERROR_NONE;
1366 
1367     VerifyOrExit(ifm->ifm_index == static_cast<int>(gNetifIndex));
1368 
1369     UpdateLink(aInstance);
1370 
1371 exit:
1372     if (error != OT_ERROR_NONE)
1373     {
1374         otLogWarnPlat("[netif] Failed to process info event: %s", otThreadErrorToString(error));
1375     }
1376 }
1377 
1378 #endif
1379 
processNetlinkEvent(otInstance * aInstance)1380 static void processNetlinkEvent(otInstance *aInstance)
1381 {
1382     const size_t kMaxNetifEvent = 8192;
1383     ssize_t      length;
1384 
1385     union
1386     {
1387 #if defined(__linux__)
1388         nlmsghdr nlMsg;
1389 #else
1390         rt_msghdr rtMsg;
1391 #endif
1392         char buffer[kMaxNetifEvent];
1393     } msgBuffer;
1394 
1395     length = recv(sNetlinkFd, msgBuffer.buffer, sizeof(msgBuffer.buffer), 0);
1396 
1397     VerifyOrExit(length > 0);
1398 
1399 #if defined(__linux__)
1400     for (struct nlmsghdr *msg = &msgBuffer.nlMsg; NLMSG_OK(msg, static_cast<size_t>(length));
1401          msg                  = NLMSG_NEXT(msg, length))
1402     {
1403 #else
1404     {
1405         // BSD sends one message per read to routing socket (see route.c, monitor command)
1406         struct rt_msghdr *msg;
1407 
1408         msg = &msgBuffer.rtMsg;
1409 
1410 #define nlmsg_type rtm_type
1411 
1412 #endif
1413         switch (msg->nlmsg_type)
1414         {
1415         case RTM_NEWADDR:
1416         case RTM_DELADDR:
1417             processNetifAddrEvent(aInstance, msg);
1418             break;
1419 
1420 #if defined(RTM_NEWLINK) && defined(RTM_DELLINK)
1421         case RTM_NEWLINK:
1422         case RTM_DELLINK:
1423             processNetifLinkEvent(aInstance, msg);
1424             break;
1425 #endif
1426 
1427 #if defined(RTM_NEWMADDR) && defined(RTM_DELMADDR)
1428         case RTM_NEWMADDR:
1429         case RTM_DELMADDR:
1430             processNetifAddrEvent(aInstance, msg);
1431             break;
1432 #endif
1433 
1434 #if !defined(__linux__)
1435         case RTM_IFINFO:
1436             processNetifInfoEvent(aInstance, msg);
1437             break;
1438 
1439 #else
1440         case NLMSG_ERROR:
1441         {
1442             const struct nlmsgerr *err = reinterpret_cast<const nlmsgerr *>(NLMSG_DATA(msg));
1443 
1444             if (err->error == 0)
1445             {
1446                 otLogInfoPlat("[netif] Succeeded to process request#%u", err->msg.nlmsg_seq);
1447             }
1448             else
1449             {
1450                 otLogWarnPlat("[netif] Failed to process request#%u: %s", err->msg.nlmsg_seq, strerror(err->error));
1451             }
1452 
1453             break;
1454         }
1455 #endif
1456 
1457 #if defined(ROUTE_FILTER) || defined(RO_MSGFILTER) || defined(__linux__)
1458         default:
1459             otLogWarnPlat("[netif] Unhandled/Unexpected netlink/route message (%d).", (int)msg->nlmsg_type);
1460             break;
1461 #else
1462         // this platform doesn't support filtering, so we expect messages of other types...we just ignore them
1463 #endif
1464         }
1465     }
1466 
1467 exit:
1468     return;
1469 }
1470 
1471 #if OPENTHREAD_POSIX_USE_MLD_MONITOR
1472 static void mldListenerInit(void)
1473 {
1474     struct ipv6_mreq mreq6;
1475 
1476     sMLDMonitorFd          = SocketWithCloseExec(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, kSocketNonBlock);
1477     mreq6.ipv6mr_interface = gNetifIndex;
1478     memcpy(&mreq6.ipv6mr_multiaddr, kMLDv2MulticastAddress.mFields.m8, sizeof(kMLDv2MulticastAddress.mFields.m8));
1479 
1480     VerifyOrDie(setsockopt(sMLDMonitorFd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) == 0, OT_EXIT_FAILURE);
1481 #if defined(__linux__)
1482     VerifyOrDie(setsockopt(sMLDMonitorFd, SOL_SOCKET, SO_BINDTODEVICE, gNetifName,
1483                            static_cast<socklen_t>(strnlen(gNetifName, IFNAMSIZ))) == 0,
1484                 OT_EXIT_FAILURE);
1485 #endif
1486 }
1487 
1488 static void processMLDEvent(otInstance *aInstance)
1489 {
1490     const size_t        kMaxMLDEvent = 8192;
1491     uint8_t             buffer[kMaxMLDEvent];
1492     ssize_t             bufferLen = -1;
1493     struct sockaddr_in6 srcAddr;
1494     socklen_t           addrLen  = sizeof(srcAddr);
1495     bool                fromSelf = false;
1496     MLDv2Header *       hdr      = reinterpret_cast<MLDv2Header *>(buffer);
1497     size_t              offset;
1498     uint8_t             type;
1499     struct ifaddrs *    ifAddrs = nullptr;
1500     char                addressString[INET6_ADDRSTRLEN + 1];
1501 
1502     bufferLen = recvfrom(sMLDMonitorFd, buffer, sizeof(buffer), 0, reinterpret_cast<sockaddr *>(&srcAddr), &addrLen);
1503     VerifyOrExit(bufferLen > 0);
1504 
1505     type = buffer[0];
1506     VerifyOrExit(type == kICMPv6MLDv2Type && bufferLen >= static_cast<ssize_t>(sizeof(MLDv2Header)));
1507 
1508     // Check whether it is sent by self
1509     VerifyOrExit(getifaddrs(&ifAddrs) == 0);
1510     for (struct ifaddrs *ifAddr = ifAddrs; ifAddr != nullptr; ifAddr = ifAddr->ifa_next)
1511     {
1512         if (ifAddr->ifa_addr != nullptr && ifAddr->ifa_addr->sa_family == AF_INET6 &&
1513             strncmp(gNetifName, ifAddr->ifa_name, IFNAMSIZ) == 0)
1514         {
1515 #pragma GCC diagnostic push
1516 #pragma GCC diagnostic ignored "-Wcast-align"
1517             struct sockaddr_in6 *addr6 = reinterpret_cast<struct sockaddr_in6 *>(ifAddr->ifa_addr);
1518 #pragma GCC diagnostic pop
1519 
1520             if (memcmp(&addr6->sin6_addr, &srcAddr.sin6_addr, sizeof(in6_addr)) == 0)
1521             {
1522                 fromSelf = true;
1523                 break;
1524             }
1525         }
1526     }
1527     VerifyOrExit(fromSelf);
1528 
1529     hdr    = reinterpret_cast<MLDv2Header *>(buffer);
1530     offset = sizeof(MLDv2Header);
1531 
1532     for (size_t i = 0; i < ntohs(hdr->mNumRecords) && offset < static_cast<size_t>(bufferLen); i++)
1533     {
1534         if (static_cast<size_t>(bufferLen) >= (sizeof(MLDv2Record) + offset))
1535         {
1536             MLDv2Record *record = reinterpret_cast<MLDv2Record *>(&buffer[offset]);
1537 
1538             otError          err;
1539             ot::Ip6::Address address;
1540 
1541             memcpy(&address.mFields.m8, &record->mMulticastAddress, sizeof(address.mFields.m8));
1542             inet_ntop(AF_INET6, &record->mMulticastAddress, addressString, sizeof(addressString));
1543             if (record->mRecordType == kICMPv6MLDv2RecordChangeToIncludeType)
1544             {
1545                 err = otIp6SubscribeMulticastAddress(aInstance, &address);
1546                 logAddrEvent(/* isAdd */ true, address, err);
1547             }
1548             else if (record->mRecordType == kICMPv6MLDv2RecordChangeToExcludeType)
1549             {
1550                 err = otIp6UnsubscribeMulticastAddress(aInstance, &address);
1551                 logAddrEvent(/* isAdd */ false, address, err);
1552             }
1553 
1554             offset += sizeof(MLDv2Record) + sizeof(in6_addr) * ntohs(record->mNumSources);
1555         }
1556     }
1557 
1558 exit:
1559     if (ifAddrs)
1560     {
1561         freeifaddrs(ifAddrs);
1562     }
1563 }
1564 #endif
1565 
1566 #if defined(__linux__)
1567 // set up the tun device
1568 static void platformConfigureTunDevice(const char *aInterfaceName, char *deviceName, size_t deviceNameLen)
1569 {
1570     struct ifreq ifr;
1571 
1572     sTunFd = open(OPENTHREAD_POSIX_TUN_DEVICE, O_RDWR | O_CLOEXEC | O_NONBLOCK);
1573     VerifyOrDie(sTunFd >= 0, OT_EXIT_ERROR_ERRNO);
1574 
1575     memset(&ifr, 0, sizeof(ifr));
1576     ifr.ifr_flags = IFF_TUN | IFF_NO_PI | static_cast<short>(IFF_TUN_EXCL);
1577 
1578     if (aInterfaceName)
1579     {
1580         VerifyOrDie(strlen(aInterfaceName) < IFNAMSIZ, OT_EXIT_INVALID_ARGUMENTS);
1581 
1582         strncpy(ifr.ifr_name, aInterfaceName, IFNAMSIZ);
1583     }
1584     else
1585     {
1586         strncpy(ifr.ifr_name, "wpan%d", IFNAMSIZ);
1587     }
1588 
1589     VerifyOrDie(ioctl(sTunFd, TUNSETIFF, static_cast<void *>(&ifr)) == 0, OT_EXIT_ERROR_ERRNO);
1590     VerifyOrDie(ioctl(sTunFd, TUNSETLINK, ARPHRD_VOID) == 0, OT_EXIT_ERROR_ERRNO);
1591 
1592     strncpy(deviceName, ifr.ifr_name, deviceNameLen);
1593 
1594     ifr.ifr_mtu = static_cast<int>(kMaxIp6Size);
1595     VerifyOrDie(ioctl(sIpFd, SIOCSIFMTU, static_cast<void *>(&ifr)) == 0, OT_EXIT_ERROR_ERRNO);
1596 }
1597 #endif
1598 
1599 #if defined(__APPLE__) && (OPENTHREAD_POSIX_CONFIG_MACOS_TUN_OPTION == OT_POSIX_CONFIG_MACOS_UTUN)
1600 static void platformConfigureTunDevice(const char *aInterfaceName, char *deviceName, size_t deviceNameLen)
1601 {
1602     (void)aInterfaceName;
1603     int                 err = 0;
1604     struct sockaddr_ctl addr;
1605     struct ctl_info     info;
1606 
1607     sTunFd = SocketWithCloseExec(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL, kSocketNonBlock);
1608     VerifyOrDie(sTunFd >= 0, OT_EXIT_ERROR_ERRNO);
1609 
1610     memset(&info, 0, sizeof(info));
1611     strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME));
1612     err = ioctl(sTunFd, CTLIOCGINFO, &info);
1613     VerifyOrDie(err == 0, OT_EXIT_ERROR_ERRNO);
1614 
1615     addr.sc_id      = info.ctl_id;
1616     addr.sc_len     = sizeof(addr);
1617     addr.sc_family  = AF_SYSTEM;
1618     addr.ss_sysaddr = AF_SYS_CONTROL;
1619 
1620     addr.sc_unit = 0;
1621     err          = connect(sTunFd, (struct sockaddr *)&addr, sizeof(addr));
1622     VerifyOrDie(err == 0, OT_EXIT_ERROR_ERRNO);
1623 
1624     socklen_t devNameLen;
1625     devNameLen = (socklen_t)deviceNameLen;
1626     err        = getsockopt(sTunFd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, deviceName, &devNameLen);
1627     VerifyOrDie(err == 0, OT_EXIT_ERROR_ERRNO);
1628 
1629     otLogInfoPlat("[netif] Tunnel device name = '%s'", deviceName);
1630 }
1631 #endif
1632 
1633 #if defined(__NetBSD__) || defined(__FreeBSD__)
1634 static otError destroyTunnel(void)
1635 {
1636     otError      error;
1637     struct ifreq ifr;
1638 
1639     memset(&ifr, 0, sizeof(ifr));
1640     strncpy(ifr.ifr_name, gNetifName, sizeof(ifr.ifr_name));
1641     VerifyOrExit(ioctl(sIpFd, SIOCIFDESTROY, &ifr) == 0, perror("ioctl"); error = OT_ERROR_FAILED);
1642     error = OT_ERROR_NONE;
1643 
1644 exit:
1645     return error;
1646 }
1647 #endif
1648 
1649 #if defined(__NetBSD__) ||                                                                             \
1650     (defined(__APPLE__) && (OPENTHREAD_POSIX_CONFIG_MACOS_TUN_OPTION == OT_POSIX_CONFIG_MACOS_TUN)) || \
1651     defined(__FreeBSD__)
1652 static void platformConfigureTunDevice(const char *aInterfaceName, char *deviceName, size_t deviceNameLen)
1653 {
1654     int         flags = IFF_BROADCAST | IFF_MULTICAST;
1655     int         err;
1656     const char *last_slash;
1657     const char *path;
1658 
1659     (void)aInterfaceName;
1660 
1661     path = OPENTHREAD_POSIX_TUN_DEVICE;
1662 
1663     sTunFd = open(path, O_RDWR | O_NONBLOCK);
1664     VerifyOrDie(sTunFd >= 0, OT_EXIT_ERROR_ERRNO);
1665 
1666 #if defined(__NetBSD__) || defined(__FreeBSD__)
1667     err = ioctl(sTunFd, TUNSIFMODE, &flags);
1668     VerifyOrDie(err == 0, OT_EXIT_ERROR_ERRNO);
1669 #endif
1670 
1671     flags = 1;
1672     err   = ioctl(sTunFd, TUNSIFHEAD, &flags);
1673     VerifyOrDie(err == 0, OT_EXIT_ERROR_ERRNO);
1674 
1675     last_slash = strrchr(OPENTHREAD_POSIX_TUN_DEVICE, '/');
1676     VerifyOrDie(last_slash != nullptr, OT_EXIT_ERROR_ERRNO);
1677     last_slash++;
1678 
1679     strncpy(deviceName, last_slash, deviceNameLen);
1680 }
1681 #endif
1682 
1683 static void platformConfigureNetLink(void)
1684 {
1685 #if defined(__linux__)
1686     sNetlinkFd = SocketWithCloseExec(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, kSocketNonBlock);
1687 #elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
1688     sNetlinkFd = SocketWithCloseExec(PF_ROUTE, SOCK_RAW, 0, kSocketNonBlock);
1689 #else
1690 #error "!! Unknown platform !!"
1691 #endif
1692     VerifyOrDie(sNetlinkFd >= 0, OT_EXIT_ERROR_ERRNO);
1693 
1694 #if defined(__linux__)
1695     {
1696         struct sockaddr_nl sa;
1697 
1698         memset(&sa, 0, sizeof(sa));
1699         sa.nl_family = AF_NETLINK;
1700         sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR;
1701         VerifyOrDie(bind(sNetlinkFd, reinterpret_cast<struct sockaddr *>(&sa), sizeof(sa)) == 0, OT_EXIT_ERROR_ERRNO);
1702     }
1703 #endif
1704 
1705 #if defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
1706     {
1707         int status;
1708 #ifdef ROUTE_FILTER
1709         unsigned int msgfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_NEWADDR) | ROUTE_FILTER(RTM_DELADDR) |
1710                                  ROUTE_FILTER(RTM_NEWMADDR) | ROUTE_FILTER(RTM_DELMADDR);
1711 #define FILTER_CMD ROUTE_MSGFILTER
1712 #define FILTER_ARG msgfilter
1713 #define FILTER_ARG_SZ sizeof(msgfilter)
1714 #endif
1715 #ifdef RO_MSGFILTER
1716         uint8_t msgfilter[] = {RTM_IFINFO, RTM_NEWADDR, RTM_DELADDR};
1717 #define FILTER_CMD RO_MSGFILTER
1718 #define FILTER_ARG msgfilter
1719 #define FILTER_ARG_SZ sizeof(msgfilter)
1720 #endif
1721 #if defined(ROUTE_FILTER) || defined(RO_MSGFILTER)
1722         status = setsockopt(sNetlinkFd, AF_ROUTE, FILTER_CMD, FILTER_ARG, FILTER_ARG_SZ);
1723         VerifyOrDie(status == 0, OT_EXIT_ERROR_ERRNO);
1724 #endif
1725         status = fcntl(sNetlinkFd, F_SETFL, O_NONBLOCK);
1726         VerifyOrDie(status == 0, OT_EXIT_ERROR_ERRNO);
1727     }
1728 #endif // defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
1729 }
1730 
1731 void platformNetifInit(const char *aInterfaceName)
1732 {
1733     sIpFd = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketNonBlock);
1734     VerifyOrDie(sIpFd >= 0, OT_EXIT_ERROR_ERRNO);
1735 
1736     platformConfigureNetLink();
1737     platformConfigureTunDevice(aInterfaceName, gNetifName, sizeof(gNetifName));
1738 
1739     gNetifIndex = if_nametoindex(gNetifName);
1740     VerifyOrDie(gNetifIndex > 0, OT_EXIT_FAILURE);
1741 
1742 #if OPENTHREAD_POSIX_USE_MLD_MONITOR
1743     mldListenerInit();
1744 #endif
1745 }
1746 
1747 void platformNetifSetUp(void)
1748 {
1749     OT_ASSERT(gInstance != nullptr);
1750 
1751     otIp6SetReceiveFilterEnabled(gInstance, true);
1752 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1753     otIcmp6SetEchoMode(gInstance, OT_ICMP6_ECHO_HANDLER_ALL);
1754 #else
1755     otIcmp6SetEchoMode(gInstance, OT_ICMP6_ECHO_HANDLER_DISABLED);
1756 #endif
1757     otIp6SetReceiveCallback(gInstance, processReceive, gInstance);
1758     otIp6SetAddressCallback(gInstance, processAddressChange, gInstance);
1759 #if OPENTHREAD_POSIX_MULTICAST_PROMISCUOUS_REQUIRED
1760     otIp6SetMulticastPromiscuousEnabled(aInstance, true);
1761 #endif
1762 }
1763 
1764 void platformNetifTearDown(void)
1765 {
1766 }
1767 
1768 void platformNetifDeinit(void)
1769 {
1770     if (sTunFd != -1)
1771     {
1772         close(sTunFd);
1773         sTunFd = -1;
1774 
1775 #if defined(__NetBSD__) || defined(__FreeBSD__)
1776         destroyTunnel();
1777 #endif
1778     }
1779 
1780     if (sIpFd != -1)
1781     {
1782         close(sIpFd);
1783         sIpFd = -1;
1784     }
1785 
1786     if (sNetlinkFd != -1)
1787     {
1788         close(sNetlinkFd);
1789         sNetlinkFd = -1;
1790     }
1791 
1792 #if OPENTHREAD_POSIX_USE_MLD_MONITOR
1793     if (sMLDMonitorFd != -1)
1794     {
1795         close(sMLDMonitorFd);
1796         sMLDMonitorFd = -1;
1797     }
1798 #endif
1799 
1800     gNetifIndex = 0;
1801 }
1802 
1803 void platformNetifUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aErrorFdSet, int *aMaxFd)
1804 {
1805     OT_UNUSED_VARIABLE(aWriteFdSet);
1806 
1807     VerifyOrExit(gNetifIndex > 0);
1808 
1809     assert(sTunFd >= 0);
1810     assert(sNetlinkFd >= 0);
1811     assert(sIpFd >= 0);
1812 
1813     FD_SET(sTunFd, aReadFdSet);
1814     FD_SET(sTunFd, aErrorFdSet);
1815     FD_SET(sNetlinkFd, aReadFdSet);
1816     FD_SET(sNetlinkFd, aErrorFdSet);
1817 #if OPENTHREAD_POSIX_USE_MLD_MONITOR
1818     FD_SET(sMLDMonitorFd, aReadFdSet);
1819     FD_SET(sMLDMonitorFd, aErrorFdSet);
1820 #endif
1821 
1822     if (sTunFd > *aMaxFd)
1823     {
1824         *aMaxFd = sTunFd;
1825     }
1826 
1827     if (sNetlinkFd > *aMaxFd)
1828     {
1829         *aMaxFd = sNetlinkFd;
1830     }
1831 
1832 #if OPENTHREAD_POSIX_USE_MLD_MONITOR
1833     if (sMLDMonitorFd > *aMaxFd)
1834     {
1835         *aMaxFd = sMLDMonitorFd;
1836     }
1837 #endif
1838 exit:
1839     return;
1840 }
1841 
1842 void platformNetifProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, const fd_set *aErrorFdSet)
1843 {
1844     OT_UNUSED_VARIABLE(aWriteFdSet);
1845     VerifyOrExit(gNetifIndex > 0);
1846 
1847     if (FD_ISSET(sTunFd, aErrorFdSet))
1848     {
1849         close(sTunFd);
1850         DieNow(OT_EXIT_FAILURE);
1851     }
1852 
1853     if (FD_ISSET(sNetlinkFd, aErrorFdSet))
1854     {
1855         close(sNetlinkFd);
1856         DieNow(OT_EXIT_FAILURE);
1857     }
1858 
1859 #if OPENTHREAD_POSIX_USE_MLD_MONITOR
1860     if (FD_ISSET(sMLDMonitorFd, aErrorFdSet))
1861     {
1862         close(sMLDMonitorFd);
1863         DieNow(OT_EXIT_FAILURE);
1864     }
1865 #endif
1866 
1867     if (FD_ISSET(sTunFd, aReadFdSet))
1868     {
1869         processTransmit(gInstance);
1870     }
1871 
1872     if (FD_ISSET(sNetlinkFd, aReadFdSet))
1873     {
1874         processNetlinkEvent(gInstance);
1875     }
1876 
1877 #if OPENTHREAD_POSIX_USE_MLD_MONITOR
1878     if (FD_ISSET(sMLDMonitorFd, aReadFdSet))
1879     {
1880         processMLDEvent(gInstance);
1881     }
1882 #endif
1883 
1884 exit:
1885     return;
1886 }
1887 
1888 #endif // OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
1889