| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/address_tracker_linux.h" | 5 #include "net/base/address_tracker_linux.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <linux/if.h> | 8 #include <linux/if.h> |
| 9 #include <sys/ioctl.h> | 9 #include <sys/ioctl.h> |
| 10 | 10 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 switch (attr->rta_type) { | 52 switch (attr->rta_type) { |
| 53 case IFA_ADDRESS: | 53 case IFA_ADDRESS: |
| 54 DCHECK_GE(RTA_PAYLOAD(attr), address_length); | 54 DCHECK_GE(RTA_PAYLOAD(attr), address_length); |
| 55 address = reinterpret_cast<unsigned char*>(RTA_DATA(attr)); | 55 address = reinterpret_cast<unsigned char*>(RTA_DATA(attr)); |
| 56 break; | 56 break; |
| 57 case IFA_LOCAL: | 57 case IFA_LOCAL: |
| 58 DCHECK_GE(RTA_PAYLOAD(attr), address_length); | 58 DCHECK_GE(RTA_PAYLOAD(attr), address_length); |
| 59 local = reinterpret_cast<unsigned char*>(RTA_DATA(attr)); | 59 local = reinterpret_cast<unsigned char*>(RTA_DATA(attr)); |
| 60 break; | 60 break; |
| 61 case IFA_CACHEINFO: { | 61 case IFA_CACHEINFO: { |
| 62 const struct ifa_cacheinfo *cache_info = | 62 const struct ifa_cacheinfo* cache_info = |
| 63 reinterpret_cast<const struct ifa_cacheinfo*>(RTA_DATA(attr)); | 63 reinterpret_cast<const struct ifa_cacheinfo*>(RTA_DATA(attr)); |
| 64 if (really_deprecated) | 64 if (really_deprecated) |
| 65 *really_deprecated = (cache_info->ifa_prefered == 0); | 65 *really_deprecated = (cache_info->ifa_prefered == 0); |
| 66 } break; | 66 } break; |
| 67 default: | 67 default: |
| 68 break; | 68 break; |
| 69 } | 69 } |
| 70 } | 70 } |
| 71 if (local) | 71 if (local) |
| 72 address = local; | 72 address = local; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 PLOG(ERROR) << "Could not create NETLINK socket"; | 122 PLOG(ERROR) << "Could not create NETLINK socket"; |
| 123 AbortAndForceOnline(); | 123 AbortAndForceOnline(); |
| 124 return; | 124 return; |
| 125 } | 125 } |
| 126 | 126 |
| 127 // Request notifications. | 127 // Request notifications. |
| 128 struct sockaddr_nl addr = {}; | 128 struct sockaddr_nl addr = {}; |
| 129 addr.nl_family = AF_NETLINK; | 129 addr.nl_family = AF_NETLINK; |
| 130 addr.nl_pid = getpid(); | 130 addr.nl_pid = getpid(); |
| 131 // TODO(szym): Track RTMGRP_LINK as well for ifi_type, http://crbug.com/113993 | 131 // TODO(szym): Track RTMGRP_LINK as well for ifi_type, http://crbug.com/113993 |
| 132 addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY | | 132 addr.nl_groups = |
| 133 RTMGRP_LINK; | 133 RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY | RTMGRP_LINK; |
| 134 int rv = bind(netlink_fd_, | 134 int rv = bind( |
| 135 reinterpret_cast<struct sockaddr*>(&addr), | 135 netlink_fd_, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)); |
| 136 sizeof(addr)); | |
| 137 if (rv < 0) { | 136 if (rv < 0) { |
| 138 PLOG(ERROR) << "Could not bind NETLINK socket"; | 137 PLOG(ERROR) << "Could not bind NETLINK socket"; |
| 139 AbortAndForceOnline(); | 138 AbortAndForceOnline(); |
| 140 return; | 139 return; |
| 141 } | 140 } |
| 142 | 141 |
| 143 // Request dump of addresses. | 142 // Request dump of addresses. |
| 144 struct sockaddr_nl peer = {}; | 143 struct sockaddr_nl peer = {}; |
| 145 peer.nl_family = AF_NETLINK; | 144 peer.nl_family = AF_NETLINK; |
| 146 | 145 |
| 147 struct { | 146 struct { |
| 148 struct nlmsghdr header; | 147 struct nlmsghdr header; |
| 149 struct rtgenmsg msg; | 148 struct rtgenmsg msg; |
| 150 } request = {}; | 149 } request = {}; |
| 151 | 150 |
| 152 request.header.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg)); | 151 request.header.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg)); |
| 153 request.header.nlmsg_type = RTM_GETADDR; | 152 request.header.nlmsg_type = RTM_GETADDR; |
| 154 request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; | 153 request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; |
| 155 request.header.nlmsg_pid = getpid(); | 154 request.header.nlmsg_pid = getpid(); |
| 156 request.msg.rtgen_family = AF_UNSPEC; | 155 request.msg.rtgen_family = AF_UNSPEC; |
| 157 | 156 |
| 158 rv = HANDLE_EINTR(sendto(netlink_fd_, &request, request.header.nlmsg_len, | 157 rv = HANDLE_EINTR(sendto(netlink_fd_, |
| 159 0, reinterpret_cast<struct sockaddr*>(&peer), | 158 &request, |
| 159 request.header.nlmsg_len, |
| 160 0, |
| 161 reinterpret_cast<struct sockaddr*>(&peer), |
| 160 sizeof(peer))); | 162 sizeof(peer))); |
| 161 if (rv < 0) { | 163 if (rv < 0) { |
| 162 PLOG(ERROR) << "Could not send NETLINK request"; | 164 PLOG(ERROR) << "Could not send NETLINK request"; |
| 163 AbortAndForceOnline(); | 165 AbortAndForceOnline(); |
| 164 return; | 166 return; |
| 165 } | 167 } |
| 166 | 168 |
| 167 // Consume pending message to populate the AddressMap, but don't notify. | 169 // Consume pending message to populate the AddressMap, but don't notify. |
| 168 // Sending another request without first reading responses results in EBUSY. | 170 // Sending another request without first reading responses results in EBUSY. |
| 169 bool address_changed; | 171 bool address_changed; |
| 170 bool link_changed; | 172 bool link_changed; |
| 171 bool tunnel_changed; | 173 bool tunnel_changed; |
| 172 ReadMessages(&address_changed, &link_changed, &tunnel_changed); | 174 ReadMessages(&address_changed, &link_changed, &tunnel_changed); |
| 173 | 175 |
| 174 // Request dump of link state | 176 // Request dump of link state |
| 175 request.header.nlmsg_type = RTM_GETLINK; | 177 request.header.nlmsg_type = RTM_GETLINK; |
| 176 | 178 |
| 177 rv = HANDLE_EINTR(sendto(netlink_fd_, &request, request.header.nlmsg_len, 0, | 179 rv = HANDLE_EINTR(sendto(netlink_fd_, |
| 180 &request, |
| 181 request.header.nlmsg_len, |
| 182 0, |
| 178 reinterpret_cast<struct sockaddr*>(&peer), | 183 reinterpret_cast<struct sockaddr*>(&peer), |
| 179 sizeof(peer))); | 184 sizeof(peer))); |
| 180 if (rv < 0) { | 185 if (rv < 0) { |
| 181 PLOG(ERROR) << "Could not send NETLINK request"; | 186 PLOG(ERROR) << "Could not send NETLINK request"; |
| 182 AbortAndForceOnline(); | 187 AbortAndForceOnline(); |
| 183 return; | 188 return; |
| 184 } | 189 } |
| 185 | 190 |
| 186 // Consume pending message to populate links_online_, but don't notify. | 191 // Consume pending message to populate links_online_, but don't notify. |
| 187 ReadMessages(&address_changed, &link_changed, &tunnel_changed); | 192 ReadMessages(&address_changed, &link_changed, &tunnel_changed); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 217 AddressTrackerLinux::GetCurrentConnectionType() { | 222 AddressTrackerLinux::GetCurrentConnectionType() { |
| 218 // http://crbug.com/125097 | 223 // http://crbug.com/125097 |
| 219 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 224 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 220 base::AutoLock lock(is_offline_lock_); | 225 base::AutoLock lock(is_offline_lock_); |
| 221 // Make sure the initial offline state is set before returning. | 226 // Make sure the initial offline state is set before returning. |
| 222 while (!is_offline_initialized_) { | 227 while (!is_offline_initialized_) { |
| 223 is_offline_initialized_cv_.Wait(); | 228 is_offline_initialized_cv_.Wait(); |
| 224 } | 229 } |
| 225 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. | 230 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. |
| 226 // http://crbug.com/160537 | 231 // http://crbug.com/160537 |
| 227 return is_offline_ ? NetworkChangeNotifier::CONNECTION_NONE : | 232 return is_offline_ ? NetworkChangeNotifier::CONNECTION_NONE |
| 228 NetworkChangeNotifier::CONNECTION_UNKNOWN; | 233 : NetworkChangeNotifier::CONNECTION_UNKNOWN; |
| 229 } | 234 } |
| 230 | 235 |
| 231 void AddressTrackerLinux::ReadMessages(bool* address_changed, | 236 void AddressTrackerLinux::ReadMessages(bool* address_changed, |
| 232 bool* link_changed, | 237 bool* link_changed, |
| 233 bool* tunnel_changed) { | 238 bool* tunnel_changed) { |
| 234 *address_changed = false; | 239 *address_changed = false; |
| 235 *link_changed = false; | 240 *link_changed = false; |
| 236 *tunnel_changed = false; | 241 *tunnel_changed = false; |
| 237 char buffer[4096]; | 242 char buffer[4096]; |
| 238 bool first_loop = true; | 243 bool first_loop = true; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 for (struct nlmsghdr* header = reinterpret_cast<struct nlmsghdr*>(buffer); | 275 for (struct nlmsghdr* header = reinterpret_cast<struct nlmsghdr*>(buffer); |
| 271 NLMSG_OK(header, length); | 276 NLMSG_OK(header, length); |
| 272 header = NLMSG_NEXT(header, length)) { | 277 header = NLMSG_NEXT(header, length)) { |
| 273 switch (header->nlmsg_type) { | 278 switch (header->nlmsg_type) { |
| 274 case NLMSG_DONE: | 279 case NLMSG_DONE: |
| 275 return; | 280 return; |
| 276 case NLMSG_ERROR: { | 281 case NLMSG_ERROR: { |
| 277 const struct nlmsgerr* msg = | 282 const struct nlmsgerr* msg = |
| 278 reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(header)); | 283 reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(header)); |
| 279 LOG(ERROR) << "Unexpected netlink error " << msg->error << "."; | 284 LOG(ERROR) << "Unexpected netlink error " << msg->error << "."; |
| 280 } return; | 285 } |
| 286 return; |
| 281 case RTM_NEWADDR: { | 287 case RTM_NEWADDR: { |
| 282 IPAddressNumber address; | 288 IPAddressNumber address; |
| 283 bool really_deprecated; | 289 bool really_deprecated; |
| 284 if (GetAddress(header, &address, &really_deprecated)) { | 290 if (GetAddress(header, &address, &really_deprecated)) { |
| 285 base::AutoLock lock(address_map_lock_); | 291 base::AutoLock lock(address_map_lock_); |
| 286 struct ifaddrmsg* msg = | 292 struct ifaddrmsg* msg = |
| 287 reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(header)); | 293 reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(header)); |
| 288 // Routers may frequently (every few seconds) output the IPv6 ULA | 294 // Routers may frequently (every few seconds) output the IPv6 ULA |
| 289 // prefix which can cause the linux kernel to frequently output two | 295 // prefix which can cause the linux kernel to frequently output two |
| 290 // back-to-back messages, one without the deprecated flag and one with | 296 // back-to-back messages, one without the deprecated flag and one with |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 bool tunnel_changed; | 360 bool tunnel_changed; |
| 355 ReadMessages(&address_changed, &link_changed, &tunnel_changed); | 361 ReadMessages(&address_changed, &link_changed, &tunnel_changed); |
| 356 if (address_changed) | 362 if (address_changed) |
| 357 address_callback_.Run(); | 363 address_callback_.Run(); |
| 358 if (link_changed) | 364 if (link_changed) |
| 359 link_callback_.Run(); | 365 link_callback_.Run(); |
| 360 if (tunnel_changed) | 366 if (tunnel_changed) |
| 361 tunnel_callback_.Run(); | 367 tunnel_callback_.Run(); |
| 362 } | 368 } |
| 363 | 369 |
| 364 void AddressTrackerLinux::OnFileCanWriteWithoutBlocking(int /* fd */) {} | 370 void AddressTrackerLinux::OnFileCanWriteWithoutBlocking(int /* fd */) { |
| 371 } |
| 365 | 372 |
| 366 void AddressTrackerLinux::CloseSocket() { | 373 void AddressTrackerLinux::CloseSocket() { |
| 367 if (netlink_fd_ >= 0 && IGNORE_EINTR(close(netlink_fd_)) < 0) | 374 if (netlink_fd_ >= 0 && IGNORE_EINTR(close(netlink_fd_)) < 0) |
| 368 PLOG(ERROR) << "Could not close NETLINK socket."; | 375 PLOG(ERROR) << "Could not close NETLINK socket."; |
| 369 netlink_fd_ = -1; | 376 netlink_fd_ = -1; |
| 370 } | 377 } |
| 371 | 378 |
| 372 bool AddressTrackerLinux::IsTunnelInterface(const struct ifinfomsg* msg) const { | 379 bool AddressTrackerLinux::IsTunnelInterface(const struct ifinfomsg* msg) const { |
| 373 // Linux kernel drivers/net/tun.c uses "tun" name prefix. | 380 // Linux kernel drivers/net/tun.c uses "tun" name prefix. |
| 374 return strncmp(get_interface_name_(msg->ifi_index), "tun", 3) == 0; | 381 return strncmp(get_interface_name_(msg->ifi_index), "tun", 3) == 0; |
| 375 } | 382 } |
| 376 | 383 |
| 377 } // namespace internal | 384 } // namespace internal |
| 378 } // namespace net | 385 } // namespace net |
| OLD | NEW |