diff --git a/src/inet/TCPEndPoint.cpp b/src/inet/TCPEndPoint.cpp index e667cf1c06260c..0ab0149fd799b7 100644 --- a/src/inet/TCPEndPoint.cpp +++ b/src/inet/TCPEndPoint.cpp @@ -696,6 +696,67 @@ INET_ERROR TCPEndPoint::GetLocalInfo(IPAddress * retAddr, uint16_t * retPort) return res; } +INET_ERROR TCPEndPoint::GetInterfaceId(InterfaceId * retInterface) +{ + if (!IsConnected()) + return INET_ERROR_INCORRECT_STATE; + +#if CHIP_SYSTEM_CONFIG_USE_LWIP + // TODO: Does netif_get_by_index(mTCP->netif_idx) do the right thing? I + // can't quite tell whether LwIP supports a specific interface id for TCP at + // all. For now just claim no particular interface id. + *retInterface = INET_NULL_INTERFACEID; + return INET_NO_ERROR; +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP + +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS + union + { + sockaddr any; + sockaddr_in6 in6; +#if INET_CONFIG_ENABLE_IPV4 + sockaddr_in in; +#endif // INET_CONFIG_ENABLE_IPV4 + } sa; + + memset(&sa, 0, sizeof(sa)); + socklen_t saLen = sizeof(sa); + + if (getpeername(mSocket, &sa.any, &saLen) != 0) + { + return chip::System::MapErrorPOSIX(errno); + } + + if (sa.any.sa_family == AF_INET6) + { + if (IPAddress::FromIPv6(sa.in6.sin6_addr).IsIPv6LinkLocal()) + { + *retInterface = sa.in6.sin6_scope_id; + } + else + { + // TODO: Is there still a meaningful interface id in this case? + *retInterface = INET_NULL_INTERFACEID; + } + return INET_NO_ERROR; + } + +#if INET_CONFIG_ENABLE_IPV4 + if (sa.any.sa_family == AF_INET) + { + // No interface id available for IPv4 sockets. + *retInterface = INET_NULL_INTERFACEID; + } +#endif // INET_CONFIG_ENABLE_IPV4 + + return INET_ERROR_INCORRECT_STATE; + +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS + + *retInterface = INET_NULL_INTERFACEID; + return INET_NO_ERROR; +} + INET_ERROR TCPEndPoint::Send(System::PacketBufferHandle && data, bool push) { INET_ERROR res = INET_NO_ERROR; diff --git a/src/inet/TCPEndPoint.h b/src/inet/TCPEndPoint.h index a5d6589a839a66..95391e828ca1e9 100644 --- a/src/inet/TCPEndPoint.h +++ b/src/inet/TCPEndPoint.h @@ -192,6 +192,17 @@ class DLL_EXPORT TCPEndPoint : public EndPointBasis */ INET_ERROR GetLocalInfo(IPAddress * retAddr, uint16_t * retPort); + /** + * @brief Extract the interface id of the TCP endpoint. + * + * @param[out] retInterface The interface id. + * + * @retval INET_NO_ERROR success: address and port extracted. + * @retval INET_ERROR_INCORRECT_STATE TCP connection not established. + * @retval INET_ERROR_CONNECTION_ABORTED TCP connection no longer open. + */ + INET_ERROR GetInterfaceId(InterfaceId * retInterface); + /** * @brief Send message text on TCP connection. * diff --git a/src/transport/raw/PeerAddress.h b/src/transport/raw/PeerAddress.h index 76d5a94f635288..b4632898d41f25 100644 --- a/src/transport/raw/PeerAddress.h +++ b/src/transport/raw/PeerAddress.h @@ -170,6 +170,10 @@ class PeerAddress } static PeerAddress TCP(const Inet::IPAddress & addr) { return PeerAddress(addr, Type::kTcp); } static PeerAddress TCP(const Inet::IPAddress & addr, uint16_t port) { return TCP(addr).SetPort(port); } + static PeerAddress TCP(const Inet::IPAddress & addr, uint16_t port, Inet::InterfaceId interface) + { + return TCP(addr).SetPort(port).SetInterface(interface); + } private: Inet::IPAddress mIPAddress; diff --git a/src/transport/raw/TCP.cpp b/src/transport/raw/TCP.cpp index 62bb76c383ac85..e7b28c84df86a5 100644 --- a/src/transport/raw/TCP.cpp +++ b/src/transport/raw/TCP.cpp @@ -356,9 +356,11 @@ INET_ERROR TCPBase::OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBuf { Inet::IPAddress ipAddress; uint16_t port; + Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID; endPoint->GetPeerInfo(&ipAddress, &port); - PeerAddress peerAddress = PeerAddress::TCP(ipAddress, port); + endPoint->GetInterfaceId(&interfaceId); + PeerAddress peerAddress = PeerAddress::TCP(ipAddress, port, interfaceId); TCPBase * tcp = reinterpret_cast(endPoint->AppState); CHIP_ERROR err = tcp->ProcessReceivedBuffer(endPoint, peerAddress, std::move(buffer)); @@ -379,9 +381,11 @@ void TCPBase::OnConnectionComplete(Inet::TCPEndPoint * endPoint, INET_ERROR inet TCPBase * tcp = reinterpret_cast(endPoint->AppState); Inet::IPAddress ipAddress; uint16_t port; + Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID; endPoint->GetPeerInfo(&ipAddress, &port); - PeerAddress addr = PeerAddress::TCP(ipAddress, port); + endPoint->GetInterfaceId(&interfaceId); + PeerAddress addr = PeerAddress::TCP(ipAddress, port, interfaceId); // Send any pending packets for (size_t i = 0; i < tcp->mPendingPacketsSize; i++) @@ -507,9 +511,11 @@ void TCPBase::Disconnect(const PeerAddress & address) { Inet::IPAddress ipAddress; uint16_t port; + Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID; mActiveConnections[i].mEndPoint->GetPeerInfo(&ipAddress, &port); - if (address == PeerAddress::TCP(ipAddress, port)) + mActiveConnections[i].mEndPoint->GetInterfaceId(&interfaceId); + if (address == PeerAddress::TCP(ipAddress, port, interfaceId)) { // NOTE: this leaves the socket in TIME_WAIT. // Calling Abort() would clean it since SO_LINGER would be set to 0,