| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/connectivity/network/mdns/service/mdns_interface_transceiver_v6.h" |
| |
| #include <arpa/inet.h> |
| #include <errno.h> |
| #include <sys/socket.h> |
| |
| #include "src/connectivity/network/mdns/service/mdns_addresses.h" |
| #include "src/lib/syslog/cpp/logger.h" |
| |
| namespace mdns { |
| |
| MdnsInterfaceTransceiverV6::MdnsInterfaceTransceiverV6(inet::IpAddress address, |
| const std::string& name, uint32_t index) |
| : MdnsInterfaceTransceiver(address, name, index) {} |
| |
| MdnsInterfaceTransceiverV6::~MdnsInterfaceTransceiverV6() {} |
| |
| int MdnsInterfaceTransceiverV6::SetOptionDisableMulticastLoop() { |
| int param = 0; |
| int result = |
| setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_MULTICAST_LOOP, ¶m, sizeof(param)); |
| if (result < 0) { |
| if (errno == ENOPROTOOPT) { |
| FX_LOGS(WARNING) << "NET-291 IPV6_MULTICAST_LOOP not supported " |
| "(ENOPROTOOPT), continuing anyway"; |
| result = 0; |
| } else { |
| FX_LOGS(ERROR) << "Failed to set socket option IPV6_MULTICAST_LOOP, " << strerror(errno); |
| } |
| } |
| |
| return result; |
| } |
| |
| int MdnsInterfaceTransceiverV6::SetOptionJoinMulticastGroup() { |
| ipv6_mreq param; |
| param.ipv6mr_multiaddr = addresses().v6_multicast().as_sockaddr_in6().sin6_addr; |
| param.ipv6mr_interface = index(); |
| int result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_JOIN_GROUP, ¶m, sizeof(param)); |
| if (result < 0) { |
| if (errno == ENODEV) { |
| FX_LOGS(WARNING) << "NET-2180 IPV6_JOIN_GROUP returned ENODEV, mDNS will " |
| "not communicate via IPV6"; |
| } else { |
| FX_LOGS(ERROR) << "Failed to set socket option IPV6_JOIN_GROUP, " << strerror(errno); |
| } |
| } |
| |
| return result; |
| } |
| |
| int MdnsInterfaceTransceiverV6::SetOptionOutboundInterface() { |
| uint32_t index = this->index(); |
| int result = |
| setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)); |
| if (result < 0) { |
| if (errno == EOPNOTSUPP) { |
| FX_LOGS(WARNING) << "NET-1901 IPV6_MULTICAST_IF not supported " |
| "(EOPNOTSUPP), continuing anyway"; |
| result = 0; |
| } else { |
| FX_LOGS(ERROR) << "Failed to set socket option IPV6_MULTICAST_IF, " << strerror(errno); |
| } |
| } |
| |
| return result; |
| } |
| |
| int MdnsInterfaceTransceiverV6::SetOptionUnicastTtl() { |
| int param = kTimeToLive_; |
| int result = |
| setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_UNICAST_HOPS, ¶m, sizeof(param)); |
| if (result < 0) { |
| if (errno == ENOPROTOOPT) { |
| // TODO(fxb/41357): remove the bug reference when the bug is fixed. |
| FX_LOGS(WARNING) |
| << "fxb/41357: IPV6_UNICAST_HOPS not supported (ENOPROTOOPT), continuing anyway"; |
| result = 0; |
| } else { |
| FX_LOGS(ERROR) << "Failed to set socket option IPV6_UNICAST_HOPS, " << strerror(errno); |
| } |
| } |
| |
| return result; |
| } |
| |
| int MdnsInterfaceTransceiverV6::SetOptionMulticastTtl() { |
| int param = kTimeToLive_; |
| int result = |
| setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_MULTICAST_HOPS, ¶m, sizeof(param)); |
| if (result < 0) { |
| if (errno == ENOPROTOOPT) { |
| FX_LOGS(WARNING) << "IPV6_MULTICAST_HOPS not supported (ENOPROTOOPT), continuing anyway"; |
| result = 0; |
| } else { |
| FX_LOGS(ERROR) << "Failed to set socket option IPV6_MULTICAST_HOPS, " << strerror(errno); |
| } |
| } |
| |
| return result; |
| } |
| |
| int MdnsInterfaceTransceiverV6::SetOptionFamilySpecific() { |
| // Set hop limit. |
| int param = 1; |
| int result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_HOPLIMIT, ¶m, sizeof(param)); |
| if (result < 0) { |
| if (errno == ENOPROTOOPT) { |
| // TODO(fxb/41358): remove the bug reference when the bug is fixed. |
| FX_LOGS(WARNING) << "fxb/41358: IPV6_HOPLIMIT not supported (ENOPROTOOPT), continuing anyway"; |
| result = 0; |
| } else { |
| FX_LOGS(ERROR) << "Failed to set socket option IPV6_HOPLIMIT, " << strerror(errno); |
| } |
| return result; |
| } |
| |
| // Receive V6 packets only. |
| param = 1; |
| result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_V6ONLY, ¶m, sizeof(param)); |
| if (result < 0) { |
| FX_LOGS(ERROR) << "Failed to set socket option IPV6_V6ONLY, " << strerror(errno); |
| return false; |
| } |
| |
| return result; |
| } |
| |
| int MdnsInterfaceTransceiverV6::Bind() { |
| int result = |
| bind(socket_fd().get(), addresses().v6_bind().as_sockaddr(), addresses().v6_bind().socklen()); |
| if (result < 0) { |
| FX_LOGS(ERROR) << "Failed to bind socket to V6 address, " << strerror(errno); |
| } |
| |
| return result; |
| } |
| |
| int MdnsInterfaceTransceiverV6::SendTo(const void* buffer, size_t size, |
| const inet::SocketAddress& address) { |
| if (address == addresses().v4_multicast()) { |
| return sendto(socket_fd().get(), buffer, size, 0, addresses().v6_multicast().as_sockaddr(), |
| addresses().v6_multicast().socklen()); |
| } |
| |
| return sendto(socket_fd().get(), buffer, size, 0, address.as_sockaddr(), address.socklen()); |
| } |
| |
| } // namespace mdns |