Coverage Report

Created: 2025-12-24 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openweave-core/src/inet/IPEndPointBasis.cpp
Line
Count
Source
1
/*
2
 *
3
 *    Copyright (c) 2018 Google LLC.
4
 *    All rights reserved.
5
 *
6
 *    Licensed under the Apache License, Version 2.0 (the "License");
7
 *    you may not use this file except in compliance with the License.
8
 *    You may obtain a copy of the License at
9
 *
10
 *        http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 *    Unless required by applicable law or agreed to in writing, software
13
 *    distributed under the License is distributed on an "AS IS" BASIS,
14
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 *    See the License for the specific language governing permissions and
16
 *    limitations under the License.
17
 */
18
19
/**
20
 *    @file
21
 *      This header file implements the <tt>nl::Inet::IPEndPointBasis</tt>
22
 *      class, an intermediate, non-instantiable basis class
23
 *      supporting other IP-based end points.
24
 *
25
 */
26
27
// define to ensure we have the IPV6_PKTINFO
28
#define __APPLE_USE_RFC_3542
29
30
#include <InetLayer/IPEndPointBasis.h>
31
32
#include <string.h>
33
34
#include <InetLayer/EndPointBasis.h>
35
#include <InetLayer/InetInterface.h>
36
#include <InetLayer/InetLayer.h>
37
38
#include <Weave/Support/CodeUtils.h>
39
40
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
41
#if INET_CONFIG_ENABLE_IPV4
42
#include <lwip/igmp.h>
43
#endif // INET_CONFIG_ENABLE_IPV4
44
#include <lwip/init.h>
45
#include <lwip/ip.h>
46
#include <lwip/mld6.h>
47
#include <lwip/netif.h>
48
#include <lwip/raw.h>
49
#include <lwip/udp.h>
50
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
51
52
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
53
#include <sys/socket.h>
54
#include <errno.h>
55
#include <unistd.h>
56
#include <netinet/in.h>
57
#include <net/if.h>
58
#include <sys/ioctl.h>
59
#if HAVE_SYS_SOCKET_H
60
#include <sys/socket.h>
61
#endif // HAVE_SYS_SOCKET_H
62
63
/*
64
 * Some systems define both IPV6_{ADD,DROP}_MEMBERSHIP and
65
 * IPV6_{JOIN,LEAVE}_GROUP while others only define
66
 * IPV6_{JOIN,LEAVE}_GROUP. Prefer the "_MEMBERSHIP" flavor for
67
 * parallelism with IPv4 and create the alias to the availabile
68
 * definitions.
69
 */
70
#if !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP)
71
#define INET_IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
72
#elif defined(IPV6_ADD_MEMBERSHIP)
73
0
#define INET_IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
74
#else
75
#error "Neither IPV6_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP are defined which are required for generalized IPv6 multicast group support."
76
#endif // !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP)
77
78
#if !defined(IPV6_DROP_MEMBERSHIP) && defined(IPV6_LEAVE_GROUP)
79
#define INET_IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
80
#elif defined(IPV6_DROP_MEMBERSHIP)
81
0
#define INET_IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
82
#else
83
#error "Neither IPV6_DROP_MEMBERSHIP nor IPV6_LEAVE_GROUP are defined which are required for generalized IPv6 multicast group support."
84
#endif // !defined(IPV6_DROP_MEMBERSHIP) && defined(IPV6_LEAVE_GROUP)
85
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
86
87
namespace nl {
88
namespace Inet {
89
90
using Weave::System::PacketBuffer;
91
92
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
93
union PeerSockAddr
94
{
95
    sockaddr     any;
96
    sockaddr_in  in;
97
    sockaddr_in6 in6;
98
};
99
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
100
101
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
102
#if INET_CONFIG_ENABLE_IPV4
103
#define LWIP_IPV4_ADDR_T           ip4_addr_t
104
#define IPV4_TO_LWIPADDR(aAddress) (aAddress).ToIPv4()
105
#endif // INET_CONFIG_ENABLE_IPV4
106
#define LWIP_IPV6_ADDR_T           ip6_addr_t
107
#define IPV6_TO_LWIPADDR(aAddress) (aAddress).ToIPv6()
108
109
#if !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) || !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags)
110
#define HAVE_LWIP_MULTICAST_LOOP 0
111
#else
112
#define HAVE_LWIP_MULTICAST_LOOP 1
113
#endif // !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) || !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags)
114
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
115
116
static INET_ERROR CheckMulticastGroupArgs(InterfaceId aInterfaceId, const IPAddress &aAddress)
117
0
{
118
0
    INET_ERROR          lRetval = INET_NO_ERROR;
119
0
    bool                lIsPresent, lIsMulticast;
120
121
0
    lIsPresent = IsInterfaceIdPresent(aInterfaceId);
122
0
    VerifyOrExit(lIsPresent, lRetval = INET_ERROR_UNKNOWN_INTERFACE);
123
124
0
    lIsMulticast = aAddress.IsMulticast();
125
0
    VerifyOrExit(lIsMulticast, lRetval = INET_ERROR_WRONG_ADDRESS_TYPE);
126
127
0
exit:
128
0
    return (lRetval);
129
0
}
130
131
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
132
#if INET_CONFIG_ENABLE_IPV4
133
#if LWIP_IPV4 && LWIP_IGMP
134
static INET_ERROR LwIPIPv4JoinLeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress &aAddress, err_t (*aMethod)(struct netif *, const LWIP_IPV4_ADDR_T *))
135
{
136
    INET_ERROR        lRetval = INET_NO_ERROR;
137
    err_t             lStatus;
138
    struct netif *    lNetif;
139
    LWIP_IPV4_ADDR_T  lIPv4Address;
140
141
    lNetif = IPEndPointBasis::FindNetifFromInterfaceId(aInterfaceId);
142
    VerifyOrExit(lNetif != NULL, lRetval = INET_ERROR_UNKNOWN_INTERFACE);
143
144
    lIPv4Address = IPV4_TO_LWIPADDR(aAddress);
145
146
    lStatus = aMethod(lNetif, &lIPv4Address);
147
148
    switch (lStatus)
149
    {
150
151
    case ERR_MEM:
152
        lRetval = INET_ERROR_NO_MEMORY;
153
        break;
154
155
    default:
156
        lRetval = Weave::System::MapErrorLwIP(lStatus);
157
        break;
158
159
    }
160
161
exit:
162
    return (lRetval);
163
}
164
#endif // LWIP_IPV4 && LWIP_IGMP
165
#endif // INET_CONFIG_ENABLE_IPV4
166
167
#if LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
168
static INET_ERROR LwIPIPv6JoinLeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress &aAddress, err_t (*aMethod)(struct netif *, const LWIP_IPV6_ADDR_T *))
169
{
170
    INET_ERROR        lRetval = INET_NO_ERROR;
171
    err_t             lStatus;
172
    struct netif *    lNetif;
173
    LWIP_IPV6_ADDR_T  lIPv6Address;
174
175
    lNetif = IPEndPointBasis::FindNetifFromInterfaceId(aInterfaceId);
176
    VerifyOrExit(lNetif != NULL, lRetval = INET_ERROR_UNKNOWN_INTERFACE);
177
178
    lIPv6Address = IPV6_TO_LWIPADDR(aAddress);
179
180
    lStatus = aMethod(lNetif, &lIPv6Address);
181
182
    switch (lStatus)
183
    {
184
185
    case ERR_MEM:
186
        lRetval = INET_ERROR_NO_MEMORY;
187
        break;
188
189
    default:
190
        lRetval = Weave::System::MapErrorLwIP(lStatus);
191
        break;
192
193
    }
194
195
exit:
196
    return (lRetval);
197
}
198
#endif // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
199
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
200
201
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
202
static INET_ERROR SocketsSetMulticastLoopback(int aSocket, bool aLoopback, int aProtocol, int aOption)
203
0
{
204
0
    INET_ERROR    lRetval = INET_NO_ERROR;
205
0
    int           lStatus;
206
0
    unsigned int  lValue = aLoopback;
207
208
0
    lStatus = setsockopt(aSocket, aProtocol, aOption, &lValue, sizeof (lValue));
209
0
    VerifyOrExit(lStatus == 0, lRetval = Weave::System::MapErrorPOSIX(errno));
210
211
0
exit:
212
0
    return (lRetval);
213
0
}
214
215
static INET_ERROR SocketsSetMulticastLoopback(int aSocket, IPVersion aIPVersion, bool aLoopback)
216
0
{
217
0
    INET_ERROR  lRetval;
218
219
0
    switch (aIPVersion)
220
0
    {
221
222
0
    case kIPVersion_6:
223
0
        lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
224
0
        break;
225
226
0
#if INET_CONFIG_ENABLE_IPV4
227
0
    case kIPVersion_4:
228
0
        lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IP, IP_MULTICAST_LOOP);
229
0
        break;
230
0
#endif // INET_CONFIG_ENABLE_IPV4
231
232
0
    default:
233
0
        lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
234
0
        break;
235
236
0
    }
237
238
0
    return (lRetval);
239
0
}
240
241
#if INET_CONFIG_ENABLE_IPV4
242
static INET_ERROR SocketsIPv4JoinLeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress &aAddress, int aCommand)
243
0
{
244
0
    INET_ERROR       lRetval = INET_NO_ERROR;
245
0
    IPAddress        lInterfaceAddress;
246
0
    bool             lInterfaceAddressFound = false;
247
0
    struct ip_mreq   lMulticastRequest;
248
249
0
    for (InterfaceAddressIterator lAddressIterator; lAddressIterator.HasCurrent(); lAddressIterator.Next())
250
0
    {
251
0
        const IPAddress lCurrentAddress = lAddressIterator.GetAddress();
252
253
0
        if (lAddressIterator.GetInterface() == aInterfaceId)
254
0
        {
255
0
            if (lCurrentAddress.IsIPv4())
256
0
            {
257
0
                lInterfaceAddressFound = true;
258
0
                lInterfaceAddress = lCurrentAddress;
259
0
                break;
260
0
            }
261
0
        }
262
0
    }
263
264
0
    VerifyOrExit(lInterfaceAddressFound, lRetval = INET_ERROR_ADDRESS_NOT_FOUND);
265
266
0
    memset(&lMulticastRequest, 0, sizeof (lMulticastRequest));
267
0
    lMulticastRequest.imr_interface = lInterfaceAddress.ToIPv4();
268
0
    lMulticastRequest.imr_multiaddr = aAddress.ToIPv4();
269
270
0
    lRetval = setsockopt(aSocket, IPPROTO_IP, aCommand, &lMulticastRequest, sizeof (lMulticastRequest));
271
0
    VerifyOrExit(lRetval == 0, lRetval = Weave::System::MapErrorPOSIX(errno));
272
273
0
exit:
274
0
    return (lRetval);
275
0
}
276
#endif // INET_CONFIG_ENABLE_IPV4
277
278
static INET_ERROR SocketsIPv6JoinLeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress &aAddress, int aCommand)
279
0
{
280
0
    INET_ERROR       lRetval = INET_NO_ERROR;
281
0
    const int        lIfIndex = static_cast<int>(aInterfaceId);
282
0
    struct ipv6_mreq lMulticastRequest;
283
284
0
    memset(&lMulticastRequest, 0, sizeof (lMulticastRequest));
285
0
    lMulticastRequest.ipv6mr_interface = lIfIndex;
286
0
    lMulticastRequest.ipv6mr_multiaddr = aAddress.ToIPv6();
287
288
0
    lRetval = setsockopt(aSocket, IPPROTO_IPV6, aCommand, &lMulticastRequest, sizeof (lMulticastRequest));
289
0
    VerifyOrExit(lRetval == 0, lRetval = Weave::System::MapErrorPOSIX(errno));
290
291
0
exit:
292
0
    return (lRetval);
293
0
}
294
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
295
296
/**
297
 *  @brief Set whether IP multicast traffic should be looped back.
298
 *
299
 *  @param[in]   aIPVersion
300
 *
301
 *  @param[in]   aLoop
302
 *
303
 *  @retval  INET_NO_ERROR
304
 *       success: multicast loopback behavior set
305
 *  @retval  other
306
 *       another system or platform error
307
 *
308
 *  @details
309
 *     Set whether or not IP multicast traffic should be looped back
310
 *     to this endpoint.
311
 *
312
 */
313
INET_ERROR IPEndPointBasis::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback)
314
0
{
315
0
    INET_ERROR          lRetval = INET_ERROR_NOT_IMPLEMENTED;
316
317
0
#if WEAVE_SYSTEM_CONFIG_USE_LWIP || WEAVE_SYSTEM_CONFIG_USE_SOCKETS
318
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
319
#if !HAVE_LWIP_MULTICAST_LOOP
320
#pragma message "\n \
321
The version of LwIP appears older than that required for multicast loopback support.\n \
322
Please upgrade your version of LwIP for SetMulticastLoopback support."
323
    lRetval = INET_ERROR_NOT_SUPPORTED;
324
#else
325
    if (aLoopback)
326
    {
327
        switch (mLwIPEndPointType)
328
        {
329
330
#if INET_CONFIG_ENABLE_RAW_ENDPOINT
331
        case kLwIPEndPointType_Raw:
332
            raw_set_flags(mRaw, RAW_FLAGS_MULTICAST_LOOP);
333
            break;
334
#endif // INET_CONFIG_ENABLE_RAW_ENDPOINT
335
336
#if INET_CONFIG_ENABLE_UDP_ENDPOINT
337
        case kLwIPEndPointType_UDP:
338
            udp_set_flags(mUDP, UDP_FLAGS_MULTICAST_LOOP);
339
            break;
340
#endif // INET_CONFIG_ENABLE_UDP_ENDPOINT
341
342
        default:
343
            lRetval = INET_ERROR_NOT_SUPPORTED;
344
            break;
345
346
        }
347
    }
348
    else
349
    {
350
        switch (mLwIPEndPointType)
351
        {
352
353
#if INET_CONFIG_ENABLE_RAW_ENDPOINT
354
        case kLwIPEndPointType_Raw:
355
            raw_clear_flags(mRaw, RAW_FLAGS_MULTICAST_LOOP);
356
            break;
357
#endif // INET_CONFIG_ENABLE_RAW_ENDPOINT
358
359
#if INET_CONFIG_ENABLE_UDP_ENDPOINT
360
        case kLwIPEndPointType_UDP:
361
            udp_clear_flags(mUDP, UDP_FLAGS_MULTICAST_LOOP);
362
            break;
363
#endif // INET_CONFIG_ENABLE_UDP_ENDPOINT
364
365
        default:
366
            lRetval = INET_ERROR_NOT_SUPPORTED;
367
            break;
368
369
        }
370
    }
371
372
    lRetval = INET_NO_ERROR;
373
#endif // !HAVE_LWIP_MULTICAST_LOOP
374
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
375
376
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
377
0
    lRetval = SocketsSetMulticastLoopback(mSocket, aIPVersion, aLoopback);
378
0
    SuccessOrExit(lRetval);
379
380
0
exit:
381
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
382
0
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP || WEAVE_SYSTEM_CONFIG_USE_SOCKETS
383
0
    return (lRetval);
384
0
}
385
386
/**
387
 *  @brief Join an IP multicast group.
388
 *
389
 *  @param[in]   aInterfaceId  the indicator of the network interface to
390
 *                             add to the multicast group
391
 *
392
 *  @param[in]   aAddress      the multicast group to add the
393
 *                             interface to
394
 *
395
 *  @retval  INET_NO_ERROR
396
 *       success: multicast group removed
397
 *
398
 *  @retval  INET_ERROR_UNKNOWN_INTERFACE
399
 *       unknown network interface, \c aInterfaceId
400
 *
401
 *  @retval  INET_ERROR_WRONG_ADDRESS_TYPE
402
 *       \c aAddress is not \c kIPAddressType_IPv4 or
403
 *       \c kIPAddressType_IPv6 or is not multicast
404
 *
405
 *  @retval  other
406
 *       another system or platform error
407
 *
408
 *  @details
409
 *     Join the endpoint to the supplied multicast group on the
410
 *     specified interface.
411
 *
412
 */
413
INET_ERROR IPEndPointBasis::JoinMulticastGroup(InterfaceId aInterfaceId, const IPAddress &aAddress)
414
0
{
415
0
    const IPAddressType lAddrType = aAddress.Type();
416
0
    INET_ERROR          lRetval = INET_ERROR_NOT_IMPLEMENTED;
417
418
0
#if WEAVE_SYSTEM_CONFIG_USE_LWIP || WEAVE_SYSTEM_CONFIG_USE_SOCKETS
419
0
    lRetval = CheckMulticastGroupArgs(aInterfaceId, aAddress);
420
0
    SuccessOrExit(lRetval);
421
422
0
    switch (lAddrType)
423
0
    {
424
425
0
#if INET_CONFIG_ENABLE_IPV4
426
0
    case kIPAddressType_IPv4:
427
0
        {
428
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
429
#if LWIP_IPV4 && LWIP_IGMP
430
            lRetval = LwIPIPv4JoinLeaveMulticastGroup(aInterfaceId, aAddress, igmp_joingroup_netif);
431
#else // LWIP_IPV4 && LWIP_IGMP
432
#pragma message "\n \
433
Please enable LWIP_IPV4 and LWIP_IGMP for IPv4 JoinMulticastGroup and LeaveMulticastGroup support."
434
            lRetval = INET_ERROR_NOT_SUPPORTED;
435
#endif // LWIP_IPV4 && LWIP_IGMP
436
            SuccessOrExit(lRetval);
437
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
438
439
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
440
0
            lRetval = SocketsIPv4JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, IP_ADD_MEMBERSHIP);
441
0
            SuccessOrExit(lRetval);
442
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
443
0
        }
444
0
        break;
445
0
#endif // INET_CONFIG_ENABLE_IPV4
446
447
0
    case kIPAddressType_IPv6:
448
0
        {
449
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
450
#if LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
451
            lRetval = LwIPIPv6JoinLeaveMulticastGroup(aInterfaceId, aAddress, mld6_joingroup_netif);
452
#else // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
453
#pragma message "\n \
454
Please enable LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6 for IPv6 JoinMulticastGroup and LeaveMulticastGroup support."
455
            lRetval = INET_ERROR_NOT_SUPPORTED;
456
#endif // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
457
            SuccessOrExit(lRetval);
458
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
459
460
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
461
0
            lRetval = SocketsIPv6JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, INET_IPV6_ADD_MEMBERSHIP);
462
0
            SuccessOrExit(lRetval);
463
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
464
0
        }
465
0
        break;
466
467
0
    default:
468
0
        lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
469
0
        break;
470
0
    }
471
472
0
exit:
473
0
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP || WEAVE_SYSTEM_CONFIG_USE_SOCKETS
474
0
    return (lRetval);
475
0
}
476
477
/**
478
 *  @brief Leave an IP multicast group.
479
 *
480
 *  @param[in]   aInterfaceId  the indicator of the network interface to
481
 *                             remove from the multicast group
482
 *
483
 *  @param[in]   aAddress      the multicast group to remove the
484
 *                             interface from
485
 *
486
 *  @retval  INET_NO_ERROR
487
 *       success: multicast group removed
488
 *
489
 *  @retval  INET_ERROR_UNKNOWN_INTERFACE
490
 *       unknown network interface, \c aInterfaceId
491
 *
492
 *  @retval  INET_ERROR_WRONG_ADDRESS_TYPE
493
 *       \c aAddress is not \c kIPAddressType_IPv4 or
494
 *       \c kIPAddressType_IPv6 or is not multicast
495
 *
496
 *  @retval  other
497
 *       another system or platform error
498
 *
499
 *  @details
500
 *     Remove the endpoint from the supplied multicast group on the
501
 *     specified interface.
502
 *
503
 */
504
INET_ERROR IPEndPointBasis::LeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress &aAddress)
505
0
{
506
0
    const IPAddressType lAddrType = aAddress.Type();
507
0
    INET_ERROR          lRetval = INET_ERROR_NOT_IMPLEMENTED;
508
509
0
#if WEAVE_SYSTEM_CONFIG_USE_LWIP || WEAVE_SYSTEM_CONFIG_USE_SOCKETS
510
0
    lRetval = CheckMulticastGroupArgs(aInterfaceId, aAddress);
511
0
    SuccessOrExit(lRetval);
512
513
0
    switch (lAddrType)
514
0
    {
515
516
0
#if INET_CONFIG_ENABLE_IPV4
517
0
    case kIPAddressType_IPv4:
518
0
        {
519
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
520
#if LWIP_IPV4 && LWIP_IGMP
521
            lRetval = LwIPIPv4JoinLeaveMulticastGroup(aInterfaceId, aAddress, igmp_leavegroup_netif);
522
#else // LWIP_IPV4 && LWIP_IGMP
523
#pragma message "\n \
524
Please enable LWIP_IPV4 and LWIP_IGMP for IPv4 JoinMulticastGroup and LeaveMulticastGroup support."
525
            lRetval = INET_ERROR_NOT_SUPPORTED;
526
#endif // LWIP_IPV4 && LWIP_IGMP
527
            SuccessOrExit(lRetval);
528
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
529
530
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
531
0
            lRetval = SocketsIPv4JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, IP_DROP_MEMBERSHIP);
532
0
            SuccessOrExit(lRetval);
533
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
534
0
        }
535
0
        break;
536
0
#endif // INET_CONFIG_ENABLE_IPV4
537
538
0
    case kIPAddressType_IPv6:
539
0
        {
540
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
541
#if LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
542
            lRetval = LwIPIPv6JoinLeaveMulticastGroup(aInterfaceId, aAddress, mld6_leavegroup_netif);
543
#else // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
544
#pragma message "\n \
545
Please enable LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6 for IPv6 JoinMulticastGroup and LeaveMulticastGroup support."
546
            lRetval = INET_ERROR_NOT_SUPPORTED;
547
#endif // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
548
            SuccessOrExit(lRetval);
549
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
550
551
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
552
0
            lRetval = SocketsIPv6JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, INET_IPV6_DROP_MEMBERSHIP);
553
0
            SuccessOrExit(lRetval);
554
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
555
0
        }
556
0
        break;
557
558
0
    default:
559
0
        lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
560
0
        break;
561
0
    }
562
563
0
exit:
564
0
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP || WEAVE_SYSTEM_CONFIG_USE_SOCKETS
565
0
    return (lRetval);
566
0
}
567
568
void IPEndPointBasis::Init(InetLayer *aInetLayer)
569
0
{
570
0
    InitEndPointBasis(*aInetLayer);
571
572
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
573
0
    mBoundIntfId = INET_NULL_INTERFACEID;
574
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
575
0
}
576
577
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
578
void IPEndPointBasis::HandleDataReceived(PacketBuffer *aBuffer)
579
{
580
    if ((mState == kState_Listening) && (OnMessageReceived != NULL))
581
    {
582
        const IPPacketInfo *pktInfo = GetPacketInfo(aBuffer);
583
584
        if (pktInfo != NULL)
585
        {
586
            const IPPacketInfo pktInfoCopy = *pktInfo;  // copy the address info so that the app can free the
587
                                                        // PacketBuffer without affecting access to address info.
588
            OnMessageReceived(this, aBuffer, &pktInfoCopy);
589
        }
590
        else
591
        {
592
            if (OnReceiveError != NULL)
593
                OnReceiveError(this, INET_ERROR_INBOUND_MESSAGE_TOO_BIG, NULL);
594
            PacketBuffer::Free(aBuffer);
595
        }
596
    }
597
    else
598
    {
599
        PacketBuffer::Free(aBuffer);
600
    }
601
}
602
603
/**
604
 *  @brief Get LwIP IP layer source and destination addressing information.
605
 *
606
 *  @param[in]   aBuffer       the packet buffer containing the IP message
607
 *
608
 *  @returns  a pointer to the address information on success; otherwise,
609
 *            NULL if there is insufficient space in the packet for
610
 *            the address information.
611
 *
612
 *  @details
613
 *     When using LwIP information about the packet is 'hidden' in the
614
 *     reserved space before the start of the data in the packet
615
 *     buffer. This is necessary because the system layer events only
616
 *     have two arguments, which in this case are used to convey the
617
 *     pointer to the end point and the pointer to the buffer.
618
 *
619
 *     In most cases this trick of storing information before the data
620
 *     works because the first buffer in an LwIP IP message contains
621
 *     the space that was used for the Ethernet/IP/UDP headers. However,
622
 *     given the current size of the IPPacketInfo structure (40 bytes),
623
 *     it is possible for there to not be enough room to store the
624
 *     structure along with the payload in a single packet buffer. In
625
 *     practice, this should only happen for extremely large IPv4
626
 *     packets that arrive without an Ethernet header.
627
 *
628
 */
629
IPPacketInfo *IPEndPointBasis::GetPacketInfo(PacketBuffer *aBuffer)
630
{
631
    uintptr_t       lStart;
632
    uintptr_t       lPacketInfoStart;
633
    IPPacketInfo *  lPacketInfo = NULL;
634
635
    if (!aBuffer->EnsureReservedSize(sizeof (IPPacketInfo) + 3))
636
        goto done;
637
638
    lStart           = (uintptr_t)aBuffer->Start();
639
    lPacketInfoStart = lStart - sizeof (IPPacketInfo);
640
641
    // Align to a 4-byte boundary
642
643
    lPacketInfo      = reinterpret_cast<IPPacketInfo *>(lPacketInfoStart & ~(sizeof (uint32_t) - 1));
644
645
 done:
646
    return (lPacketInfo);
647
}
648
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
649
650
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
651
INET_ERROR IPEndPointBasis::Bind(IPAddressType aAddressType, IPAddress aAddress, uint16_t aPort, InterfaceId aInterfaceId)
652
0
{
653
0
    INET_ERROR lRetval = INET_NO_ERROR;
654
655
0
    if (aAddressType == kIPAddressType_IPv6)
656
0
    {
657
0
        struct sockaddr_in6 sa;
658
659
0
        memset(&sa, 0, sizeof (sa));
660
661
0
        sa.sin6_family   = AF_INET6;
662
0
        sa.sin6_port     = htons(aPort);
663
0
        sa.sin6_flowinfo = 0;
664
0
        sa.sin6_addr     = aAddress.ToIPv6();
665
0
        sa.sin6_scope_id = aInterfaceId;
666
667
0
        if (bind(mSocket, (const sockaddr *) &sa, (unsigned) sizeof (sa)) != 0)
668
0
            lRetval = Weave::System::MapErrorPOSIX(errno);
669
670
        // Instruct the kernel that any messages to multicast destinations should be
671
        // sent down the interface specified by the caller.
672
0
#ifdef IPV6_MULTICAST_IF
673
0
        if (lRetval == INET_NO_ERROR)
674
0
            setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &aInterfaceId, sizeof (aInterfaceId));
675
0
#endif // defined(IPV6_MULTICAST_IF)
676
677
        // Instruct the kernel that any messages to multicast destinations should be
678
        // set with the configured hop limit value.
679
0
#ifdef IPV6_MULTICAST_HOPS
680
0
        int hops = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
681
0
        setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof (hops));
682
0
#endif // defined(IPV6_MULTICAST_HOPS)
683
0
    }
684
0
#if INET_CONFIG_ENABLE_IPV4
685
0
    else if (aAddressType == kIPAddressType_IPv4)
686
0
    {
687
0
        struct sockaddr_in sa;
688
0
        int enable = 1;
689
690
0
        memset(&sa, 0, sizeof (sa));
691
692
0
        sa.sin_family = AF_INET;
693
0
        sa.sin_port   = htons(aPort);
694
0
        sa.sin_addr   = aAddress.ToIPv4();
695
696
0
        if (bind(mSocket, (const sockaddr *) &sa, (unsigned) sizeof (sa)) != 0)
697
0
            lRetval = Weave::System::MapErrorPOSIX(errno);
698
699
        // Instruct the kernel that any messages to multicast destinations should be
700
        // sent down the interface to which the specified IPv4 address is bound.
701
0
#ifdef IP_MULTICAST_IF
702
0
        if (lRetval == INET_NO_ERROR)
703
0
            setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_IF, &sa, sizeof (sa));
704
0
#endif // defined(IP_MULTICAST_IF)
705
706
        // Instruct the kernel that any messages to multicast destinations should be
707
        // set with the configured hop limit value.
708
0
#ifdef IP_MULTICAST_TTL
709
0
        int ttl = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
710
0
        setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof (ttl));
711
0
#endif // defined(IP_MULTICAST_TTL)
712
713
        // Allow socket transmitting broadcast packets.
714
0
        if (lRetval == INET_NO_ERROR)
715
0
            setsockopt(mSocket, SOL_SOCKET, SO_BROADCAST, &enable, sizeof (enable));
716
0
    }
717
0
#endif // INET_CONFIG_ENABLE_IPV4
718
0
    else
719
0
        lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
720
721
0
    return (lRetval);
722
0
}
723
724
INET_ERROR IPEndPointBasis::BindInterface(IPAddressType aAddressType, InterfaceId aInterfaceId)
725
0
{
726
0
    INET_ERROR lRetval = INET_NO_ERROR;
727
728
0
#if HAVE_SO_BINDTODEVICE
729
0
    if (aInterfaceId == INET_NULL_INTERFACEID)
730
0
    {
731
        //Stop interface-based filtering.
732
0
        if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, "", 0) == -1)
733
0
        {
734
0
            lRetval = Weave::System::MapErrorPOSIX(errno);
735
0
        }
736
0
    }
737
0
    else
738
0
    {
739
        //Start filtering on the passed interface.
740
0
        char lInterfaceName[IF_NAMESIZE];
741
742
0
        if (if_indextoname(aInterfaceId, lInterfaceName) == NULL)
743
0
        {
744
0
            lRetval = Weave::System::MapErrorPOSIX(errno);
745
0
        }
746
747
0
        if (lRetval == INET_NO_ERROR && setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, lInterfaceName, strlen(lInterfaceName)) == -1)
748
0
        {
749
0
            lRetval = Weave::System::MapErrorPOSIX(errno);
750
0
        }
751
0
    }
752
753
0
    if (lRetval == INET_NO_ERROR)
754
0
        mBoundIntfId = aInterfaceId;
755
756
#else // !HAVE_SO_BINDTODEVICE
757
    lRetval = INET_ERROR_NOT_IMPLEMENTED;
758
#endif // HAVE_SO_BINDTODEVICE
759
760
0
    return (lRetval);
761
0
}
762
763
INET_ERROR IPEndPointBasis::SendMsg(const IPPacketInfo *aPktInfo, Weave::System::PacketBuffer *aBuffer, uint16_t aSendFlags)
764
0
{
765
0
    INET_ERROR     res = INET_NO_ERROR;
766
0
    PeerSockAddr   peerSockAddr;
767
0
    struct iovec   msgIOV;
768
0
    uint8_t        controlData[256];
769
0
    struct msghdr  msgHeader;
770
0
    InterfaceId    intfId = aPktInfo->Interface;
771
772
    // Ensure the destination address type is compatible with the endpoint address type.
773
0
    VerifyOrExit(mAddrType == aPktInfo->DestAddress.Type(), res = INET_ERROR_BAD_ARGS);
774
775
    // For now the entire message must fit within a single buffer.
776
0
    VerifyOrExit(aBuffer->Next() == NULL, res = INET_ERROR_MESSAGE_TOO_LONG);
777
778
0
    memset(&msgHeader, 0, sizeof (msgHeader));
779
780
0
    msgIOV.iov_base      = aBuffer->Start();
781
0
    msgIOV.iov_len       = aBuffer->DataLength();
782
0
    msgHeader.msg_iov    = &msgIOV;
783
0
    msgHeader.msg_iovlen = 1;
784
785
    // Construct a sockaddr_in/sockaddr_in6 structure containing the destination information.
786
0
    memset(&peerSockAddr, 0, sizeof (peerSockAddr));
787
0
    msgHeader.msg_name = &peerSockAddr;
788
0
    if (mAddrType == kIPAddressType_IPv6)
789
0
    {
790
0
        peerSockAddr.in6.sin6_family    = AF_INET6;
791
0
        peerSockAddr.in6.sin6_port      = htons(aPktInfo->DestPort);
792
0
        peerSockAddr.in6.sin6_flowinfo  = 0;
793
0
        peerSockAddr.in6.sin6_addr      = aPktInfo->DestAddress.ToIPv6();
794
0
        peerSockAddr.in6.sin6_scope_id  = aPktInfo->Interface;
795
0
        msgHeader.msg_namelen           = sizeof(sockaddr_in6);
796
0
    }
797
0
#if INET_CONFIG_ENABLE_IPV4
798
0
    else
799
0
    {
800
0
        peerSockAddr.in.sin_family      = AF_INET;
801
0
        peerSockAddr.in.sin_port        = htons(aPktInfo->DestPort);
802
0
        peerSockAddr.in.sin_addr        = aPktInfo->DestAddress.ToIPv4();
803
0
        msgHeader.msg_namelen           = sizeof(sockaddr_in);
804
0
    }
805
0
#endif // INET_CONFIG_ENABLE_IPV4
806
807
    // If the endpoint has been bound to a particular interface,
808
    // and the caller didn't supply a specific interface to send
809
    // on, use the bound interface. This appears to be necessary
810
    // for messages to multicast addresses, which under Linux
811
    // don't seem to get sent out the correct interface, despite
812
    // the socket being bound.
813
0
    if (intfId == INET_NULL_INTERFACEID)
814
0
        intfId = mBoundIntfId;
815
816
    // If the packet should be sent over a specific interface, or with a specific source
817
    // address, construct an IP_PKTINFO/IPV6_PKTINFO "control message" to that effect
818
    // add add it to the message header.  If the local OS doesn't support IP_PKTINFO/IPV6_PKTINFO
819
    // fail with an error.
820
0
    if (intfId != INET_NULL_INTERFACEID || aPktInfo->SrcAddress.Type() != kIPAddressType_Any)
821
0
    {
822
0
#if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
823
0
        memset(controlData, 0, sizeof(controlData));
824
0
        msgHeader.msg_control = controlData;
825
0
        msgHeader.msg_controllen = sizeof(controlData);
826
827
0
        struct cmsghdr *controlHdr = CMSG_FIRSTHDR(&msgHeader);
828
829
0
#if INET_CONFIG_ENABLE_IPV4
830
831
0
        if (mAddrType == kIPAddressType_IPv4)
832
0
        {
833
0
#if defined(IP_PKTINFO)
834
0
            controlHdr->cmsg_level = IPPROTO_IP;
835
0
            controlHdr->cmsg_type  = IP_PKTINFO;
836
0
            controlHdr->cmsg_len   = CMSG_LEN(sizeof(in_pktinfo));
837
838
0
            struct in_pktinfo *pktInfo = (struct in_pktinfo *)CMSG_DATA(controlHdr);
839
0
            pktInfo->ipi_ifindex = intfId;
840
0
            pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4();
841
842
0
            msgHeader.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo));
843
#else // !defined(IP_PKTINFO)
844
            ExitNow(res = INET_ERROR_NOT_SUPPORTED);
845
#endif // !defined(IP_PKTINFO)
846
0
        }
847
848
0
#endif // INET_CONFIG_ENABLE_IPV4
849
850
0
        if (mAddrType == kIPAddressType_IPv6)
851
0
        {
852
0
#if defined(IPV6_PKTINFO)
853
0
            controlHdr->cmsg_level = IPPROTO_IPV6;
854
0
            controlHdr->cmsg_type  = IPV6_PKTINFO;
855
0
            controlHdr->cmsg_len   = CMSG_LEN(sizeof(in6_pktinfo));
856
857
0
            struct in6_pktinfo *pktInfo = (struct in6_pktinfo *)CMSG_DATA(controlHdr);
858
0
            pktInfo->ipi6_ifindex = intfId;
859
0
            pktInfo->ipi6_addr = aPktInfo->SrcAddress.ToIPv6();
860
861
0
            msgHeader.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo));
862
#else // !defined(IPV6_PKTINFO)
863
            ExitNow(res = INET_ERROR_NOT_SUPPORTED);
864
#endif // !defined(IPV6_PKTINFO)
865
0
        }
866
867
#else // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
868
869
        ExitNow(res = INET_ERROR_NOT_SUPPORTED);
870
871
#endif // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
872
0
    }
873
874
    // Send IP packet.
875
0
    {
876
0
        const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0);
877
0
        if (lenSent == -1)
878
0
            res = Weave::System::MapErrorPOSIX(errno);
879
0
        else if (lenSent != aBuffer->DataLength())
880
0
            res = INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED;
881
0
    }
882
883
0
exit:
884
0
    return (res);
885
0
}
886
887
INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int aProtocol)
888
0
{
889
0
    INET_ERROR res = INET_NO_ERROR;
890
891
0
    if (mSocket == INET_INVALID_SOCKET_FD)
892
0
    {
893
0
        const int one = 1;
894
0
        int family;
895
896
0
        switch (aAddressType)
897
0
        {
898
0
        case kIPAddressType_IPv6:
899
0
            family = PF_INET6;
900
0
            break;
901
902
0
#if INET_CONFIG_ENABLE_IPV4
903
0
        case kIPAddressType_IPv4:
904
0
            family = PF_INET;
905
0
            break;
906
0
#endif // INET_CONFIG_ENABLE_IPV4
907
908
0
        default:
909
0
            return INET_ERROR_WRONG_ADDRESS_TYPE;
910
0
        }
911
912
0
        mSocket = ::socket(family, aType, aProtocol);
913
0
        if (mSocket == -1)
914
0
            return Weave::System::MapErrorPOSIX(errno);
915
916
0
        mAddrType = aAddressType;
917
918
        // NOTE WELL: the errors returned by setsockopt() here are not
919
        // returned as Inet layer Weave::System::MapErrorPOSIX(errno)
920
        // codes because they are normally expected to fail on some
921
        // platforms where the socket option code is defined in the
922
        // header files but not [yet] implemented. Certainly, there is
923
        // room to improve this by connecting the build configuration
924
        // logic up to check for implementations of these options and
925
        // to provide appropriate HAVE_xxxxx definitions accordingly.
926
927
0
        res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR,  (void*)&one, sizeof (one));
928
0
        static_cast<void>(res);
929
930
0
#ifdef SO_REUSEPORT
931
0
        res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT,  (void*)&one, sizeof (one));
932
0
        if (res != 0)
933
0
        {
934
0
            WeaveLogError(Inet, "SO_REUSEPORT failed: %d", errno);
935
0
        }
936
0
#endif // defined(SO_REUSEPORT)
937
938
        // If creating an IPv6 socket, tell the kernel that it will be
939
        // IPv6 only.  This makes it posible to bind two sockets to
940
        // the same port, one for IPv4 and one for IPv6.
941
942
0
#ifdef IPV6_V6ONLY
943
0
        if (aAddressType == kIPAddressType_IPv6)
944
0
        {
945
0
            res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &one, sizeof (one));
946
0
            if (res != 0)
947
0
            {
948
0
                WeaveLogError(Inet, "IPV6_V6ONLY failed: %d", errno);
949
0
            }
950
0
        }
951
0
#endif // defined(IPV6_V6ONLY)
952
953
0
#if INET_CONFIG_ENABLE_IPV4
954
0
#ifdef IP_PKTINFO
955
0
        if (aAddressType == kIPAddressType_IPv4)
956
0
        {
957
0
            res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, (void *) &one, sizeof (one));
958
0
            if (res != 0)
959
0
            {
960
0
                WeaveLogError(Inet, "IP_PKTINFO failed: %d", errno);
961
0
            }
962
0
        }
963
0
#endif // defined(IP_PKTINFO)
964
0
#endif // INET_CONFIG_ENABLE_IPV4
965
966
0
#ifdef IPV6_RECVPKTINFO
967
0
        if (aAddressType == kIPAddressType_IPv6)
968
0
        {
969
0
            res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *) &one, sizeof (one));
970
0
            if (res != 0)
971
0
            {
972
0
                WeaveLogError(Inet, "IPV6_PKTINFO failed: %d", errno);
973
0
            }
974
0
        }
975
0
#endif // defined(IPV6_RECVPKTINFO)
976
977
        // On systems that support it, disable the delivery of SIGPIPE
978
        // signals when writing to a closed socket.  This is mostly
979
        // needed on iOS which has the peculiar habit of sending
980
        // SIGPIPEs on unconnected UDP sockets.
981
#ifdef SO_NOSIGPIPE
982
        {
983
            res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof (one));
984
            if (res != 0)
985
            {
986
                WeaveLogError(Inet, "SO_NOSIGPIPE failed: %d", errno);
987
            }
988
        }
989
#endif // defined(SO_NOSIGPIPE)
990
991
0
    }
992
0
    else if (mAddrType != aAddressType)
993
0
    {
994
0
        return INET_ERROR_INCORRECT_STATE;
995
0
    }
996
997
0
    return INET_NO_ERROR;
998
0
}
999
1000
SocketEvents IPEndPointBasis::PrepareIO(void)
1001
0
{
1002
0
    SocketEvents res;
1003
1004
0
    if (mState == kState_Listening && OnMessageReceived != NULL)
1005
0
        res.SetRead();
1006
1007
0
    return res;
1008
0
}
1009
1010
void IPEndPointBasis::HandlePendingIO(uint16_t aPort)
1011
0
{
1012
0
    INET_ERROR      lStatus = INET_NO_ERROR;
1013
0
    IPPacketInfo    lPacketInfo;
1014
0
    PacketBuffer *  lBuffer;
1015
1016
0
    lPacketInfo.Clear();
1017
0
    lPacketInfo.DestPort = aPort;
1018
1019
0
    lBuffer = PacketBuffer::New(0);
1020
1021
0
    if (lBuffer != NULL)
1022
0
    {
1023
0
        struct iovec msgIOV;
1024
0
        PeerSockAddr lPeerSockAddr;
1025
0
        uint8_t controlData[256];
1026
0
        struct msghdr msgHeader;
1027
1028
0
        msgIOV.iov_base = lBuffer->Start();
1029
0
        msgIOV.iov_len = lBuffer->AvailableDataLength();
1030
1031
0
        memset(&lPeerSockAddr, 0, sizeof (lPeerSockAddr));
1032
1033
0
        memset(&msgHeader, 0, sizeof (msgHeader));
1034
1035
0
        msgHeader.msg_name = &lPeerSockAddr;
1036
0
        msgHeader.msg_namelen = sizeof (lPeerSockAddr);
1037
0
        msgHeader.msg_iov = &msgIOV;
1038
0
        msgHeader.msg_iovlen = 1;
1039
0
        msgHeader.msg_control = controlData;
1040
0
        msgHeader.msg_controllen = sizeof (controlData);
1041
1042
0
        ssize_t rcvLen = recvmsg(mSocket, &msgHeader, MSG_DONTWAIT);
1043
1044
0
        if (rcvLen < 0)
1045
0
        {
1046
0
            lStatus = Weave::System::MapErrorPOSIX(errno);
1047
0
        }
1048
0
        else if (rcvLen > lBuffer->AvailableDataLength())
1049
0
        {
1050
0
            lStatus = INET_ERROR_INBOUND_MESSAGE_TOO_BIG;
1051
0
        }
1052
0
        else
1053
0
        {
1054
0
            lBuffer->SetDataLength((uint16_t) rcvLen);
1055
1056
0
            if (lPeerSockAddr.any.sa_family == AF_INET6)
1057
0
            {
1058
0
                lPacketInfo.SrcAddress = IPAddress::FromIPv6(lPeerSockAddr.in6.sin6_addr);
1059
0
                lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in6.sin6_port);
1060
0
            }
1061
0
#if INET_CONFIG_ENABLE_IPV4
1062
0
            else if (lPeerSockAddr.any.sa_family == AF_INET)
1063
0
            {
1064
0
                lPacketInfo.SrcAddress = IPAddress::FromIPv4(lPeerSockAddr.in.sin_addr);
1065
0
                lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in.sin_port);
1066
0
            }
1067
0
#endif // INET_CONFIG_ENABLE_IPV4
1068
0
            else
1069
0
            {
1070
0
                lStatus = INET_ERROR_INCORRECT_STATE;
1071
0
            }
1072
0
        }
1073
1074
0
        if (lStatus == INET_NO_ERROR)
1075
0
        {
1076
0
            for (struct cmsghdr *controlHdr = CMSG_FIRSTHDR(&msgHeader);
1077
0
                 controlHdr != NULL;
1078
0
                 controlHdr = CMSG_NXTHDR(&msgHeader, controlHdr))
1079
0
            {
1080
0
#if INET_CONFIG_ENABLE_IPV4
1081
0
#ifdef IP_PKTINFO
1082
0
                if (controlHdr->cmsg_level == IPPROTO_IP && controlHdr->cmsg_type == IP_PKTINFO)
1083
0
                {
1084
0
                    struct in_pktinfo *inPktInfo = (struct in_pktinfo *)CMSG_DATA(controlHdr);
1085
0
                    lPacketInfo.Interface = inPktInfo->ipi_ifindex;
1086
0
                    lPacketInfo.DestAddress = IPAddress::FromIPv4(inPktInfo->ipi_addr);
1087
0
                    continue;
1088
0
                }
1089
0
#endif // defined(IP_PKTINFO)
1090
0
#endif // INET_CONFIG_ENABLE_IPV4
1091
1092
0
#ifdef IPV6_PKTINFO
1093
0
                if (controlHdr->cmsg_level == IPPROTO_IPV6 && controlHdr->cmsg_type == IPV6_PKTINFO)
1094
0
                {
1095
0
                    struct in6_pktinfo *in6PktInfo = (struct in6_pktinfo *)CMSG_DATA(controlHdr);
1096
0
                    lPacketInfo.Interface = in6PktInfo->ipi6_ifindex;
1097
0
                    lPacketInfo.DestAddress = IPAddress::FromIPv6(in6PktInfo->ipi6_addr);
1098
0
                    continue;
1099
0
                }
1100
0
#endif // defined(IPV6_PKTINFO)
1101
0
            }
1102
0
        }
1103
0
    }
1104
0
    else
1105
0
    {
1106
0
        lStatus = INET_ERROR_NO_MEMORY;
1107
0
    }
1108
1109
0
    if (lStatus == INET_NO_ERROR)
1110
0
        OnMessageReceived(this, lBuffer, &lPacketInfo);
1111
0
    else
1112
0
    {
1113
0
        PacketBuffer::Free(lBuffer);
1114
0
        if (OnReceiveError != NULL
1115
0
            && lStatus != Weave::System::MapErrorPOSIX(EAGAIN)
1116
0
           )
1117
0
            OnReceiveError(this, lStatus, NULL);
1118
0
    }
1119
1120
0
    return;
1121
0
}
1122
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1123
1124
} // namespace Inet
1125
} // namespace nl