author | Ryan VanderMeulen <ryanvm@gmail.com> |
Tue, 28 Aug 2012 16:02:29 -0400 | |
changeset 103700 | 1f93692fea1ebc066e7df9119da5d8f5d16d3565 |
parent 103695 | d63bb4e02b3dfd4e864ea18a5ba38699ed3d4a0b (current diff) |
parent 103699 | 61faabceedd4d18ac34178fca4f5e4fd16b4f26e (diff) |
child 103701 | 020c834a8991eb38904817fd64e3089f03d236a4 |
push id | 14120 |
push user | ryanvm@gmail.com |
push date | Tue, 28 Aug 2012 20:02:35 +0000 |
treeherder | mozilla-inbound@1f93692fea1e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 18.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/wifi/DOMWifiManager.js +++ b/dom/wifi/DOMWifiManager.js @@ -78,17 +78,18 @@ DOMWifiManager.prototype = { "WifiManager:getNetworks:Return:OK", "WifiManager:getNetworks:Return:NO", "WifiManager:associate:Return:OK", "WifiManager:associate:Return:NO", "WifiManager:forget:Return:OK", "WifiManager:forget:Return:NO", "WifiManager:wps:Return:OK", "WifiManager:wps:Return:NO", "WifiManager:wifiDown", "WifiManager:wifiUp", "WifiManager:onconnecting", "WifiManager:onassociate", "WifiManager:onconnect", "WifiManager:ondisconnect", "WifiManager:onwpstimeout", "WifiManager:onwpsfail", - "WifiManager:onwpsoverlap", "WifiManager:connectionInfoUpdate"]; + "WifiManager:onwpsoverlap", "WifiManager:connectionInfoUpdate", + "WifiManager:onconnectingfailed"]; this.initHelper(aWindow, messages); this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender); var state = this._mm.sendSyncMessage("WifiManager:getState")[0]; if (state) { this._currentNetwork = state.network; if (this._currentNetwork) exposeCurrentNetwork(this._currentNetwork); @@ -236,16 +237,22 @@ DOMWifiManager.prototype = { this._lastConnectionInfo = null; this._fireStatusChangeEvent(); break; case "WifiManager:connectionInfoUpdate": this._lastConnectionInfo = msg; this._fireConnectionInfoUpdate(msg); break; + case "WifiManager:onconnectingfailed": + this._currentNetwork = null; + this._connectionStatus = "connectingfailed"; + this._lastConnectionInfo = null; + this._fireStatusChangeEvent(); + break; } }, _fireStatusChangeEvent: function StatusChangeEvent() { if (this._onStatusChange) { debug("StatusChangeEvent"); var event = new this._window.MozWifiStatusChangeEvent("statusChangeEvent", { network: this._currentNetwork,
--- a/dom/wifi/WifiWorker.js +++ b/dom/wifi/WifiWorker.js @@ -15,16 +15,19 @@ const DEBUG = false; // set to true to s const WIFIWORKER_CONTRACTID = "@mozilla.org/wifi/worker;1"; const WIFIWORKER_CID = Components.ID("{a14e8977-d259-433a-a88d-58dd44657e5b}"); const WIFIWORKER_WORKER = "resource://gre/modules/wifi_worker.js"; const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed"; +const MAX_RETRIES_ON_AUTHENTICATION_FAILURE = 2; +const MAX_SUPPLICANT_LOOP_ITERATIONS = 4; + XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", "@mozilla.org/network/manager;1", "nsINetworkManager"); // A note about errors and error handling in this file: // The libraries that we use in this file are intended for C code. For // C code, it is natural to return -1 for errors and 0 for success. // Therefore, the code that interacts directly with the worker uses this @@ -48,17 +51,17 @@ var WifiManager = (function() { } c_property_get(key, cbuf, defaultValue); return cbuf.readString(); } return { sdkVersion: parseInt(property_get("ro.build.version.sdk")), device: property_get("ro.product.device") }; } catch(e) { // Eat it. Hopefully we're on a non-Gonk system ... - // + // // XXX we should check that return 0; } } let { sdkVersion, device } = getSdkVersionAndDevice(); var controlWorker = new ChromeWorker(WIFIWORKER_WORKER); @@ -584,16 +587,18 @@ var WifiManager = (function() { fields.state !== "INTERFACE_DISABLED" && fields.state !== "INACTIVE" && fields.state !== "SCANNING") { return false; } fields.prevState = manager.state; manager.state = fields.state; + // Detect wpa_supplicant's loop iterations. + manager.supplicantLoopDetection(fields.prevState, fields.state); notify("statechange", fields); return true; } function parseStatus(status, reconnected) { if (status === null) { debug("Unable to get wpa supplicant's status"); return; @@ -822,19 +827,25 @@ var WifiManager = (function() { if (eventData.indexOf("recv error") !== -1 && ++recvErrors < 10) return true; notifyStateChange({ state: "DISCONNECTED", BSSID: null, id: -1 }); notify("supplicantlost"); return false; } if (eventData.indexOf("CTRL-EVENT-DISCONNECTED") === 0) { + var token = event.split(" ")[1]; + var bssid = token.split("=")[1]; manager.connectionInfo.bssid = null; manager.connectionInfo.ssid = null; manager.connectionInfo.id = -1; + if (manager.authenticationFailuresCount > MAX_RETRIES_ON_AUTHENTICATION_FAILURE) { + notify("disconnected", {BSSID: bssid}); + manager.authenticationFailuresCount = 0; + } return true; } if (eventData.indexOf("CTRL-EVENT-CONNECTED") === 0) { // Format: CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=] var bssid = eventData.split(" ")[4]; var id = eventData.substr(eventData.indexOf("id=")).split(" ")[0]; // Don't call onconnected if we ignored this state change (since we were @@ -942,16 +953,18 @@ var WifiManager = (function() { }); } // Initial state manager.state = "UNINITIALIZED"; manager.enabled = false; manager.supplicantStarted = false; manager.connectionInfo = { ssid: null, bssid: null, id: -1 }; + manager.authenticationFailuresCount = 0; + manager.loopDetectionCount = 0; // Public interface of the wifi service manager.setWifiEnabled = function(enable, callback) { if (enable === manager.enabled) { callback("no change"); return; } @@ -1184,16 +1197,64 @@ var WifiManager = (function() { manager.wpsPin = wpsPinCommand; manager.wpsCancel = wpsCancelCommand; manager.getRssiApprox = getRssiApproxCommand; manager.getLinkSpeed = getLinkSpeedCommand; manager.getDhcpInfo = function() { return dhcpInfo; } manager.getConnectionInfo = (sdkVersion >= 15) ? getConnectionInfoICS : getConnectionInfoGB; + + manager.isHandShakeState = function(state) { + switch (state) { + case "AUTHENTICATING": + case "ASSOCIATING": + case "ASSOCIATED": + case "FOUR_WAY_HANDSHAKE": + case "GROUP_HANDSHAKE": + return true; + case "DORMANT": + case "COMPLETED": + case "DISCONNECTED": + case "INTERFACE_DISABLED": + case "INACTIVE": + case "SCANNING": + case "UNINITIALIZED": + case "INVALID": + case "CONNECTED": + default: + return false; + } + } + manager.stateOrdinal = function(state) { + return supplicantStatesMap.indexOf(state); + } + manager.supplicantLoopDetection = function(prevState, state) { + var isPrevStateInHandShake = manager.isHandShakeState(prevState); + var isStateInHandShake = manager.isHandShakeState(state); + + if (isPrevStateInHandShake) { + if (isStateInHandShake) { + // Increase the count only if we are in the loop. + if (manager.stateOrdinal(state) > manager.stateOrdinal(prevState)) { + manager.loopDetectionCount++; + } + if (manager.loopDetectionCount > MAX_SUPPLICANT_LOOP_ITERATIONS) { + notify("disconnected"); + manager.loopDetectionCount = 0; + } + } + } else { + // From others state to HandShake state. Reset the count. + if (isStateInHandShake) { + manager.loopDetectionCount = 0; + } + } + } + return manager; })(); function getKeyManagement(flags) { var types = []; if (!flags) return types; @@ -1463,16 +1524,27 @@ function WifiWorker() { WifiManager.enabled = WifiManager.supplicantStarted = false; WifiManager.state = "UNINITIALIZED"; debug("Couldn't connect to supplicant"); if (self._stateRequests.length > 0) self._notifyAfterStateChange(false, false); } + WifiManager.onpasswordmaybeincorrect = function() { + WifiManager.authenticationFailuresCount++; + } + WifiManager.ondisconnected = function() { + var currentNetwork = self.currentNetwork; + if (currentNetwork) { + WifiManager.disableNetwork(currentNetwork.netId, function() {}); + self._fireEvent("onconnectingfailed", {network: currentNetwork}); + } + } + WifiManager.onstatechange = function() { debug("State change: " + this.prevState + " -> " + this.state); if (self._connectionInfoTimer && this.state !== "CONNECTED" && this.state !== "COMPLETED") { self._stopConnectionInfoTimer(); } @@ -1521,16 +1593,19 @@ function WifiWorker() { // In this case, we connected to an already-connected wpa_supplicant, // because of that we need to gather information about the current // network here. self.currentNetwork = { ssid: quote(WifiManager.connectionInfo.ssid), netId: WifiManager.connectionInfo.id }; WifiManager.getNetworkConfiguration(self.currentNetwork, function(){}); } + // The full authentication process is completed, reset the count. + WifiManager.authenticationFailuresCount = 0; + WifiManager.loopDetectionCount = 0; self._startConnectionInfoTimer(); self._fireEvent("onassociate", { network: netToDOM(self.currentNetwork) }); break; case "CONNECTED": break; case "DISCONNECTED": self._fireEvent("ondisconnect", {}); self.currentNetwork = null; @@ -1580,17 +1655,17 @@ function WifiWorker() { WifiNetworkInterface.dns1 = this.info.dns1_str; WifiNetworkInterface.dns2 = this.info.dns2_str; Services.obs.notifyObservers(WifiNetworkInterface, kNetworkInterfaceStateChangedTopic, null); self._fireEvent("onconnect", { network: netToDOM(self.currentNetwork) }); } else { - WifiManager.disconnect(function(){}); + WifiManager.reassociate(function(){}); } }; WifiManager.onscanresultsavailable = function() { if (self.wantScanResults.length === 0) { debug("Scan results available, but we don't need them"); return; } @@ -1945,20 +2020,33 @@ WifiWorker.prototype = { getNetworks: function(msg) { const message = "WifiManager:getNetworks:Return"; if (!WifiManager.enabled) { this._sendMessage(message, false, "Wifi is disabled", msg); return; } - this.waitForScan((function (networks) { + let callback = (function (networks) { this._sendMessage(message, networks !== null, networks, msg); + }).bind(this); + this.waitForScan(callback); + + WifiManager.scan(true, (function(ok) { + // If the scan command succeeded, we're done. + if (ok) + return; + + // Avoid sending multiple responses. + this.wantScanResults.splice(this.wantScanResults.indexOf(callback), 1); + + // Otherwise, let the client know that it failed, it's responsible for + // trying again in a few seconds. + this._sendMessage(message, false, "ScanFailed", msg); }).bind(this)); - WifiManager.scan(true, function() {}); }, _notifyAfterStateChange: function(success, newState) { // First, notify all of the requests that were trying to make this change. let state = this._stateRequests[0].enabled; // If the new state is not the same as state, then we weren't processing // the first request (we were racing somehow) so don't notify.