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