Coverage Report

Created: 2026-04-09 06:31

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