Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / inet / InetInterface.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2019 Google LLC.
5  *    Copyright (c) 2013-2017 Nest Labs, Inc.
6  *
7  *    Licensed under the Apache License, Version 2.0 (the "License");
8  *    you may not use this file except in compliance with the License.
9  *    You may obtain a copy of the License at
10  *
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *    Unless required by applicable law or agreed to in writing, software
14  *    distributed under the License is distributed on an "AS IS" BASIS,
15  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *    See the License for the specific language governing permissions and
17  *    limitations under the License.
18  */
19
20 /**
21  *    @file
22  *      Implementation of network interface abstraction layer.
23  *
24  */
25
26 #ifndef __STDC_LIMIT_MACROS
27 #define __STDC_LIMIT_MACROS
28 #endif
29
30 #include "InetInterface.h"
31
32 #include "InetLayer.h"
33 #include "InetLayerEvents.h"
34
35 #include <support/CHIPMemString.h>
36 #include <support/CodeUtils.h>
37 #include <support/DLLUtil.h>
38
39 #if CHIP_SYSTEM_CONFIG_USE_LWIP
40 #include <lwip/netif.h>
41 #include <lwip/sys.h>
42 #include <lwip/tcpip.h>
43 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
44
45 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <sys/socket.h>
49 #include <unistd.h>
50 #ifdef HAVE_SYS_SOCKIO_H
51 #include <sys/sockio.h>
52 #endif /* HAVE_SYS_SOCKIO_H */
53 #include <net/if.h>
54 #include <sys/ioctl.h>
55 #ifdef __ANDROID__
56 #include "ifaddrs-android.h"
57 #else // !defined(__ANDROID__)
58 #include <ifaddrs.h>
59 #endif // !defined(__ANDROID__)
60 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
61
62 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
63 #include <net/net_if.h>
64 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
65
66 #include <stdio.h>
67 #include <string.h>
68
69 namespace chip {
70 namespace Inet {
71
72 /**
73  * @brief   Get the name of a network interface
74  *
75  * @param[in]   intfId      a network interface
76  * @param[in]   nameBuf     region of memory to write the interface name
77  * @param[in]   nameBufSize size of the region denoted by \c nameBuf
78  *
79  * @retval  INET_NO_ERROR           successful result, interface name written
80  * @retval  INET_ERROR_NO_MEMORY    name is too large to be written in buffer
81  * @retval  other                   another system or platform error
82  *
83  * @details
84  *     Writes the name of the network interface as \c NUL terminated text string
85  *     at \c nameBuf. The name of the unspecified network interface is the empty
86  *     string.
87  */
88 DLL_EXPORT INET_ERROR GetInterfaceName(InterfaceId intfId, char * nameBuf, size_t nameBufSize)
89 {
90     if (intfId != INET_NULL_INTERFACEID)
91     {
92 #if CHIP_SYSTEM_CONFIG_USE_LWIP
93         int status = snprintf(nameBuf, nameBufSize, "%c%c%d", intfId->name[0], intfId->name[1], intfId->num);
94         if (status >= static_cast<int>(nameBufSize))
95             return INET_ERROR_NO_MEMORY;
96         return INET_NO_ERROR;
97 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
98
99 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
100         char intfName[IF_NAMESIZE];
101         if (if_indextoname(intfId, intfName) == nullptr)
102             return chip::System::MapErrorPOSIX(errno);
103         if (strlen(intfName) >= nameBufSize)
104             return INET_ERROR_NO_MEMORY;
105         strcpy(nameBuf, intfName);
106         return INET_NO_ERROR;
107 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
108
109 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
110         net_if * currentInterface = net_if_get_by_index(intfId);
111         if (!currentInterface)
112             return INET_ERROR_INCORRECT_STATE;
113         const char * name = net_if_get_device(currentInterface)->name;
114         if (strlen(name) >= nameBufSize)
115             return INET_ERROR_NO_MEMORY;
116         strcpy(nameBuf, name);
117         return INET_NO_ERROR;
118
119 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
120     }
121
122     if (nameBufSize < 1)
123         return INET_ERROR_NO_MEMORY;
124
125     nameBuf[0] = 0;
126     return INET_NO_ERROR;
127 }
128
129 /**
130  * @brief   Search the list of network interfaces for the indicated name.
131  *
132  * @param[in]   intfName    name of the network interface to find
133  * @param[out]  intfId      indicator of the network interface to assign
134  *
135  * @retval  INET_NO_ERROR                 success, network interface indicated
136  * @retval  INET_ERROR_UNKNOWN_INTERFACE  no network interface found
137  * @retval  other                   another system or platform error
138  *
139  * @details
140  *     On LwIP, this function must be called with the LwIP stack lock acquired.
141  *
142  *     The \c intfId parameter is not updated unless the value returned is
143  *     \c INET_NO_ERROR. It should be initialized with \c INET_NULL_INTERFACEID
144  *     before calling this function.
145  */
146 DLL_EXPORT INET_ERROR InterfaceNameToId(const char * intfName, InterfaceId & intfId)
147 {
148 #if CHIP_SYSTEM_CONFIG_USE_LWIP
149     if (strlen(intfName) < 3)
150         return INET_ERROR_UNKNOWN_INTERFACE;
151     char * parseEnd;
152     unsigned long intfNum = strtoul(intfName + 2, &parseEnd, 10);
153     if (*parseEnd != 0 || intfNum > UINT8_MAX)
154         return INET_ERROR_UNKNOWN_INTERFACE;
155     struct netif * intf;
156 #if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH)
157     NETIF_FOREACH(intf)
158 #else
159     for (intf = netif_list; intf != NULL; intf = intf->next)
160 #endif
161     {
162         if (intf->name[0] == intfName[0] && intf->name[1] == intfName[1] && intf->num == (uint8_t) intfNum)
163         {
164             intfId = intf;
165             return INET_NO_ERROR;
166         }
167     }
168     intfId = INET_NULL_INTERFACEID;
169     return INET_ERROR_UNKNOWN_INTERFACE;
170 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
171
172 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
173     intfId = if_nametoindex(intfName);
174     if (intfId == 0)
175         return (errno == ENXIO) ? INET_ERROR_UNKNOWN_INTERFACE : chip::System::MapErrorPOSIX(errno);
176     return INET_NO_ERROR;
177 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
178
179 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
180     int currentId = 0;
181     net_if * currentInterface;
182
183     while ((currentInterface = net_if_get_by_index(++currentId)) != nullptr)
184     {
185         if (strcmp(net_if_get_device(currentInterface)->name, intfName) == 0)
186         {
187             intfId = currentId;
188             return INET_NO_ERROR;
189         }
190     }
191     return INET_ERROR_UNKNOWN_INTERFACE;
192 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
193 } // namespace Inet
194
195 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
196
197 static int sIOCTLSocket = -1;
198
199 /**
200  * @brief   Returns a global general purpose socket useful for invoking certain network IOCTLs.
201  *
202  * This function is thread-safe on all platforms.
203  */
204 int GetIOCTLSocket()
205 {
206     if (sIOCTLSocket == -1)
207     {
208         int s;
209 #ifdef SOCK_CLOEXEC
210         s = socket(AF_INET, SOCK_STREAM, SOCK_CLOEXEC);
211         if (s < 0)
212 #endif
213         {
214             s = socket(AF_INET, SOCK_STREAM, 0);
215             fcntl(s, O_CLOEXEC);
216         }
217
218         if (!__sync_bool_compare_and_swap(&sIOCTLSocket, -1, s))
219         {
220             close(s);
221         }
222     }
223     return sIOCTLSocket;
224 }
225
226 /**
227  * @brief   Close the global socket created by \c GetIOCTLSocket.
228  *
229  * @details
230  *   This function is provided for cases were leaving the global IOCTL socket
231  *   open would register as a leak.
232  *
233  *   NB: This function is NOT thread-safe with respect to \c GetIOCTLSocket.
234  */
235 void CloseIOCTLSocket()
236 {
237     if (sIOCTLSocket == -1)
238     {
239         close(sIOCTLSocket);
240         sIOCTLSocket = -1;
241     }
242 }
243
244 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
245
246 /**
247  * @fn      InterfaceIterator::InterfaceIterator(void)
248  *
249  * @brief   Constructs an InterfaceIterator object.
250  *
251  * @details
252  *     Starts the iterator at the first network interface. On some platforms,
253  *     this constructor may allocate resources recycled by the destructor.
254  */
255
256 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
257
258 #if __ANDROID__ && __ANDROID_API__ < 24
259
260 static struct if_nameindex * backport_if_nameindex(void);
261 static void backport_if_freenameindex(struct if_nameindex *);
262
263 static void backport_if_freenameindex(struct if_nameindex * inArray)
264 {
265     if (inArray == NULL)
266     {
267         return;
268     }
269
270     for (size_t i = 0; inArray[i].if_index != 0; i++)
271     {
272         if (inArray[i].if_name != NULL)
273         {
274             free(inArray[i].if_name);
275         }
276     }
277
278     free(inArray);
279 }
280
281 static struct if_nameindex * backport_if_nameindex(void)
282 {
283     int err;
284     unsigned index;
285     size_t intfIter              = 0;
286     size_t maxIntfNum            = 0;
287     size_t numIntf               = 0;
288     size_t numAddrs              = 0;
289     struct if_nameindex * retval = NULL;
290     struct if_nameindex * tmpval = NULL;
291     struct ifaddrs * addrList    = NULL;
292     struct ifaddrs * addrIter    = NULL;
293     const char * lastIntfName    = "";
294
295     err = getifaddrs(&addrList);
296     VerifyOrExit(err >= 0, );
297
298     // coalesce on consecutive interface names
299     for (addrIter = addrList; addrIter != NULL; addrIter = addrIter->ifa_next)
300     {
301         numAddrs++;
302         if (strcmp(addrIter->ifa_name, lastIntfName) == 0)
303         {
304             continue;
305         }
306         numIntf++;
307         lastIntfName = addrIter->ifa_name;
308     }
309
310     tmpval = (struct if_nameindex *) malloc((numIntf + 1) * sizeof(struct if_nameindex));
311     VerifyOrExit(tmpval != NULL, );
312     memset(tmpval, 0, (numIntf + 1) * sizeof(struct if_nameindex));
313
314     lastIntfName = "";
315     for (addrIter = addrList; addrIter != NULL; addrIter = addrIter->ifa_next)
316     {
317         if (strcmp(addrIter->ifa_name, lastIntfName) == 0)
318         {
319             continue;
320         }
321
322         index = if_nametoindex(addrIter->ifa_name);
323         if (index != 0)
324         {
325             tmpval[intfIter].if_index = index;
326             tmpval[intfIter].if_name  = strdup(addrIter->ifa_name);
327             intfIter++;
328         }
329         lastIntfName = addrIter->ifa_name;
330     }
331
332     // coalesce on interface index
333     maxIntfNum = 0;
334     for (size_t i = 0; tmpval[i].if_index != 0; i++)
335     {
336         if (maxIntfNum < tmpval[i].if_index)
337         {
338             maxIntfNum = tmpval[i].if_index;
339         }
340     }
341
342     retval = (struct if_nameindex *) malloc((maxIntfNum + 1) * sizeof(struct if_nameindex));
343     VerifyOrExit(retval != NULL, );
344     memset(retval, 0, (maxIntfNum + 1) * sizeof(struct if_nameindex));
345
346     for (size_t i = 0; tmpval[i].if_index != 0; i++)
347     {
348         struct if_nameindex * intf = &tmpval[i];
349         if (retval[intf->if_index - 1].if_index == 0)
350         {
351             retval[intf->if_index - 1] = *intf;
352         }
353         else
354         {
355             free(intf->if_name);
356             intf->if_index = 0;
357             intf->if_name  = 0;
358         }
359     }
360
361     intfIter = 0;
362
363     // coalesce potential gaps between indeces
364     for (size_t i = 0; i < maxIntfNum; i++)
365     {
366         if (retval[i].if_index != 0)
367         {
368             retval[intfIter] = retval[i];
369             intfIter++;
370         }
371     }
372
373     for (size_t i = intfIter; i < maxIntfNum; i++)
374     {
375         retval[i].if_index = 0;
376         retval[i].if_name  = NULL;
377     }
378
379 exit:
380     if (tmpval != NULL)
381     {
382         free(tmpval);
383     }
384
385     if (addrList != NULL)
386     {
387         freeifaddrs(addrList);
388     }
389
390     return retval;
391 }
392
393 #endif // __ANDROID__ && __ANDROID_API__ < 24
394
395 InterfaceIterator::InterfaceIterator()
396 {
397     mIntfArray       = nullptr;
398     mCurIntf         = 0;
399     mIntfFlags       = 0;
400     mIntfFlagsCached = false;
401 }
402
403 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
404
405 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
406 InterfaceIterator::InterfaceIterator() : mCurrentInterface(net_if_get_by_index(mCurrentId)) {}
407 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
408
409 /**
410  * @fn      InterfaceIterator::~InterfaceIterator(void)
411  *
412  * @brief   Destroys an InterfaceIterator object.
413  *
414  * @details
415  *     Recycles any resources allocated by the constructor.
416  */
417
418 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
419
420 InterfaceIterator::~InterfaceIterator()
421 {
422     if (mIntfArray != nullptr)
423     {
424 #if __ANDROID__ && __ANDROID_API__ < 24
425         backport_if_freenameindex(mIntfArray);
426 #else
427         if_freenameindex(mIntfArray);
428 #endif
429         mIntfArray = nullptr;
430     }
431 }
432
433 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
434
435 /**
436  * @fn      bool InterfaceIterator::HasCurrent(void)
437  *
438  * @brief   Test whether the iterator is positioned on an interface
439  *
440  * @return  \c true if the iterator is positioned on an interface;
441  *          \c false if positioned beyond the end of the interface list.
442  */
443
444 #if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
445 bool InterfaceIterator::HasCurrent()
446 {
447     return (mIntfArray != nullptr) ? mIntfArray[mCurIntf].if_index != 0 : Next();
448 }
449 #endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
450
451 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
452 bool InterfaceIterator::HasCurrent(void)
453 {
454     return mCurrentInterface != nullptr;
455 }
456 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
457
458 /**
459  * @fn      bool InterfaceIterator::Next(void)
460  *
461  * @brief   Advance the iterator to the next network interface.
462  *
463  * @return  \c false if advanced beyond the end, else \c true.
464  *
465  * @details
466  *     Advances the internal iterator to the next network interface or to a position
467  *     beyond the end of the interface list.
468  *
469  *     On multi-threaded LwIP systems, this method is thread-safe relative to other
470  *     threads accessing the global LwIP state provided that: 1) the other threads
471  *     hold the LwIP core lock while mutating the list of netifs; and 2) netif objects
472  *     themselves are never destroyed.
473  *
474  *     Iteration is stable in the face of changes to the underlying system's
475  *     interfaces, *except* in the case of LwIP systems when the currently selected
476  *     interface is removed from the list, which causes iteration to end immediately.
477  */
478 bool InterfaceIterator::Next()
479 {
480 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
481
482     if (mIntfArray == nullptr)
483     {
484 #if __ANDROID__ && __ANDROID_API__ < 24
485         mIntfArray = backport_if_nameindex();
486 #else
487         mIntfArray = if_nameindex();
488 #endif
489     }
490     else if (mIntfArray[mCurIntf].if_index != 0)
491     {
492         mCurIntf++;
493         mIntfFlags       = 0;
494         mIntfFlagsCached = false;
495     }
496     return (mIntfArray != nullptr && mIntfArray[mCurIntf].if_index != 0);
497
498 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
499
500 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
501     mCurrentInterface = net_if_get_by_index(++mCurrentId);
502     return HasCurrent();
503 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
504
505 #if CHIP_SYSTEM_CONFIG_USE_LWIP
506
507     // Lock LwIP stack
508     LOCK_TCPIP_CORE();
509
510     // Verify the previous netif is still on the list if netifs.  If so,
511     // advance to the next nextif.
512     struct netif * prevNetif = mCurNetif;
513 #if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH)
514     NETIF_FOREACH(mCurNetif)
515 #else
516     for (mCurNetif = netif_list; mCurNetif != NULL; mCurNetif = mCurNetif->next)
517 #endif
518     {
519         if (mCurNetif == prevNetif)
520         {
521             mCurNetif = mCurNetif->next;
522             break;
523         }
524     }
525
526     // Unlock LwIP stack
527     UNLOCK_TCPIP_CORE();
528
529     return mCurNetif != NULL;
530
531 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
532 }
533
534 /**
535  * @fn      InterfaceId InterfaceIterator::GetInterfaceId(void)
536  *
537  * @brief   Returns the network interface id at the current iterator position.
538  *
539  * @retval  INET_NULL_INTERFACEID   if advanced beyond the end of the list.
540  * @retval  id                      the current network interface id.
541  */
542
543 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
544 InterfaceId InterfaceIterator::GetInterfaceId()
545 {
546     return (HasCurrent()) ? mIntfArray[mCurIntf].if_index : INET_NULL_INTERFACEID;
547 }
548 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
549
550 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
551 InterfaceId InterfaceIterator::GetInterfaceId(void)
552 {
553     return HasCurrent() ? mCurrentId : INET_NULL_INTERFACEID;
554 }
555 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
556
557 /**
558  * @brief   Get the name of the current network interface
559  *
560  * @param[in]   nameBuf     region of memory to write the interface name
561  * @param[in]   nameBufSize size of the region denoted by \c nameBuf
562  *
563  * @retval  INET_NO_ERROR           successful result, interface name written
564  * @retval  INET_ERROR_INCORRECT_STATE
565  *                                  iterator is positioned beyond the end of
566  *                                  the list
567  * @retval  INET_ERROR_NO_MEMORY    name is too large to be written in buffer
568  * @retval  other                   another system or platform error
569  *
570  * @details
571  *     Writes the name of the network interface as \c NUL terminated text string
572  *     at \c nameBuf.
573  */
574 INET_ERROR InterfaceIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
575 {
576     INET_ERROR err = INET_ERROR_NOT_IMPLEMENTED;
577
578     VerifyOrExit(HasCurrent(), err = INET_ERROR_INCORRECT_STATE);
579
580 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
581     VerifyOrExit(strlen(mIntfArray[mCurIntf].if_name) < nameBufSize, err = INET_ERROR_NO_MEMORY);
582     strncpy(nameBuf, mIntfArray[mCurIntf].if_name, nameBufSize);
583     err = INET_NO_ERROR;
584 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
585
586 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
587     err = ::chip::Inet::GetInterfaceName(mCurrentId, nameBuf, nameBufSize);
588 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
589
590 #if CHIP_SYSTEM_CONFIG_USE_LWIP
591     err = ::chip::Inet::GetInterfaceName(mCurNetif, nameBuf, nameBufSize);
592 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
593
594 exit:
595     return err;
596 }
597
598 /**
599  * @brief   Returns whether the current network interface is up.
600  *
601  * @return  \c true if current network interface is up, \c false if not
602  *          or if the iterator is positioned beyond the end of the list.
603  */
604 bool InterfaceIterator::IsUp()
605 {
606 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
607     return (GetFlags() & IFF_UP) != 0;
608 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
609
610 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
611     return HasCurrent() && net_if_is_up(mCurrentInterface);
612 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
613
614 #if CHIP_SYSTEM_CONFIG_USE_LWIP
615     return HasCurrent() && netif_is_up(mCurNetif);
616 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
617 }
618
619 /**
620  * @brief   Returns whether the current network interface supports multicast.
621  *
622  * @return  \c true if current network interface supports multicast, \c false
623  *          if not, or if the iterator is positioned beyond the end of the list.
624  */
625 bool InterfaceIterator::SupportsMulticast()
626 {
627 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
628     return (GetFlags() & IFF_MULTICAST) != 0;
629 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
630
631 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
632     return HasCurrent() && NET_IF_MAX_IPV6_MADDR > 0;
633 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
634
635 #if CHIP_SYSTEM_CONFIG_USE_LWIP
636     return HasCurrent() &&
637 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
638         (mCurNetif->flags & (NETIF_FLAG_IGMP | NETIF_FLAG_MLD6 | NETIF_FLAG_BROADCAST)) != 0;
639 #else
640         (mCurNetif->flags & NETIF_FLAG_POINTTOPOINT) == 0;
641 #endif // LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
642 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
643 }
644
645 /**
646  * @brief   Returns whether the current network interface has a broadcast address.
647  *
648  * @return  \c true if current network interface has a broadcast address, \c false
649  *          if not, or if the iterator is positioned beyond the end of the list.
650  */
651 bool InterfaceIterator::HasBroadcastAddress()
652 {
653 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
654     return (GetFlags() & IFF_BROADCAST) != 0;
655 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
656
657 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
658     // Zephyr seems to handle broadcast address for IPv4 implicitly
659     return HasCurrent() && INET_CONFIG_ENABLE_IPV4;
660 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
661
662 #if CHIP_SYSTEM_CONFIG_USE_LWIP
663     return HasCurrent() && (mCurNetif->flags & NETIF_FLAG_BROADCAST) != 0;
664 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
665 }
666
667 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
668
669 /**
670  * @fn      short InterfaceIterator::GetFlags(void)
671  *
672  * @brief   Returns the ifr_flags value for the current interface.
673  */
674 short InterfaceIterator::GetFlags()
675 {
676     struct ifreq intfData;
677
678     if (!mIntfFlagsCached && HasCurrent())
679     {
680         strncpy(intfData.ifr_name, mIntfArray[mCurIntf].if_name, IFNAMSIZ);
681         intfData.ifr_name[IFNAMSIZ - 1] = '\0';
682
683         int res = ioctl(GetIOCTLSocket(), SIOCGIFFLAGS, &intfData);
684         if (res == 0)
685         {
686             mIntfFlags       = intfData.ifr_flags;
687             mIntfFlagsCached = true;
688         }
689     }
690
691     return mIntfFlags;
692 }
693
694 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
695
696 #if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
697 /**
698  * @fn      InterfaceAddressIterator::InterfaceAddressIterator(void)
699  *
700  * @brief   Constructs an InterfaceAddressIterator object.
701  *
702  * @details
703  *     Starts the iterator at the first network address. On some platforms,
704  *     this constructor may allocate resources recycled by the destructor.
705  */
706 InterfaceAddressIterator::InterfaceAddressIterator()
707 {
708     mAddrsList = nullptr;
709     mCurAddr   = nullptr;
710 }
711 #endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
712
713 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
714 InterfaceAddressIterator::InterfaceAddressIterator() = default;
715 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
716
717 /**
718  * @fn      InterfaceAddressIterator::~InterfaceAddressIterator(void)
719  *
720  * @brief   Destroys an InterfaceAddressIterator object.
721  *
722  * @details
723  *  Recycles any resources allocated by the constructor.
724  */
725
726 #if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
727 InterfaceAddressIterator::~InterfaceAddressIterator()
728 {
729     if (mAddrsList != nullptr)
730     {
731         freeifaddrs(mAddrsList);
732         mAddrsList = mCurAddr = nullptr;
733     }
734 }
735 #endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
736
737 /**
738  * @fn      bool InterfaceIterator::HasCurrent(void)
739  *
740  * @brief   Test whether the iterator is positioned on an interface address
741  *
742  * @return  \c true if the iterator is positioned on an interface address;
743  *          \c false if positioned beyond the end of the address list.
744  */
745 bool InterfaceAddressIterator::HasCurrent()
746 {
747 #if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
748     return (mAddrsList != nullptr) ? (mCurAddr != nullptr) : Next();
749 #endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
750
751 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
752     return mIntfIter.HasCurrent() && (mCurAddrIndex >= 0 || Next());
753 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
754
755 #if CHIP_SYSTEM_CONFIG_USE_LWIP
756     return mIntfIter.HasCurrent() && ((mCurAddrIndex != kBeforeStartIndex) || Next());
757 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
758 }
759
760 /**
761  * @fn      bool InterfaceAddressIterator::Next(void)
762  *
763  * @brief   Advance the iterator to the next interface address.
764  *
765  * @return  \c false if advanced beyond the end, else \c true.
766  *
767  * @details
768  *     Advances the iterator to the next interface address or to a position
769  *     beyond the end of the address list.
770  *
771  *     On LwIP, this method is thread-safe provided that: 1) other threads hold
772  *     the LwIP core lock while mutating the netif list; and 2) netif objects
773  *     themselves are never destroyed.  Additionally, iteration on LwIP systems
774  *     will terminate early if the current interface is removed from the list.
775  */
776 bool InterfaceAddressIterator::Next()
777 {
778 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
779     while (true)
780     {
781         if (mAddrsList == nullptr)
782         {
783             int res = getifaddrs(&mAddrsList);
784             if (res < 0)
785             {
786                 return false;
787             }
788             mCurAddr = mAddrsList;
789         }
790         else if (mCurAddr != nullptr)
791         {
792             mCurAddr = mCurAddr->ifa_next;
793         }
794
795         if (mCurAddr == nullptr)
796         {
797             return false;
798         }
799
800         if (mCurAddr->ifa_addr != nullptr &&
801             (mCurAddr->ifa_addr->sa_family == AF_INET6
802 #if INET_CONFIG_ENABLE_IPV4
803              || mCurAddr->ifa_addr->sa_family == AF_INET
804 #endif // INET_CONFIG_ENABLE_IPV4
805              ))
806         {
807             return true;
808         }
809     }
810 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
811
812 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
813     while (mIntfIter.HasCurrent())
814     {
815         if (mCurAddrIndex == -1) // first address for the current interface
816         {
817             const net_if_config * config = net_if_get_config(net_if_get_by_index(mIntfIter.GetInterfaceId()));
818             mIpv6                        = config->ip.ipv6;
819         }
820
821         while (++mCurAddrIndex < NET_IF_MAX_IPV6_ADDR)
822             if (mIpv6->unicast[mCurAddrIndex].is_used)
823                 return true;
824
825         mCurAddrIndex = -1;
826         mIntfIter.Next();
827     }
828
829     return false;
830 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
831
832 #if CHIP_SYSTEM_CONFIG_USE_LWIP
833     mCurAddrIndex++;
834
835     while (mIntfIter.HasCurrent())
836     {
837         struct netif * curIntf = mIntfIter.GetInterfaceId();
838
839         while (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES)
840         {
841             if (ip6_addr_isvalid(netif_ip6_addr_state(curIntf, mCurAddrIndex)))
842             {
843                 return true;
844             }
845             mCurAddrIndex++;
846         }
847
848 #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
849         if (mCurAddrIndex == LWIP_IPV6_NUM_ADDRESSES)
850         {
851             if (!ip4_addr_isany(netif_ip4_addr(curIntf)))
852             {
853                 return true;
854             }
855         }
856 #endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
857
858         mIntfIter.Next();
859         mCurAddrIndex = 0;
860     }
861
862     return false;
863 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
864 }
865
866 /**
867  * @fn      IPAddress InterfaceAddressIterator::GetAddress(void)
868  *
869  * @brief   Get the current interface address.
870  *
871  * @return  the current interface address or \c IPAddress::Any if the iterator
872  *          is positioned beyond the end of the address list.
873  */
874 IPAddress InterfaceAddressIterator::GetAddress()
875 {
876     if (HasCurrent())
877     {
878 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
879         return IPAddress::FromSockAddr(*mCurAddr->ifa_addr);
880 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
881
882 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
883         return IPAddress::FromIPv6(mIpv6->unicast[mCurAddrIndex].address.in6_addr);
884 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
885
886 #if CHIP_SYSTEM_CONFIG_USE_LWIP
887         struct netif * curIntf = mIntfIter.GetInterfaceId();
888
889         if (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES)
890         {
891             return IPAddress::FromIPv6(*netif_ip6_addr(curIntf, mCurAddrIndex));
892         }
893 #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
894         else
895         {
896             return IPAddress::FromIPv4(*netif_ip4_addr(curIntf));
897         }
898 #endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
899 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
900     }
901
902     return IPAddress::Any;
903 }
904
905 /**
906  * @fn      uint8_t InterfaceAddressIterator::GetPrefixLength(void)
907  *
908  * @brief   Gets the network prefix associated with the current interface address.
909  *
910  * @return  the network prefix (in bits) or 0 if the iterator is positioned beyond
911  *          the end of the address list.
912  *
913  * @details
914  *     On LwIP, this method simply returns the hard-coded constant 64.
915  *
916  *     Note Well: the standard subnet prefix on all links other than PPP
917  *     links is 64 bits. On PPP links and some non-broadcast multipoint access
918  *     links, the convention is either 127 bits or 128 bits, but it might be
919  *     something else. On most platforms, the system's interface address
920  *     structure can represent arbitrary prefix lengths between 0 and 128.
921  */
922 uint8_t InterfaceAddressIterator::GetPrefixLength()
923 {
924     if (HasCurrent())
925     {
926 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
927         if (mCurAddr->ifa_addr->sa_family == AF_INET6)
928         {
929             struct sockaddr_in6 & netmask = *reinterpret_cast<struct sockaddr_in6 *>(mCurAddr->ifa_netmask);
930             return NetmaskToPrefixLength(netmask.sin6_addr.s6_addr, 16);
931         }
932         if (mCurAddr->ifa_addr->sa_family == AF_INET)
933         {
934             struct sockaddr_in & netmask = *reinterpret_cast<struct sockaddr_in *>(mCurAddr->ifa_netmask);
935             return NetmaskToPrefixLength(reinterpret_cast<const uint8_t *>(&netmask.sin_addr.s_addr), 4);
936         }
937 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
938
939 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
940         net_if * const iface              = net_if_get_by_index(mIntfIter.GetInterfaceId());
941         net_if_ipv6_prefix * const prefix = net_if_ipv6_prefix_get(iface, &mIpv6->unicast[mCurAddrIndex].address.in6_addr);
942         return prefix ? prefix->len : 128;
943 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
944
945 #if CHIP_SYSTEM_CONFIG_USE_LWIP
946         if (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES)
947         {
948             return 64;
949         }
950 #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
951         else
952         {
953             struct netif * curIntf = mIntfIter.GetInterfaceId();
954             return NetmaskToPrefixLength((const uint8_t *) netif_ip4_netmask(curIntf), 4);
955         }
956 #endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
957 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
958     }
959     return 0;
960 }
961
962 /**
963  * @fn      InterfaceId InterfaceAddressIterator::GetInterfaceId(void)
964  *
965  * @brief   Returns the network interface id associated with the current
966  *          interface address.
967  *
968  * @return  the interface id or \c INET_NULL_INTERFACEID if the iterator
969  *          is positioned beyond the end of the address list.
970  */
971 InterfaceId InterfaceAddressIterator::GetInterfaceId()
972 {
973     if (HasCurrent())
974     {
975 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
976         return if_nametoindex(mCurAddr->ifa_name);
977 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
978
979 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
980         return mIntfIter.GetInterfaceId();
981 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
982     }
983     return INET_NULL_INTERFACEID;
984 }
985
986 /**
987  * @fn      INET_ERROR InterfaceAddressIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
988  *
989  * @brief   Get the name of the network interface associated with the
990  *          current interface address.
991  *
992  * @param[in]   nameBuf     region of memory to write the interface name
993  * @param[in]   nameBufSize size of the region denoted by \c nameBuf
994  *
995  * @retval  INET_NO_ERROR           successful result, interface name written
996  * @retval  INET_ERROR_NO_MEMORY    name is too large to be written in buffer
997  * @retval  INET_ERROR_INCORRECT_STATE
998  *                                  the iterator is not currently positioned on an
999  *                                  interface address
1000  * @retval  other                   another system or platform error
1001  *
1002  * @details
1003  *     Writes the name of the network interface as \c NUL terminated text string
1004  *     at \c nameBuf.
1005  */
1006 INET_ERROR InterfaceAddressIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
1007 {
1008     INET_ERROR err = INET_ERROR_NOT_IMPLEMENTED;
1009
1010     VerifyOrExit(HasCurrent(), err = INET_ERROR_INCORRECT_STATE);
1011
1012 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1013     VerifyOrExit(strlen(mCurAddr->ifa_name) < nameBufSize, err = INET_ERROR_NO_MEMORY);
1014     strncpy(nameBuf, mCurAddr->ifa_name, nameBufSize);
1015     err = INET_NO_ERROR;
1016 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1017
1018 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1019     err = mIntfIter.GetInterfaceName(nameBuf, nameBufSize);
1020 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1021
1022 exit:
1023     return err;
1024 }
1025
1026 /**
1027  * @fn      bool InterfaceAddressIterator::IsUp(void)
1028  *
1029  * @brief   Returns whether the network interface associated with the current
1030  *          interface address is up.
1031  *
1032  * @return  \c true if current network interface is up, \c false if not, or
1033  *          if the iterator is not positioned on an interface address.
1034  */
1035 bool InterfaceAddressIterator::IsUp()
1036 {
1037     if (HasCurrent())
1038     {
1039 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1040         return (mCurAddr->ifa_flags & IFF_UP) != 0;
1041 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1042
1043 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1044         return mIntfIter.IsUp();
1045 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1046     }
1047     return false;
1048 }
1049
1050 /**
1051  * @fn      bool InterfaceAddressIterator::SupportsMulticast(void)
1052  *
1053  * @brief   Returns whether the network interface associated with the current
1054  *          interface address supports multicast.
1055  *
1056  * @return  \c true if multicast is supported, \c false if not, or
1057  *          if the iterator is not positioned on an interface address.
1058  */
1059 bool InterfaceAddressIterator::SupportsMulticast()
1060 {
1061     if (HasCurrent())
1062     {
1063 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1064         return (mCurAddr->ifa_flags & IFF_MULTICAST) != 0;
1065 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1066
1067 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1068         return mIntfIter.SupportsMulticast();
1069 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1070     }
1071     return false;
1072 }
1073
1074 /**
1075  * @fn      bool InterfaceAddressIterator::HasBroadcastAddress(void)
1076  *
1077  * @brief   Returns whether the network interface associated with the current
1078  *          interface address has an IPv4 broadcast address.
1079  *
1080  * @return  \c true if the interface has a broadcast address, \c false if not, or
1081  *          if the iterator is not positioned on an interface address.
1082  */
1083 bool InterfaceAddressIterator::HasBroadcastAddress()
1084 {
1085     if (HasCurrent())
1086     {
1087 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1088         return (mCurAddr->ifa_flags & IFF_BROADCAST) != 0;
1089 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1090
1091 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1092         return mIntfIter.HasBroadcastAddress();
1093 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1094     }
1095     return false;
1096 }
1097
1098 /**
1099  * @fn       void InterfaceAddressIterator::GetAddressWithPrefix(IPPrefix & addrWithPrefix)
1100  *
1101  * @brief    Returns an IPPrefix containing the address and prefix length
1102  *           for the current address.
1103  */
1104 void InterfaceAddressIterator::GetAddressWithPrefix(IPPrefix & addrWithPrefix)
1105 {
1106     if (HasCurrent())
1107     {
1108         addrWithPrefix.IPAddr = GetAddress();
1109         addrWithPrefix.Length = GetPrefixLength();
1110     }
1111     else
1112     {
1113         addrWithPrefix = IPPrefix::Zero;
1114     }
1115 }
1116
1117 /**
1118  * @fn       uint8_t NetmaskToPrefixLength(const uint8_t * netmask, uint16_t netmaskLen)
1119  *
1120  * @brief    Compute a prefix length from a variable-length netmask.
1121  */
1122 uint8_t NetmaskToPrefixLength(const uint8_t * netmask, uint16_t netmaskLen)
1123 {
1124     uint8_t prefixLen = 0;
1125
1126     for (uint16_t i = 0; i < netmaskLen; i++, prefixLen = static_cast<uint8_t>(prefixLen + 8u))
1127     {
1128         uint8_t b = netmask[i];
1129         if (b != 0xFF)
1130         {
1131             if ((b & 0xF0) == 0xF0)
1132                 prefixLen = static_cast<uint8_t>(prefixLen + 4u);
1133             else
1134                 b = static_cast<uint8_t>(b >> 4);
1135
1136             if ((b & 0x0C) == 0x0C)
1137                 prefixLen = static_cast<uint8_t>(prefixLen + 2u);
1138             else
1139                 b = static_cast<uint8_t>(b >> 2);
1140
1141             if ((b & 0x02) == 0x02)
1142                 prefixLen++;
1143
1144             break;
1145         }
1146     }
1147
1148     return prefixLen;
1149 }
1150
1151 } // namespace Inet
1152 } // namespace chip