summaryrefslogtreecommitdiffstats
path: root/wifi
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2013-08-08 19:38:37 +0900
committerLorenzo Colitti <lorenzo@google.com>2013-09-06 08:21:23 +0900
commit34b2b9b6db7d57993bd71c2b62191c1fc533ebff (patch)
tree6976da68a4aaa199ab24fdc3aef2a0cb8918dbdb /wifi
parent22f407b11e11cfdb336e06e8c0d4a7ef1eafc783 (diff)
downloadframeworks_base-34b2b9b6db7d57993bd71c2b62191c1fc533ebff.zip
frameworks_base-34b2b9b6db7d57993bd71c2b62191c1fc533ebff.tar.gz
frameworks_base-34b2b9b6db7d57993bd71c2b62191c1fc533ebff.tar.bz2
Track IP addresses in WifiStateMachine.
This makes WifiStateMachine listen for interface address changes. When an address changes, WifiStateMachine will update its LinkProperties to match reality and notify the system that the link configuration has changed. This allows wifi to keep track of IPv6 addresses as well (previously it only knew about the IPv4 address passed in by DHCP). IP addresses are obtained directly from the kernel and always match those configured on the interface, so we treat them as authoritative and ignore addresses passed in via DHCP (by the time DHCP passes them in we've already been notified by the kernel anyway). Since we now have multiple sources of link information (the kernel for addresses and DHCP for routes and DNS, plus various bits of static information), also move all the code that sets mLinkProperties into one place. This allows us to be clearer about who is authoritative for which parts of mLinkProperties. Bug: 10232006 Change-Id: I4f262342379ce7fed172b67a1d403e3cd34f4232
Diffstat (limited to 'wifi')
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java185
1 files changed, 151 insertions, 34 deletions
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index d4e98c5..3ccdbea 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -51,6 +51,7 @@ import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkUtils;
+import android.net.RouteInfo;
import android.net.wifi.WpsResult.Status;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pService;
@@ -79,9 +80,12 @@ import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.server.net.BaseNetworkObserver;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.net.InetAddress;
+import java.net.Inet6Address;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -198,8 +202,19 @@ public class WifiStateMachine extends StateMachine {
/* Tracks sequence number on a driver time out */
private int mDriverStartToken = 0;
+ /**
+ * The link properties of the wifi interface.
+ * Do not modify this directly; use updateLinkProperties instead.
+ */
private LinkProperties mLinkProperties;
+ /**
+ * Subset of link properties coming from netlink.
+ * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers
+ * and domains obtained from router advertisements (RFC 6106).
+ */
+ private final LinkProperties mNetlinkLinkProperties;
+
/* Tracks sequence number on a periodic scan message */
private int mPeriodicScanToken = 0;
@@ -215,6 +230,39 @@ public class WifiStateMachine extends StateMachine {
private SupplicantStateTracker mSupplicantStateTracker;
private DhcpStateMachine mDhcpStateMachine;
+ private class InterfaceObserver extends BaseNetworkObserver {
+ private WifiStateMachine mWifiStateMachine;
+
+ InterfaceObserver(WifiStateMachine wifiStateMachine) {
+ super();
+ mWifiStateMachine = wifiStateMachine;
+ }
+
+ @Override
+ public void addressUpdated(String address, String iface, int flags, int scope) {
+ if (mWifiStateMachine.mInterfaceName.equals(iface)) {
+ if (DBG) {
+ log("addressUpdated: " + address + " on " + iface +
+ " flags " + flags + " scope " + scope);
+ }
+ mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_UPDATED, new LinkAddress(address));
+ }
+ }
+
+ @Override
+ public void addressRemoved(String address, String iface, int flags, int scope) {
+ if (mWifiStateMachine.mInterfaceName.equals(iface)) {
+ if (DBG) {
+ log("addressRemoved: " + address + " on " + iface +
+ " flags " + flags + " scope " + scope);
+ }
+ mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_REMOVED, new LinkAddress(address));
+ }
+ }
+ }
+
+ private InterfaceObserver mInterfaceObserver;
+
private AlarmManager mAlarmManager;
private PendingIntent mScanIntent;
private PendingIntent mDriverStopIntent;
@@ -372,6 +420,12 @@ public class WifiStateMachine extends StateMachine {
public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136;
public static final int CMD_POLL_BATCHED_SCAN = BASE + 137;
+ /* Link configuration (IP address, DNS, ...) changes */
+ /* An new IP address was added to our interface, or an existing IP address was updated */
+ static final int CMD_IP_ADDRESS_UPDATED = BASE + 140;
+ /* An IP address was removed from our interface */
+ static final int CMD_IP_ADDRESS_REMOVED = BASE + 141;
+
public static final int CONNECT_MODE = 1;
public static final int SCAN_ONLY_MODE = 2;
public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
@@ -585,15 +639,22 @@ public class WifiStateMachine extends StateMachine {
mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore,
getHandler());
mLinkProperties = new LinkProperties();
+ mNetlinkLinkProperties = new LinkProperties();
mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
mNetworkInfo.setIsAvailable(false);
- mLinkProperties.clear();
mLastBssid = null;
mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
mLastSignalLevel = -1;
+ mInterfaceObserver = new InterfaceObserver(this);
+ try {
+ mNwService.registerObserver(mInterfaceObserver);
+ } catch (RemoteException e) {
+ loge("Couldn't register interface observer: " + e.toString());
+ }
+
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
Intent scanIntent = new Intent(ACTION_START_SCAN, null);
mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
@@ -1906,19 +1967,82 @@ public class WifiStateMachine extends StateMachine {
}
}
- private void configureLinkProperties() {
- if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
- mLinkProperties = mWifiConfigStore.getLinkProperties(mLastNetworkId);
- } else {
- synchronized (mDhcpResultsLock) {
- if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) {
- mLinkProperties = mDhcpResults.linkProperties;
+ /**
+ * Updates mLinkProperties by merging information from various sources.
+ *
+ * This is needed because the information in mLinkProperties comes from multiple sources (DHCP,
+ * netlink, static configuration, ...). When one of these sources of information has updated
+ * link properties, we can't just assign them to mLinkProperties or we'd lose track of the
+ * information that came from other sources. Instead, when one of those sources has new
+ * information, we update the object that tracks the information from that source and then
+ * call this method to apply the change to mLinkProperties.
+ *
+ * The information in mLinkProperties is currently obtained as follows:
+ * - Interface name: set in the constructor.
+ * - IPv4 and IPv6 addresses: netlink, via mInterfaceObserver.
+ * - IPv4 routes, DNS servers, and domains: DHCP.
+ * - HTTP proxy: the wifi config store.
+ */
+ private void updateLinkProperties() {
+ LinkProperties newLp = new LinkProperties();
+
+ // Interface name and proxy are locally configured.
+ newLp.setInterfaceName(mInterfaceName);
+ newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
+
+ // IPv4 and IPv6 addresses come from netlink.
+ newLp.setLinkAddresses(mNetlinkLinkProperties.getLinkAddresses());
+
+ // For now, routing and DNS only come from DHCP or static configuration. In the future,
+ // we'll need to merge IPv6 DNS servers and domains coming from netlink.
+ synchronized (mDhcpResultsLock) {
+ // Even when we're using static configuration, we don't need to look at the config
+ // store, because static IP configuration also populates mDhcpResults.
+ if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) {
+ LinkProperties lp = mDhcpResults.linkProperties;
+ for (RouteInfo route: lp.getRoutes()) {
+ newLp.addRoute(route);
+ }
+ for (InetAddress dns: lp.getDnses()) {
+ newLp.addDns(dns);
}
+ newLp.setDomains(lp.getDomains());
+ }
+ }
+
+ // If anything has changed, and we're already connected, send out a notification.
+ // If we're still connecting, apps will be notified when we connect.
+ if (!newLp.equals(mLinkProperties)) {
+ if (DBG) {
+ log("Link configuration changed for netId: " + mLastNetworkId
+ + " old: " + mLinkProperties + "new: " + newLp);
+ }
+ mLinkProperties = newLp;
+ if (getNetworkDetailedState() == DetailedState.CONNECTED) {
+ sendLinkConfigurationChangedBroadcast();
}
- mLinkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
}
- mLinkProperties.setInterfaceName(mInterfaceName);
- if (DBG) log("netId=" + mLastNetworkId + " Link configured: " + mLinkProperties);
+ }
+
+ /**
+ * Clears all our link properties.
+ */
+ private void clearLinkProperties() {
+ // If the network used DHCP, clear the LinkProperties we stored in the config store.
+ if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+ mWifiConfigStore.clearLinkProperties(mLastNetworkId);
+ }
+
+ // Clear the link properties obtained from DHCP and netlink.
+ synchronized(mDhcpResultsLock) {
+ if (mDhcpResults != null && mDhcpResults.linkProperties != null) {
+ mDhcpResults.linkProperties.clear();
+ }
+ }
+ mNetlinkLinkProperties.clear();
+
+ // Now clear the merged link properties.
+ mLinkProperties.clear();
}
private int getMaxDhcpRetries() {
@@ -2041,16 +2165,11 @@ public class WifiStateMachine extends StateMachine {
mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
/* Clear network properties */
- mLinkProperties.clear();
+ clearLinkProperties();
/* send event to CM & network change broadcast */
sendNetworkStateChangeBroadcast(mLastBssid);
- /* Clear IP settings if the network used DHCP */
- if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
- mWifiConfigStore.clearLinkProperties(mLastNetworkId);
- }
-
mLastBssid= null;
mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
}
@@ -2149,20 +2268,7 @@ public class WifiStateMachine extends StateMachine {
}
mWifiInfo.setInetAddress(addr);
mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
- if (getNetworkDetailedState() == DetailedState.CONNECTED) {
- //DHCP renewal in connected state
- linkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
- if (!linkProperties.equals(mLinkProperties)) {
- if (DBG) {
- log("Link configuration changed for netId: " + mLastNetworkId
- + " old: " + mLinkProperties + "new: " + linkProperties);
- }
- mLinkProperties = linkProperties;
- sendLinkConfigurationChangedBroadcast();
- }
- } else {
- configureLinkProperties();
- }
+ updateLinkProperties();
}
private void handleFailedIpConfiguration() {
@@ -2387,6 +2493,17 @@ public class WifiStateMachine extends StateMachine {
mTemporarilyDisconnectWifi = (message.arg1 == 1);
replyToMessage(message, WifiP2pService.DISCONNECT_WIFI_RESPONSE);
break;
+ case CMD_IP_ADDRESS_UPDATED:
+ // addLinkAddress is a no-op if called more than once with the same address.
+ if (mNetlinkLinkProperties.addLinkAddress((LinkAddress) message.obj)) {
+ updateLinkProperties();
+ }
+ break;
+ case CMD_IP_ADDRESS_REMOVED:
+ if (mNetlinkLinkProperties.removeLinkAddress((LinkAddress) message.obj)) {
+ updateLinkProperties();
+ }
+ break;
default:
loge("Error! unhandled message" + message);
break;
@@ -3405,8 +3522,7 @@ public class WifiStateMachine extends StateMachine {
}
if (result.hasProxyChanged()) {
log("Reconfiguring proxy on connection");
- configureLinkProperties();
- sendLinkConfigurationChangedBroadcast();
+ updateLinkProperties();
}
}
@@ -3460,13 +3576,14 @@ public class WifiStateMachine extends StateMachine {
@Override
public void enter() {
if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+ // TODO: If we're switching between static IP configuration and DHCP, remove the
+ // static configuration first.
startDhcp();
} else {
// stop any running dhcp before assigning static IP
stopDhcp();
DhcpResults dhcpResults = new DhcpResults(
mWifiConfigStore.getLinkProperties(mLastNetworkId));
- dhcpResults.linkProperties.setInterfaceName(mInterfaceName);
InterfaceConfiguration ifcg = new InterfaceConfiguration();
Iterator<LinkAddress> addrs =
dhcpResults.linkProperties.getLinkAddresses().iterator();