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/RawEndPoint.cpp
Line
Count
Source
1
/*
2
 *
3
 *    Copyright (c) 2018 Google LLC.
4
 *    Copyright (c) 2013-2018 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
 *      This file implements the <tt>nl::Inet::RawEndPoint</tt> class,
23
 *      where the Nest Inet Layer encapsulates methods for interacting
24
 *      interacting with IP network endpoints (SOCK_RAW sockets
25
 *      on Linux and BSD-derived systems) or LwIP raw protocol
26
 *      control blocks, as the system is configured accordingly.
27
 *
28
 */
29
30
#define __APPLE_USE_RFC_3542
31
32
#include <string.h>
33
34
#include <InetLayer/RawEndPoint.h>
35
#include <InetLayer/InetLayer.h>
36
#include <InetLayer/InetFaultInjection.h>
37
#include <SystemLayer/SystemFaultInjection.h>
38
39
#include <Weave/Support/CodeUtils.h>
40
#include <Weave/Support/logging/WeaveLogging.h>
41
42
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
43
#include <lwip/raw.h>
44
#include <lwip/tcpip.h>
45
#include <lwip/ip.h>
46
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
47
48
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
49
#include <poll.h>
50
#if HAVE_SYS_SOCKET_H
51
#include <sys/socket.h>
52
#endif // HAVE_SYS_SOCKET_H
53
#include <errno.h>
54
#include <unistd.h>
55
#include <net/if.h>
56
#include <sys/ioctl.h>
57
#if HAVE_NETINET_ICMP6_H
58
#include <netinet/icmp6.h>
59
#endif // HAVE_NETINET_ICMP6_H
60
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
61
62
// SOCK_CLOEXEC not defined on all platforms, e.g. iOS/MacOS:
63
#ifdef SOCK_CLOEXEC
64
0
#define SOCK_FLAGS SOCK_CLOEXEC
65
#else
66
#define SOCK_FLAGS 0
67
#endif
68
69
namespace nl {
70
namespace Inet {
71
72
using Weave::System::PacketBuffer;
73
74
Weave::System::ObjectPool<RawEndPoint, INET_CONFIG_NUM_RAW_ENDPOINTS> RawEndPoint::sPool;
75
76
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
77
/*
78
 * Note that for LwIP InterfaceId is already defined to be 'struct
79
 * netif'; consequently, some of the checking performed here could
80
 * conceivably be optimized out and the HAVE_LWIP_UDP_BIND_NETIF case
81
 * could simply be:
82
 *
83
 *   udp_bind_netif(aUDP, intfId);
84
 *
85
 */
86
static INET_ERROR LwIPBindInterface(struct raw_pcb *aRaw, InterfaceId intfId)
87
{
88
    INET_ERROR res = INET_NO_ERROR;
89
90
#if HAVE_LWIP_RAW_BIND_NETIF
91
        if (!IsInterfaceIdPresent(intfId))
92
            raw_bind_netif(aRaw, NULL);
93
        else
94
        {
95
            struct netif *netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId);
96
97
            if (netifp == NULL)
98
                res = INET_ERROR_UNKNOWN_INTERFACE;
99
            else
100
                raw_bind_netif(aRaw, netifp);
101
        }
102
#else
103
        if (!IsInterfaceIdPresent(intfId))
104
            aRaw->intf_filter = NULL;
105
        else
106
        {
107
            struct netif *netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId);
108
109
            if (netifp == NULL)
110
                res = INET_ERROR_UNKNOWN_INTERFACE;
111
            else
112
                aRaw->intf_filter = netifp;
113
        }
114
#endif // HAVE_LWIP_RAW_BIND_NETIF
115
116
    return res;
117
}
118
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
119
120
/**
121
 * @brief   Bind the endpoint to an interface IP address.
122
 *
123
 * @param[in]   addrType    the protocol version of the IP address
124
 * @param[in]   addr        the IP address (must be an interface address)
125
 * @param[in]   intfId      an optional network interface indicator
126
 *
127
 * @retval  INET_NO_ERROR               success: endpoint bound to address
128
 * @retval  INET_ERROR_INCORRECT_STATE  endpoint has been bound previously
129
 * @retval  INET_NO_MEMORY              insufficient memory for endpoint
130
 *
131
 * @retval  INET_ERROR_UNKNOWN_INTERFACE
132
 *      On some platforms, the optionally specified interface is not
133
 *      present.
134
 *
135
 * @retval  INET_ERROR_WRONG_PROTOCOL_TYPE
136
 *      \c addrType does not match \c IPVer.
137
 *
138
 * @retval  INET_ERROR_WRONG_ADDRESS_TYPE
139
 *      \c addrType is \c kIPAddressType_Any, or the type of \c addr is not
140
 *      equal to \c addrType.
141
 *
142
 * @retval  other                   another system or platform error
143
 *
144
 * @details
145
 *  Binds the endpoint to the specified network interface IP address.
146
 *
147
 *  On LwIP, this method must not be called with the LwIP stack lock
148
 *  already acquired.
149
 */
150
INET_ERROR RawEndPoint::Bind(IPAddressType addrType, IPAddress addr, InterfaceId intfId)
151
0
{
152
0
    INET_ERROR res = INET_NO_ERROR;
153
154
0
    if (mState != kState_Ready && mState != kState_Bound)
155
0
  {
156
0
        res = INET_ERROR_INCORRECT_STATE;
157
0
        goto exit;
158
0
    }
159
160
0
    if ((addr != IPAddress::Any) && (addr.Type() != kIPAddressType_Any) && (addr.Type() != addrType))
161
0
    {
162
0
        res = INET_ERROR_WRONG_ADDRESS_TYPE;
163
0
        goto exit;
164
0
    }
165
166
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
167
168
    // Lock LwIP stack
169
    LOCK_TCPIP_CORE();
170
171
    // Make sure we have the appropriate type of PCB.
172
    res = GetPCB(addrType);
173
174
    // Bind the PCB to the specified address.
175
    if (res == INET_NO_ERROR)
176
    {
177
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
178
        ip_addr_t ipAddr = addr.ToLwIPAddr();
179
#if INET_CONFIG_ENABLE_IPV4
180
        lwip_ip_addr_type lType = IPAddress::ToLwIPAddrType(addrType);
181
        IP_SET_TYPE_VAL(ipAddr, lType);
182
#endif // INET_CONFIG_ENABLE_IPV4
183
        res = Weave::System::MapErrorLwIP(raw_bind(mRaw, &ipAddr));
184
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
185
        if (addrType == kIPAddressType_IPv6)
186
        {
187
            ip6_addr_t ipv6Addr = addr.ToIPv6();
188
            res = Weave::System::MapErrorLwIP(raw_bind_ip6(mRaw, &ipv6Addr));
189
        }
190
#if INET_CONFIG_ENABLE_IPV4
191
        else if (addrType == kIPAddressType_IPv4)
192
        {
193
            ip4_addr_t ipv4Addr = addr.ToIPv4();
194
            res = Weave::System::MapErrorLwIP(raw_bind(mRaw, &ipv4Addr));
195
        }
196
#endif // INET_CONFIG_ENABLE_IPV4
197
        else
198
            res = INET_ERROR_WRONG_ADDRESS_TYPE;
199
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
200
    }
201
202
    if (res == INET_NO_ERROR)
203
    {
204
        res = LwIPBindInterface(mRaw, intfId);
205
    }
206
207
    // Unlock LwIP stack
208
    UNLOCK_TCPIP_CORE();
209
210
    SuccessOrExit(res);
211
212
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
213
214
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
215
    // Make sure we have the appropriate type of socket.
216
0
    res = GetSocket(addrType);
217
0
    SuccessOrExit(res);
218
219
0
    res = IPEndPointBasis::Bind(addrType, addr, 0, intfId);
220
0
    SuccessOrExit(res);
221
222
0
    mBoundIntfId = intfId;
223
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
224
225
0
    if (res == INET_NO_ERROR)
226
0
    {
227
0
        mState = kState_Bound;
228
0
    }
229
230
0
exit:
231
0
    return res;
232
0
}
233
234
/**
235
 * Bind the raw endpoint to an IPv6 link-local scope address at the specified
236
 * interface index.  Also sets various IPv6 socket options appropriate for
237
 * transmitting packets to and from on-link destinations.
238
 *
239
 * @param[in]   intf    An InterfaceId to identify the scope of the address.
240
 *
241
 * @param[in]   addr    An IPv6 link-local scope IPAddress object.
242
 *
243
 * @return INET_NO_ERROR on success, or a mapped OS error on failure. An invalid
244
 * parameter list can result in INET_ERROR_WRONG_ADDRESS_TYPE. If the raw endpoint
245
 * is already bound or is listening, then returns INET_ERROR_INCORRECT_STATE.
246
 */
247
/**
248
 * @brief   Bind the endpoint to an interface IPv6 link-local address.
249
 *
250
 * @param[in]   intf    the indicator of the network interface
251
 * @param[in]   addr    the IP address (must be an interface address)
252
 *
253
 * @retval  INET_NO_ERROR               success: endpoint bound to address
254
 * @retval  INET_ERROR_INCORRECT_STATE  endpoint has been bound previously
255
 * @retval  INET_NO_MEMORY              insufficient memory for endpoint
256
 *
257
 * @retval  INET_ERROR_WRONG_PROTOCOL_TYPE
258
 *      \c addrType does not match \c IPVer.
259
 *
260
 * @retval  INET_ERROR_WRONG_ADDRESS_TYPE
261
 *      \c addr is not an IPv6 link-local address or \c intf is
262
 *      \c INET_NULL_INTERFACEID.
263
 *
264
 * @retval  other                   another system or platform error
265
 *
266
 * @details
267
 *  Binds the endpoint to the IPv6 link-local address \c addr on the
268
 *  network interface indicated by \c intf.
269
 *
270
 *  On LwIP, this method must not be called with the LwIP stack lock
271
 *  already acquired.
272
 */
273
INET_ERROR RawEndPoint::BindIPv6LinkLocal(InterfaceId intf, IPAddress addr)
274
0
{
275
0
    INET_ERROR res = INET_NO_ERROR;
276
277
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
278
0
    const int lIfIndex = static_cast<int>(intf);
279
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
280
281
0
    if (mState != kState_Ready && mState != kState_Bound)
282
0
    {
283
0
        res = INET_ERROR_INCORRECT_STATE;
284
0
        goto ret;
285
0
    }
286
287
0
    if (!addr.IsIPv6LinkLocal())
288
0
    {
289
0
        res = INET_ERROR_WRONG_ADDRESS_TYPE;
290
0
        goto ret;
291
0
    }
292
293
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
294
295
    // Lock LwIP stack
296
    LOCK_TCPIP_CORE();
297
298
    // Make sure we have the appropriate type of PCB.
299
    res = GetPCB(addr.Type());
300
301
    // Bind the PCB to the specified address.
302
    if (res == INET_NO_ERROR)
303
    {
304
#if LWIP_VERSION_MAJOR > 1
305
        ip_addr_t ipAddr = addr.ToLwIPAddr();
306
        res = Weave::System::MapErrorLwIP(raw_bind(mRaw, &ipAddr));
307
#else // LWIP_VERSION_MAJOR <= 1
308
        ip6_addr_t ipv6Addr = addr.ToIPv6();
309
        res = Weave::System::MapErrorLwIP(raw_bind_ip6(mRaw, &ipv6Addr));
310
#endif // LWIP_VERSION_MAJOR <= 1
311
312
        if (res != INET_NO_ERROR)
313
        {
314
            raw_remove(mRaw);
315
            mRaw = NULL;
316
            mLwIPEndPointType = kLwIPEndPointType_Unknown;
317
        }
318
    }
319
320
    // Unlock LwIP stack
321
    UNLOCK_TCPIP_CORE();
322
323
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
324
325
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
326
327
0
    static const int sInt255 = 255;
328
329
    // Make sure we have the appropriate type of socket.
330
0
    res = GetSocket(kIPAddressType_IPv6);
331
0
    if (res != INET_NO_ERROR)
332
0
    {
333
0
        goto ret;
334
0
    }
335
336
0
    if (::setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &lIfIndex, sizeof(lIfIndex)) != 0)
337
0
    {
338
0
        goto optfail;
339
0
    }
340
341
0
    if (::setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &sInt255, sizeof(sInt255)) != 0)
342
0
    {
343
0
        goto optfail;
344
0
    }
345
346
0
    if (::setsockopt(mSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &sInt255, sizeof(sInt255)) != 0)
347
0
    {
348
0
        goto optfail;
349
0
    }
350
351
0
    mAddrType = kIPAddressType_IPv6;
352
0
    goto ret;
353
354
0
optfail:
355
0
    res = Weave::System::MapErrorPOSIX(errno);
356
0
    ::close(mSocket);
357
0
    mSocket = INET_INVALID_SOCKET_FD;
358
0
    mAddrType = kIPAddressType_Unknown;
359
360
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
361
362
0
ret:
363
0
    if (res == INET_NO_ERROR)
364
0
    {
365
0
        mState = kState_Bound;
366
0
    }
367
368
0
    return res;
369
0
}
370
371
/**
372
 * @brief   Prepare the endpoint to receive ICMP messages.
373
 *
374
 * @retval  INET_NO_ERROR   always returned.
375
 *
376
 * @details
377
 *  If \c mState is already \c kState_Listening, then no operation is
378
 *  performed, otherwise the \c mState is set to \c kState_Listening and
379
 *  the endpoint is prepared to received ICMPv6 messages, according to the
380
 *  semantics of the platform.
381
 *
382
 *  On LwIP, this method must not be called with the LwIP stack lock
383
 *  already acquired
384
 */
385
INET_ERROR RawEndPoint::Listen(void)
386
0
{
387
0
    INET_ERROR res = INET_NO_ERROR;
388
389
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
390
0
    Weave::System::Layer& lSystemLayer = SystemLayer();
391
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
392
393
0
    if (mState == kState_Listening)
394
0
    {
395
0
        res = INET_NO_ERROR;
396
0
        goto exit;
397
0
    }
398
399
0
    if (mState != kState_Bound)
400
0
    {
401
0
        res = INET_ERROR_INCORRECT_STATE;
402
0
        goto exit;
403
0
    }
404
405
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
406
407
    // Lock LwIP stack
408
    LOCK_TCPIP_CORE();
409
410
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
411
    raw_recv(mRaw, LwIPReceiveRawMessage, this);
412
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
413
    if (PCB_ISIPV6(mRaw))
414
        raw_recv_ip6(mRaw, LwIPReceiveRawMessage, this);
415
    else
416
        raw_recv(mRaw, LwIPReceiveRawMessage, this);
417
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
418
419
    // Unlock LwIP stack
420
    UNLOCK_TCPIP_CORE();
421
422
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
423
424
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
425
426
    // Wake the thread calling select so that it starts selecting on the new socket.
427
0
    lSystemLayer.WakeSelect();
428
429
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
430
431
0
    if (res == INET_NO_ERROR)
432
0
    {
433
0
        mState = kState_Listening;
434
0
    }
435
436
0
 exit:
437
0
    return res;
438
0
}
439
440
/**
441
 * @brief   Close the endpoint.
442
 *
443
 * @details
444
 *  If <tt>mState != kState_Closed</tt>, then closes the endpoint, removing
445
 *  it from the set of endpoints eligible for communication events.
446
 *
447
 *  On LwIP systems, this method must not be called with the LwIP stack
448
 *  lock already acquired.
449
 */
450
void RawEndPoint::Close(void)
451
0
{
452
0
    if (mState != kState_Closed)
453
0
    {
454
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
455
456
        // Lock LwIP stack
457
        LOCK_TCPIP_CORE();
458
459
        // Since Raw PCB is released synchronously here, but Raw endpoint itself might have to wait
460
        // for destruction asynchronously, there could be more allocated Raw endpoints than Raw PCBs.
461
        if (mRaw != NULL)
462
        {
463
            raw_remove(mRaw);
464
            mRaw = NULL;
465
            mLwIPEndPointType = kLwIPEndPointType_Unknown;
466
        }
467
468
        // Unlock LwIP stack
469
        UNLOCK_TCPIP_CORE();
470
471
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
472
473
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
474
475
0
        if (mSocket != INET_INVALID_SOCKET_FD)
476
0
        {
477
0
            Weave::System::Layer& lSystemLayer = SystemLayer();
478
479
            // Wake the thread calling select so that it recognizes the socket is closed.
480
0
            lSystemLayer.WakeSelect();
481
482
0
            close(mSocket);
483
0
            mSocket = INET_INVALID_SOCKET_FD;
484
0
        }
485
486
        // Clear any results from select() that indicate pending I/O for the socket.
487
0
        mPendingIO.Clear();
488
489
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
490
491
0
        mState = kState_Closed;
492
0
    }
493
0
}
494
495
/**
496
 * @brief   Close the endpoint and recycle its memory.
497
 *
498
 * @details
499
 *  Invokes the \c Close method, then invokes the
500
 *  <tt>InetLayerBasis::Release</tt> method to return the object to its
501
 *  memory pool.
502
 *
503
 *  On LwIP systems, this method must not be called with the LwIP stack
504
 *  lock already acquired.
505
 */
506
void RawEndPoint::Free(void)
507
0
{
508
0
    Close();
509
510
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
511
    DeferredFree(kReleaseDeferralErrorTactic_Die);
512
#else // !WEAVE_SYSTEM_CONFIG_USE_LWIP
513
0
    Release();
514
0
#endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP
515
0
}
516
517
/**
518
 *  A synonym for <tt>SendTo(addr, INET_NULL_INTERFACEID, msg,
519
 *  sendFlags)</tt>.
520
 */
521
INET_ERROR RawEndPoint::SendTo(IPAddress addr, Weave::System::PacketBuffer *msg, uint16_t sendFlags)
522
0
{
523
0
    return SendTo(addr, INET_NULL_INTERFACEID, msg, sendFlags);
524
0
}
525
526
/**
527
 * @brief   Send an ICMP message to the specified destination address.
528
 *
529
 * @param[in]   addr        the destination IP address
530
 * @param[in]   intfId      an optional network interface indicator
531
 * @param[in]   msg         the packet buffer containing the UDP message
532
 * @param[in]   sendFlags   optional transmit option flags
533
 *
534
 * @retval  INET_NO_ERROR
535
 *      success: \c msg is queued for transmit.
536
 *
537
 * @retval  INET_ERROR_NOT_SUPPORTED
538
 *      the system does not support the requested operation.
539
 *
540
 * @retval  INET_ERROR_WRONG_ADDRESS_TYPE
541
 *      the destination address and the bound interface address do not
542
 *      have matching protocol versions or address type.
543
 *
544
 * @retval  INET_ERROR_MESSAGE_TOO_LONG
545
 *      \c msg does not contain the whole ICMP message.
546
 *
547
 * @retval  INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED
548
 *      On some platforms, only a truncated portion of \c msg was queued
549
 *      for transmit.
550
 *
551
 * @retval  other                   another system or platform error
552
 *
553
 * @details
554
 *      Send the ICMP message in \c msg to the destination given in \c addr.
555
 *
556
 *      Where <tt>(sendFlags & kSendFlag_RetainBuffer) != 0</tt>, calls
557
 *      <tt>Weave::System::PacketBuffer::Free</tt> on behalf of the caller, otherwise this
558
 *      method deep-copies \c msg into a fresh object, and queues that for
559
 *      transmission, leaving the original \c msg available after return.
560
 */
561
INET_ERROR RawEndPoint::SendTo(IPAddress addr, InterfaceId intfId, Weave::System::PacketBuffer *msg, uint16_t sendFlags)
562
0
{
563
0
    IPPacketInfo pktInfo;
564
0
    pktInfo.Clear();
565
0
    pktInfo.DestAddress = addr;
566
0
    pktInfo.Interface = intfId;
567
0
    return SendMsg(&pktInfo, msg, sendFlags);
568
0
}
569
570
/**
571
 * @brief   Send an ICMP message to the specified destination.
572
 *
573
 * @param[in]   pktInfo     destination information for the message
574
 * @param[in]   msg         the packet buffer containing the UDP message
575
 * @param[in]   sendFlags   optional transmit option flags
576
 *
577
 * @retval  INET_NO_ERROR
578
 *      success: \c msg is queued for transmit.
579
 *
580
 * @retval  INET_ERROR_NOT_SUPPORTED
581
 *      the system does not support the requested operation.
582
 *
583
 * @retval  INET_ERROR_WRONG_ADDRESS_TYPE
584
 *      the destination address and the bound interface address do not
585
 *      have matching protocol versions or address type.
586
 *
587
 * @retval  INET_ERROR_MESSAGE_TOO_LONG
588
 *      \c msg does not contain the whole ICMP message.
589
 *
590
 * @retval  INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED
591
 *      On some platforms, only a truncated portion of \c msg was queued
592
 *      for transmit.
593
 *
594
 * @retval  other                   another system or platform error
595
 *
596
 * @details
597
 *      Send the ICMP message \c msg using the destination information given in \c addr.
598
 *
599
 *      Where <tt>(sendFlags & kSendFlag_RetainBuffer) != 0</tt>, calls
600
 *      <tt>Weave::System::PacketBuffer::Free</tt> on behalf of the caller, otherwise this
601
 *      method deep-copies \c msg into a fresh object, and queues that for
602
 *      transmission, leaving the original \c msg available after return.
603
 */
604
INET_ERROR RawEndPoint::SendMsg(const IPPacketInfo *pktInfo, Weave::System::PacketBuffer *msg, uint16_t sendFlags)
605
0
{
606
0
    INET_ERROR res = INET_NO_ERROR;
607
0
    const IPAddress & addr = pktInfo->DestAddress;
608
609
0
    INET_FAULT_INJECT(FaultInjection::kFault_Send,
610
0
            if ((sendFlags & kSendFlag_RetainBuffer) == 0)
611
0
                PacketBuffer::Free(msg);
612
0
            return INET_ERROR_UNKNOWN_INTERFACE;
613
0
            );
614
0
    INET_FAULT_INJECT(FaultInjection::kFault_SendNonCritical,
615
0
            if ((sendFlags & kSendFlag_RetainBuffer) == 0)
616
0
                PacketBuffer::Free(msg);
617
0
            return INET_ERROR_NO_MEMORY;
618
0
            );
619
620
    // Do not allow sending an IPv4 address on an IPv6 end point and
621
    // vice versa.
622
623
0
    if (IPVer == kIPVersion_6 && addr.Type() != kIPAddressType_IPv6)
624
0
    {
625
0
        return INET_ERROR_WRONG_ADDRESS_TYPE;
626
0
    }
627
0
#if INET_CONFIG_ENABLE_IPV4
628
0
    else if (IPVer == kIPVersion_4 && addr.Type() != kIPAddressType_IPv4)
629
0
    {
630
0
        return INET_ERROR_WRONG_ADDRESS_TYPE;
631
0
    }
632
0
#endif // INET_CONFIG_ENABLE_IPV4
633
634
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
635
636
    if (sendFlags & kSendFlag_RetainBuffer)
637
    {
638
        // when retaining a buffer, the caller expects the msg to be
639
        // unmodified.  LwIP stack will normally prepend the packet
640
        // headers as the packet traverses the IP/netif layers,
641
        // which normally modifies the packet.  We prepend a small
642
        // pbuf to the beginning of the pbuf chain, s.t. all headers
643
        // are added to the temporary space, just large enough to hold
644
        // the transport headers. Careful reader will note:
645
        //
646
        // * we're actually oversizing the reserved space, the
647
        //   transport header is large enough for the TCP header which
648
        //   is larger than the UDP header, but it seemed cleaner than
649
        //   the combination of PBUF_IP for reserve space, UDP_HLEN
650
        //   for payload, and post allocation adjustment of the header
651
        //   space).
652
        //
653
        // * the code deviates from the existing PacketBuffer
654
        //   abstractions and needs to reach into the underlying pbuf
655
        //   code.  The code in PacketBuffer also forces us to perform
656
        //   (effectively) a reinterpret_cast rather than a
657
        //   static_cast.  JIRA WEAV-811 is filed to track the
658
        //   re-architecting of the memory management.
659
660
        pbuf *msgCopy = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM);
661
662
        if (msgCopy == NULL)
663
        {
664
            return INET_ERROR_NO_MEMORY;
665
        }
666
667
        pbuf_chain(msgCopy, (pbuf *) msg);
668
        msg = (PacketBuffer *)msgCopy;
669
    }
670
671
    // Lock LwIP stack
672
    LOCK_TCPIP_CORE();
673
674
    // Make sure we have the appropriate type of PCB based on the destination address.
675
    res = GetPCB(addr.Type());
676
    SuccessOrExit(res);
677
678
    // Send the message to the specified address/port.
679
    {
680
        err_t lwipErr = ERR_VAL;
681
682
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
683
        ip_addr_t ipAddr = addr.ToLwIPAddr();
684
685
        lwipErr = raw_sendto(mRaw, (pbuf *)msg, &ipAddr);
686
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
687
        if (PCB_ISIPV6(mRaw))
688
        {
689
            ip6_addr_t ipv6Addr = addr.ToIPv6();
690
691
            lwipErr = raw_sendto_ip6(mRaw, (pbuf *)msg, &ipv6Addr);
692
        }
693
#if INET_CONFIG_ENABLE_IPV4
694
        else
695
        {
696
            ip4_addr_t ipv4Addr = addr.ToIPv4();
697
698
            lwipErr = raw_sendto(mRaw, (pbuf *)msg, &ipv4Addr);
699
        }
700
#endif // INET_CONFIG_ENABLE_IPV4
701
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
702
703
        if (lwipErr != ERR_OK)
704
            res = Weave::System::MapErrorLwIP(lwipErr);
705
    }
706
707
    // Unlock LwIP stack
708
    UNLOCK_TCPIP_CORE();
709
710
    PacketBuffer::Free(msg);
711
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
712
713
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
714
    // Make sure we have the appropriate type of socket based on the
715
    // destination address.
716
717
0
    res = GetSocket(addr.Type());
718
0
    SuccessOrExit(res);
719
720
0
    res = IPEndPointBasis::SendMsg(pktInfo, msg, sendFlags);
721
722
0
    if ((sendFlags & kSendFlag_RetainBuffer) == 0)
723
0
        PacketBuffer::Free(msg);
724
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
725
726
0
exit:
727
0
    WEAVE_SYSTEM_FAULT_INJECT_ASYNC_EVENT();
728
729
0
    return res;
730
0
}
731
732
/**
733
 * @brief   Set the ICMP6 filter parameters in the network stack.
734
 *
735
 * @param[in]   numICMPTypes    length of array at \c aICMPTypes
736
 * @param[in]   aICMPTypes      the set of ICMPv6 type codes to filter.
737
 *
738
 * @retval  INET_NO_ERROR                   success: filter parameters set
739
 * @retval  INET_ERROR_NOT_IMPLEMENTED      system does not implement
740
 * @retval  INET_ERROR_WRONG_ADDRESS_TYPE   endpoint not IPv6 type
741
 * @retval  INET_ERROR_WRONG_PROTOCOL_TYPE  endpoint not ICMP6 type
742
 *
743
 * @retval  other                   another system or platform error
744
 *
745
 * @details
746
 *  Apply the ICMPv6 filtering parameters for the codes in \c aICMPTypes to
747
 *  the underlying endpoint in the system networking stack.
748
 */
749
INET_ERROR RawEndPoint::SetICMPFilter(uint8_t numICMPTypes, const uint8_t * aICMPTypes)
750
0
{
751
0
    INET_ERROR err;
752
753
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
754
#if !(HAVE_NETINET_ICMP6_H && HAVE_ICMP6_FILTER)
755
    err = INET_ERROR_NOT_IMPLEMENTED;
756
    ExitNow();
757
#endif //!(HAVE_NETINET_ICMP6_H && HAVE_ICMP6_FILTER)
758
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
759
760
0
    VerifyOrExit(IPVer == kIPVersion_6, err = INET_ERROR_WRONG_ADDRESS_TYPE);
761
0
    VerifyOrExit(IPProto == kIPProtocol_ICMPv6, err = INET_ERROR_WRONG_PROTOCOL_TYPE);
762
0
    VerifyOrExit((numICMPTypes == 0 && aICMPTypes == NULL) || (numICMPTypes != 0 && aICMPTypes != NULL), err =
763
0
        INET_ERROR_BAD_ARGS);
764
765
0
    err = INET_NO_ERROR;
766
767
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
768
    LOCK_TCPIP_CORE();
769
    NumICMPTypes = numICMPTypes;
770
    ICMPTypes = aICMPTypes;
771
    UNLOCK_TCPIP_CORE();
772
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
773
774
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
775
0
#if HAVE_NETINET_ICMP6_H && HAVE_ICMP6_FILTER
776
0
    struct icmp6_filter filter;
777
0
    if (numICMPTypes > 0)
778
0
    {
779
0
        ICMP6_FILTER_SETBLOCKALL(&filter);
780
0
        for (int j = 0; j < numICMPTypes; ++j)
781
0
        {
782
0
            ICMP6_FILTER_SETPASS(aICMPTypes[j], &filter);
783
0
        }
784
0
    }
785
0
    else
786
0
    {
787
0
        ICMP6_FILTER_SETPASSALL(&filter);
788
0
    }
789
0
    if (setsockopt(mSocket, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
790
0
    {
791
0
        err = Weave::System::MapErrorPOSIX(errno);
792
0
    }
793
0
#endif // HAVE_NETINET_ICMP6_H && HAVE_ICMP6_FILTER
794
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
795
796
0
exit:
797
0
    return err;
798
0
}
799
800
/**
801
 * @brief   Bind the endpoint to a network interface.
802
 *
803
 * @param[in]   addrType    the protocol version of the IP address.
804
 *
805
 * @param[in]   intf        indicator of the network interface.
806
 *
807
 * @retval  INET_NO_ERROR               success: endpoint bound to address
808
 * @retval  INET_NO_MEMORY              insufficient memory for endpoint
809
 * @retval  INET_ERROR_NOT_IMPLEMENTED  system implementation not complete.
810
 *
811
 * @retval  INET_ERROR_UNKNOWN_INTERFACE
812
 *      On some platforms, the interface is not present.
813
 *
814
 * @retval  other                   another system or platform error
815
 *
816
 * @details
817
 *  Binds the endpoint to the specified network interface IP address.
818
 *
819
 *  On LwIP, this method must not be called with the LwIP stack lock
820
 *  already acquired.
821
 */
822
INET_ERROR RawEndPoint::BindInterface(IPAddressType addrType, InterfaceId intfId)
823
0
{
824
0
    INET_ERROR err = INET_NO_ERROR;
825
826
    //A lock is required because the LwIP thread may be referring to intf_filter,
827
    //while this code running in the Inet application is potentially modifying it.
828
    //NOTE: this only supports LwIP interfaces whose number is no bigger than 9.
829
830
0
    if (mState != kState_Ready && mState != kState_Bound)
831
0
        return INET_ERROR_INCORRECT_STATE;
832
833
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
834
    LOCK_TCPIP_CORE();
835
836
    // Make sure we have the appropriate type of PCB.
837
    err = GetPCB(addrType);
838
    SuccessOrExit(err);
839
840
    err = LwIPBindInterface(mRaw, intfId);
841
842
    UNLOCK_TCPIP_CORE();
843
844
    SuccessOrExit(err);
845
846
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
847
848
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
849
    // Make sure we have the appropriate type of socket.
850
0
    err = GetSocket(addrType);
851
0
    SuccessOrExit(err);
852
853
0
    err = IPEndPointBasis::BindInterface(addrType, intfId);
854
0
    SuccessOrExit(err);
855
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
856
857
0
    if (err == INET_NO_ERROR)
858
0
    {
859
0
        mState = kState_Bound;
860
0
    }
861
862
0
exit:
863
0
    return err;
864
0
}
865
866
void RawEndPoint::Init(InetLayer *inetLayer, IPVersion ipVer, IPProtocol ipProto)
867
0
{
868
0
    IPEndPointBasis::Init(inetLayer);
869
870
0
    IPVer = ipVer;
871
0
    IPProto = ipProto;
872
0
}
873
874
/**
875
 * Get the bound interface on this endpoint.
876
 *
877
 * @return InterfaceId   The bound interface id.
878
 */
879
InterfaceId RawEndPoint::GetBoundInterface(void)
880
0
{
881
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
882
#if HAVE_LWIP_RAW_BIND_NETIF
883
    return netif_get_by_index(mRaw->netif_idx);
884
#else
885
    return mRaw->intf_filter;
886
#endif
887
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
888
889
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
890
0
    return mBoundIntfId;
891
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
892
0
}
893
894
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
895
896
void RawEndPoint::HandleDataReceived(PacketBuffer *msg)
897
{
898
    IPEndPointBasis::HandleDataReceived(msg);
899
}
900
901
INET_ERROR RawEndPoint::GetPCB(IPAddressType addrType)
902
{
903
    INET_ERROR lRetval = INET_NO_ERROR;
904
905
    // IMPORTANT: This method MUST be called with the LwIP stack LOCKED!
906
907
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
908
    if (mRaw == NULL)
909
    {
910
        switch (addrType)
911
        {
912
        case kIPAddressType_IPv6:
913
#if INET_CONFIG_ENABLE_IPV4
914
        case kIPAddressType_IPv4:
915
#endif // INET_CONFIG_ENABLE_IPV4
916
            mRaw = raw_new_ip_type(IPAddress::ToLwIPAddrType(addrType), IPProto);
917
            break;
918
919
        default:
920
            lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
921
            goto exit;
922
        }
923
924
        if (mRaw == NULL)
925
        {
926
            WeaveLogError(Inet, "raw_new_ip_type failed");
927
            lRetval = INET_ERROR_NO_MEMORY;
928
            goto exit;
929
        }
930
        else
931
        {
932
            mLwIPEndPointType = kLwIPEndPointType_Raw;
933
        }
934
    }
935
    else
936
    {
937
        const lwip_ip_addr_type lLwIPAddrType = static_cast<lwip_ip_addr_type>(IP_GET_TYPE(&mRaw->local_ip));
938
939
        switch (lLwIPAddrType)
940
        {
941
        case IPADDR_TYPE_V6:
942
            VerifyOrExit(addrType == kIPAddressType_IPv6, lRetval = INET_ERROR_WRONG_ADDRESS_TYPE);
943
            break;
944
945
#if INET_CONFIG_ENABLE_IPV4
946
        case IPADDR_TYPE_V4:
947
            VerifyOrExit(addrType == kIPAddressType_IPv4, lRetval = INET_ERROR_WRONG_ADDRESS_TYPE);
948
            break;
949
#endif // INET_CONFIG_ENABLE_IPV4
950
951
        default:
952
            break;
953
        }
954
    }
955
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
956
    if (mRaw == NULL)
957
    {
958
        if (IPVer == kIPVersion_6)
959
        {
960
            mRaw = raw_new_ip6(IPProto);
961
            if (mRaw != NULL)
962
                ip_set_option(mRaw, SOF_REUSEADDR);
963
        }
964
#if INET_CONFIG_ENABLE_IPV4
965
        else if (IPVer == kIPVersion_4)
966
        {
967
            mRaw = raw_new(IPProto);
968
        }
969
#endif // INET_CONFIG_ENABLE_IPV4
970
        else
971
        {
972
            lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
973
            goto exit;
974
        }
975
976
        if (mRaw == NULL)
977
        {
978
            WeaveLogError(Inet, "raw_new failed");
979
            lRetval = INET_ERROR_NO_MEMORY;
980
            goto exit;
981
        }
982
        else
983
        {
984
            mLwIPEndPointType = kLwIPEndPointType_Raw;
985
        }
986
    }
987
    else
988
    {
989
#if INET_CONFIG_ENABLE_IPV4
990
        const IPAddressType pcbType = PCB_ISIPV6(mRaw) ? kIPAddressType_IPv6 : kIPAddressType_IPv4;
991
#else // !INET_CONFIG_ENABLE_IPV4
992
        const IPAddressType pcbType = kIPAddressType_IPv6;
993
#endif // !INET_CONFIG_ENABLE_IPV4
994
995
        if (addrType != pcbType) {
996
            lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
997
            goto exit;
998
        }
999
    }
1000
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
1001
1002
exit:
1003
    return (lRetval);
1004
}
1005
1006
/* This function is executed when a raw_pcb is listening and an IP datagram (v4 or v6) is received.
1007
 * NOTE: currently ICMPv4 filtering is currently not implemented, but it can easily be added later.
1008
 * This fn() may be executed concurrently with SetICMPFilter()
1009
 * - this fn() runs in the LwIP thread (and the lock has already been taken)
1010
 * - SetICMPFilter() runs in the Inet thread.
1011
 */
1012
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
1013
u8_t RawEndPoint::LwIPReceiveRawMessage(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr)
1014
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
1015
u8_t RawEndPoint::LwIPReceiveRawMessage(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr)
1016
#endif // LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
1017
{
1018
    RawEndPoint*            ep              = static_cast<RawEndPoint*>(arg);
1019
    PacketBuffer*           buf             = reinterpret_cast<PacketBuffer*>(static_cast<void*>(p));
1020
    Weave::System::Layer&   lSystemLayer    = ep->SystemLayer();
1021
    IPPacketInfo*           pktInfo     = NULL;
1022
    uint8_t                 enqueue         = 1;
1023
1024
    //Filtering based on the saved ICMP6 types (the only protocol currently supported.)
1025
    if ((ep->IPVer == kIPVersion_6) &&
1026
        (ep->IPProto == kIPProtocol_ICMPv6))
1027
    {
1028
        if (ep->NumICMPTypes > 0)
1029
        { //When no filter is defined, let all ICMPv6 packets pass
1030
          //The type is the first 8 bits field of an ICMP (v4 or v6) packet
1031
            uint8_t icmp_type = *(buf->Start() + ip_current_header_tot_len());
1032
            uint8_t icmp_type_found = 0;
1033
            for (int j = 0; j < ep->NumICMPTypes; ++j)
1034
            {
1035
                if (ep->ICMPTypes[j] == icmp_type)
1036
                {
1037
                    icmp_type_found = 1;
1038
                    break;
1039
                }
1040
            }
1041
            if ( !icmp_type_found )
1042
            {
1043
                enqueue = 0;            //do not eat it
1044
            }
1045
        }
1046
    }
1047
1048
    if (enqueue)
1049
    {
1050
        pktInfo = GetPacketInfo(buf);
1051
1052
        if (pktInfo != NULL)
1053
    {
1054
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
1055
            pktInfo->SrcAddress = IPAddress::FromLwIPAddr(*addr);
1056
            pktInfo->DestAddress = IPAddress::FromLwIPAddr(*ip_current_dest_addr());
1057
#else // LWIP_VERSION_MAJOR <= 1
1058
            if (PCB_ISIPV6(pcb))
1059
            {
1060
                pktInfo->SrcAddress = IPAddress::FromIPv6(*(ip6_addr_t *)addr);
1061
                pktInfo->DestAddress = IPAddress::FromIPv6(*ip6_current_dest_addr());
1062
            }
1063
#if INET_CONFIG_ENABLE_IPV4
1064
            else
1065
            {
1066
                pktInfo->SrcAddress = IPAddress::FromIPv4(*addr);
1067
                pktInfo->DestAddress = IPAddress::FromIPv4(*ip_current_dest_addr());
1068
            }
1069
#endif // INET_CONFIG_ENABLE_IPV4
1070
#endif // LWIP_VERSION_MAJOR <= 1
1071
1072
            pktInfo->Interface = ip_current_netif();
1073
            pktInfo->SrcPort = 0;
1074
            pktInfo->DestPort = 0;
1075
        }
1076
1077
        if (lSystemLayer.PostEvent(*ep, kInetEvent_RawDataReceived, (uintptr_t)buf) != INET_NO_ERROR)
1078
            PacketBuffer::Free(buf);
1079
    }
1080
1081
    return enqueue;
1082
}
1083
1084
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1085
1086
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1087
INET_ERROR RawEndPoint::GetSocket(IPAddressType aAddressType)
1088
0
{
1089
0
    INET_ERROR lRetval = INET_NO_ERROR;
1090
0
    const int lType = (SOCK_RAW | SOCK_FLAGS);
1091
0
    int lProtocol;
1092
1093
0
    switch (aAddressType)
1094
0
    {
1095
0
    case kIPAddressType_IPv6:
1096
0
        lProtocol = IPPROTO_ICMPV6;
1097
0
        break;
1098
1099
0
#if INET_CONFIG_ENABLE_IPV4
1100
0
    case kIPAddressType_IPv4:
1101
0
        lProtocol = IPPROTO_ICMP;
1102
0
        break;
1103
0
#endif // INET_CONFIG_ENABLE_IPV4
1104
1105
0
    default:
1106
0
        lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
1107
0
        goto exit;
1108
0
    }
1109
1110
0
    lRetval = IPEndPointBasis::GetSocket(aAddressType, lType, lProtocol);
1111
0
    SuccessOrExit(lRetval);
1112
1113
0
exit:
1114
0
    return (lRetval);
1115
0
}
1116
1117
SocketEvents RawEndPoint::PrepareIO(void)
1118
0
{
1119
0
    return (IPEndPointBasis::PrepareIO());
1120
0
}
1121
1122
void RawEndPoint::HandlePendingIO(void)
1123
0
{
1124
0
    if (mState == kState_Listening && OnMessageReceived != NULL && mPendingIO.IsReadable())
1125
0
    {
1126
0
        const uint16_t lPort = 0;
1127
1128
0
        IPEndPointBasis::HandlePendingIO(lPort);
1129
0
    }
1130
1131
0
    mPendingIO.Clear();
1132
0
}
1133
1134
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1135
1136
} // namespace Inet
1137
} // namespace nl