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