Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / inet / IPEndPointBasis.cpp
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *    Copyright (c) 2018 Google LLC.
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>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 "IPEndPointBasis.h"
31
32 #include <string.h>
33 #include <utility>
34
35 #include <inet/EndPointBasis.h>
36 #include <inet/InetInterface.h>
37 #include <inet/InetLayer.h>
38
39 #include <support/CodeUtils.h>
40 #include <support/SafeInt.h>
41
42 #if CHIP_SYSTEM_CONFIG_USE_LWIP
43 #if INET_CONFIG_ENABLE_IPV4
44 #include <lwip/igmp.h>
45 #endif // INET_CONFIG_ENABLE_IPV4
46 #include <lwip/init.h>
47 #include <lwip/ip.h>
48 #include <lwip/mld6.h>
49 #include <lwip/netif.h>
50 #include <lwip/raw.h>
51 #include <lwip/udp.h>
52 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
53
54 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
55 #include <errno.h>
56 #include <net/if.h>
57 #include <netinet/in.h>
58 #include <sys/ioctl.h>
59 #include <sys/socket.h>
60 #include <unistd.h>
61 #if HAVE_SYS_SOCKET_H
62 #include <sys/socket.h>
63 #endif // HAVE_SYS_SOCKET_H
64
65 /*
66  * Some systems define both IPV6_{ADD,DROP}_MEMBERSHIP and
67  * IPV6_{JOIN,LEAVE}_GROUP while others only define
68  * IPV6_{JOIN,LEAVE}_GROUP. Prefer the "_MEMBERSHIP" flavor for
69  * parallelism with IPv4 and create the alias to the availabile
70  * definitions.
71  */
72 #if defined(IPV6_ADD_MEMBERSHIP)
73 #define INET_IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
74 #elif defined(IPV6_JOIN_GROUP)
75 #define INET_IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
76 #elif !__ZEPHYR__
77 #error                                                                                                                             \
78     "Neither IPV6_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP are defined which are required for generalized IPv6 multicast group support."
79 #endif // IPV6_ADD_MEMBERSHIP
80
81 #if defined(IPV6_DROP_MEMBERSHIP)
82 #define INET_IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
83 #elif defined(IPV6_LEAVE_GROUP)
84 #define INET_IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
85 #elif !__ZEPHYR__
86 #error                                                                                                                             \
87     "Neither IPV6_DROP_MEMBERSHIP nor IPV6_LEAVE_GROUP are defined which are required for generalized IPv6 multicast group support."
88 #endif // IPV6_DROP_MEMBERSHIP
89 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
90
91 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
92 #define INET_PORTSTRLEN 6
93 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
94
95 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
96 #include "ZephyrSocket.h"
97 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
98
99 namespace chip {
100 namespace Inet {
101
102 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
103 union PeerSockAddr
104 {
105     sockaddr any;
106     sockaddr_in in;
107     sockaddr_in6 in6;
108 };
109 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
110
111 #if CHIP_SYSTEM_CONFIG_USE_LWIP
112 #if INET_CONFIG_ENABLE_IPV4
113 #define LWIP_IPV4_ADDR_T ip4_addr_t
114 #define IPV4_TO_LWIPADDR(aAddress) (aAddress).ToIPv4()
115 #endif // INET_CONFIG_ENABLE_IPV4
116 #define LWIP_IPV6_ADDR_T ip6_addr_t
117 #define IPV6_TO_LWIPADDR(aAddress) (aAddress).ToIPv6()
118
119 #if !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) ||                       \
120     !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags)
121 #define HAVE_LWIP_MULTICAST_LOOP 0
122 #else
123 #define HAVE_LWIP_MULTICAST_LOOP 1
124 #endif // !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) ||
125        // !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags)
126 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
127
128 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
129 static INET_ERROR CheckMulticastGroupArgs(InterfaceId aInterfaceId, const IPAddress & aAddress)
130 {
131     INET_ERROR lRetval = INET_NO_ERROR;
132     bool lIsPresent, lIsMulticast;
133
134     lIsPresent = IsInterfaceIdPresent(aInterfaceId);
135     VerifyOrExit(lIsPresent, lRetval = INET_ERROR_UNKNOWN_INTERFACE);
136
137     lIsMulticast = aAddress.IsMulticast();
138     VerifyOrExit(lIsMulticast, lRetval = INET_ERROR_WRONG_ADDRESS_TYPE);
139
140 exit:
141     return (lRetval);
142 }
143 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
144
145 #if CHIP_SYSTEM_CONFIG_USE_LWIP
146 #if INET_CONFIG_ENABLE_IPV4
147 #if LWIP_IPV4 && LWIP_IGMP
148 static INET_ERROR LwIPIPv4JoinLeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress,
149                                                   err_t (*aMethod)(struct netif *, const LWIP_IPV4_ADDR_T *))
150 {
151     INET_ERROR lRetval = INET_NO_ERROR;
152     err_t lStatus;
153     struct netif * lNetif;
154     LWIP_IPV4_ADDR_T lIPv4Address;
155
156     lNetif = IPEndPointBasis::FindNetifFromInterfaceId(aInterfaceId);
157     VerifyOrExit(lNetif != NULL, lRetval = INET_ERROR_UNKNOWN_INTERFACE);
158
159     lIPv4Address = IPV4_TO_LWIPADDR(aAddress);
160
161     lStatus = aMethod(lNetif, &lIPv4Address);
162
163     switch (lStatus)
164     {
165
166     case ERR_MEM:
167         lRetval = INET_ERROR_NO_MEMORY;
168         break;
169
170     default:
171         lRetval = chip::System::MapErrorLwIP(lStatus);
172         break;
173     }
174
175 exit:
176     return (lRetval);
177 }
178 #endif // LWIP_IPV4 && LWIP_IGMP
179 #endif // INET_CONFIG_ENABLE_IPV4
180
181 // unusual define check for LWIP_IPV6_ND is because espressif fork
182 // of LWIP does not define the _ND constant.
183 #if LWIP_IPV6_MLD && (!defined(LWIP_IPV6_ND) || LWIP_IPV6_ND) && LWIP_IPV6
184 #define HAVE_IPV6_MULTICAST
185 #else
186 // Within Project CHIP multicast support is highly desirable: used for mDNS
187 // as well as group communication.
188 #undef HAVE_IPV6_MULTICAST
189 #endif
190
191 #ifdef HAVE_IPV6_MULTICAST
192 static INET_ERROR LwIPIPv6JoinLeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress,
193                                                   err_t (*aMethod)(struct netif *, const LWIP_IPV6_ADDR_T *))
194 {
195     INET_ERROR lRetval = INET_NO_ERROR;
196     err_t lStatus;
197     struct netif * lNetif;
198     LWIP_IPV6_ADDR_T lIPv6Address;
199
200     lNetif = IPEndPointBasis::FindNetifFromInterfaceId(aInterfaceId);
201     VerifyOrExit(lNetif != NULL, lRetval = INET_ERROR_UNKNOWN_INTERFACE);
202
203     lIPv6Address = IPV6_TO_LWIPADDR(aAddress);
204
205     lStatus = aMethod(lNetif, &lIPv6Address);
206
207     switch (lStatus)
208     {
209
210     case ERR_MEM:
211         lRetval = INET_ERROR_NO_MEMORY;
212         break;
213
214     default:
215         lRetval = chip::System::MapErrorLwIP(lStatus);
216         break;
217     }
218
219 exit:
220     return (lRetval);
221 }
222 #endif // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
223 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
224
225 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
226 #if IP_MULTICAST_LOOP || IPV6_MULTICAST_LOOP
227 static INET_ERROR SocketsSetMulticastLoopback(int aSocket, bool aLoopback, int aProtocol, int aOption)
228 {
229     INET_ERROR lRetval = INET_NO_ERROR;
230     int lStatus;
231     unsigned int lValue = aLoopback;
232
233     lStatus = setsockopt(aSocket, aProtocol, aOption, &lValue, sizeof(lValue));
234     VerifyOrExit(lStatus == 0, lRetval = chip::System::MapErrorPOSIX(errno));
235
236 exit:
237     return (lRetval);
238 }
239 #endif // IP_MULTICAST_LOOP || IPV6_MULTICAST_LOOP
240
241 static INET_ERROR SocketsSetMulticastLoopback(int aSocket, IPVersion aIPVersion, bool aLoopback)
242 {
243 #ifdef IPV6_MULTICAST_LOOP
244     INET_ERROR lRetval;
245
246     switch (aIPVersion)
247     {
248
249     case kIPVersion_6:
250         lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
251         break;
252
253 #if INET_CONFIG_ENABLE_IPV4
254     case kIPVersion_4:
255         lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IP, IP_MULTICAST_LOOP);
256         break;
257 #endif // INET_CONFIG_ENABLE_IPV4
258
259     default:
260         lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
261         break;
262     }
263
264     return (lRetval);
265 #else  // IPV6_MULTICAST_LOOP
266     return INET_ERROR_NOT_SUPPORTED;
267 #endif // IPV6_MULTICAST_LOOP
268 }
269
270 #if INET_CONFIG_ENABLE_IPV4
271 static INET_ERROR SocketsIPv4JoinLeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress,
272                                                      int aCommand)
273 {
274     INET_ERROR lRetval = INET_NO_ERROR;
275     IPAddress lInterfaceAddress;
276     bool lInterfaceAddressFound = false;
277     struct ip_mreq lMulticastRequest;
278
279     for (InterfaceAddressIterator lAddressIterator; lAddressIterator.HasCurrent(); lAddressIterator.Next())
280     {
281         const IPAddress lCurrentAddress = lAddressIterator.GetAddress();
282
283         if (lAddressIterator.GetInterface() == aInterfaceId)
284         {
285             if (lCurrentAddress.IsIPv4())
286             {
287                 lInterfaceAddressFound = true;
288                 lInterfaceAddress      = lCurrentAddress;
289                 break;
290             }
291         }
292     }
293
294     VerifyOrExit(lInterfaceAddressFound, lRetval = INET_ERROR_ADDRESS_NOT_FOUND);
295
296     memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
297     lMulticastRequest.imr_interface = lInterfaceAddress.ToIPv4();
298     lMulticastRequest.imr_multiaddr = aAddress.ToIPv4();
299
300     lRetval = setsockopt(aSocket, IPPROTO_IP, aCommand, &lMulticastRequest, sizeof(lMulticastRequest));
301     VerifyOrExit(lRetval == 0, lRetval = chip::System::MapErrorPOSIX(errno));
302
303 exit:
304     return (lRetval);
305 }
306 #endif // INET_CONFIG_ENABLE_IPV4
307
308 #if INET_IPV6_ADD_MEMBERSHIP || INET_IPV6_DROP_MEMBERSHIP
309 static INET_ERROR SocketsIPv6JoinLeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress,
310                                                      int aCommand)
311 {
312     INET_ERROR lRetval          = INET_NO_ERROR;
313     const unsigned int lIfIndex = static_cast<unsigned int>(aInterfaceId);
314     struct ipv6_mreq lMulticastRequest;
315
316     // Check whether that cast we did was actually safe.  We can't VerifyOrExit
317     // before declaring variables, and can't reassign lIfIndex without making it
318     // non-const, so have to do things in this order.
319     VerifyOrExit(CanCastTo<unsigned int>(aInterfaceId), lRetval = INET_ERROR_UNEXPECTED_EVENT);
320
321     memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
322     VerifyOrExit(CanCastTo<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex), lRetval = INET_ERROR_UNEXPECTED_EVENT);
323
324     lMulticastRequest.ipv6mr_interface = static_cast<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex);
325     lMulticastRequest.ipv6mr_multiaddr = aAddress.ToIPv6();
326
327     lRetval = setsockopt(aSocket, IPPROTO_IPV6, aCommand, &lMulticastRequest, sizeof(lMulticastRequest));
328     VerifyOrExit(lRetval == 0, lRetval = chip::System::MapErrorPOSIX(errno));
329
330 exit:
331     return (lRetval);
332 }
333 #endif // INET_IPV6_ADD_MEMBERSHIP || INET_IPV6_DROP_MEMBERSHIP
334
335 static INET_ERROR SocketsIPv6JoinMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress)
336 {
337 #if INET_IPV6_ADD_MEMBERSHIP
338     return SocketsIPv6JoinLeaveMulticastGroup(aSocket, aInterfaceId, aAddress, INET_IPV6_ADD_MEMBERSHIP);
339 #else
340     return INET_ERROR_NOT_SUPPORTED;
341 #endif
342 }
343
344 static INET_ERROR SocketsIPv6LeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress)
345 {
346 #if INET_IPV6_DROP_MEMBERSHIP
347     return SocketsIPv6JoinLeaveMulticastGroup(aSocket, aInterfaceId, aAddress, INET_IPV6_DROP_MEMBERSHIP);
348 #else
349     return INET_ERROR_NOT_SUPPORTED;
350 #endif
351 }
352
353 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
354
355 /**
356  *  @brief Set whether IP multicast traffic should be looped back.
357  *
358  *  @param[in]   aIPVersion
359  *
360  *  @param[in]   aLoopback
361  *
362  *  @retval  INET_NO_ERROR
363  *       success: multicast loopback behavior set
364  *  @retval  other
365  *       another system or platform error
366  *
367  *  @details
368  *     Set whether or not IP multicast traffic should be looped back
369  *     to this endpoint.
370  *
371  */
372 INET_ERROR IPEndPointBasis::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback)
373 {
374     INET_ERROR lRetval = INET_ERROR_NOT_IMPLEMENTED;
375
376 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
377 #if CHIP_SYSTEM_CONFIG_USE_LWIP
378 #if !HAVE_LWIP_MULTICAST_LOOP
379     lRetval = INET_ERROR_NOT_SUPPORTED;
380 #else
381     if (aLoopback)
382     {
383         switch (mLwIPEndPointType)
384         {
385
386 #if INET_CONFIG_ENABLE_RAW_ENDPOINT
387         case kLwIPEndPointType_Raw:
388             raw_set_flags(mRaw, RAW_FLAGS_MULTICAST_LOOP);
389             break;
390 #endif // INET_CONFIG_ENABLE_RAW_ENDPOINT
391
392 #if INET_CONFIG_ENABLE_UDP_ENDPOINT
393         case kLwIPEndPointType_UDP:
394             udp_set_flags(mUDP, UDP_FLAGS_MULTICAST_LOOP);
395             break;
396 #endif // INET_CONFIG_ENABLE_UDP_ENDPOINT
397
398         default:
399             lRetval = INET_ERROR_NOT_SUPPORTED;
400             break;
401         }
402     }
403     else
404     {
405         switch (mLwIPEndPointType)
406         {
407
408 #if INET_CONFIG_ENABLE_RAW_ENDPOINT
409         case kLwIPEndPointType_Raw:
410             raw_clear_flags(mRaw, RAW_FLAGS_MULTICAST_LOOP);
411             break;
412 #endif // INET_CONFIG_ENABLE_RAW_ENDPOINT
413
414 #if INET_CONFIG_ENABLE_UDP_ENDPOINT
415         case kLwIPEndPointType_UDP:
416             udp_clear_flags(mUDP, UDP_FLAGS_MULTICAST_LOOP);
417             break;
418 #endif // INET_CONFIG_ENABLE_UDP_ENDPOINT
419
420         default:
421             lRetval = INET_ERROR_NOT_SUPPORTED;
422             break;
423         }
424     }
425
426     lRetval = INET_NO_ERROR;
427 #endif // !HAVE_LWIP_MULTICAST_LOOP
428 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
429
430 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
431     lRetval = SocketsSetMulticastLoopback(mSocket, aIPVersion, aLoopback);
432     SuccessOrExit(lRetval);
433
434 exit:
435 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
436 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
437     return (lRetval);
438 }
439
440 /**
441  *  @brief Join an IP multicast group.
442  *
443  *  @param[in]   aInterfaceId  the indicator of the network interface to
444  *                             add to the multicast group
445  *
446  *  @param[in]   aAddress      the multicast group to add the
447  *                             interface to
448  *
449  *  @retval  INET_NO_ERROR
450  *       success: multicast group removed
451  *
452  *  @retval  INET_ERROR_UNKNOWN_INTERFACE
453  *       unknown network interface, \c aInterfaceId
454  *
455  *  @retval  INET_ERROR_WRONG_ADDRESS_TYPE
456  *       \c aAddress is not \c kIPAddressType_IPv4 or
457  *       \c kIPAddressType_IPv6 or is not multicast
458  *
459  *  @retval  other
460  *       another system or platform error
461  *
462  *  @details
463  *     Join the endpoint to the supplied multicast group on the
464  *     specified interface.
465  *
466  */
467 INET_ERROR IPEndPointBasis::JoinMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress)
468 {
469     INET_ERROR lRetval = INET_ERROR_NOT_IMPLEMENTED;
470
471 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
472     const IPAddressType lAddrType = aAddress.Type();
473     lRetval                       = CheckMulticastGroupArgs(aInterfaceId, aAddress);
474     SuccessOrExit(lRetval);
475
476     switch (lAddrType)
477     {
478
479 #if INET_CONFIG_ENABLE_IPV4
480     case kIPAddressType_IPv4: {
481 #if CHIP_SYSTEM_CONFIG_USE_LWIP
482 #if LWIP_IPV4 && LWIP_IGMP
483         lRetval = LwIPIPv4JoinLeaveMulticastGroup(aInterfaceId, aAddress, igmp_joingroup_netif);
484 #else  // LWIP_IPV4 && LWIP_IGMP
485         lRetval = INET_ERROR_NOT_SUPPORTED;
486 #endif // LWIP_IPV4 && LWIP_IGMP
487         SuccessOrExit(lRetval);
488 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
489
490 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
491         lRetval = SocketsIPv4JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, IP_ADD_MEMBERSHIP);
492         SuccessOrExit(lRetval);
493 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
494     }
495     break;
496 #endif // INET_CONFIG_ENABLE_IPV4
497
498     case kIPAddressType_IPv6: {
499 #if CHIP_SYSTEM_CONFIG_USE_LWIP
500 #ifdef HAVE_IPV6_MULTICAST
501         lRetval = LwIPIPv6JoinLeaveMulticastGroup(aInterfaceId, aAddress, mld6_joingroup_netif);
502 #else  // HAVE_IPV6_MULTICAST
503         lRetval = INET_ERROR_NOT_SUPPORTED;
504 #endif // HAVE_IPV6_MULTICAST
505         SuccessOrExit(lRetval);
506 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
507
508 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
509         lRetval = SocketsIPv6JoinMulticastGroup(mSocket, aInterfaceId, aAddress);
510         SuccessOrExit(lRetval);
511 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
512     }
513     break;
514
515     default:
516         lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
517         break;
518     }
519
520 exit:
521 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
522     return (lRetval);
523 }
524
525 /**
526  *  @brief Leave an IP multicast group.
527  *
528  *  @param[in]   aInterfaceId  the indicator of the network interface to
529  *                             remove from the multicast group
530  *
531  *  @param[in]   aAddress      the multicast group to remove the
532  *                             interface from
533  *
534  *  @retval  INET_NO_ERROR
535  *       success: multicast group removed
536  *
537  *  @retval  INET_ERROR_UNKNOWN_INTERFACE
538  *       unknown network interface, \c aInterfaceId
539  *
540  *  @retval  INET_ERROR_WRONG_ADDRESS_TYPE
541  *       \c aAddress is not \c kIPAddressType_IPv4 or
542  *       \c kIPAddressType_IPv6 or is not multicast
543  *
544  *  @retval  other
545  *       another system or platform error
546  *
547  *  @details
548  *     Remove the endpoint from the supplied multicast group on the
549  *     specified interface.
550  *
551  */
552 INET_ERROR IPEndPointBasis::LeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress)
553 {
554     INET_ERROR lRetval = INET_ERROR_NOT_IMPLEMENTED;
555
556 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
557     const IPAddressType lAddrType = aAddress.Type();
558     lRetval                       = CheckMulticastGroupArgs(aInterfaceId, aAddress);
559     SuccessOrExit(lRetval);
560
561     switch (lAddrType)
562     {
563
564 #if INET_CONFIG_ENABLE_IPV4
565     case kIPAddressType_IPv4: {
566 #if CHIP_SYSTEM_CONFIG_USE_LWIP
567 #if LWIP_IPV4 && LWIP_IGMP
568         lRetval = LwIPIPv4JoinLeaveMulticastGroup(aInterfaceId, aAddress, igmp_leavegroup_netif);
569 #else  // LWIP_IPV4 && LWIP_IGMP
570         lRetval = INET_ERROR_NOT_SUPPORTED;
571 #endif // LWIP_IPV4 && LWIP_IGMP
572         SuccessOrExit(lRetval);
573 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
574
575 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
576         lRetval = SocketsIPv4JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, IP_DROP_MEMBERSHIP);
577         SuccessOrExit(lRetval);
578 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
579     }
580     break;
581 #endif // INET_CONFIG_ENABLE_IPV4
582
583     case kIPAddressType_IPv6: {
584 #if CHIP_SYSTEM_CONFIG_USE_LWIP
585 #if LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
586         lRetval = LwIPIPv6JoinLeaveMulticastGroup(aInterfaceId, aAddress, mld6_leavegroup_netif);
587 #else  // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
588         lRetval = INET_ERROR_NOT_SUPPORTED;
589 #endif // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
590         SuccessOrExit(lRetval);
591 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
592
593 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
594         lRetval = SocketsIPv6LeaveMulticastGroup(mSocket, aInterfaceId, aAddress);
595         SuccessOrExit(lRetval);
596 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
597     }
598     break;
599
600     default:
601         lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
602         break;
603     }
604
605 exit:
606 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
607     return (lRetval);
608 }
609
610 void IPEndPointBasis::Init(InetLayer * aInetLayer)
611 {
612     InitEndPointBasis(*aInetLayer);
613
614 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
615     mBoundIntfId = INET_NULL_INTERFACEID;
616 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
617 }
618
619 #if CHIP_SYSTEM_CONFIG_USE_LWIP
620 void IPEndPointBasis::HandleDataReceived(System::PacketBufferHandle aBuffer)
621 {
622     if ((mState == kState_Listening) && (OnMessageReceived != NULL))
623     {
624         const IPPacketInfo * pktInfo = GetPacketInfo(aBuffer);
625
626         if (pktInfo != NULL)
627         {
628             const IPPacketInfo pktInfoCopy = *pktInfo; // copy the address info so that the app can free the
629                                                        // PacketBuffer without affecting access to address info.
630             OnMessageReceived(this, std::move(aBuffer), &pktInfoCopy);
631         }
632         else
633         {
634             if (OnReceiveError != NULL)
635                 OnReceiveError(this, INET_ERROR_INBOUND_MESSAGE_TOO_BIG, NULL);
636         }
637     }
638 }
639
640 /**
641  *  @brief Get LwIP IP layer source and destination addressing information.
642  *
643  *  @param[in]   aBuffer       the packet buffer containing the IP message
644  *
645  *  @returns  a pointer to the address information on success; otherwise,
646  *            NULL if there is insufficient space in the packet for
647  *            the address information.
648  *
649  *  @details
650  *     When using LwIP information about the packet is 'hidden' in the
651  *     reserved space before the start of the data in the packet
652  *     buffer. This is necessary because the system layer events only
653  *     have two arguments, which in this case are used to convey the
654  *     pointer to the end point and the pointer to the buffer.
655  *
656  *     In most cases this trick of storing information before the data
657  *     works because the first buffer in an LwIP IP message contains
658  *     the space that was used for the Ethernet/IP/UDP headers. However,
659  *     given the current size of the IPPacketInfo structure (40 bytes),
660  *     it is possible for there to not be enough room to store the
661  *     structure along with the payload in a single packet buffer. In
662  *     practice, this should only happen for extremely large IPv4
663  *     packets that arrive without an Ethernet header.
664  *
665  */
666 IPPacketInfo * IPEndPointBasis::GetPacketInfo(const System::PacketBufferHandle & aBuffer)
667 {
668     uintptr_t lStart;
669     uintptr_t lPacketInfoStart;
670     IPPacketInfo * lPacketInfo = NULL;
671
672     if (!aBuffer->EnsureReservedSize(sizeof(IPPacketInfo) + 3))
673         goto done;
674
675     lStart           = (uintptr_t) aBuffer->Start();
676     lPacketInfoStart = lStart - sizeof(IPPacketInfo);
677
678     // Align to a 4-byte boundary
679
680     lPacketInfo = reinterpret_cast<IPPacketInfo *>(lPacketInfoStart & ~(sizeof(uint32_t) - 1));
681
682 done:
683     return (lPacketInfo);
684 }
685
686 System::Error IPEndPointBasis::PostPacketBufferEvent(chip::System::Layer & aLayer, System::Object & aTarget,
687                                                      System::EventType aEventType, System::PacketBufferHandle aBuffer)
688 {
689     System::Error error =
690         aLayer.PostEvent(aTarget, aEventType, (uintptr_t) System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(aBuffer));
691     if (error == INET_NO_ERROR)
692     {
693         // If PostEvent() succeeded, it has ownership of the buffer, so we need to release it (without freeing it).
694         static_cast<void>(std::move(aBuffer).UnsafeRelease());
695     }
696     return error;
697 }
698
699 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
700
701 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
702 INET_ERROR IPEndPointBasis::Bind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort, InterfaceId aInterfaceId)
703 {
704     INET_ERROR lRetval = INET_NO_ERROR;
705
706     if (aAddressType == kIPAddressType_IPv6)
707     {
708         struct sockaddr_in6 sa;
709
710         memset(&sa, 0, sizeof(sa));
711
712         sa.sin6_family = AF_INET6;
713         sa.sin6_port   = htons(aPort);
714         sa.sin6_addr   = aAddress.ToIPv6();
715         if (!CanCastTo<decltype(sa.sin6_scope_id)>(aInterfaceId))
716         {
717             return INET_ERROR_INCORRECT_STATE;
718         }
719         sa.sin6_scope_id = static_cast<decltype(sa.sin6_scope_id)>(aInterfaceId);
720
721         if (bind(mSocket, reinterpret_cast<const sockaddr *>(&sa), static_cast<unsigned>(sizeof(sa))) != 0)
722             lRetval = chip::System::MapErrorPOSIX(errno);
723
724             // Instruct the kernel that any messages to multicast destinations should be
725             // sent down the interface specified by the caller.
726 #ifdef IPV6_MULTICAST_IF
727         if (lRetval == INET_NO_ERROR)
728             setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &aInterfaceId, sizeof(aInterfaceId));
729 #endif // defined(IPV6_MULTICAST_IF)
730
731             // Instruct the kernel that any messages to multicast destinations should be
732             // set with the configured hop limit value.
733 #ifdef IPV6_MULTICAST_HOPS
734         int hops = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
735         setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
736 #endif // defined(IPV6_MULTICAST_HOPS)
737     }
738 #if INET_CONFIG_ENABLE_IPV4
739     else if (aAddressType == kIPAddressType_IPv4)
740     {
741         struct sockaddr_in sa;
742         int enable = 1;
743
744         memset(&sa, 0, sizeof(sa));
745
746         sa.sin_family = AF_INET;
747         sa.sin_port   = htons(aPort);
748         sa.sin_addr   = aAddress.ToIPv4();
749
750         if (bind(mSocket, reinterpret_cast<const sockaddr *>(&sa), static_cast<unsigned>(sizeof(sa))) != 0)
751             lRetval = chip::System::MapErrorPOSIX(errno);
752
753             // Instruct the kernel that any messages to multicast destinations should be
754             // sent down the interface to which the specified IPv4 address is bound.
755 #ifdef IP_MULTICAST_IF
756         if (lRetval == INET_NO_ERROR)
757             setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_IF, &sa, sizeof(sa));
758 #endif // defined(IP_MULTICAST_IF)
759
760             // Instruct the kernel that any messages to multicast destinations should be
761             // set with the configured hop limit value.
762 #ifdef IP_MULTICAST_TTL
763         int ttl = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
764         setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
765 #endif // defined(IP_MULTICAST_TTL)
766
767         // Allow socket transmitting broadcast packets.
768         if (lRetval == INET_NO_ERROR)
769             setsockopt(mSocket, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(enable));
770     }
771 #endif // INET_CONFIG_ENABLE_IPV4
772     else
773         lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
774
775     return (lRetval);
776 }
777
778 INET_ERROR IPEndPointBasis::BindInterface(IPAddressType aAddressType, InterfaceId aInterfaceId)
779 {
780     INET_ERROR lRetval = INET_NO_ERROR;
781
782 #if HAVE_SO_BINDTODEVICE
783     if (aInterfaceId == INET_NULL_INTERFACEID)
784     {
785         // Stop interface-based filtering.
786         if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, "", 0) == -1)
787         {
788             lRetval = chip::System::MapErrorPOSIX(errno);
789         }
790     }
791     else
792     {
793         // Start filtering on the passed interface.
794         char lInterfaceName[IF_NAMESIZE];
795
796         if (if_indextoname(aInterfaceId, lInterfaceName) == NULL)
797         {
798             lRetval = chip::System::MapErrorPOSIX(errno);
799         }
800
801         if (lRetval == INET_NO_ERROR &&
802             setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, lInterfaceName, socklen_t(strlen(lInterfaceName))) == -1)
803         {
804             lRetval = chip::System::MapErrorPOSIX(errno);
805         }
806     }
807
808     if (lRetval == INET_NO_ERROR)
809         mBoundIntfId = aInterfaceId;
810
811 #else  // !HAVE_SO_BINDTODEVICE
812     lRetval = INET_ERROR_NOT_IMPLEMENTED;
813 #endif // HAVE_SO_BINDTODEVICE
814
815     return (lRetval);
816 }
817
818 INET_ERROR IPEndPointBasis::SendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle aBuffer, uint16_t aSendFlags)
819 {
820     INET_ERROR res = INET_NO_ERROR;
821     PeerSockAddr peerSockAddr;
822     struct iovec msgIOV;
823     uint8_t controlData[256];
824     struct msghdr msgHeader;
825     InterfaceId intfId = aPktInfo->Interface;
826
827     // Ensure the destination address type is compatible with the endpoint address type.
828     VerifyOrExit(mAddrType == aPktInfo->DestAddress.Type(), res = INET_ERROR_BAD_ARGS);
829
830     // For now the entire message must fit within a single buffer.
831     VerifyOrExit(!aBuffer->HasChainedBuffer(), res = INET_ERROR_MESSAGE_TOO_LONG);
832
833     memset(&msgHeader, 0, sizeof(msgHeader));
834
835     msgIOV.iov_base      = aBuffer->Start();
836     msgIOV.iov_len       = aBuffer->DataLength();
837     msgHeader.msg_iov    = &msgIOV;
838     msgHeader.msg_iovlen = 1;
839
840     // Construct a sockaddr_in/sockaddr_in6 structure containing the destination information.
841     memset(&peerSockAddr, 0, sizeof(peerSockAddr));
842     msgHeader.msg_name = &peerSockAddr;
843     if (mAddrType == kIPAddressType_IPv6)
844     {
845         peerSockAddr.in6.sin6_family = AF_INET6;
846         peerSockAddr.in6.sin6_port   = htons(aPktInfo->DestPort);
847         peerSockAddr.in6.sin6_addr   = aPktInfo->DestAddress.ToIPv6();
848         VerifyOrExit(CanCastTo<decltype(peerSockAddr.in6.sin6_scope_id)>(aPktInfo->Interface), res = INET_ERROR_INCORRECT_STATE);
849         peerSockAddr.in6.sin6_scope_id = static_cast<decltype(peerSockAddr.in6.sin6_scope_id)>(aPktInfo->Interface);
850         msgHeader.msg_namelen          = sizeof(sockaddr_in6);
851     }
852 #if INET_CONFIG_ENABLE_IPV4
853     else
854     {
855         peerSockAddr.in.sin_family = AF_INET;
856         peerSockAddr.in.sin_port   = htons(aPktInfo->DestPort);
857         peerSockAddr.in.sin_addr   = aPktInfo->DestAddress.ToIPv4();
858         msgHeader.msg_namelen      = sizeof(sockaddr_in);
859     }
860 #endif // INET_CONFIG_ENABLE_IPV4
861
862     // If the endpoint has been bound to a particular interface,
863     // and the caller didn't supply a specific interface to send
864     // on, use the bound interface. This appears to be necessary
865     // for messages to multicast addresses, which under Linux
866     // don't seem to get sent out the correct interface, despite
867     // the socket being bound.
868     if (intfId == INET_NULL_INTERFACEID)
869         intfId = mBoundIntfId;
870
871     // If the packet should be sent over a specific interface, or with a specific source
872     // address, construct an IP_PKTINFO/IPV6_PKTINFO "control message" to that effect
873     // add add it to the message header.  If the local OS doesn't support IP_PKTINFO/IPV6_PKTINFO
874     // fail with an error.
875     if (intfId != INET_NULL_INTERFACEID || aPktInfo->SrcAddress.Type() != kIPAddressType_Any)
876     {
877 #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
878         memset(controlData, 0, sizeof(controlData));
879         msgHeader.msg_control    = controlData;
880         msgHeader.msg_controllen = sizeof(controlData);
881
882         struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader);
883
884 #if INET_CONFIG_ENABLE_IPV4
885
886         if (mAddrType == kIPAddressType_IPv4)
887         {
888 #if defined(IP_PKTINFO)
889             controlHdr->cmsg_level = IPPROTO_IP;
890             controlHdr->cmsg_type  = IP_PKTINFO;
891             controlHdr->cmsg_len   = CMSG_LEN(sizeof(in_pktinfo));
892
893             struct in_pktinfo * pktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
894             if (!CanCastTo<decltype(pktInfo->ipi_ifindex)>(intfId))
895             {
896                 ExitNow(res = INET_ERROR_NOT_SUPPORTED);
897             }
898
899             pktInfo->ipi_ifindex  = static_cast<decltype(pktInfo->ipi_ifindex)>(intfId);
900             pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4();
901
902             msgHeader.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo));
903 #else  // !defined(IP_PKTINFO)
904             ExitNow(res = INET_ERROR_NOT_SUPPORTED);
905 #endif // !defined(IP_PKTINFO)
906         }
907
908 #endif // INET_CONFIG_ENABLE_IPV4
909
910         if (mAddrType == kIPAddressType_IPv6)
911         {
912 #if defined(IPV6_PKTINFO)
913             controlHdr->cmsg_level = IPPROTO_IPV6;
914             controlHdr->cmsg_type  = IPV6_PKTINFO;
915             controlHdr->cmsg_len   = CMSG_LEN(sizeof(in6_pktinfo));
916
917             struct in6_pktinfo * pktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
918             if (!CanCastTo<decltype(pktInfo->ipi6_ifindex)>(intfId))
919             {
920                 ExitNow(res = INET_ERROR_UNEXPECTED_EVENT);
921             }
922             pktInfo->ipi6_ifindex = static_cast<decltype(pktInfo->ipi6_ifindex)>(intfId);
923             pktInfo->ipi6_addr    = aPktInfo->SrcAddress.ToIPv6();
924
925             msgHeader.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo));
926 #else  // !defined(IPV6_PKTINFO)
927             ExitNow(res = INET_ERROR_NOT_SUPPORTED);
928 #endif // !defined(IPV6_PKTINFO)
929         }
930
931 #else  // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
932         IgnoreUnusedVariable(controlData);
933         ExitNow(res = INET_ERROR_NOT_SUPPORTED);
934 #endif // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
935     }
936
937     // Send IP packet.
938     {
939         const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0);
940         if (lenSent == -1)
941             res = chip::System::MapErrorPOSIX(errno);
942         else if (lenSent != aBuffer->DataLength())
943             res = INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED;
944     }
945
946 exit:
947     return (res);
948 }
949
950 INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int aProtocol)
951 {
952     INET_ERROR res = INET_NO_ERROR;
953
954     if (mSocket == INET_INVALID_SOCKET_FD)
955     {
956         const int one = 1;
957         int family;
958
959         switch (aAddressType)
960         {
961         case kIPAddressType_IPv6:
962             family = PF_INET6;
963             break;
964
965 #if INET_CONFIG_ENABLE_IPV4
966         case kIPAddressType_IPv4:
967             family = PF_INET;
968             break;
969 #endif // INET_CONFIG_ENABLE_IPV4
970
971         default:
972             return INET_ERROR_WRONG_ADDRESS_TYPE;
973         }
974
975         mSocket = ::socket(family, aType, aProtocol);
976         if (mSocket == -1)
977             return chip::System::MapErrorPOSIX(errno);
978
979         mAddrType = aAddressType;
980
981         // NOTE WELL: the errors returned by setsockopt() here are not
982         // returned as Inet layer chip::System::MapErrorPOSIX(errno)
983         // codes because they are normally expected to fail on some
984         // platforms where the socket option code is defined in the
985         // header files but not [yet] implemented. Certainly, there is
986         // room to improve this by connecting the build configuration
987         // logic up to check for implementations of these options and
988         // to provide appropriate HAVE_xxxxx definitions accordingly.
989
990         res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
991         static_cast<void>(res);
992
993 #ifdef SO_REUSEPORT
994         res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
995         if (res != 0)
996         {
997             ChipLogError(Inet, "SO_REUSEPORT failed: %d", errno);
998         }
999 #endif // defined(SO_REUSEPORT)
1000
1001         // If creating an IPv6 socket, tell the kernel that it will be
1002         // IPv6 only.  This makes it posible to bind two sockets to
1003         // the same port, one for IPv4 and one for IPv6.
1004
1005 #ifdef IPV6_V6ONLY
1006         if (aAddressType == kIPAddressType_IPv6)
1007         {
1008             res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
1009             if (res != 0)
1010             {
1011                 ChipLogError(Inet, "IPV6_V6ONLY failed: %d", errno);
1012             }
1013         }
1014 #endif // defined(IPV6_V6ONLY)
1015
1016 #if INET_CONFIG_ENABLE_IPV4
1017 #ifdef IP_PKTINFO
1018         if (aAddressType == kIPAddressType_IPv4)
1019         {
1020             res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
1021             if (res != 0)
1022             {
1023                 ChipLogError(Inet, "IP_PKTINFO failed: %d", errno);
1024             }
1025         }
1026 #endif // defined(IP_PKTINFO)
1027 #endif // INET_CONFIG_ENABLE_IPV4
1028
1029 #ifdef IPV6_RECVPKTINFO
1030         if (aAddressType == kIPAddressType_IPv6)
1031         {
1032             res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
1033             if (res != 0)
1034             {
1035                 ChipLogError(Inet, "IPV6_PKTINFO failed: %d", errno);
1036             }
1037         }
1038 #endif // defined(IPV6_RECVPKTINFO)
1039
1040         // On systems that support it, disable the delivery of SIGPIPE
1041         // signals when writing to a closed socket.  This is mostly
1042         // needed on iOS which has the peculiar habit of sending
1043         // SIGPIPEs on unconnected UDP sockets.
1044 #ifdef SO_NOSIGPIPE
1045         {
1046             res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
1047             if (res != 0)
1048             {
1049                 ChipLogError(Inet, "SO_NOSIGPIPE failed: %d", errno);
1050             }
1051         }
1052 #endif // defined(SO_NOSIGPIPE)
1053     }
1054     else if (mAddrType != aAddressType)
1055     {
1056         return INET_ERROR_INCORRECT_STATE;
1057     }
1058
1059     return INET_NO_ERROR;
1060 }
1061
1062 SocketEvents IPEndPointBasis::PrepareIO()
1063 {
1064     SocketEvents res;
1065
1066     if (mState == kState_Listening && OnMessageReceived != nullptr)
1067         res.SetRead();
1068
1069     return res;
1070 }
1071
1072 void IPEndPointBasis::HandlePendingIO(uint16_t aPort)
1073 {
1074     INET_ERROR lStatus = INET_NO_ERROR;
1075     IPPacketInfo lPacketInfo;
1076     System::PacketBufferHandle lBuffer;
1077
1078     lPacketInfo.Clear();
1079     lPacketInfo.DestPort = aPort;
1080
1081     lBuffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSizeWithoutReserve, 0);
1082
1083     if (!lBuffer.IsNull())
1084     {
1085         struct iovec msgIOV;
1086         PeerSockAddr lPeerSockAddr;
1087         uint8_t controlData[256];
1088         struct msghdr msgHeader;
1089
1090         msgIOV.iov_base = lBuffer->Start();
1091         msgIOV.iov_len  = lBuffer->AvailableDataLength();
1092
1093         memset(&lPeerSockAddr, 0, sizeof(lPeerSockAddr));
1094
1095         memset(&msgHeader, 0, sizeof(msgHeader));
1096
1097         msgHeader.msg_name       = &lPeerSockAddr;
1098         msgHeader.msg_namelen    = sizeof(lPeerSockAddr);
1099         msgHeader.msg_iov        = &msgIOV;
1100         msgHeader.msg_iovlen     = 1;
1101         msgHeader.msg_control    = controlData;
1102         msgHeader.msg_controllen = sizeof(controlData);
1103
1104         ssize_t rcvLen = recvmsg(mSocket, &msgHeader, MSG_DONTWAIT);
1105
1106         if (rcvLen < 0)
1107         {
1108             lStatus = chip::System::MapErrorPOSIX(errno);
1109         }
1110         else if (rcvLen > lBuffer->AvailableDataLength())
1111         {
1112             lStatus = INET_ERROR_INBOUND_MESSAGE_TOO_BIG;
1113         }
1114         else
1115         {
1116             lBuffer->SetDataLength(static_cast<uint16_t>(rcvLen));
1117
1118             if (lPeerSockAddr.any.sa_family == AF_INET6)
1119             {
1120                 lPacketInfo.SrcAddress = IPAddress::FromIPv6(lPeerSockAddr.in6.sin6_addr);
1121                 lPacketInfo.SrcPort    = ntohs(lPeerSockAddr.in6.sin6_port);
1122             }
1123 #if INET_CONFIG_ENABLE_IPV4
1124             else if (lPeerSockAddr.any.sa_family == AF_INET)
1125             {
1126                 lPacketInfo.SrcAddress = IPAddress::FromIPv4(lPeerSockAddr.in.sin_addr);
1127                 lPacketInfo.SrcPort    = ntohs(lPeerSockAddr.in.sin_port);
1128             }
1129 #endif // INET_CONFIG_ENABLE_IPV4
1130             else
1131             {
1132                 lStatus = INET_ERROR_INCORRECT_STATE;
1133             }
1134         }
1135
1136         if (lStatus == INET_NO_ERROR)
1137         {
1138             for (struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); controlHdr != nullptr;
1139                  controlHdr                  = CMSG_NXTHDR(&msgHeader, controlHdr))
1140             {
1141 #if INET_CONFIG_ENABLE_IPV4
1142 #ifdef IP_PKTINFO
1143                 if (controlHdr->cmsg_level == IPPROTO_IP && controlHdr->cmsg_type == IP_PKTINFO)
1144                 {
1145                     struct in_pktinfo * inPktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
1146                     if (!CanCastTo<InterfaceId>(inPktInfo->ipi_ifindex))
1147                     {
1148                         lStatus = INET_ERROR_INCORRECT_STATE;
1149                         break;
1150                     }
1151                     lPacketInfo.Interface   = static_cast<InterfaceId>(inPktInfo->ipi_ifindex);
1152                     lPacketInfo.DestAddress = IPAddress::FromIPv4(inPktInfo->ipi_addr);
1153                     continue;
1154                 }
1155 #endif // defined(IP_PKTINFO)
1156 #endif // INET_CONFIG_ENABLE_IPV4
1157
1158 #ifdef IPV6_PKTINFO
1159                 if (controlHdr->cmsg_level == IPPROTO_IPV6 && controlHdr->cmsg_type == IPV6_PKTINFO)
1160                 {
1161                     struct in6_pktinfo * in6PktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
1162                     if (!CanCastTo<InterfaceId>(in6PktInfo->ipi6_ifindex))
1163                     {
1164                         lStatus = INET_ERROR_INCORRECT_STATE;
1165                         break;
1166                     }
1167                     lPacketInfo.Interface   = static_cast<InterfaceId>(in6PktInfo->ipi6_ifindex);
1168                     lPacketInfo.DestAddress = IPAddress::FromIPv6(in6PktInfo->ipi6_addr);
1169                     continue;
1170                 }
1171 #endif // defined(IPV6_PKTINFO)
1172             }
1173         }
1174     }
1175     else
1176     {
1177         lStatus = INET_ERROR_NO_MEMORY;
1178     }
1179
1180     if (lStatus == INET_NO_ERROR)
1181     {
1182         lBuffer.RightSize();
1183         OnMessageReceived(this, std::move(lBuffer), &lPacketInfo);
1184     }
1185     else
1186     {
1187         if (OnReceiveError != nullptr && lStatus != chip::System::MapErrorPOSIX(EAGAIN))
1188             OnReceiveError(this, lStatus, nullptr);
1189     }
1190 }
1191 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
1192
1193 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
1194 INET_ERROR IPEndPointBasis::ConfigureProtocol(IPAddressType aAddressType, const nw_parameters_t & aParameters)
1195 {
1196     INET_ERROR res = INET_NO_ERROR;
1197
1198     nw_protocol_stack_t protocolStack = nw_parameters_copy_default_protocol_stack(aParameters);
1199     nw_protocol_options_t ipOptions   = nw_protocol_stack_copy_internet_protocol(protocolStack);
1200
1201     switch (aAddressType)
1202     {
1203
1204     case kIPAddressType_IPv6:
1205         nw_ip_options_set_version(ipOptions, nw_ip_version_6);
1206         break;
1207
1208 #if INET_CONFIG_ENABLE_IPV4
1209     case kIPAddressType_IPv4:
1210         nw_ip_options_set_version(ipOptions, nw_ip_version_4);
1211         break;
1212 #endif // INET_CONFIG_ENABLE_IPV4
1213
1214     default:
1215         res = INET_ERROR_WRONG_ADDRESS_TYPE;
1216         break;
1217     }
1218     nw_release(ipOptions);
1219     nw_release(protocolStack);
1220
1221     return res;
1222 }
1223
1224 INET_ERROR IPEndPointBasis::Bind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort,
1225                                  const nw_parameters_t & aParameters)
1226 {
1227     INET_ERROR res         = INET_NO_ERROR;
1228     nw_endpoint_t endpoint = nullptr;
1229
1230     VerifyOrExit(aParameters != NULL, res = INET_ERROR_BAD_ARGS);
1231
1232     res = ConfigureProtocol(aAddressType, aParameters);
1233     SuccessOrExit(res);
1234
1235     res = GetEndPoint(endpoint, aAddressType, aAddress, aPort);
1236     nw_parameters_set_local_endpoint(aParameters, endpoint);
1237     nw_release(endpoint);
1238     SuccessOrExit(res);
1239
1240     mDispatchQueue = dispatch_queue_create("inet_dispatch_global", DISPATCH_QUEUE_CONCURRENT);
1241     VerifyOrExit(mDispatchQueue != NULL, res = INET_ERROR_NO_MEMORY);
1242     dispatch_retain(mDispatchQueue);
1243
1244     mConnectionSemaphore = dispatch_semaphore_create(0);
1245     VerifyOrExit(mConnectionSemaphore != NULL, res = INET_ERROR_NO_MEMORY);
1246     dispatch_retain(mConnectionSemaphore);
1247
1248     mSendSemaphore = dispatch_semaphore_create(0);
1249     VerifyOrExit(mSendSemaphore != NULL, res = INET_ERROR_NO_MEMORY);
1250     dispatch_retain(mSendSemaphore);
1251
1252     mAddrType   = aAddressType;
1253     mConnection = NULL;
1254
1255 exit:
1256     return res;
1257 }
1258
1259 INET_ERROR IPEndPointBasis::SendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle aBuffer, uint16_t aSendFlags)
1260 {
1261     __block INET_ERROR res = INET_NO_ERROR;
1262     dispatch_data_t content;
1263
1264     // Ensure the destination address type is compatible with the endpoint address type.
1265     VerifyOrExit(mAddrType == aPktInfo->DestAddress.Type(), res = INET_ERROR_BAD_ARGS);
1266
1267     // For now the entire message must fit within a single buffer.
1268     VerifyOrExit(aBuffer->Next() == NULL, res = INET_ERROR_MESSAGE_TOO_LONG);
1269
1270     res = GetConnection(aPktInfo);
1271     SuccessOrExit(res);
1272
1273     // Send a message, and wait for it to be dispatched.
1274     content = dispatch_data_create(aBuffer->Start(), aBuffer->DataLength(), mDispatchQueue, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
1275
1276     // If there is a current message pending and the state of the network connection change (e.g switch to a
1277     // different network) the connection will enter a nw_connection_state_failed state and the completion handler
1278     // will never be called. In such cases a signal is sent from the connection state change handler to release
1279     // the semaphore. In this case the INET_ERROR will not update with the result of the completion handler.
1280     // To make sure caller knows that sending a message has failed the following code consider there is an error
1281     // _unless_ the completion handler says otherwise.
1282     res = INET_ERROR_UNEXPECTED_EVENT;
1283     nw_connection_send(mConnection, content, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, true, ^(nw_error_t error) {
1284         if (error)
1285         {
1286             res = chip::System::MapErrorPOSIX(nw_error_get_error_code(error));
1287         }
1288         else
1289         {
1290             res = INET_NO_ERROR;
1291         }
1292         dispatch_semaphore_signal(mSendSemaphore);
1293     });
1294     dispatch_release(content);
1295
1296     dispatch_semaphore_wait(mSendSemaphore, DISPATCH_TIME_FOREVER);
1297
1298 exit:
1299     return res;
1300 }
1301
1302 void IPEndPointBasis::HandleDataReceived(const nw_connection_t & aConnection)
1303 {
1304
1305     nw_connection_receive_completion_t handler =
1306         ^(dispatch_data_t content, nw_content_context_t context, bool is_complete, nw_error_t receive_error) {
1307             dispatch_block_t schedule_next_receive = ^{
1308                 if (receive_error == NULL)
1309                 {
1310                     HandleDataReceived(aConnection);
1311                 }
1312                 else if (OnReceiveError != NULL)
1313                 {
1314                     nw_error_domain_t error_domain = nw_error_get_error_domain(receive_error);
1315                     errno                          = nw_error_get_error_code(receive_error);
1316                     if (!(error_domain == nw_error_domain_posix && errno == ECANCELED))
1317                     {
1318                         INET_ERROR error = chip::System::MapErrorPOSIX(errno);
1319                         IPPacketInfo packetInfo;
1320                         GetPacketInfo(aConnection, packetInfo);
1321                         dispatch_async(mDispatchQueue, ^{
1322                             OnReceiveError((IPEndPointBasis *) this, error, &packetInfo);
1323                         });
1324                     }
1325                 }
1326             };
1327
1328             if (content != NULL && OnMessageReceived != NULL)
1329             {
1330                 size_t count                              = dispatch_data_get_size(content);
1331                 System::PacketBufferHandle * packetBuffer = System::PacketBufferHandle::New(count);
1332                 dispatch_data_apply(content, ^(dispatch_data_t data, size_t offset, const void * buffer, size_t size) {
1333                     memmove(packetBuffer->Start() + offset, buffer, size);
1334                     return true;
1335                 });
1336                 packetBuffer->SetDataLength(count);
1337
1338                 IPPacketInfo packetInfo;
1339                 GetPacketInfo(aConnection, packetInfo);
1340                 dispatch_async(mDispatchQueue, ^{
1341                     OnMessageReceived((IPEndPointBasis *) this, packetBuffer, &packetInfo);
1342                 });
1343             }
1344
1345             schedule_next_receive();
1346         };
1347
1348     nw_connection_receive_message(aConnection, handler);
1349 }
1350
1351 void IPEndPointBasis::GetPacketInfo(const nw_connection_t & aConnection, IPPacketInfo & aPacketInfo)
1352 {
1353     nw_path_t path              = nw_connection_copy_current_path(aConnection);
1354     nw_endpoint_t dest_endpoint = nw_path_copy_effective_local_endpoint(path);
1355     nw_endpoint_t src_endpoint  = nw_path_copy_effective_remote_endpoint(path);
1356
1357     aPacketInfo.Clear();
1358     aPacketInfo.SrcAddress  = IPAddress::FromSockAddr(*nw_endpoint_get_address(src_endpoint));
1359     aPacketInfo.DestAddress = IPAddress::FromSockAddr(*nw_endpoint_get_address(dest_endpoint));
1360     aPacketInfo.SrcPort     = nw_endpoint_get_port(src_endpoint);
1361     aPacketInfo.DestPort    = nw_endpoint_get_port(dest_endpoint);
1362 }
1363
1364 INET_ERROR IPEndPointBasis::GetEndPoint(nw_endpoint_t & aEndPoint, const IPAddressType aAddressType, const IPAddress & aAddress,
1365                                         uint16_t aPort)
1366 {
1367     INET_ERROR res = INET_NO_ERROR;
1368     char addrStr[INET6_ADDRSTRLEN];
1369     char portStr[INET_PORTSTRLEN];
1370
1371     // Note: aAddress.ToString will return the IPv6 Any address if the address type is Any, but that's not what
1372     // we want if the locale endpoint is IPv4.
1373     if (aAddressType == kIPAddressType_IPv4 && aAddress.Type() == kIPAddressType_Any)
1374     {
1375         const IPAddress anyAddr = IPAddress::FromIPv4(aAddress.ToIPv4());
1376         anyAddr.ToString(addrStr, sizeof(addrStr));
1377     }
1378     else
1379     {
1380         aAddress.ToString(addrStr, sizeof(addrStr));
1381     }
1382
1383     snprintf(portStr, sizeof(portStr), "%u", aPort);
1384
1385     aEndPoint = nw_endpoint_create_host(addrStr, portStr);
1386     VerifyOrExit(aEndPoint != NULL, res = INET_ERROR_BAD_ARGS);
1387
1388 exit:
1389     return res;
1390 }
1391
1392 INET_ERROR IPEndPointBasis::GetConnection(const IPPacketInfo * aPktInfo)
1393 {
1394     INET_ERROR res             = INET_NO_ERROR;
1395     nw_endpoint_t endpoint     = NULL;
1396     nw_connection_t connection = NULL;
1397
1398     VerifyOrExit(mParameters != NULL, res = INET_ERROR_INCORRECT_STATE);
1399
1400     if (mConnection)
1401     {
1402         nw_path_t path                 = nw_connection_copy_current_path(mConnection);
1403         nw_endpoint_t remote_endpoint  = nw_path_copy_effective_remote_endpoint(path);
1404         const IPAddress remote_address = IPAddress::FromSockAddr(*nw_endpoint_get_address(remote_endpoint));
1405         const uint16_t remote_port     = nw_endpoint_get_port(remote_endpoint);
1406         const bool isDifferentEndPoint = aPktInfo->DestPort != remote_port || aPktInfo->DestAddress != remote_address;
1407         VerifyOrExit(isDifferentEndPoint, res = INET_NO_ERROR);
1408
1409         res = ReleaseConnection();
1410     }
1411     SuccessOrExit(res);
1412
1413     res = GetEndPoint(endpoint, mAddrType, aPktInfo->DestAddress, aPktInfo->DestPort);
1414     SuccessOrExit(res);
1415
1416     connection = nw_connection_create(endpoint, mParameters);
1417     nw_release(endpoint);
1418
1419     VerifyOrExit(connection != NULL, res = INET_ERROR_INCORRECT_STATE);
1420
1421     res = StartConnection(connection);
1422
1423 exit:
1424     return res;
1425 }
1426
1427 INET_ERROR IPEndPointBasis::StartListener()
1428 {
1429     __block INET_ERROR res = INET_NO_ERROR;
1430     nw_listener_t listener;
1431
1432     VerifyOrExit(mListener == NULL, res = INET_ERROR_INCORRECT_STATE);
1433     VerifyOrExit(mListenerSemaphore == NULL, res = INET_ERROR_INCORRECT_STATE);
1434     VerifyOrExit(mListenerQueue == NULL, res = INET_ERROR_INCORRECT_STATE);
1435
1436     listener = nw_listener_create(mParameters);
1437     VerifyOrExit(listener != NULL, res = INET_ERROR_INCORRECT_STATE);
1438
1439     mListenerSemaphore = dispatch_semaphore_create(0);
1440     VerifyOrExit(mListenerSemaphore != NULL, res = INET_ERROR_NO_MEMORY);
1441     dispatch_retain(mListenerSemaphore);
1442
1443     mListenerQueue = dispatch_queue_create("inet_dispatch_listener", DISPATCH_QUEUE_CONCURRENT);
1444     VerifyOrExit(mListenerQueue != NULL, res = INET_ERROR_NO_MEMORY);
1445     dispatch_retain(mListenerQueue);
1446
1447     nw_listener_set_queue(listener, mListenerQueue);
1448
1449     nw_listener_set_new_connection_handler(listener, ^(nw_connection_t connection) {
1450         ReleaseConnection();
1451         StartConnection(connection);
1452     });
1453
1454     nw_listener_set_state_changed_handler(listener, ^(nw_listener_state_t state, nw_error_t error) {
1455         switch (state)
1456         {
1457
1458         case nw_listener_state_invalid:
1459             ChipLogDetail(Inet, "Listener: Invalid");
1460             res = INET_ERROR_INCORRECT_STATE;
1461             nw_listener_cancel(listener);
1462             break;
1463
1464         case nw_listener_state_waiting:
1465             ChipLogDetail(Inet, "Listener: Waiting");
1466             break;
1467
1468         case nw_listener_state_failed:
1469             ChipLogDetail(Inet, "Listener: Failed");
1470             res = chip::System::MapErrorPOSIX(nw_error_get_error_code(error));
1471             break;
1472
1473         case nw_listener_state_ready:
1474             ChipLogDetail(Inet, "Listener: Ready");
1475             res = INET_NO_ERROR;
1476             dispatch_semaphore_signal(mListenerSemaphore);
1477             break;
1478
1479         case nw_listener_state_cancelled:
1480             ChipLogDetail(Inet, "Listener: Cancelled");
1481             if (res == INET_NO_ERROR)
1482                 res = INET_ERROR_CONNECTION_ABORTED;
1483
1484             dispatch_semaphore_signal(mListenerSemaphore);
1485             break;
1486         }
1487     });
1488
1489     nw_listener_start(listener);
1490     dispatch_semaphore_wait(mListenerSemaphore, DISPATCH_TIME_FOREVER);
1491     SuccessOrExit(res);
1492
1493     mListener = listener;
1494     nw_retain(mListener);
1495 exit:
1496     return res;
1497 }
1498
1499 INET_ERROR IPEndPointBasis::StartConnection(nw_connection_t & aConnection)
1500 {
1501     __block INET_ERROR res = INET_NO_ERROR;
1502
1503     nw_connection_set_queue(aConnection, mDispatchQueue);
1504
1505     nw_connection_set_state_changed_handler(aConnection, ^(nw_connection_state_t state, nw_error_t error) {
1506         switch (state)
1507         {
1508
1509         case nw_connection_state_invalid:
1510             ChipLogDetail(Inet, "Connection: Invalid");
1511             res = INET_ERROR_INCORRECT_STATE;
1512             nw_connection_cancel(aConnection);
1513             break;
1514
1515         case nw_connection_state_preparing:
1516             ChipLogDetail(Inet, "Connection: Preparing");
1517             res = INET_ERROR_INCORRECT_STATE;
1518             break;
1519
1520         case nw_connection_state_waiting:
1521             ChipLogDetail(Inet, "Connection: Waiting");
1522             nw_connection_cancel(aConnection);
1523             break;
1524
1525         case nw_connection_state_failed:
1526             ChipLogDetail(Inet, "Connection: Failed");
1527             res = chip::System::MapErrorPOSIX(nw_error_get_error_code(error));
1528             break;
1529
1530         case nw_connection_state_ready:
1531             ChipLogDetail(Inet, "Connection: Ready");
1532             res = INET_NO_ERROR;
1533             dispatch_semaphore_signal(mConnectionSemaphore);
1534             break;
1535
1536         case nw_connection_state_cancelled:
1537             ChipLogDetail(Inet, "Connection: Cancelled");
1538             if (res == INET_NO_ERROR)
1539                 res = INET_ERROR_CONNECTION_ABORTED;
1540
1541             dispatch_semaphore_signal(mConnectionSemaphore);
1542             break;
1543         }
1544     });
1545
1546     nw_connection_start(aConnection);
1547     dispatch_semaphore_wait(mConnectionSemaphore, DISPATCH_TIME_FOREVER);
1548     SuccessOrExit(res);
1549
1550     mConnection = aConnection;
1551     nw_retain(mConnection);
1552     HandleDataReceived(mConnection);
1553
1554 exit:
1555     return res;
1556 }
1557
1558 void IPEndPointBasis::ReleaseAll()
1559 {
1560
1561     OnMessageReceived = NULL;
1562     OnReceiveError    = NULL;
1563
1564     ReleaseConnection();
1565     ReleaseListener();
1566
1567     if (mParameters)
1568     {
1569         nw_release(mParameters);
1570         mParameters = NULL;
1571     }
1572
1573     if (mDispatchQueue)
1574     {
1575         dispatch_suspend(mDispatchQueue);
1576         dispatch_release(mDispatchQueue);
1577         mDispatchQueue = NULL;
1578     }
1579
1580     if (mConnectionSemaphore)
1581     {
1582         dispatch_release(mConnectionSemaphore);
1583         mConnectionSemaphore = NULL;
1584     }
1585
1586     if (mListenerQueue)
1587     {
1588         dispatch_suspend(mListenerQueue);
1589         dispatch_release(mListenerQueue);
1590         mListenerQueue = NULL;
1591     }
1592
1593     if (mListenerSemaphore)
1594     {
1595         dispatch_release(mListenerSemaphore);
1596         mListenerSemaphore = NULL;
1597     }
1598
1599     if (mSendSemaphore)
1600     {
1601         dispatch_release(mSendSemaphore);
1602         mSendSemaphore = NULL;
1603     }
1604 }
1605
1606 INET_ERROR IPEndPointBasis::ReleaseListener()
1607 {
1608     INET_ERROR res = INET_NO_ERROR;
1609
1610     VerifyOrExit(mListener, res = INET_ERROR_INCORRECT_STATE);
1611     VerifyOrExit(mDispatchQueue, res = INET_ERROR_INCORRECT_STATE);
1612     VerifyOrExit(mConnectionSemaphore, res = INET_ERROR_INCORRECT_STATE);
1613
1614     nw_listener_cancel(mListener);
1615     dispatch_semaphore_wait(mListenerSemaphore, DISPATCH_TIME_FOREVER);
1616     nw_release(mListener);
1617     mListener = NULL;
1618
1619 exit:
1620     return res;
1621 }
1622
1623 INET_ERROR IPEndPointBasis::ReleaseConnection()
1624 {
1625     INET_ERROR res = INET_NO_ERROR;
1626     VerifyOrExit(mConnection, res = INET_ERROR_INCORRECT_STATE);
1627     VerifyOrExit(mDispatchQueue, res = INET_ERROR_INCORRECT_STATE);
1628     VerifyOrExit(mConnectionSemaphore, res = INET_ERROR_INCORRECT_STATE);
1629
1630     nw_connection_cancel(mConnection);
1631     dispatch_semaphore_wait(mConnectionSemaphore, DISPATCH_TIME_FOREVER);
1632     nw_release(mConnection);
1633     mConnection = NULL;
1634
1635 exit:
1636     return res;
1637 }
1638
1639 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
1640
1641 } // namespace Inet
1642 } // namespace chip