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 59 : CHIP_ERROR IPv6Bind(int socket, const IPAddress & address, uint16_t port, InterfaceId interface)
91 : {
92 : struct sockaddr_in6 sa;
93 59 : memset(&sa, 0, sizeof(sa));
94 59 : sa.sin6_family = AF_INET6;
95 59 : sa.sin6_port = htons(port);
96 59 : sa.sin6_addr = address.ToIPv6();
97 59 : InterfaceId::PlatformType interfaceId = interface.GetPlatformInterface();
98 59 : if (!CanCastTo<decltype(sa.sin6_scope_id)>(interfaceId))
99 : {
100 0 : return CHIP_ERROR_INCORRECT_STATE;
101 : }
102 59 : sa.sin6_scope_id = static_cast<decltype(sa.sin6_scope_id)>(interfaceId);
103 :
104 59 : CHIP_ERROR status = CHIP_NO_ERROR;
105 :
106 : // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): Function called only with valid socket after GetSocket
107 59 : 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 59 : 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 59 : int hops = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
124 59 : setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
125 : #endif // defined(IPV6_MULTICAST_HOPS)
126 :
127 59 : return status;
128 : }
129 :
130 : #if INET_CONFIG_ENABLE_IPV4
131 58 : CHIP_ERROR IPv4Bind(int socket, const IPAddress & address, uint16_t port)
132 : {
133 : struct sockaddr_in sa;
134 58 : memset(&sa, 0, sizeof(sa));
135 58 : sa.sin_family = AF_INET;
136 58 : sa.sin_port = htons(port);
137 58 : sa.sin_addr = address.ToIPv4();
138 :
139 58 : CHIP_ERROR status = CHIP_NO_ERROR;
140 :
141 : // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): Function called only with valid socket after GetSocket
142 58 : 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 57 : constexpr int enable = 1;
150 57 : 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 57 : 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 58 : constexpr int ttl = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
163 58 : setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
164 : #endif // defined(IP_MULTICAST_TTL)
165 :
166 58 : 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 118 : 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 118 : ReturnErrorOnFailure(GetSocket(addressType));
180 :
181 117 : if (addressType == IPAddressType::kIPv6)
182 : {
183 59 : ReturnErrorOnFailure(IPv6Bind(mSocket, addr, port, interface));
184 : }
185 : #if INET_CONFIG_ENABLE_IPV4
186 58 : else if (addressType == IPAddressType::kIPv4)
187 : {
188 58 : 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 116 : mBoundPort = port;
197 116 : mBoundIntfId = interface;
198 :
199 : // If an ephemeral port was requested, retrieve the actual bound port.
200 116 : if (port == 0)
201 : {
202 : SockAddr boundAddr;
203 60 : socklen_t boundAddrLen = sizeof(boundAddr);
204 :
205 60 : if (getsockname(mSocket, &boundAddr.any, &boundAddrLen) == 0)
206 : {
207 60 : if (boundAddr.any.sa_family == AF_INET)
208 : {
209 30 : mBoundPort = ntohs(boundAddr.in.sin_port);
210 : }
211 30 : else if (boundAddr.any.sa_family == AF_INET6)
212 : {
213 30 : mBoundPort = ntohs(boundAddr.in6.sin6_port);
214 : }
215 : }
216 : }
217 :
218 116 : 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 67 : InterfaceId UDPEndPointImplSockets::GetBoundInterface() const
263 : {
264 67 : return mBoundIntfId;
265 : }
266 :
267 4 : uint16_t UDPEndPointImplSockets::GetBoundPort() const
268 : {
269 4 : return mBoundPort;
270 : }
271 :
272 116 : CHIP_ERROR UDPEndPointImplSockets::ListenImpl()
273 : {
274 : // Wait for ability to read on this endpoint.
275 116 : auto * layer = static_cast<System::LayerSockets *>(&GetSystemLayer());
276 116 : ReturnErrorOnFailure(layer->SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this)));
277 116 : return layer->RequestCallbackOnPendingRead(mWatch);
278 : }
279 :
280 70 : CHIP_ERROR UDPEndPointImplSockets::SendMsgImpl(const IPPacketInfo * aPktInfo, System::PacketBufferHandle && msg)
281 : {
282 : // Ensure packet buffer is not null
283 70 : 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 70 : ReturnErrorOnFailure(GetSocket(aPktInfo->DestAddress.Type()));
288 :
289 : // Ensure the destination address type is compatible with the endpoint address type.
290 70 : VerifyOrReturnError(mAddrType == aPktInfo->DestAddress.Type(), CHIP_ERROR_INVALID_ARGUMENT);
291 :
292 : // For now the entire message must fit within a single buffer.
293 70 : VerifyOrReturnError(!msg->HasChainedBuffer(), CHIP_ERROR_MESSAGE_TOO_LONG);
294 :
295 : struct iovec msgIOV;
296 70 : msgIOV.iov_base = msg->Start();
297 70 : msgIOV.iov_len = msg->DataLength();
298 :
299 : #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
300 : uint8_t controlData[256];
301 70 : memset(controlData, 0, sizeof(controlData));
302 : #endif // defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
303 :
304 : struct msghdr msgHeader;
305 70 : memset(&msgHeader, 0, sizeof(msgHeader));
306 70 : msgHeader.msg_iov = &msgIOV;
307 70 : msgHeader.msg_iovlen = 1;
308 :
309 : // Construct a sockaddr_in/sockaddr_in6 structure containing the destination information.
310 : SockAddr peerSockAddr;
311 70 : memset(&peerSockAddr, 0, sizeof(peerSockAddr));
312 70 : msgHeader.msg_name = &peerSockAddr;
313 70 : if (mAddrType == IPAddressType::kIPv6)
314 : {
315 35 : peerSockAddr.in6.sin6_family = AF_INET6;
316 35 : peerSockAddr.in6.sin6_port = htons(aPktInfo->DestPort);
317 35 : peerSockAddr.in6.sin6_addr = aPktInfo->DestAddress.ToIPv6();
318 35 : InterfaceId::PlatformType intfId = aPktInfo->Interface.GetPlatformInterface();
319 35 : VerifyOrReturnError(CanCastTo<decltype(peerSockAddr.in6.sin6_scope_id)>(intfId), CHIP_ERROR_INCORRECT_STATE);
320 35 : peerSockAddr.in6.sin6_scope_id = static_cast<decltype(peerSockAddr.in6.sin6_scope_id)>(intfId);
321 35 : msgHeader.msg_namelen = sizeof(sockaddr_in6);
322 : }
323 : #if INET_CONFIG_ENABLE_IPV4
324 : else
325 : {
326 35 : peerSockAddr.in.sin_family = AF_INET;
327 35 : peerSockAddr.in.sin_port = htons(aPktInfo->DestPort);
328 35 : peerSockAddr.in.sin_addr = aPktInfo->DestAddress.ToIPv4();
329 35 : 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 70 : InterfaceId intf = aPktInfo->Interface;
340 70 : 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 70 : if (intf.IsPresent() || aPktInfo->SrcAddress.Type() != IPAddressType::kAny)
351 : {
352 : #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
353 66 : msgHeader.msg_control = controlData;
354 66 : msgHeader.msg_controllen = sizeof(controlData);
355 :
356 66 : struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader);
357 66 : InterfaceId::PlatformType intfId = intf.GetPlatformInterface();
358 :
359 : #if INET_CONFIG_ENABLE_IPV4
360 :
361 66 : if (mAddrType == IPAddressType::kIPv4)
362 : {
363 : #if defined(IP_PKTINFO)
364 33 : controlHdr->cmsg_level = IPPROTO_IP;
365 33 : controlHdr->cmsg_type = IP_PKTINFO;
366 33 : controlHdr->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
367 :
368 33 : auto * pktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
369 33 : if (!CanCastTo<decltype(pktInfo->ipi_ifindex)>(intfId))
370 : {
371 0 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
372 : }
373 :
374 33 : pktInfo->ipi_ifindex = static_cast<decltype(pktInfo->ipi_ifindex)>(intfId);
375 33 : pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4();
376 :
377 33 : 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 66 : if (mAddrType == IPAddressType::kIPv6)
386 : {
387 : #if defined(IPV6_PKTINFO)
388 33 : controlHdr->cmsg_level = IPPROTO_IPV6;
389 33 : controlHdr->cmsg_type = IPV6_PKTINFO;
390 33 : controlHdr->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
391 :
392 33 : auto * pktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
393 33 : if (!CanCastTo<decltype(pktInfo->ipi6_ifindex)>(intfId))
394 : {
395 0 : return CHIP_ERROR_UNEXPECTED_EVENT;
396 : }
397 33 : pktInfo->ipi6_ifindex = static_cast<decltype(pktInfo->ipi6_ifindex)>(intfId);
398 33 : pktInfo->ipi6_addr = aPktInfo->SrcAddress.ToIPv6();
399 :
400 33 : 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 70 : const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0);
415 70 : if (lenSent == -1)
416 : {
417 0 : return CHIP_ERROR_POSIX(errno);
418 : }
419 :
420 70 : size_t len = static_cast<size_t>(lenSent);
421 :
422 70 : if (len != msg->DataLength())
423 : {
424 0 : return CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG;
425 : }
426 70 : return CHIP_NO_ERROR;
427 : }
428 :
429 117 : void UDPEndPointImplSockets::CloseImpl()
430 : {
431 117 : if (mSocket != kInvalidSocketFd)
432 : {
433 117 : TEMPORARY_RETURN_IGNORED static_cast<System::LayerSockets *>(&GetSystemLayer())->StopWatchingSocket(&mWatch);
434 117 : close(mSocket);
435 117 : mSocket = kInvalidSocketFd;
436 : }
437 117 : }
438 :
439 189 : CHIP_ERROR UDPEndPointImplSockets::GetSocket(IPAddressType addressType)
440 : {
441 189 : if (mSocket == kInvalidSocketFd)
442 : {
443 118 : constexpr int type = (SOCK_DGRAM | SOCK_CLOEXEC);
444 118 : constexpr int protocol = 0;
445 :
446 118 : int family = PF_UNSPEC;
447 :
448 118 : switch (addressType)
449 : {
450 59 : case IPAddressType::kIPv6:
451 59 : family = PF_INET6;
452 59 : break;
453 :
454 : #if INET_CONFIG_ENABLE_IPV4
455 58 : case IPAddressType::kIPv4:
456 58 : family = PF_INET;
457 58 : break;
458 : #endif // INET_CONFIG_ENABLE_IPV4
459 :
460 1 : default:
461 1 : return INET_ERROR_WRONG_ADDRESS_TYPE;
462 : }
463 :
464 117 : mSocket = ::socket(family, type, protocol);
465 117 : if (mSocket == -1)
466 : {
467 0 : return CHIP_ERROR_POSIX(errno);
468 : }
469 117 : CHIP_ERROR err = static_cast<System::LayerSockets *>(&GetSystemLayer())->StartWatchingSocket(mSocket, &mWatch);
470 234 : 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 117 : 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 117 : constexpr int one = 1;
490 117 : int res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
491 : static_cast<void>(res);
492 :
493 : #ifdef SO_REUSEPORT
494 117 : res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
495 117 : 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 117 : if (addressType == IPAddressType::kIPv6)
507 : {
508 59 : res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
509 59 : 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 117 : if (addressType == IPAddressType::kIPv4)
519 : {
520 58 : res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
521 58 : 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 117 : if (addressType == IPAddressType::kIPv6)
531 : {
532 59 : res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
533 59 : 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 71 : else if (mAddrType != addressType)
555 : {
556 0 : return CHIP_ERROR_INCORRECT_STATE;
557 : }
558 :
559 188 : return CHIP_NO_ERROR;
560 : }
561 :
562 : // static
563 16 : void UDPEndPointImplSockets::HandlePendingIO(System::SocketEvents events, intptr_t data)
564 : {
565 16 : auto * endPoint = reinterpret_cast<UDPEndPointImplSockets *>(data);
566 16 : VerifyOrReturn(endPoint != nullptr);
567 16 : endPoint->HandlePendingIO(events);
568 : }
569 :
570 16 : void UDPEndPointImplSockets::HandlePendingIO(System::SocketEvents events)
571 : {
572 16 : if (mState != State::kListening || OnMessageReceived == nullptr || !events.Has(System::SocketEventFlags::kRead))
573 : {
574 0 : return;
575 : }
576 :
577 : // Prevent the endpoint from being freed while in the middle of a callback.
578 16 : UDPEndPointHandle ref(this);
579 16 : CHIP_ERROR lStatus = CHIP_NO_ERROR;
580 16 : IPPacketInfo lPacketInfo;
581 16 : System::PacketBufferHandle lBuffer;
582 :
583 16 : lPacketInfo.Clear();
584 16 : lPacketInfo.DestPort = mBoundPort;
585 16 : lPacketInfo.Interface = mBoundIntfId;
586 :
587 16 : lBuffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSizeWithoutReserve, 0);
588 :
589 16 : if (!lBuffer.IsNull())
590 : {
591 : struct iovec msgIOV;
592 : SockAddr lPeerSockAddr;
593 : uint8_t controlData[256];
594 : struct msghdr msgHeader;
595 :
596 16 : msgIOV.iov_base = lBuffer->Start();
597 16 : msgIOV.iov_len = lBuffer->AvailableDataLength();
598 :
599 16 : memset(&lPeerSockAddr, 0, sizeof(lPeerSockAddr));
600 16 : memset(controlData, 0, sizeof(controlData));
601 16 : memset(&msgHeader, 0, sizeof(msgHeader));
602 :
603 16 : msgHeader.msg_name = &lPeerSockAddr;
604 16 : msgHeader.msg_namelen = sizeof(lPeerSockAddr);
605 16 : msgHeader.msg_iov = &msgIOV;
606 16 : msgHeader.msg_iovlen = 1;
607 16 : msgHeader.msg_control = controlData;
608 16 : msgHeader.msg_controllen = sizeof(controlData);
609 :
610 16 : ssize_t rcvLen = recvmsg(mSocket, &msgHeader, MSG_DONTWAIT);
611 :
612 16 : if (rcvLen == -1)
613 : {
614 2 : lStatus = CHIP_ERROR_POSIX(errno);
615 : }
616 14 : else if (lBuffer->AvailableDataLength() < static_cast<size_t>(rcvLen))
617 : {
618 0 : lStatus = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG;
619 : }
620 : else
621 : {
622 14 : lBuffer->SetDataLength(static_cast<uint16_t>(rcvLen));
623 :
624 14 : if (lPeerSockAddr.any.sa_family == AF_INET6)
625 : {
626 7 : lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in6.sin6_addr);
627 7 : lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in6.sin6_port);
628 : }
629 : #if INET_CONFIG_ENABLE_IPV4
630 7 : else if (lPeerSockAddr.any.sa_family == AF_INET)
631 : {
632 7 : lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in.sin_addr);
633 7 : lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in.sin_port);
634 : }
635 : #endif // INET_CONFIG_ENABLE_IPV4
636 : else
637 : {
638 0 : lStatus = CHIP_ERROR_INCORRECT_STATE;
639 : }
640 : }
641 :
642 32 : if (lStatus == CHIP_NO_ERROR)
643 : {
644 28 : for (struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); controlHdr != nullptr;
645 14 : controlHdr = CMSG_NXTHDR(&msgHeader, controlHdr))
646 : {
647 : #if INET_CONFIG_ENABLE_IPV4
648 : #ifdef IP_PKTINFO
649 14 : if (controlHdr->cmsg_level == IPPROTO_IP && controlHdr->cmsg_type == IP_PKTINFO)
650 : {
651 7 : auto * inPktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
652 7 : if (!CanCastTo<InterfaceId::PlatformType>(inPktInfo->ipi_ifindex))
653 : {
654 0 : lStatus = CHIP_ERROR_INCORRECT_STATE;
655 0 : break;
656 : }
657 7 : lPacketInfo.Interface = InterfaceId(static_cast<InterfaceId::PlatformType>(inPktInfo->ipi_ifindex));
658 7 : lPacketInfo.DestAddress = IPAddress(inPktInfo->ipi_addr);
659 7 : continue;
660 7 : }
661 : #endif // defined(IP_PKTINFO)
662 : #endif // INET_CONFIG_ENABLE_IPV4
663 :
664 : #ifdef IPV6_PKTINFO
665 7 : if (controlHdr->cmsg_level == IPPROTO_IPV6 && controlHdr->cmsg_type == IPV6_PKTINFO)
666 : {
667 7 : auto * in6PktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
668 7 : if (!CanCastTo<InterfaceId::PlatformType>(in6PktInfo->ipi6_ifindex))
669 : {
670 0 : lStatus = CHIP_ERROR_INCORRECT_STATE;
671 0 : break;
672 : }
673 7 : lPacketInfo.Interface = InterfaceId(static_cast<InterfaceId::PlatformType>(in6PktInfo->ipi6_ifindex));
674 7 : lPacketInfo.DestAddress = IPAddress(in6PktInfo->ipi6_addr);
675 7 : continue;
676 7 : }
677 : #endif // defined(IPV6_PKTINFO)
678 : }
679 : }
680 : }
681 : else
682 : {
683 0 : lStatus = CHIP_ERROR_NO_MEMORY;
684 : }
685 :
686 32 : if (lStatus == CHIP_NO_ERROR)
687 : {
688 14 : lBuffer.RightSize();
689 14 : OnMessageReceived(this, std::move(lBuffer), &lPacketInfo);
690 : }
691 : else
692 : {
693 2 : if (OnReceiveError != nullptr && lStatus != CHIP_ERROR_POSIX(EAGAIN))
694 : {
695 0 : OnReceiveError(this, lStatus, nullptr);
696 : }
697 : }
698 16 : }
699 :
700 : #ifdef IPV6_MULTICAST_LOOP
701 0 : static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, bool aLoopback, int aProtocol, int aOption)
702 : {
703 0 : const unsigned int lValue = static_cast<unsigned int>(aLoopback);
704 0 : if (setsockopt(aSocket, aProtocol, aOption, &lValue, sizeof(lValue)) != 0)
705 : {
706 0 : return CHIP_ERROR_POSIX(errno);
707 : }
708 :
709 0 : return CHIP_NO_ERROR;
710 : }
711 : #endif // IPV6_MULTICAST_LOOP
712 :
713 0 : static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, IPVersion aIPVersion, bool aLoopback)
714 : {
715 : #ifdef IPV6_MULTICAST_LOOP
716 : CHIP_ERROR lRetval;
717 :
718 0 : switch (aIPVersion)
719 : {
720 :
721 0 : case kIPVersion_6:
722 0 : lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
723 0 : break;
724 :
725 : #if INET_CONFIG_ENABLE_IPV4 && defined(IP_MULTICAST_LOOP)
726 0 : case kIPVersion_4:
727 0 : lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IP, IP_MULTICAST_LOOP);
728 0 : break;
729 : #endif // INET_CONFIG_ENABLE_IPV4 && defined(IP_MULTICAST_LOOP)
730 :
731 0 : default:
732 0 : lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
733 0 : break;
734 : }
735 :
736 0 : return (lRetval);
737 : #else // IPV6_MULTICAST_LOOP
738 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
739 : #endif // IPV6_MULTICAST_LOOP
740 : }
741 :
742 0 : CHIP_ERROR UDPEndPointImplSockets::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback)
743 : {
744 0 : CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED;
745 :
746 0 : lRetval = SocketsSetMulticastLoopback(mSocket, aIPVersion, aLoopback);
747 0 : SuccessOrExit(lRetval);
748 :
749 0 : exit:
750 0 : return (lRetval);
751 : }
752 :
753 : #if INET_CONFIG_ENABLE_IPV4
754 :
755 27 : CHIP_ERROR UDPEndPointImplSockets::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join)
756 : {
757 : in_addr interfaceAddr;
758 :
759 27 : if (aInterfaceId.IsPresent())
760 : {
761 : IPAddress lInterfaceAddress;
762 27 : bool lInterfaceAddressFound = false;
763 :
764 54 : for (InterfaceAddressIterator lAddressIterator; lAddressIterator.HasCurrent(); lAddressIterator.Next())
765 : {
766 : IPAddress lCurrentAddress;
767 81 : if ((lAddressIterator.GetInterfaceId() == aInterfaceId) &&
768 108 : (lAddressIterator.GetAddress(lCurrentAddress) == CHIP_NO_ERROR))
769 : {
770 27 : if (lCurrentAddress.IsIPv4())
771 : {
772 27 : lInterfaceAddressFound = true;
773 27 : lInterfaceAddress = lCurrentAddress;
774 27 : break;
775 : }
776 : }
777 27 : }
778 27 : VerifyOrReturnError(lInterfaceAddressFound, INET_ERROR_ADDRESS_NOT_FOUND);
779 :
780 27 : interfaceAddr = lInterfaceAddress.ToIPv4();
781 : }
782 : else
783 : {
784 0 : interfaceAddr.s_addr = htonl(INADDR_ANY);
785 : }
786 :
787 : #if INET_CONFIG_UDP_SOCKET_MREQN
788 : struct ip_mreqn lMulticastRequest;
789 : memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
790 : lMulticastRequest.imr_ifindex = aInterfaceId.GetPlatformInterface(); /* Network interface index */
791 : lMulticastRequest.imr_address = interfaceAddr; /* IP address of local interface */
792 : lMulticastRequest.imr_multiaddr = aAddress.ToIPv4(); /* IP multicast group address*/
793 :
794 : #else
795 :
796 : struct ip_mreq lMulticastRequest;
797 27 : memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
798 27 : lMulticastRequest.imr_interface = interfaceAddr;
799 27 : lMulticastRequest.imr_multiaddr = aAddress.ToIPv4();
800 :
801 : #endif
802 :
803 27 : const int command = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
804 27 : if (setsockopt(mSocket, IPPROTO_IP, command, &lMulticastRequest, sizeof(lMulticastRequest)) != 0)
805 : {
806 0 : return CHIP_ERROR_POSIX(errno);
807 : }
808 27 : return CHIP_NO_ERROR;
809 : }
810 :
811 : #endif // INET_CONFIG_ENABLE_IPV4
812 :
813 27 : CHIP_ERROR UDPEndPointImplSockets::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join)
814 : {
815 : #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
816 : if (sMulticastGroupHandler != nullptr)
817 : {
818 : return sMulticastGroupHandler(aInterfaceId, aAddress, join ? MulticastOperation::kJoin : MulticastOperation::kLeave);
819 : }
820 : #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
821 :
822 : #ifdef IPV6_MULTICAST_IMPLEMENTED
823 27 : if (!aInterfaceId.IsPresent())
824 : {
825 : // Do it on all the viable interfaces.
826 0 : bool interfaceFound = false;
827 :
828 0 : InterfaceIterator interfaceIt;
829 0 : while (interfaceIt.Next())
830 : {
831 0 : if (!interfaceIt.SupportsMulticast() || !interfaceIt.IsUp())
832 : {
833 0 : continue;
834 : }
835 :
836 0 : InterfaceId interfaceId = interfaceIt.GetInterfaceId();
837 :
838 : IPAddress ifAddr;
839 0 : if (interfaceId.GetLinkLocalAddr(&ifAddr) != CHIP_NO_ERROR)
840 : {
841 0 : continue;
842 : }
843 :
844 0 : if (ifAddr.Type() != IPAddressType::kIPv6)
845 : {
846 : // Not the right sort of interface.
847 0 : continue;
848 : }
849 :
850 0 : interfaceFound = true;
851 :
852 : char ifName[InterfaceId::kMaxIfNameLength];
853 0 : TEMPORARY_RETURN_IGNORED interfaceIt.GetInterfaceName(ifName, sizeof(ifName));
854 :
855 : // Ignore errors here, except for logging, because we expect some of
856 : // these interfaces to not work, and some (e.g. loopback) to always
857 : // work.
858 0 : CHIP_ERROR err = IPv6JoinLeaveMulticastGroupImpl(interfaceId, aAddress, join);
859 0 : if (err == CHIP_NO_ERROR)
860 : {
861 0 : ChipLogDetail(Inet, " %s multicast group on interface %s", (join ? "Joined" : "Left"), ifName);
862 : }
863 : else
864 : {
865 0 : ChipLogError(Inet, " Failed to %s multicast group on interface %s", (join ? "join" : "leave"), ifName);
866 : }
867 : }
868 :
869 0 : if (interfaceFound)
870 : {
871 : // Assume we're good.
872 0 : return CHIP_NO_ERROR;
873 : }
874 :
875 : // Else go ahead and try to work with the default interface.
876 0 : ChipLogError(Inet, "No valid IPv6 multicast interface found");
877 0 : }
878 :
879 27 : const InterfaceId::PlatformType lIfIndex = aInterfaceId.GetPlatformInterface();
880 :
881 : struct ipv6_mreq lMulticastRequest;
882 27 : memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
883 27 : VerifyOrReturnError(CanCastTo<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex), CHIP_ERROR_UNEXPECTED_EVENT);
884 :
885 27 : lMulticastRequest.ipv6mr_interface = static_cast<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex);
886 27 : lMulticastRequest.ipv6mr_multiaddr = aAddress.ToIPv6();
887 :
888 27 : const int command = join ? INET_IPV6_ADD_MEMBERSHIP : INET_IPV6_DROP_MEMBERSHIP;
889 27 : if (setsockopt(mSocket, IPPROTO_IPV6, command, &lMulticastRequest, sizeof(lMulticastRequest)) != 0)
890 : {
891 0 : return CHIP_ERROR_POSIX(errno);
892 : }
893 27 : return CHIP_NO_ERROR;
894 : #else
895 : return CHIP_ERROR_NOT_IMPLEMENTED;
896 : #endif
897 : }
898 :
899 : } // namespace Inet
900 : } // namespace chip
|