Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2025 Project CHIP Authors
4 : * Copyright (c) 2018 Google LLC.
5 : * Copyright (c) 2013-2018 Nest Labs, Inc.
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : /**
21 : * This file implements Inet::UDPEndPoint using sockets.
22 : */
23 :
24 : // Required to properly support underlying RFC3542-related fields to IPV6_PKTINFO
25 : // on Darwin.
26 : #define __APPLE_USE_RFC_3542
27 : #include <inet/UDPEndPointImplSockets.h>
28 :
29 : #include <lib/support/CodeUtils.h>
30 : #include <lib/support/SafeInt.h>
31 : #include <lib/support/logging/CHIPLogging.h>
32 :
33 : #if CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
34 : #if HAVE_SYS_SOCKET_H
35 : #include <sys/socket.h>
36 : #endif // HAVE_SYS_SOCKET_H
37 : #include <net/if.h>
38 : #include <netinet/in.h>
39 : #include <sys/ioctl.h>
40 : #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
41 :
42 : #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKETS || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
43 : #include "ZephyrSocket.h" // nogncheck
44 : #endif
45 :
46 : #include <cerrno>
47 : #include <unistd.h>
48 : #include <utility>
49 :
50 : // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS:
51 : #ifndef SOCK_CLOEXEC
52 : #define SOCK_CLOEXEC 0
53 : #endif
54 :
55 : // On MbedOS, INADDR_ANY does not seem to exist...
56 : #ifndef INADDR_ANY
57 : #define INADDR_ANY 0
58 : #endif
59 :
60 : /*
61 : * Some systems define both IPV6_{ADD,DROP}_MEMBERSHIP and
62 : * IPV6_{JOIN,LEAVE}_GROUP while others only define
63 : * IPV6_{JOIN,LEAVE}_GROUP. Prefer the "_MEMBERSHIP" flavor for
64 : * parallelism with IPv4 and create the alias to the availabile
65 : * definitions.
66 : */
67 : #if defined(IPV6_ADD_MEMBERSHIP)
68 : #define INET_IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
69 : #elif defined(IPV6_JOIN_GROUP)
70 : #define INET_IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
71 : #elif !CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
72 : #error \
73 : "Neither IPV6_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP are defined which are required for generalized IPv6 multicast group support."
74 : #endif // IPV6_ADD_MEMBERSHIP
75 :
76 : #if defined(IPV6_DROP_MEMBERSHIP)
77 : #define INET_IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
78 : #elif defined(IPV6_LEAVE_GROUP)
79 : #define INET_IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
80 : #elif !CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
81 : #error \
82 : "Neither IPV6_DROP_MEMBERSHIP nor IPV6_LEAVE_GROUP are defined which are required for generalized IPv6 multicast group support."
83 : #endif // IPV6_DROP_MEMBERSHIP
84 :
85 : namespace chip {
86 : namespace Inet {
87 :
88 : namespace {
89 :
90 49 : CHIP_ERROR IPv6Bind(int socket, const IPAddress & address, uint16_t port, InterfaceId interface)
91 : {
92 : struct sockaddr_in6 sa;
93 49 : memset(&sa, 0, sizeof(sa));
94 49 : sa.sin6_family = AF_INET6;
95 49 : sa.sin6_port = htons(port);
96 49 : sa.sin6_addr = address.ToIPv6();
97 49 : InterfaceId::PlatformType interfaceId = interface.GetPlatformInterface();
98 49 : if (!CanCastTo<decltype(sa.sin6_scope_id)>(interfaceId))
99 : {
100 0 : return CHIP_ERROR_INCORRECT_STATE;
101 : }
102 49 : sa.sin6_scope_id = static_cast<decltype(sa.sin6_scope_id)>(interfaceId);
103 :
104 49 : CHIP_ERROR status = CHIP_NO_ERROR;
105 :
106 : // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): Function called only with valid socket after GetSocket
107 49 : if (bind(socket, reinterpret_cast<const sockaddr *>(&sa), static_cast<unsigned>(sizeof(sa))) != 0)
108 : {
109 0 : status = CHIP_ERROR_POSIX(errno);
110 : }
111 : else
112 : {
113 : #ifdef IPV6_MULTICAST_IF
114 : // Instruct the kernel that any messages to multicast destinations should be
115 : // sent down the interface specified by the caller.
116 49 : setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interfaceId, sizeof(interfaceId));
117 : #endif // defined(IPV6_MULTICAST_IF)
118 : }
119 :
120 : #ifdef IPV6_MULTICAST_HOPS
121 : // Instruct the kernel that any messages to multicast destinations should be
122 : // set with the configured hop limit value.
123 49 : int hops = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
124 49 : setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
125 : #endif // defined(IPV6_MULTICAST_HOPS)
126 :
127 49 : return status;
128 : }
129 :
130 : #if INET_CONFIG_ENABLE_IPV4
131 48 : CHIP_ERROR IPv4Bind(int socket, const IPAddress & address, uint16_t port)
132 : {
133 : struct sockaddr_in sa;
134 48 : memset(&sa, 0, sizeof(sa));
135 48 : sa.sin_family = AF_INET;
136 48 : sa.sin_port = htons(port);
137 48 : sa.sin_addr = address.ToIPv4();
138 :
139 48 : CHIP_ERROR status = CHIP_NO_ERROR;
140 :
141 : // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): Function called only with valid socket after GetSocket
142 48 : if (bind(socket, reinterpret_cast<const sockaddr *>(&sa), static_cast<unsigned>(sizeof(sa))) != 0)
143 : {
144 1 : status = CHIP_ERROR_POSIX(errno);
145 : }
146 : else
147 : {
148 : // Allow socket transmitting broadcast packets.
149 47 : constexpr int enable = 1;
150 47 : setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(enable));
151 :
152 : #ifdef IP_MULTICAST_IF
153 : // Instruct the kernel that any messages to multicast destinations should be
154 : // sent down the interface to which the specified IPv4 address is bound.
155 47 : setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &sa, sizeof(sa));
156 : #endif // defined(IP_MULTICAST_IF)
157 : }
158 :
159 : #ifdef IP_MULTICAST_TTL
160 : // Instruct the kernel that any messages to multicast destinations should be
161 : // set with the configured hop limit value.
162 48 : constexpr int ttl = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
163 48 : setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
164 : #endif // defined(IP_MULTICAST_TTL)
165 :
166 48 : return status;
167 : }
168 : #endif // INET_CONFIG_ENABLE_IPV4
169 :
170 : } // anonymous namespace
171 :
172 : #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
173 : UDPEndPointImplSockets::MulticastGroupHandler UDPEndPointImplSockets::sMulticastGroupHandler;
174 : #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
175 :
176 98 : CHIP_ERROR UDPEndPointImplSockets::BindImpl(IPAddressType addressType, const IPAddress & addr, uint16_t port, InterfaceId interface)
177 : {
178 : // Make sure we have the appropriate type of socket.
179 98 : ReturnErrorOnFailure(GetSocket(addressType));
180 :
181 97 : if (addressType == IPAddressType::kIPv6)
182 : {
183 49 : ReturnErrorOnFailure(IPv6Bind(mSocket, addr, port, interface));
184 : }
185 : #if INET_CONFIG_ENABLE_IPV4
186 48 : else if (addressType == IPAddressType::kIPv4)
187 : {
188 48 : ReturnErrorOnFailure(IPv4Bind(mSocket, addr, port));
189 : }
190 : #endif // INET_CONFIG_ENABLE_IPV4
191 : else
192 : {
193 0 : return INET_ERROR_WRONG_ADDRESS_TYPE;
194 : }
195 :
196 96 : mBoundPort = port;
197 96 : mBoundIntfId = interface;
198 :
199 : // If an ephemeral port was requested, retrieve the actual bound port.
200 96 : if (port == 0)
201 : {
202 : SockAddr boundAddr;
203 50 : socklen_t boundAddrLen = sizeof(boundAddr);
204 :
205 50 : if (getsockname(mSocket, &boundAddr.any, &boundAddrLen) == 0)
206 : {
207 50 : if (boundAddr.any.sa_family == AF_INET)
208 : {
209 25 : mBoundPort = ntohs(boundAddr.in.sin_port);
210 : }
211 25 : else if (boundAddr.any.sa_family == AF_INET6)
212 : {
213 25 : mBoundPort = ntohs(boundAddr.in6.sin6_port);
214 : }
215 : }
216 : }
217 :
218 96 : return CHIP_NO_ERROR;
219 : }
220 :
221 1 : CHIP_ERROR UDPEndPointImplSockets::BindInterfaceImpl(IPAddressType addressType, InterfaceId interfaceId)
222 : {
223 : // Make sure we have the appropriate type of socket.
224 1 : ReturnErrorOnFailure(GetSocket(addressType));
225 :
226 : #if HAVE_SO_BINDTODEVICE
227 1 : CHIP_ERROR status = CHIP_NO_ERROR;
228 :
229 1 : if (interfaceId.IsPresent())
230 : {
231 : // Start filtering on the passed interface.
232 : char interfaceName[IF_NAMESIZE];
233 1 : if (if_indextoname(interfaceId.GetPlatformInterface(), interfaceName) == nullptr)
234 : {
235 0 : status = CHIP_ERROR_POSIX(errno);
236 : }
237 1 : else if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, interfaceName, socklen_t(strlen(interfaceName))) == -1)
238 : {
239 0 : status = CHIP_ERROR_POSIX(errno);
240 : }
241 : }
242 : else
243 : {
244 : // Stop interface-based filtering.
245 0 : if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, "", 0) == -1)
246 : {
247 0 : status = CHIP_ERROR_POSIX(errno);
248 : }
249 : }
250 :
251 2 : if (status == CHIP_NO_ERROR)
252 : {
253 1 : mBoundIntfId = interfaceId;
254 : }
255 :
256 1 : return status;
257 : #else // !HAVE_SO_BINDTODEVICE
258 : return CHIP_ERROR_NOT_IMPLEMENTED;
259 : #endif // HAVE_SO_BINDTODEVICE
260 : }
261 :
262 55 : InterfaceId UDPEndPointImplSockets::GetBoundInterface() const
263 : {
264 55 : return mBoundIntfId;
265 : }
266 :
267 11 : uint16_t UDPEndPointImplSockets::GetBoundPort() const
268 : {
269 11 : return mBoundPort;
270 : }
271 :
272 96 : CHIP_ERROR UDPEndPointImplSockets::ListenImpl()
273 : {
274 : // Wait for ability to read on this endpoint.
275 96 : auto * layer = static_cast<System::LayerSockets *>(&GetSystemLayer());
276 96 : ReturnErrorOnFailure(layer->SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this)));
277 96 : return layer->RequestCallbackOnPendingRead(mWatch);
278 : }
279 :
280 58 : CHIP_ERROR UDPEndPointImplSockets::SendMsgImpl(const IPPacketInfo * aPktInfo, System::PacketBufferHandle && msg)
281 : {
282 : // Ensure packet buffer is not null
283 58 : VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
284 :
285 : // Make sure we have the appropriate type of socket based on the
286 : // destination address.
287 58 : ReturnErrorOnFailure(GetSocket(aPktInfo->DestAddress.Type()));
288 :
289 : // Ensure the destination address type is compatible with the endpoint address type.
290 58 : VerifyOrReturnError(mAddrType == aPktInfo->DestAddress.Type(), CHIP_ERROR_INVALID_ARGUMENT);
291 :
292 : // For now the entire message must fit within a single buffer.
293 58 : VerifyOrReturnError(!msg->HasChainedBuffer(), CHIP_ERROR_MESSAGE_TOO_LONG);
294 :
295 : struct iovec msgIOV;
296 58 : msgIOV.iov_base = msg->Start();
297 58 : msgIOV.iov_len = msg->DataLength();
298 :
299 : #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
300 : uint8_t controlData[256];
301 58 : memset(controlData, 0, sizeof(controlData));
302 : #endif // defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
303 :
304 : struct msghdr msgHeader;
305 58 : memset(&msgHeader, 0, sizeof(msgHeader));
306 58 : msgHeader.msg_iov = &msgIOV;
307 58 : msgHeader.msg_iovlen = 1;
308 :
309 : // Construct a sockaddr_in/sockaddr_in6 structure containing the destination information.
310 : SockAddr peerSockAddr;
311 58 : memset(&peerSockAddr, 0, sizeof(peerSockAddr));
312 58 : msgHeader.msg_name = &peerSockAddr;
313 58 : if (mAddrType == IPAddressType::kIPv6)
314 : {
315 29 : peerSockAddr.in6.sin6_family = AF_INET6;
316 29 : peerSockAddr.in6.sin6_port = htons(aPktInfo->DestPort);
317 29 : peerSockAddr.in6.sin6_addr = aPktInfo->DestAddress.ToIPv6();
318 29 : InterfaceId::PlatformType intfId = aPktInfo->Interface.GetPlatformInterface();
319 29 : VerifyOrReturnError(CanCastTo<decltype(peerSockAddr.in6.sin6_scope_id)>(intfId), CHIP_ERROR_INCORRECT_STATE);
320 29 : peerSockAddr.in6.sin6_scope_id = static_cast<decltype(peerSockAddr.in6.sin6_scope_id)>(intfId);
321 29 : msgHeader.msg_namelen = sizeof(sockaddr_in6);
322 : }
323 : #if INET_CONFIG_ENABLE_IPV4
324 : else
325 : {
326 29 : peerSockAddr.in.sin_family = AF_INET;
327 29 : peerSockAddr.in.sin_port = htons(aPktInfo->DestPort);
328 29 : peerSockAddr.in.sin_addr = aPktInfo->DestAddress.ToIPv4();
329 29 : msgHeader.msg_namelen = sizeof(sockaddr_in);
330 : }
331 : #endif // INET_CONFIG_ENABLE_IPV4
332 :
333 : // If the endpoint has been bound to a particular interface,
334 : // and the caller didn't supply a specific interface to send
335 : // on, use the bound interface. This appears to be necessary
336 : // for messages to multicast addresses, which under Linux
337 : // don't seem to get sent out the correct interface, despite
338 : // the socket being bound.
339 58 : InterfaceId intf = aPktInfo->Interface;
340 58 : if (!intf.IsPresent())
341 : {
342 4 : intf = mBoundIntfId;
343 : }
344 :
345 : #if INET_CONFIG_UDP_SOCKET_PKTINFO
346 : // If the packet should be sent over a specific interface, or with a specific source
347 : // address, construct an IP_PKTINFO/IPV6_PKTINFO "control message" to that effect
348 : // add add it to the message header. If the local OS doesn't support IP_PKTINFO/IPV6_PKTINFO
349 : // fail with an error.
350 58 : if (intf.IsPresent() || aPktInfo->SrcAddress.Type() != IPAddressType::kAny)
351 : {
352 : #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
353 54 : msgHeader.msg_control = controlData;
354 54 : msgHeader.msg_controllen = sizeof(controlData);
355 :
356 54 : struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader);
357 54 : InterfaceId::PlatformType intfId = intf.GetPlatformInterface();
358 :
359 : #if INET_CONFIG_ENABLE_IPV4
360 :
361 54 : if (mAddrType == IPAddressType::kIPv4)
362 : {
363 : #if defined(IP_PKTINFO)
364 27 : controlHdr->cmsg_level = IPPROTO_IP;
365 27 : controlHdr->cmsg_type = IP_PKTINFO;
366 27 : controlHdr->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
367 :
368 27 : auto * pktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
369 27 : if (!CanCastTo<decltype(pktInfo->ipi_ifindex)>(intfId))
370 : {
371 0 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
372 : }
373 :
374 27 : pktInfo->ipi_ifindex = static_cast<decltype(pktInfo->ipi_ifindex)>(intfId);
375 27 : pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4();
376 :
377 27 : msgHeader.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo));
378 : #else // !defined(IP_PKTINFO)
379 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
380 : #endif // !defined(IP_PKTINFO)
381 : }
382 :
383 : #endif // INET_CONFIG_ENABLE_IPV4
384 :
385 54 : if (mAddrType == IPAddressType::kIPv6)
386 : {
387 : #if defined(IPV6_PKTINFO)
388 27 : controlHdr->cmsg_level = IPPROTO_IPV6;
389 27 : controlHdr->cmsg_type = IPV6_PKTINFO;
390 27 : controlHdr->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
391 :
392 27 : auto * pktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
393 27 : if (!CanCastTo<decltype(pktInfo->ipi6_ifindex)>(intfId))
394 : {
395 0 : return CHIP_ERROR_UNEXPECTED_EVENT;
396 : }
397 27 : pktInfo->ipi6_ifindex = static_cast<decltype(pktInfo->ipi6_ifindex)>(intfId);
398 27 : pktInfo->ipi6_addr = aPktInfo->SrcAddress.ToIPv6();
399 :
400 27 : msgHeader.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo));
401 : #else // !defined(IPV6_PKTINFO)
402 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
403 : #endif // !defined(IPV6_PKTINFO)
404 : }
405 :
406 : #else // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
407 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
408 : #endif // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
409 : }
410 : #endif // INET_CONFIG_UDP_SOCKET_PKTINFO
411 :
412 : // Send IP packet.
413 : // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): GetSocket calls ensure mSocket is valid
414 58 : const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0);
415 58 : if (lenSent == -1)
416 : {
417 0 : return CHIP_ERROR_POSIX(errno);
418 : }
419 :
420 58 : size_t len = static_cast<size_t>(lenSent);
421 :
422 58 : if (len != msg->DataLength())
423 : {
424 0 : return CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG;
425 : }
426 58 : return CHIP_NO_ERROR;
427 : }
428 :
429 97 : void UDPEndPointImplSockets::CloseImpl()
430 : {
431 97 : if (mSocket != kInvalidSocketFd)
432 : {
433 97 : TEMPORARY_RETURN_IGNORED static_cast<System::LayerSockets *>(&GetSystemLayer())->StopWatchingSocket(&mWatch);
434 97 : close(mSocket);
435 97 : mSocket = kInvalidSocketFd;
436 : }
437 97 : }
438 :
439 157 : CHIP_ERROR UDPEndPointImplSockets::GetSocket(IPAddressType addressType)
440 : {
441 157 : if (mSocket == kInvalidSocketFd)
442 : {
443 98 : constexpr int type = (SOCK_DGRAM | SOCK_CLOEXEC);
444 98 : constexpr int protocol = 0;
445 :
446 98 : int family = PF_UNSPEC;
447 :
448 98 : switch (addressType)
449 : {
450 49 : case IPAddressType::kIPv6:
451 49 : family = PF_INET6;
452 49 : break;
453 :
454 : #if INET_CONFIG_ENABLE_IPV4
455 48 : case IPAddressType::kIPv4:
456 48 : family = PF_INET;
457 48 : break;
458 : #endif // INET_CONFIG_ENABLE_IPV4
459 :
460 1 : default:
461 1 : return INET_ERROR_WRONG_ADDRESS_TYPE;
462 : }
463 :
464 97 : mSocket = ::socket(family, type, protocol);
465 97 : if (mSocket == -1)
466 : {
467 0 : return CHIP_ERROR_POSIX(errno);
468 : }
469 97 : CHIP_ERROR err = static_cast<System::LayerSockets *>(&GetSystemLayer())->StartWatchingSocket(mSocket, &mWatch);
470 194 : if (err != CHIP_NO_ERROR)
471 : {
472 : // Our mWatch is not valid; make sure we never use it.
473 0 : close(mSocket);
474 0 : mSocket = kInvalidSocketFd;
475 0 : return err;
476 : }
477 :
478 97 : mAddrType = addressType;
479 :
480 : // NOTE WELL: the errors returned by setsockopt() here are not
481 : // returned as Inet layer CHIP_ERROR_POSIX(errno)
482 : // codes because they are normally expected to fail on some
483 : // platforms where the socket option code is defined in the
484 : // header files but not [yet] implemented. Certainly, there is
485 : // room to improve this by connecting the build configuration
486 : // logic up to check for implementations of these options and
487 : // to provide appropriate HAVE_xxxxx definitions accordingly.
488 :
489 97 : constexpr int one = 1;
490 97 : int res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
491 : static_cast<void>(res);
492 :
493 : #ifdef SO_REUSEPORT
494 97 : res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
495 97 : if (res != 0)
496 : {
497 0 : ChipLogError(Inet, "SO_REUSEPORT failed: %d", errno);
498 : }
499 : #endif // defined(SO_REUSEPORT)
500 :
501 : // If creating an IPv6 socket, tell the kernel that it will be
502 : // IPv6 only. This makes it posible to bind two sockets to
503 : // the same port, one for IPv4 and one for IPv6.
504 :
505 : #ifdef IPV6_V6ONLY
506 97 : if (addressType == IPAddressType::kIPv6)
507 : {
508 49 : res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
509 49 : if (res != 0)
510 : {
511 0 : ChipLogError(Inet, "IPV6_V6ONLY failed: %d", errno);
512 : }
513 : }
514 : #endif // defined(IPV6_V6ONLY)
515 :
516 : #if INET_CONFIG_ENABLE_IPV4
517 : #ifdef IP_PKTINFO
518 97 : if (addressType == IPAddressType::kIPv4)
519 : {
520 48 : res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
521 48 : if (res != 0)
522 : {
523 0 : ChipLogError(Inet, "IP_PKTINFO failed: %d", errno);
524 : }
525 : }
526 : #endif // defined(IP_PKTINFO)
527 : #endif // INET_CONFIG_ENABLE_IPV4
528 :
529 : #ifdef IPV6_RECVPKTINFO
530 97 : if (addressType == IPAddressType::kIPv6)
531 : {
532 49 : res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
533 49 : if (res != 0)
534 : {
535 0 : ChipLogError(Inet, "IPV6_PKTINFO failed: %d", errno);
536 : }
537 : }
538 : #endif // defined(IPV6_RECVPKTINFO)
539 :
540 : // On systems that support it, disable the delivery of SIGPIPE
541 : // signals when writing to a closed socket. This is mostly
542 : // needed on iOS which has the peculiar habit of sending
543 : // SIGPIPEs on unconnected UDP sockets.
544 : #ifdef SO_NOSIGPIPE
545 : {
546 : res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
547 : if (res != 0)
548 : {
549 : ChipLogError(Inet, "SO_NOSIGPIPE failed: %d", errno);
550 : }
551 : }
552 : #endif // defined(SO_NOSIGPIPE)
553 : }
554 59 : else if (mAddrType != addressType)
555 : {
556 0 : return CHIP_ERROR_INCORRECT_STATE;
557 : }
558 :
559 156 : return CHIP_NO_ERROR;
560 : }
561 :
562 : // static
563 16 : void UDPEndPointImplSockets::HandlePendingIO(System::SocketEvents events, intptr_t data)
564 : {
565 16 : reinterpret_cast<UDPEndPointImplSockets *>(data)->HandlePendingIO(events);
566 16 : }
567 :
568 16 : void UDPEndPointImplSockets::HandlePendingIO(System::SocketEvents events)
569 : {
570 16 : if (mState != State::kListening || OnMessageReceived == nullptr || !events.Has(System::SocketEventFlags::kRead))
571 : {
572 0 : return;
573 : }
574 :
575 : // Prevent the endpoint from being freed while in the middle of a callback.
576 16 : UDPEndPointHandle ref(this);
577 16 : CHIP_ERROR lStatus = CHIP_NO_ERROR;
578 16 : IPPacketInfo lPacketInfo;
579 16 : System::PacketBufferHandle lBuffer;
580 :
581 16 : lPacketInfo.Clear();
582 16 : lPacketInfo.DestPort = mBoundPort;
583 16 : lPacketInfo.Interface = mBoundIntfId;
584 :
585 16 : lBuffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSizeWithoutReserve, 0);
586 :
587 16 : if (!lBuffer.IsNull())
588 : {
589 : struct iovec msgIOV;
590 : SockAddr lPeerSockAddr;
591 : uint8_t controlData[256];
592 : struct msghdr msgHeader;
593 :
594 16 : msgIOV.iov_base = lBuffer->Start();
595 16 : msgIOV.iov_len = lBuffer->AvailableDataLength();
596 :
597 16 : memset(&lPeerSockAddr, 0, sizeof(lPeerSockAddr));
598 :
599 16 : memset(&msgHeader, 0, sizeof(msgHeader));
600 :
601 16 : msgHeader.msg_name = &lPeerSockAddr;
602 16 : msgHeader.msg_namelen = sizeof(lPeerSockAddr);
603 16 : msgHeader.msg_iov = &msgIOV;
604 16 : msgHeader.msg_iovlen = 1;
605 16 : msgHeader.msg_control = controlData;
606 16 : msgHeader.msg_controllen = sizeof(controlData);
607 :
608 16 : ssize_t rcvLen = recvmsg(mSocket, &msgHeader, MSG_DONTWAIT);
609 :
610 16 : if (rcvLen == -1)
611 : {
612 2 : lStatus = CHIP_ERROR_POSIX(errno);
613 : }
614 14 : else if (lBuffer->AvailableDataLength() < static_cast<size_t>(rcvLen))
615 : {
616 0 : lStatus = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG;
617 : }
618 : else
619 : {
620 14 : lBuffer->SetDataLength(static_cast<uint16_t>(rcvLen));
621 :
622 14 : if (lPeerSockAddr.any.sa_family == AF_INET6)
623 : {
624 7 : lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in6.sin6_addr);
625 7 : lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in6.sin6_port);
626 : }
627 : #if INET_CONFIG_ENABLE_IPV4
628 7 : else if (lPeerSockAddr.any.sa_family == AF_INET)
629 : {
630 7 : lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in.sin_addr);
631 7 : lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in.sin_port);
632 : }
633 : #endif // INET_CONFIG_ENABLE_IPV4
634 : else
635 : {
636 0 : lStatus = CHIP_ERROR_INCORRECT_STATE;
637 : }
638 : }
639 :
640 32 : if (lStatus == CHIP_NO_ERROR)
641 : {
642 28 : for (struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); controlHdr != nullptr;
643 14 : controlHdr = CMSG_NXTHDR(&msgHeader, controlHdr))
644 : {
645 : #if INET_CONFIG_ENABLE_IPV4
646 : #ifdef IP_PKTINFO
647 14 : if (controlHdr->cmsg_level == IPPROTO_IP && controlHdr->cmsg_type == IP_PKTINFO)
648 : {
649 7 : auto * inPktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
650 7 : if (!CanCastTo<InterfaceId::PlatformType>(inPktInfo->ipi_ifindex))
651 : {
652 0 : lStatus = CHIP_ERROR_INCORRECT_STATE;
653 0 : break;
654 : }
655 7 : lPacketInfo.Interface = InterfaceId(static_cast<InterfaceId::PlatformType>(inPktInfo->ipi_ifindex));
656 7 : lPacketInfo.DestAddress = IPAddress(inPktInfo->ipi_addr);
657 7 : continue;
658 7 : }
659 : #endif // defined(IP_PKTINFO)
660 : #endif // INET_CONFIG_ENABLE_IPV4
661 :
662 : #ifdef IPV6_PKTINFO
663 7 : if (controlHdr->cmsg_level == IPPROTO_IPV6 && controlHdr->cmsg_type == IPV6_PKTINFO)
664 : {
665 7 : auto * in6PktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
666 7 : if (!CanCastTo<InterfaceId::PlatformType>(in6PktInfo->ipi6_ifindex))
667 : {
668 0 : lStatus = CHIP_ERROR_INCORRECT_STATE;
669 0 : break;
670 : }
671 7 : lPacketInfo.Interface = InterfaceId(static_cast<InterfaceId::PlatformType>(in6PktInfo->ipi6_ifindex));
672 7 : lPacketInfo.DestAddress = IPAddress(in6PktInfo->ipi6_addr);
673 7 : continue;
674 7 : }
675 : #endif // defined(IPV6_PKTINFO)
676 : }
677 : }
678 : }
679 : else
680 : {
681 0 : lStatus = CHIP_ERROR_NO_MEMORY;
682 : }
683 :
684 32 : if (lStatus == CHIP_NO_ERROR)
685 : {
686 14 : lBuffer.RightSize();
687 14 : OnMessageReceived(this, std::move(lBuffer), &lPacketInfo);
688 : }
689 : else
690 : {
691 2 : if (OnReceiveError != nullptr && lStatus != CHIP_ERROR_POSIX(EAGAIN))
692 : {
693 0 : OnReceiveError(this, lStatus, nullptr);
694 : }
695 : }
696 16 : }
697 :
698 : #ifdef IPV6_MULTICAST_LOOP
699 0 : static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, bool aLoopback, int aProtocol, int aOption)
700 : {
701 0 : const unsigned int lValue = static_cast<unsigned int>(aLoopback);
702 0 : if (setsockopt(aSocket, aProtocol, aOption, &lValue, sizeof(lValue)) != 0)
703 : {
704 0 : return CHIP_ERROR_POSIX(errno);
705 : }
706 :
707 0 : return CHIP_NO_ERROR;
708 : }
709 : #endif // IPV6_MULTICAST_LOOP
710 :
711 0 : static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, IPVersion aIPVersion, bool aLoopback)
712 : {
713 : #ifdef IPV6_MULTICAST_LOOP
714 : CHIP_ERROR lRetval;
715 :
716 0 : switch (aIPVersion)
717 : {
718 :
719 0 : case kIPVersion_6:
720 0 : lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
721 0 : break;
722 :
723 : #if INET_CONFIG_ENABLE_IPV4 && defined(IP_MULTICAST_LOOP)
724 0 : case kIPVersion_4:
725 0 : lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IP, IP_MULTICAST_LOOP);
726 0 : break;
727 : #endif // INET_CONFIG_ENABLE_IPV4 && defined(IP_MULTICAST_LOOP)
728 :
729 0 : default:
730 0 : lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
731 0 : break;
732 : }
733 :
734 0 : return (lRetval);
735 : #else // IPV6_MULTICAST_LOOP
736 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
737 : #endif // IPV6_MULTICAST_LOOP
738 : }
739 :
740 0 : CHIP_ERROR UDPEndPointImplSockets::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback)
741 : {
742 0 : CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED;
743 :
744 0 : lRetval = SocketsSetMulticastLoopback(mSocket, aIPVersion, aLoopback);
745 0 : SuccessOrExit(lRetval);
746 :
747 0 : exit:
748 0 : return (lRetval);
749 : }
750 :
751 : #if INET_CONFIG_ENABLE_IPV4
752 :
753 22 : CHIP_ERROR UDPEndPointImplSockets::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join)
754 : {
755 : in_addr interfaceAddr;
756 :
757 22 : if (aInterfaceId.IsPresent())
758 : {
759 : IPAddress lInterfaceAddress;
760 22 : bool lInterfaceAddressFound = false;
761 :
762 44 : for (InterfaceAddressIterator lAddressIterator; lAddressIterator.HasCurrent(); lAddressIterator.Next())
763 : {
764 : IPAddress lCurrentAddress;
765 66 : if ((lAddressIterator.GetInterfaceId() == aInterfaceId) &&
766 88 : (lAddressIterator.GetAddress(lCurrentAddress) == CHIP_NO_ERROR))
767 : {
768 22 : if (lCurrentAddress.IsIPv4())
769 : {
770 22 : lInterfaceAddressFound = true;
771 22 : lInterfaceAddress = lCurrentAddress;
772 22 : break;
773 : }
774 : }
775 22 : }
776 22 : VerifyOrReturnError(lInterfaceAddressFound, INET_ERROR_ADDRESS_NOT_FOUND);
777 :
778 22 : interfaceAddr = lInterfaceAddress.ToIPv4();
779 : }
780 : else
781 : {
782 0 : interfaceAddr.s_addr = htonl(INADDR_ANY);
783 : }
784 :
785 : #if INET_CONFIG_UDP_SOCKET_MREQN
786 : struct ip_mreqn lMulticastRequest;
787 : memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
788 : lMulticastRequest.imr_ifindex = aInterfaceId.GetPlatformInterface(); /* Network interface index */
789 : lMulticastRequest.imr_address = interfaceAddr; /* IP address of local interface */
790 : lMulticastRequest.imr_multiaddr = aAddress.ToIPv4(); /* IP multicast group address*/
791 :
792 : #else
793 :
794 : struct ip_mreq lMulticastRequest;
795 22 : memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
796 22 : lMulticastRequest.imr_interface = interfaceAddr;
797 22 : lMulticastRequest.imr_multiaddr = aAddress.ToIPv4();
798 :
799 : #endif
800 :
801 22 : const int command = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
802 22 : if (setsockopt(mSocket, IPPROTO_IP, command, &lMulticastRequest, sizeof(lMulticastRequest)) != 0)
803 : {
804 0 : return CHIP_ERROR_POSIX(errno);
805 : }
806 22 : return CHIP_NO_ERROR;
807 : }
808 :
809 : #endif // INET_CONFIG_ENABLE_IPV4
810 :
811 22 : CHIP_ERROR UDPEndPointImplSockets::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join)
812 : {
813 : #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
814 : if (sMulticastGroupHandler != nullptr)
815 : {
816 : return sMulticastGroupHandler(aInterfaceId, aAddress, join ? MulticastOperation::kJoin : MulticastOperation::kLeave);
817 : }
818 : #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
819 :
820 : #ifdef IPV6_MULTICAST_IMPLEMENTED
821 22 : if (!aInterfaceId.IsPresent())
822 : {
823 : // Do it on all the viable interfaces.
824 0 : bool interfaceFound = false;
825 :
826 0 : InterfaceIterator interfaceIt;
827 0 : while (interfaceIt.Next())
828 : {
829 0 : if (!interfaceIt.SupportsMulticast() || !interfaceIt.IsUp())
830 : {
831 0 : continue;
832 : }
833 :
834 0 : InterfaceId interfaceId = interfaceIt.GetInterfaceId();
835 :
836 : IPAddress ifAddr;
837 0 : if (interfaceId.GetLinkLocalAddr(&ifAddr) != CHIP_NO_ERROR)
838 : {
839 0 : continue;
840 : }
841 :
842 0 : if (ifAddr.Type() != IPAddressType::kIPv6)
843 : {
844 : // Not the right sort of interface.
845 0 : continue;
846 : }
847 :
848 0 : interfaceFound = true;
849 :
850 : char ifName[InterfaceId::kMaxIfNameLength];
851 0 : TEMPORARY_RETURN_IGNORED interfaceIt.GetInterfaceName(ifName, sizeof(ifName));
852 :
853 : // Ignore errors here, except for logging, because we expect some of
854 : // these interfaces to not work, and some (e.g. loopback) to always
855 : // work.
856 0 : CHIP_ERROR err = IPv6JoinLeaveMulticastGroupImpl(interfaceId, aAddress, join);
857 0 : if (err == CHIP_NO_ERROR)
858 : {
859 0 : ChipLogDetail(Inet, " %s multicast group on interface %s", (join ? "Joined" : "Left"), ifName);
860 : }
861 : else
862 : {
863 0 : ChipLogError(Inet, " Failed to %s multicast group on interface %s", (join ? "join" : "leave"), ifName);
864 : }
865 : }
866 :
867 0 : if (interfaceFound)
868 : {
869 : // Assume we're good.
870 0 : return CHIP_NO_ERROR;
871 : }
872 :
873 : // Else go ahead and try to work with the default interface.
874 0 : ChipLogError(Inet, "No valid IPv6 multicast interface found");
875 0 : }
876 :
877 22 : const InterfaceId::PlatformType lIfIndex = aInterfaceId.GetPlatformInterface();
878 :
879 : struct ipv6_mreq lMulticastRequest;
880 22 : memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
881 22 : VerifyOrReturnError(CanCastTo<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex), CHIP_ERROR_UNEXPECTED_EVENT);
882 :
883 22 : lMulticastRequest.ipv6mr_interface = static_cast<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex);
884 22 : lMulticastRequest.ipv6mr_multiaddr = aAddress.ToIPv6();
885 :
886 22 : const int command = join ? INET_IPV6_ADD_MEMBERSHIP : INET_IPV6_DROP_MEMBERSHIP;
887 22 : if (setsockopt(mSocket, IPPROTO_IPV6, command, &lMulticastRequest, sizeof(lMulticastRequest)) != 0)
888 : {
889 0 : return CHIP_ERROR_POSIX(errno);
890 : }
891 22 : return CHIP_NO_ERROR;
892 : #else
893 : return CHIP_ERROR_NOT_IMPLEMENTED;
894 : #endif
895 : }
896 :
897 : } // namespace Inet
898 : } // namespace chip
|