summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorvandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-06 01:16:26 +0000
committervandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-06 01:16:26 +0000
commitb76055fcd9220aace76ba24ad82067558518ba21 (patch)
tree4cf5b5ea955379c82145a830d32128344e5a8232 /net
parentd415b730fad0c9293970768a1b4aafc3121d97e6 (diff)
downloadchromium_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.cc36
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: