diff options
author | vandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-06 01:16:26 +0000 |
---|---|---|
committer | vandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-06 01:16:26 +0000 |
commit | b76055fcd9220aace76ba24ad82067558518ba21 (patch) | |
tree | 4cf5b5ea955379c82145a830d32128344e5a8232 /net | |
parent | d415b730fad0c9293970768a1b4aafc3121d97e6 (diff) | |
download | chromium_src-b76055fcd9220aace76ba24ad82067558518ba21.zip chromium_src-b76055fcd9220aace76ba24ad82067558518ba21.tar.gz chromium_src-b76055fcd9220aace76ba24ad82067558518ba21.tar.bz2 |
[Linux] Listen to and correctly handle IPv6 address change announcements.
BUG=36591
TEST=manually test that network change notifications happen at the right time.
Review URL: http://codereview.chromium.org/2881027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55171 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/network_change_notifier_netlink_linux.cc | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/net/base/network_change_notifier_netlink_linux.cc b/net/base/network_change_notifier_netlink_linux.cc index 5f71f45..493e17a 100644 --- a/net/base/network_change_notifier_netlink_linux.cc +++ b/net/base/network_change_notifier_netlink_linux.cc @@ -26,6 +26,35 @@ bool SetNonBlocking(int fd) { return fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0 ? true : false; } +bool IsIPv6Update(const struct nlmsghdr* netlink_message_header) { + const struct ifaddrmsg* address_message = + reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message_header)); + return address_message->ifa_family == AF_INET6; +} + +bool IsDuplicateIPv6AddressUpdate( + const struct nlmsghdr* netlink_message_header) { + const struct ifaddrmsg* address_message = + reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message_header)); + int address_message_length = IFA_PAYLOAD(netlink_message_header); + const struct rtattr* route_attribute = + reinterpret_cast<struct rtattr*>(IFA_RTA(address_message)); + DCHECK_EQ(address_message->ifa_family, AF_INET6); + + // Look for a cacheinfo attribute, and ignore new address broadcasts + // where the updated time stamp is newer than the created time stamp. + while (RTA_OK(route_attribute, address_message_length)) { + if (route_attribute->rta_type == IFA_CACHEINFO) { + struct ifa_cacheinfo* cache_info = + reinterpret_cast<struct ifa_cacheinfo*>(RTA_DATA(route_attribute)); + if (cache_info->cstamp != cache_info->tstamp) + return true; + } + route_attribute = RTA_NEXT(route_attribute, address_message_length); + } + return false; +} + } // namespace int InitializeNetlinkSocket() { @@ -46,7 +75,8 @@ int InitializeNetlinkSocket() { memset(&local_addr, 0, sizeof(local_addr)); local_addr.nl_family = AF_NETLINK; local_addr.nl_pid = getpid(); - local_addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_NOTIFY; + local_addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | + RTMGRP_NOTIFY; int ret = bind(sock, reinterpret_cast<struct sockaddr*>(&local_addr), sizeof(local_addr)); if (ret < 0) { @@ -79,6 +109,10 @@ bool HandleNetlinkMessage(char* buf, size_t len) { // may still end up notifying observers more than strictly necessary, but // if the primary interface goes down and back up, then this is necessary. case RTM_NEWADDR: + if (IsIPv6Update(netlink_message_header) && + IsDuplicateIPv6AddressUpdate(netlink_message_header)) + return false; + return true; case RTM_DELADDR: return true; case RTM_NEWLINK: |