1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/wifi/WifiWorker.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,3307 @@ 1.4 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +"use strict"; 1.11 + 1.12 +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; 1.13 + 1.14 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.15 +Cu.import("resource://gre/modules/Services.jsm"); 1.16 +Cu.import("resource://gre/modules/systemlibs.js"); 1.17 +Cu.import("resource://gre/modules/WifiCommand.jsm"); 1.18 +Cu.import("resource://gre/modules/WifiNetUtil.jsm"); 1.19 +Cu.import("resource://gre/modules/WifiP2pManager.jsm"); 1.20 +Cu.import("resource://gre/modules/WifiP2pWorkerObserver.jsm"); 1.21 + 1.22 +var DEBUG = false; // set to true to show debug messages. 1.23 + 1.24 +const WIFIWORKER_CONTRACTID = "@mozilla.org/wifi/worker;1"; 1.25 +const WIFIWORKER_CID = Components.ID("{a14e8977-d259-433a-a88d-58dd44657e5b}"); 1.26 + 1.27 +const WIFIWORKER_WORKER = "resource://gre/modules/wifi_worker.js"; 1.28 + 1.29 +const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed"; 1.30 +const kMozSettingsChangedObserverTopic = "mozsettings-changed"; 1.31 + 1.32 +const MAX_RETRIES_ON_AUTHENTICATION_FAILURE = 2; 1.33 +const MAX_SUPPLICANT_LOOP_ITERATIONS = 4; 1.34 +const MAX_RETRIES_ON_DHCP_FAILURE = 2; 1.35 + 1.36 +// Settings DB path for wifi 1.37 +const SETTINGS_WIFI_ENABLED = "wifi.enabled"; 1.38 +const SETTINGS_WIFI_DEBUG_ENABLED = "wifi.debugging.enabled"; 1.39 +// Settings DB path for Wifi tethering. 1.40 +const SETTINGS_WIFI_TETHERING_ENABLED = "tethering.wifi.enabled"; 1.41 +const SETTINGS_WIFI_SSID = "tethering.wifi.ssid"; 1.42 +const SETTINGS_WIFI_SECURITY_TYPE = "tethering.wifi.security.type"; 1.43 +const SETTINGS_WIFI_SECURITY_PASSWORD = "tethering.wifi.security.password"; 1.44 +const SETTINGS_WIFI_IP = "tethering.wifi.ip"; 1.45 +const SETTINGS_WIFI_PREFIX = "tethering.wifi.prefix"; 1.46 +const SETTINGS_WIFI_DHCPSERVER_STARTIP = "tethering.wifi.dhcpserver.startip"; 1.47 +const SETTINGS_WIFI_DHCPSERVER_ENDIP = "tethering.wifi.dhcpserver.endip"; 1.48 +const SETTINGS_WIFI_DNS1 = "tethering.wifi.dns1"; 1.49 +const SETTINGS_WIFI_DNS2 = "tethering.wifi.dns2"; 1.50 + 1.51 +// Settings DB path for USB tethering. 1.52 +const SETTINGS_USB_DHCPSERVER_STARTIP = "tethering.usb.dhcpserver.startip"; 1.53 +const SETTINGS_USB_DHCPSERVER_ENDIP = "tethering.usb.dhcpserver.endip"; 1.54 + 1.55 +// Default value for WIFI tethering. 1.56 +const DEFAULT_WIFI_IP = "192.168.1.1"; 1.57 +const DEFAULT_WIFI_PREFIX = "24"; 1.58 +const DEFAULT_WIFI_DHCPSERVER_STARTIP = "192.168.1.10"; 1.59 +const DEFAULT_WIFI_DHCPSERVER_ENDIP = "192.168.1.30"; 1.60 +const DEFAULT_WIFI_SSID = "FirefoxHotspot"; 1.61 +const DEFAULT_WIFI_SECURITY_TYPE = "open"; 1.62 +const DEFAULT_WIFI_SECURITY_PASSWORD = "1234567890"; 1.63 +const DEFAULT_DNS1 = "8.8.8.8"; 1.64 +const DEFAULT_DNS2 = "8.8.4.4"; 1.65 + 1.66 +// Default value for USB tethering. 1.67 +const DEFAULT_USB_DHCPSERVER_STARTIP = "192.168.0.10"; 1.68 +const DEFAULT_USB_DHCPSERVER_ENDIP = "192.168.0.30"; 1.69 + 1.70 +const WIFI_FIRMWARE_AP = "AP"; 1.71 +const WIFI_FIRMWARE_STATION = "STA"; 1.72 +const WIFI_SECURITY_TYPE_NONE = "open"; 1.73 +const WIFI_SECURITY_TYPE_WPA_PSK = "wpa-psk"; 1.74 +const WIFI_SECURITY_TYPE_WPA2_PSK = "wpa2-psk"; 1.75 + 1.76 +const NETWORK_INTERFACE_UP = "up"; 1.77 +const NETWORK_INTERFACE_DOWN = "down"; 1.78 + 1.79 +const DEFAULT_WLAN_INTERFACE = "wlan0"; 1.80 + 1.81 +const DRIVER_READY_WAIT = 2000; 1.82 + 1.83 +const SUPP_PROP = "init.svc.wpa_supplicant"; 1.84 +const WPA_SUPPLICANT = "wpa_supplicant"; 1.85 +const DHCP_PROP = "init.svc.dhcpcd"; 1.86 +const DHCP = "dhcpcd"; 1.87 + 1.88 +XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", 1.89 + "@mozilla.org/network/manager;1", 1.90 + "nsINetworkManager"); 1.91 + 1.92 +XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService", 1.93 + "@mozilla.org/network/service;1", 1.94 + "nsINetworkService"); 1.95 + 1.96 +XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", 1.97 + "@mozilla.org/settingsService;1", 1.98 + "nsISettingsService"); 1.99 + 1.100 +// A note about errors and error handling in this file: 1.101 +// The libraries that we use in this file are intended for C code. For 1.102 +// C code, it is natural to return -1 for errors and 0 for success. 1.103 +// Therefore, the code that interacts directly with the worker uses this 1.104 +// convention (note: command functions do get boolean results since the 1.105 +// command always succeeds and we do a string/boolean check for the 1.106 +// expected results). 1.107 +var WifiManager = (function() { 1.108 + var manager = {}; 1.109 + 1.110 + function getStartupPrefs() { 1.111 + return { 1.112 + sdkVersion: parseInt(libcutils.property_get("ro.build.version.sdk"), 10), 1.113 + unloadDriverEnabled: libcutils.property_get("ro.moz.wifi.unloaddriver") === "1", 1.114 + schedScanRecovery: libcutils.property_get("ro.moz.wifi.sched_scan_recover") === "false" ? false : true, 1.115 + driverDelay: libcutils.property_get("ro.moz.wifi.driverDelay"), 1.116 + p2pSupported: libcutils.property_get("ro.moz.wifi.p2p_supported") === "1", 1.117 + eapSimSupported: libcutils.property_get("ro.moz.wifi.eapsim_supported") === "1", 1.118 + ifname: libcutils.property_get("wifi.interface") 1.119 + }; 1.120 + } 1.121 + 1.122 + let {sdkVersion, unloadDriverEnabled, schedScanRecovery, 1.123 + driverDelay, p2pSupported, eapSimSupported, ifname} = getStartupPrefs(); 1.124 + 1.125 + let capabilities = { 1.126 + eapSim: eapSimSupported 1.127 + }; 1.128 + 1.129 + let wifiListener = { 1.130 + onWaitEvent: function(event, iface) { 1.131 + if (manager.ifname === iface && handleEvent(event)) { 1.132 + waitForEvent(iface); 1.133 + } else if (p2pSupported) { 1.134 + if (WifiP2pManager.INTERFACE_NAME === iface) { 1.135 + // If the connection is closed, wifi.c::wifi_wait_for_event() 1.136 + // will still return 'CTRL-EVENT-TERMINATING - connection closed' 1.137 + // rather than blocking. So when we see this special event string, 1.138 + // just return immediately. 1.139 + const TERMINATED_EVENT = 'CTRL-EVENT-TERMINATING - connection closed'; 1.140 + if (-1 !== event.indexOf(TERMINATED_EVENT)) { 1.141 + return; 1.142 + } 1.143 + p2pManager.handleEvent(event); 1.144 + waitForEvent(iface); 1.145 + } 1.146 + } 1.147 + }, 1.148 + 1.149 + onCommand: function(event, iface) { 1.150 + onmessageresult(event, iface); 1.151 + } 1.152 + } 1.153 + 1.154 + manager.ifname = ifname; 1.155 + manager.connectToSupplicant = false; 1.156 + // Emulator build runs to here. 1.157 + // The debug() should only be used after WifiManager. 1.158 + if (!ifname) { 1.159 + manager.ifname = DEFAULT_WLAN_INTERFACE; 1.160 + } 1.161 + manager.schedScanRecovery = schedScanRecovery; 1.162 + manager.driverDelay = driverDelay ? parseInt(driverDelay, 10) : DRIVER_READY_WAIT; 1.163 + 1.164 + // Regular Wifi stuff. 1.165 + var netUtil = WifiNetUtil(controlMessage); 1.166 + var wifiCommand = WifiCommand(controlMessage, manager.ifname); 1.167 + 1.168 + // Wifi P2P stuff 1.169 + var p2pManager; 1.170 + if (p2pSupported) { 1.171 + let p2pCommand = WifiCommand(controlMessage, WifiP2pManager.INTERFACE_NAME); 1.172 + p2pManager = WifiP2pManager(p2pCommand, netUtil); 1.173 + } 1.174 + 1.175 + let wifiService = Cc["@mozilla.org/wifi/service;1"]; 1.176 + if (wifiService) { 1.177 + wifiService = wifiService.getService(Ci.nsIWifiProxyService); 1.178 + let interfaces = [manager.ifname]; 1.179 + if (p2pSupported) { 1.180 + interfaces.push(WifiP2pManager.INTERFACE_NAME); 1.181 + } 1.182 + wifiService.start(wifiListener, interfaces, interfaces.length); 1.183 + } else { 1.184 + debug("No wifi service component available!"); 1.185 + } 1.186 + 1.187 + // Callbacks to invoke when a reply arrives from the wifi service. 1.188 + var controlCallbacks = Object.create(null); 1.189 + var idgen = 0; 1.190 + 1.191 + function controlMessage(obj, callback) { 1.192 + var id = idgen++; 1.193 + obj.id = id; 1.194 + if (callback) { 1.195 + controlCallbacks[id] = callback; 1.196 + } 1.197 + wifiService.sendCommand(obj, obj.iface); 1.198 + } 1.199 + 1.200 + let onmessageresult = function(data, iface) { 1.201 + var id = data.id; 1.202 + var callback = controlCallbacks[id]; 1.203 + if (callback) { 1.204 + callback(data); 1.205 + delete controlCallbacks[id]; 1.206 + } 1.207 + } 1.208 + 1.209 + // Polling the status worker 1.210 + var recvErrors = 0; 1.211 + 1.212 + function waitForEvent(iface) { 1.213 + wifiService.waitForEvent(iface); 1.214 + } 1.215 + 1.216 + // Commands to the control worker. 1.217 + 1.218 + var driverLoaded = false; 1.219 + 1.220 + function loadDriver(callback) { 1.221 + if (driverLoaded) { 1.222 + callback(0); 1.223 + return; 1.224 + } 1.225 + 1.226 + wifiCommand.loadDriver(function (status) { 1.227 + driverLoaded = (status >= 0); 1.228 + callback(status) 1.229 + }); 1.230 + } 1.231 + 1.232 + function unloadDriver(type, callback) { 1.233 + if (!unloadDriverEnabled) { 1.234 + // Unloading drivers is generally unnecessary and 1.235 + // can trigger bugs in some drivers. 1.236 + // On properly written drivers, bringing the interface 1.237 + // down powers down the interface. 1.238 + if (type === WIFI_FIRMWARE_STATION) { 1.239 + notify("supplicantlost", { success: true }); 1.240 + } 1.241 + callback(0); 1.242 + return; 1.243 + } 1.244 + 1.245 + wifiCommand.unloadDriver(function(status) { 1.246 + driverLoaded = (status < 0); 1.247 + if (type === WIFI_FIRMWARE_STATION) { 1.248 + notify("supplicantlost", { success: true }); 1.249 + } 1.250 + callback(status); 1.251 + }); 1.252 + } 1.253 + 1.254 + // A note about background scanning: 1.255 + // Normally, background scanning shouldn't be necessary as wpa_supplicant 1.256 + // has the capability to automatically schedule its own scans at appropriate 1.257 + // intervals. However, with some drivers, this appears to get stuck after 1.258 + // three scans, so we enable the driver's background scanning to work around 1.259 + // that when we're not connected to any network. This ensures that we'll 1.260 + // automatically reconnect to networks if one falls out of range. 1.261 + var reEnableBackgroundScan = false; 1.262 + 1.263 + // NB: This is part of the internal API. 1.264 + manager.backgroundScanEnabled = false; 1.265 + function setBackgroundScan(enable, callback) { 1.266 + var doEnable = (enable === "ON"); 1.267 + if (doEnable === manager.backgroundScanEnabled) { 1.268 + callback(false, true); 1.269 + return; 1.270 + } 1.271 + 1.272 + manager.backgroundScanEnabled = doEnable; 1.273 + wifiCommand.setBackgroundScan(manager.backgroundScanEnabled, callback); 1.274 + } 1.275 + 1.276 + var scanModeActive = false; 1.277 + 1.278 + function scan(forceActive, callback) { 1.279 + if (forceActive && !scanModeActive) { 1.280 + // Note: we ignore errors from doSetScanMode. 1.281 + wifiCommand.doSetScanMode(true, function(ignore) { 1.282 + setBackgroundScan("OFF", function(turned, ignore) { 1.283 + reEnableBackgroundScan = turned; 1.284 + manager.handlePreWifiScan(); 1.285 + wifiCommand.scan(function(ok) { 1.286 + wifiCommand.doSetScanMode(false, function(ignore) { 1.287 + // The result of scanCommand is the result of the actual SCAN 1.288 + // request. 1.289 + callback(ok); 1.290 + }); 1.291 + }); 1.292 + }); 1.293 + }); 1.294 + return; 1.295 + } 1.296 + manager.handlePreWifiScan(); 1.297 + wifiCommand.scan(callback); 1.298 + } 1.299 + 1.300 + var debugEnabled = false; 1.301 + 1.302 + function syncDebug() { 1.303 + if (debugEnabled !== DEBUG) { 1.304 + let wanted = DEBUG; 1.305 + wifiCommand.setLogLevel(wanted ? "DEBUG" : "INFO", function(ok) { 1.306 + if (ok) 1.307 + debugEnabled = wanted; 1.308 + }); 1.309 + if (p2pSupported && p2pManager) { 1.310 + p2pManager.setDebug(DEBUG); 1.311 + } 1.312 + } 1.313 + } 1.314 + 1.315 + function getDebugEnabled(callback) { 1.316 + wifiCommand.getLogLevel(function(level) { 1.317 + if (level === null) { 1.318 + debug("Unable to get wpa_supplicant's log level"); 1.319 + callback(false); 1.320 + return; 1.321 + } 1.322 + 1.323 + var lines = level.split("\n"); 1.324 + for (let i = 0; i < lines.length; ++i) { 1.325 + let match = /Current level: (.*)/.exec(lines[i]); 1.326 + if (match) { 1.327 + debugEnabled = match[1].toLowerCase() === "debug"; 1.328 + callback(true); 1.329 + return; 1.330 + } 1.331 + } 1.332 + 1.333 + // If we're here, we didn't get the current level. 1.334 + callback(false); 1.335 + }); 1.336 + } 1.337 + 1.338 + function setScanMode(setActive, callback) { 1.339 + scanModeActive = setActive; 1.340 + wifiCommand.doSetScanMode(setActive, callback); 1.341 + } 1.342 + 1.343 + var httpProxyConfig = Object.create(null); 1.344 + 1.345 + /** 1.346 + * Given a network, configure http proxy when using wifi. 1.347 + * @param network A network object to update http proxy 1.348 + * @param info Info should have following field: 1.349 + * - httpProxyHost ip address of http proxy. 1.350 + * - httpProxyPort port of http proxy, set 0 to use default port 8080. 1.351 + * @param callback callback function. 1.352 + */ 1.353 + function configureHttpProxy(network, info, callback) { 1.354 + if (!network) 1.355 + return; 1.356 + 1.357 + let networkKey = getNetworkKey(network); 1.358 + 1.359 + if (!info || info.httpProxyHost === "") { 1.360 + delete httpProxyConfig[networkKey]; 1.361 + } else { 1.362 + httpProxyConfig[networkKey] = network; 1.363 + httpProxyConfig[networkKey].httpProxyHost = info.httpProxyHost; 1.364 + httpProxyConfig[networkKey].httpProxyPort = info.httpProxyPort; 1.365 + } 1.366 + 1.367 + callback(true); 1.368 + } 1.369 + 1.370 + function getHttpProxyNetwork(network) { 1.371 + if (!network) 1.372 + return null; 1.373 + 1.374 + let networkKey = getNetworkKey(network); 1.375 + return ((networkKey in httpProxyConfig) ? httpProxyConfig : null); 1.376 + } 1.377 + 1.378 + function setHttpProxy(network) { 1.379 + if (!network) 1.380 + return; 1.381 + 1.382 + gNetworkService.setNetworkProxy(network); 1.383 + } 1.384 + 1.385 + var staticIpConfig = Object.create(null); 1.386 + function setStaticIpMode(network, info, callback) { 1.387 + let setNetworkKey = getNetworkKey(network); 1.388 + let curNetworkKey = null; 1.389 + let currentNetwork = Object.create(null); 1.390 + currentNetwork.netId = manager.connectionInfo.id; 1.391 + 1.392 + manager.getNetworkConfiguration(currentNetwork, function (){ 1.393 + curNetworkKey = getNetworkKey(currentNetwork); 1.394 + 1.395 + // Add additional information to static ip configuration 1.396 + // It is used to compatiable with information dhcp callback. 1.397 + info.ipaddr = stringToIp(info.ipaddr_str); 1.398 + info.gateway = stringToIp(info.gateway_str); 1.399 + info.mask_str = makeMask(info.maskLength); 1.400 + 1.401 + // Optional 1.402 + info.dns1 = stringToIp("dns1_str" in info ? info.dns1_str : ""); 1.403 + info.dns2 = stringToIp("dns2_str" in info ? info.dns2_str : ""); 1.404 + info.proxy = stringToIp("proxy_str" in info ? info.proxy_str : ""); 1.405 + 1.406 + staticIpConfig[setNetworkKey] = info; 1.407 + 1.408 + // If the ssid of current connection is the same as configured ssid 1.409 + // It means we need update current connection to use static IP address. 1.410 + if (setNetworkKey == curNetworkKey) { 1.411 + // Use configureInterface directly doesn't work, the network iterface 1.412 + // and routing table is changed but still cannot connect to network 1.413 + // so the workaround here is disable interface the enable again to 1.414 + // trigger network reconnect with static ip. 1.415 + netUtil.disableInterface(manager.ifname, function (ok) { 1.416 + netUtil.enableInterface(manager.ifname, function (ok) { 1.417 + }); 1.418 + }); 1.419 + } 1.420 + }); 1.421 + } 1.422 + 1.423 + var dhcpInfo = null; 1.424 + 1.425 + function runStaticIp(ifname, key) { 1.426 + debug("Run static ip"); 1.427 + 1.428 + // Read static ip information from settings. 1.429 + let staticIpInfo; 1.430 + 1.431 + if (!(key in staticIpConfig)) 1.432 + return; 1.433 + 1.434 + staticIpInfo = staticIpConfig[key]; 1.435 + 1.436 + // Stop dhcpd when use static IP 1.437 + if (dhcpInfo != null) { 1.438 + netUtil.stopDhcp(manager.ifname, function() {}); 1.439 + } 1.440 + 1.441 + // Set ip, mask length, gateway, dns to network interface 1.442 + netUtil.configureInterface( { ifname: ifname, 1.443 + ipaddr: staticIpInfo.ipaddr, 1.444 + mask: staticIpInfo.maskLength, 1.445 + gateway: staticIpInfo.gateway, 1.446 + dns1: staticIpInfo.dns1, 1.447 + dns2: staticIpInfo.dns2 }, function (data) { 1.448 + netUtil.runIpConfig(ifname, staticIpInfo, function(data) { 1.449 + dhcpInfo = data.info; 1.450 + notify("networkconnected", data); 1.451 + }); 1.452 + }); 1.453 + } 1.454 + 1.455 + var suppressEvents = false; 1.456 + function notify(eventName, eventObject) { 1.457 + if (suppressEvents) 1.458 + return; 1.459 + var handler = manager["on" + eventName]; 1.460 + if (handler) { 1.461 + if (!eventObject) 1.462 + eventObject = ({}); 1.463 + handler.call(eventObject); 1.464 + } 1.465 + } 1.466 + 1.467 + function notifyStateChange(fields) { 1.468 + // If we're already in the COMPLETED state, we might receive events from 1.469 + // the supplicant that tell us that we're re-authenticating or reminding 1.470 + // us that we're associated to a network. In those cases, we don't need to 1.471 + // do anything, so just ignore them. 1.472 + if (manager.state === "COMPLETED" && 1.473 + fields.state !== "DISCONNECTED" && 1.474 + fields.state !== "INTERFACE_DISABLED" && 1.475 + fields.state !== "INACTIVE" && 1.476 + fields.state !== "SCANNING") { 1.477 + return false; 1.478 + } 1.479 + 1.480 + // Stop background scanning if we're trying to connect to a network. 1.481 + if (manager.backgroundScanEnabled && 1.482 + (fields.state === "ASSOCIATING" || 1.483 + fields.state === "ASSOCIATED" || 1.484 + fields.state === "FOUR_WAY_HANDSHAKE" || 1.485 + fields.state === "GROUP_HANDSHAKE" || 1.486 + fields.state === "COMPLETED")) { 1.487 + setBackgroundScan("OFF", function() {}); 1.488 + } 1.489 + 1.490 + fields.prevState = manager.state; 1.491 + // Detect wpa_supplicant's loop iterations. 1.492 + manager.supplicantLoopDetection(fields.prevState, fields.state); 1.493 + notify("statechange", fields); 1.494 + 1.495 + // Don't update state when and after disabling. 1.496 + if (manager.state === "DISABLING" || 1.497 + manager.state === "UNINITIALIZED") { 1.498 + return false; 1.499 + } 1.500 + 1.501 + manager.state = fields.state; 1.502 + return true; 1.503 + } 1.504 + 1.505 + function parseStatus(status) { 1.506 + if (status === null) { 1.507 + debug("Unable to get wpa supplicant's status"); 1.508 + return; 1.509 + } 1.510 + 1.511 + var ssid; 1.512 + var bssid; 1.513 + var state; 1.514 + var ip_address; 1.515 + var id; 1.516 + 1.517 + var lines = status.split("\n"); 1.518 + for (let i = 0; i < lines.length; ++i) { 1.519 + let [key, value] = lines[i].split("="); 1.520 + switch (key) { 1.521 + case "wpa_state": 1.522 + state = value; 1.523 + break; 1.524 + case "ssid": 1.525 + ssid = value; 1.526 + break; 1.527 + case "bssid": 1.528 + bssid = value; 1.529 + break; 1.530 + case "ip_address": 1.531 + ip_address = value; 1.532 + break; 1.533 + case "id": 1.534 + id = value; 1.535 + break; 1.536 + } 1.537 + } 1.538 + 1.539 + if (bssid && ssid) { 1.540 + manager.connectionInfo.bssid = bssid; 1.541 + manager.connectionInfo.ssid = ssid; 1.542 + manager.connectionInfo.id = id; 1.543 + } 1.544 + 1.545 + if (ip_address) 1.546 + dhcpInfo = { ip_address: ip_address }; 1.547 + 1.548 + notifyStateChange({ state: state, fromStatus: true }); 1.549 + 1.550 + // If we parse the status and the supplicant has already entered the 1.551 + // COMPLETED state, then we need to set up DHCP right away. 1.552 + if (state === "COMPLETED") 1.553 + onconnected(); 1.554 + } 1.555 + 1.556 + // try to connect to the supplicant 1.557 + var connectTries = 0; 1.558 + var retryTimer = null; 1.559 + function connectCallback(ok) { 1.560 + if (ok === 0) { 1.561 + // Tell the event worker to start waiting for events. 1.562 + retryTimer = null; 1.563 + connectTries = 0; 1.564 + recvErrors = 0; 1.565 + manager.connectToSupplicant = true; 1.566 + didConnectSupplicant(function(){}); 1.567 + return; 1.568 + } 1.569 + if (connectTries++ < 5) { 1.570 + // Try again in 1 seconds. 1.571 + if (!retryTimer) 1.572 + retryTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 1.573 + 1.574 + retryTimer.initWithCallback(function(timer) { 1.575 + wifiCommand.connectToSupplicant(connectCallback); 1.576 + }, 1000, Ci.nsITimer.TYPE_ONE_SHOT); 1.577 + return; 1.578 + } 1.579 + 1.580 + retryTimer = null; 1.581 + connectTries = 0; 1.582 + notify("supplicantlost", { success: false }); 1.583 + } 1.584 + 1.585 + manager.connectionDropped = function(callback) { 1.586 + // Reset network interface when connection drop 1.587 + netUtil.configureInterface( { ifname: manager.ifname, 1.588 + ipaddr: 0, 1.589 + mask: 0, 1.590 + gateway: 0, 1.591 + dns1: 0, 1.592 + dns2: 0 }, function (data) { 1.593 + }); 1.594 + 1.595 + // If we got disconnected, kill the DHCP client in preparation for 1.596 + // reconnection. 1.597 + netUtil.resetConnections(manager.ifname, function() { 1.598 + netUtil.stopDhcp(manager.ifname, function() { 1.599 + callback(); 1.600 + }); 1.601 + }); 1.602 + } 1.603 + 1.604 + manager.start = function() { 1.605 + debug("detected SDK version " + sdkVersion); 1.606 + wifiCommand.connectToSupplicant(connectCallback); 1.607 + } 1.608 + 1.609 + function onconnected() { 1.610 + // For now we do our own DHCP. In the future, this should be handed 1.611 + // off to the Network Manager. 1.612 + let currentNetwork = Object.create(null); 1.613 + currentNetwork.netId = manager.connectionInfo.id; 1.614 + 1.615 + manager.getNetworkConfiguration(currentNetwork, function (){ 1.616 + let key = getNetworkKey(currentNetwork); 1.617 + if (staticIpConfig && 1.618 + (key in staticIpConfig) && 1.619 + staticIpConfig[key].enabled) { 1.620 + debug("Run static ip"); 1.621 + runStaticIp(manager.ifname, key); 1.622 + return; 1.623 + } 1.624 + netUtil.runDhcp(manager.ifname, function(data) { 1.625 + dhcpInfo = data.info; 1.626 + if (!dhcpInfo) { 1.627 + if (++manager.dhcpFailuresCount >= MAX_RETRIES_ON_DHCP_FAILURE) { 1.628 + manager.dhcpFailuresCount = 0; 1.629 + notify("disconnected", {ssid: manager.connectionInfo.ssid}); 1.630 + return; 1.631 + } 1.632 + // NB: We have to call disconnect first. Otherwise, we only reauth with 1.633 + // the existing AP and don't retrigger DHCP. 1.634 + manager.disconnect(function() { 1.635 + manager.reassociate(function(){}); 1.636 + }); 1.637 + return; 1.638 + } 1.639 + 1.640 + manager.dhcpFailuresCount = 0; 1.641 + notify("networkconnected", data); 1.642 + }); 1.643 + }); 1.644 + } 1.645 + 1.646 + var supplicantStatesMap = (sdkVersion >= 15) ? 1.647 + ["DISCONNECTED", "INTERFACE_DISABLED", "INACTIVE", "SCANNING", 1.648 + "AUTHENTICATING", "ASSOCIATING", "ASSOCIATED", "FOUR_WAY_HANDSHAKE", 1.649 + "GROUP_HANDSHAKE", "COMPLETED"] 1.650 + : 1.651 + ["DISCONNECTED", "INACTIVE", "SCANNING", "ASSOCIATING", 1.652 + "ASSOCIATED", "FOUR_WAY_HANDSHAKE", "GROUP_HANDSHAKE", 1.653 + "COMPLETED", "DORMANT", "UNINITIALIZED"]; 1.654 + 1.655 + var driverEventMap = { STOPPED: "driverstopped", STARTED: "driverstarted", HANGED: "driverhung" }; 1.656 + 1.657 + manager.getCurrentNetworkId = function (ssid, callback) { 1.658 + manager.getConfiguredNetworks(function(networks) { 1.659 + if (!networks) { 1.660 + debug("Unable to get configured networks"); 1.661 + return callback(null); 1.662 + } 1.663 + for (let net in networks) { 1.664 + let network = networks[net]; 1.665 + // Trying to get netId from 1.666 + // 1. CURRENT network. 1.667 + // 2. Trying to associate with SSID 'ssid' event 1.668 + if (network.status === "CURRENT" || 1.669 + (ssid && ssid === dequote(network.ssid))) { 1.670 + return callback(net); 1.671 + } 1.672 + } 1.673 + callback(null); 1.674 + }); 1.675 + } 1.676 + 1.677 + // Handle events sent to us by the event worker. 1.678 + function handleEvent(event) { 1.679 + debug("Event coming in: " + event); 1.680 + if (event.indexOf("CTRL-EVENT-") !== 0 && event.indexOf("WPS") !== 0) { 1.681 + // Handle connection fail exception on WEP-128, while password length 1.682 + // is not 5 nor 13 bytes. 1.683 + if (event.indexOf("Association request to the driver failed") !== -1) { 1.684 + notify("passwordmaybeincorrect"); 1.685 + if (manager.authenticationFailuresCount > MAX_RETRIES_ON_AUTHENTICATION_FAILURE) { 1.686 + manager.authenticationFailuresCount = 0; 1.687 + notify("disconnected", {ssid: manager.connectionInfo.ssid}); 1.688 + } 1.689 + return true; 1.690 + } 1.691 + 1.692 + if (event.indexOf("WPA:") == 0 && 1.693 + event.indexOf("pre-shared key may be incorrect") != -1) { 1.694 + notify("passwordmaybeincorrect"); 1.695 + } 1.696 + 1.697 + // This is ugly, but we need to grab the SSID here. BSSID is not guaranteed 1.698 + // to be provided, so don't grab BSSID here. 1.699 + var match = /Trying to associate with.*SSID[ =]'(.*)'/.exec(event); 1.700 + if (match) { 1.701 + debug("Matched: " + match[1] + "\n"); 1.702 + manager.connectionInfo.ssid = match[1]; 1.703 + } 1.704 + return true; 1.705 + } 1.706 + 1.707 + var space = event.indexOf(" "); 1.708 + var eventData = event.substr(0, space + 1); 1.709 + if (eventData.indexOf("CTRL-EVENT-STATE-CHANGE") === 0) { 1.710 + // Parse the event data. 1.711 + var fields = {}; 1.712 + var tokens = event.substr(space + 1).split(" "); 1.713 + for (var n = 0; n < tokens.length; ++n) { 1.714 + var kv = tokens[n].split("="); 1.715 + if (kv.length === 2) 1.716 + fields[kv[0]] = kv[1]; 1.717 + } 1.718 + if (!("state" in fields)) 1.719 + return true; 1.720 + fields.state = supplicantStatesMap[fields.state]; 1.721 + 1.722 + // The BSSID field is only valid in the ASSOCIATING and ASSOCIATED 1.723 + // states, except when we "reauth", except this seems to depend on the 1.724 + // driver, so simply check to make sure that we don't have a null BSSID. 1.725 + if (fields.BSSID !== "00:00:00:00:00:00") 1.726 + manager.connectionInfo.bssid = fields.BSSID; 1.727 + 1.728 + if (notifyStateChange(fields) && fields.state === "COMPLETED") { 1.729 + onconnected(); 1.730 + } 1.731 + return true; 1.732 + } 1.733 + if (eventData.indexOf("CTRL-EVENT-DRIVER-STATE") === 0) { 1.734 + var handlerName = driverEventMap[eventData]; 1.735 + if (handlerName) 1.736 + notify(handlerName); 1.737 + return true; 1.738 + } 1.739 + if (eventData.indexOf("CTRL-EVENT-TERMINATING") === 0) { 1.740 + // As long the monitor socket is not closed and we haven't seen too many 1.741 + // recv errors yet, we will keep going for a bit longer. 1.742 + if (event.indexOf("connection closed") === -1 && 1.743 + event.indexOf("recv error") !== -1 && ++recvErrors < 10) 1.744 + return true; 1.745 + 1.746 + notifyStateChange({ state: "DISCONNECTED", BSSID: null, id: -1 }); 1.747 + 1.748 + // If the supplicant is terminated as commanded, the supplicant lost 1.749 + // notification will be sent after driver unloaded. In such case, the 1.750 + // manager state will be "DISABLING" or "UNINITIALIZED". 1.751 + // So if supplicant terminated with incorrect manager state, implying 1.752 + // unexpected condition, we should notify supplicant lost here. 1.753 + if (manager.state !== "DISABLING" && manager.state !== "UNINITIALIZED") { 1.754 + notify("supplicantlost", { success: true }); 1.755 + } 1.756 + wifiCommand.closeSupplicantConnection(function() { 1.757 + manager.connectToSupplicant = false; 1.758 + }); 1.759 + return false; 1.760 + } 1.761 + if (eventData.indexOf("CTRL-EVENT-DISCONNECTED") === 0) { 1.762 + var token = event.split(" ")[1]; 1.763 + var bssid = token.split("=")[1]; 1.764 + if (manager.authenticationFailuresCount > MAX_RETRIES_ON_AUTHENTICATION_FAILURE) { 1.765 + manager.authenticationFailuresCount = 0; 1.766 + notify("disconnected", {ssid: manager.connectionInfo.ssid}); 1.767 + } 1.768 + manager.connectionInfo.bssid = null; 1.769 + manager.connectionInfo.ssid = null; 1.770 + manager.connectionInfo.id = -1; 1.771 + return true; 1.772 + } 1.773 + // Association reject is triggered mostly on incorrect WEP key. 1.774 + if (eventData.indexOf("CTRL-EVENT-ASSOC-REJECT") === 0) { 1.775 + notify("passwordmaybeincorrect"); 1.776 + if (manager.authenticationFailuresCount > MAX_RETRIES_ON_AUTHENTICATION_FAILURE) { 1.777 + manager.authenticationFailuresCount = 0; 1.778 + notify("disconnected", {ssid: manager.connectionInfo.ssid}); 1.779 + } 1.780 + return true; 1.781 + } 1.782 + if (eventData.indexOf("CTRL-EVENT-EAP-FAILURE") === 0) { 1.783 + if (event.indexOf("EAP authentication failed") !== -1) { 1.784 + notify("passwordmaybeincorrect"); 1.785 + } 1.786 + return true; 1.787 + } 1.788 + if (eventData.indexOf("CTRL-EVENT-CONNECTED") === 0) { 1.789 + // Format: CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=] 1.790 + var bssid = event.split(" ")[4]; 1.791 + 1.792 + var keyword = "id="; 1.793 + var id = event.substr(event.indexOf(keyword) + keyword.length).split(" ")[0]; 1.794 + // Read current BSSID here, it will always being provided. 1.795 + manager.connectionInfo.id = id; 1.796 + manager.connectionInfo.bssid = bssid; 1.797 + return true; 1.798 + } 1.799 + if (eventData.indexOf("CTRL-EVENT-SCAN-RESULTS") === 0) { 1.800 + debug("Notifying of scan results available"); 1.801 + if (reEnableBackgroundScan) { 1.802 + reEnableBackgroundScan = false; 1.803 + setBackgroundScan("ON", function() {}); 1.804 + } 1.805 + manager.handlePostWifiScan(); 1.806 + notify("scanresultsavailable"); 1.807 + return true; 1.808 + } 1.809 + if (eventData.indexOf("WPS-TIMEOUT") === 0) { 1.810 + notifyStateChange({ state: "WPS_TIMEOUT", BSSID: null, id: -1 }); 1.811 + return true; 1.812 + } 1.813 + if (eventData.indexOf("WPS-FAIL") === 0) { 1.814 + notifyStateChange({ state: "WPS_FAIL", BSSID: null, id: -1 }); 1.815 + return true; 1.816 + } 1.817 + if (eventData.indexOf("WPS-OVERLAP-DETECTED") === 0) { 1.818 + notifyStateChange({ state: "WPS_OVERLAP_DETECTED", BSSID: null, id: -1 }); 1.819 + return true; 1.820 + } 1.821 + // Unknown event. 1.822 + return true; 1.823 + } 1.824 + 1.825 + function didConnectSupplicant(callback) { 1.826 + waitForEvent(manager.ifname); 1.827 + 1.828 + // Load up the supplicant state. 1.829 + getDebugEnabled(function(ok) { 1.830 + syncDebug(); 1.831 + }); 1.832 + wifiCommand.status(function(status) { 1.833 + parseStatus(status); 1.834 + notify("supplicantconnection"); 1.835 + callback(); 1.836 + }); 1.837 + 1.838 + if (p2pSupported) { 1.839 + manager.enableP2p(function(success) {}); 1.840 + } 1.841 + } 1.842 + 1.843 + function prepareForStartup(callback) { 1.844 + let status = libcutils.property_get(DHCP_PROP + "_" + manager.ifname); 1.845 + if (status !== "running") { 1.846 + tryStopSupplicant(); 1.847 + return; 1.848 + } 1.849 + manager.connectionDropped(function() { 1.850 + tryStopSupplicant(); 1.851 + }); 1.852 + 1.853 + // Ignore any errors and kill any currently-running supplicants. On some 1.854 + // phones, stopSupplicant won't work for a supplicant that we didn't 1.855 + // start, so we hand-roll it here. 1.856 + function tryStopSupplicant () { 1.857 + let status = libcutils.property_get(SUPP_PROP); 1.858 + if (status !== "running") { 1.859 + callback(); 1.860 + return; 1.861 + } 1.862 + suppressEvents = true; 1.863 + wifiCommand.killSupplicant(function() { 1.864 + netUtil.disableInterface(manager.ifname, function (ok) { 1.865 + suppressEvents = false; 1.866 + callback(); 1.867 + }); 1.868 + }); 1.869 + } 1.870 + } 1.871 + 1.872 + // Initial state. 1.873 + manager.state = "UNINITIALIZED"; 1.874 + manager.tetheringState = "UNINITIALIZED"; 1.875 + manager.enabled = false; 1.876 + manager.supplicantStarted = false; 1.877 + manager.connectionInfo = { ssid: null, bssid: null, id: -1 }; 1.878 + manager.authenticationFailuresCount = 0; 1.879 + manager.loopDetectionCount = 0; 1.880 + manager.dhcpFailuresCount = 0; 1.881 + 1.882 + var waitForDriverReadyTimer = null; 1.883 + function cancelWaitForDriverReadyTimer() { 1.884 + if (waitForDriverReadyTimer) { 1.885 + waitForDriverReadyTimer.cancel(); 1.886 + waitForDriverReadyTimer = null; 1.887 + } 1.888 + }; 1.889 + function createWaitForDriverReadyTimer(onTimeout) { 1.890 + waitForDriverReadyTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 1.891 + waitForDriverReadyTimer.initWithCallback(onTimeout, 1.892 + manager.driverDelay, 1.893 + Ci.nsITimer.TYPE_ONE_SHOT); 1.894 + }; 1.895 + 1.896 + // Public interface of the wifi service. 1.897 + manager.setWifiEnabled = function(enabled, callback) { 1.898 + if (enabled === manager.isWifiEnabled(manager.state)) { 1.899 + callback("no change"); 1.900 + return; 1.901 + } 1.902 + 1.903 + if (enabled) { 1.904 + manager.state = "INITIALIZING"; 1.905 + // Register as network interface. 1.906 + WifiNetworkInterface.name = manager.ifname; 1.907 + if (!WifiNetworkInterface.registered) { 1.908 + gNetworkManager.registerNetworkInterface(WifiNetworkInterface); 1.909 + WifiNetworkInterface.registered = true; 1.910 + } 1.911 + WifiNetworkInterface.state = Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED; 1.912 + WifiNetworkInterface.ips = []; 1.913 + WifiNetworkInterface.prefixLengths = []; 1.914 + WifiNetworkInterface.gateways = []; 1.915 + WifiNetworkInterface.dnses = []; 1.916 + Services.obs.notifyObservers(WifiNetworkInterface, 1.917 + kNetworkInterfaceStateChangedTopic, 1.918 + null); 1.919 + prepareForStartup(function() { 1.920 + loadDriver(function (status) { 1.921 + if (status < 0) { 1.922 + callback(status); 1.923 + manager.state = "UNINITIALIZED"; 1.924 + return; 1.925 + } 1.926 + // This command is mandatory for Nexus 4. But some devices like 1.927 + // Galaxy S2 don't support it. Continue to start wpa_supplicant 1.928 + // even if we fail to set wifi operation mode to station. 1.929 + gNetworkService.setWifiOperationMode(manager.ifname, 1.930 + WIFI_FIRMWARE_STATION, 1.931 + function (status) { 1.932 + 1.933 + function startSupplicantInternal() { 1.934 + wifiCommand.startSupplicant(function (status) { 1.935 + if (status < 0) { 1.936 + unloadDriver(WIFI_FIRMWARE_STATION, function() { 1.937 + callback(status); 1.938 + }); 1.939 + manager.state = "UNINITIALIZED"; 1.940 + return; 1.941 + } 1.942 + 1.943 + manager.supplicantStarted = true; 1.944 + netUtil.enableInterface(manager.ifname, function (ok) { 1.945 + callback(ok ? 0 : -1); 1.946 + }); 1.947 + }); 1.948 + } 1.949 + 1.950 + function doStartSupplicant() { 1.951 + cancelWaitForDriverReadyTimer(); 1.952 + 1.953 + if (!manager.connectToSupplicant) { 1.954 + startSupplicantInternal(); 1.955 + return; 1.956 + } 1.957 + wifiCommand.closeSupplicantConnection(function () { 1.958 + manager.connectToSupplicant = false; 1.959 + // closeSupplicantConnection() will trigger onsupplicantlost 1.960 + // and set manager.state to "UNINITIALIZED", we have to 1.961 + // restore it here. 1.962 + manager.state = "INITIALIZING"; 1.963 + startSupplicantInternal(); 1.964 + }); 1.965 + } 1.966 + // Driver startup on certain platforms takes longer than it takes for us 1.967 + // to return from loadDriver, so wait 2 seconds before starting 1.968 + // the supplicant to give it a chance to start. 1.969 + if (manager.driverDelay > 0) { 1.970 + createWaitForDriverReadyTimer(doStartSupplicant); 1.971 + } else { 1.972 + doStartSupplicant(); 1.973 + } 1.974 + }); 1.975 + }); 1.976 + }); 1.977 + } else { 1.978 + manager.state = "DISABLING"; 1.979 + // Note these following calls ignore errors. If we fail to kill the 1.980 + // supplicant gracefully, then we need to continue telling it to die 1.981 + // until it does. 1.982 + let doDisableWifi = function() { 1.983 + wifiCommand.terminateSupplicant(function (ok) { 1.984 + manager.connectionDropped(function () { 1.985 + wifiCommand.stopSupplicant(function (status) { 1.986 + manager.state = "UNINITIALIZED"; 1.987 + netUtil.disableInterface(manager.ifname, function (ok) { 1.988 + unloadDriver(WIFI_FIRMWARE_STATION, callback); 1.989 + }); 1.990 + }); 1.991 + }); 1.992 + }); 1.993 + } 1.994 + 1.995 + if (p2pSupported) { 1.996 + p2pManager.setEnabled(false, { onDisabled: doDisableWifi }); 1.997 + } else { 1.998 + doDisableWifi(); 1.999 + } 1.1000 + } 1.1001 + } 1.1002 + 1.1003 + // Get wifi interface and load wifi driver when enable Ap mode. 1.1004 + manager.setWifiApEnabled = function(enabled, configuration, callback) { 1.1005 + if (enabled === manager.isWifiTetheringEnabled(manager.tetheringState)) { 1.1006 + callback("no change"); 1.1007 + return; 1.1008 + } 1.1009 + 1.1010 + if (enabled) { 1.1011 + manager.tetheringState = "INITIALIZING"; 1.1012 + loadDriver(function (status) { 1.1013 + if (status < 0) { 1.1014 + callback(); 1.1015 + manager.tetheringState = "UNINITIALIZED"; 1.1016 + return; 1.1017 + } 1.1018 + 1.1019 + function doStartWifiTethering() { 1.1020 + cancelWaitForDriverReadyTimer(); 1.1021 + WifiNetworkInterface.name = manager.ifname; 1.1022 + gNetworkManager.setWifiTethering(enabled, WifiNetworkInterface, 1.1023 + configuration, function(result) { 1.1024 + if (result) { 1.1025 + manager.tetheringState = "UNINITIALIZED"; 1.1026 + } else { 1.1027 + manager.tetheringState = "COMPLETED"; 1.1028 + } 1.1029 + // Pop out current request. 1.1030 + callback(); 1.1031 + // Should we fire a dom event if we fail to set wifi tethering ? 1.1032 + debug("Enable Wifi tethering result: " + (result ? result : "successfully")); 1.1033 + }); 1.1034 + } 1.1035 + 1.1036 + // Driver startup on certain platforms takes longer than it takes 1.1037 + // for us to return from loadDriver, so wait 2 seconds before 1.1038 + // turning on Wifi tethering. 1.1039 + createWaitForDriverReadyTimer(doStartWifiTethering); 1.1040 + }); 1.1041 + } else { 1.1042 + gNetworkManager.setWifiTethering(enabled, WifiNetworkInterface, 1.1043 + configuration, function(result) { 1.1044 + // Should we fire a dom event if we fail to set wifi tethering ? 1.1045 + debug("Disable Wifi tethering result: " + (result ? result : "successfully")); 1.1046 + // Unload wifi driver even if we fail to control wifi tethering. 1.1047 + unloadDriver(WIFI_FIRMWARE_AP, function(status) { 1.1048 + if (status < 0) { 1.1049 + debug("Fail to unload wifi driver"); 1.1050 + } 1.1051 + manager.tetheringState = "UNINITIALIZED"; 1.1052 + callback(); 1.1053 + }); 1.1054 + }); 1.1055 + } 1.1056 + } 1.1057 + 1.1058 + manager.disconnect = wifiCommand.disconnect; 1.1059 + manager.reconnect = wifiCommand.reconnect; 1.1060 + manager.reassociate = wifiCommand.reassociate; 1.1061 + 1.1062 + var networkConfigurationFields = [ 1.1063 + "ssid", "bssid", "psk", "wep_key0", "wep_key1", "wep_key2", "wep_key3", 1.1064 + "wep_tx_keyidx", "priority", "key_mgmt", "scan_ssid", "disabled", 1.1065 + "identity", "password", "auth_alg", "phase1", "phase2", "eap", "pin", 1.1066 + "pcsc" 1.1067 + ]; 1.1068 + 1.1069 + manager.getNetworkConfiguration = function(config, callback) { 1.1070 + var netId = config.netId; 1.1071 + var done = 0; 1.1072 + for (var n = 0; n < networkConfigurationFields.length; ++n) { 1.1073 + let fieldName = networkConfigurationFields[n]; 1.1074 + wifiCommand.getNetworkVariable(netId, fieldName, function(value) { 1.1075 + if (value !== null) 1.1076 + config[fieldName] = value; 1.1077 + if (++done == networkConfigurationFields.length) 1.1078 + callback(config); 1.1079 + }); 1.1080 + } 1.1081 + } 1.1082 + manager.setNetworkConfiguration = function(config, callback) { 1.1083 + var netId = config.netId; 1.1084 + var done = 0; 1.1085 + var errors = 0; 1.1086 + for (var n = 0; n < networkConfigurationFields.length; ++n) { 1.1087 + let fieldName = networkConfigurationFields[n]; 1.1088 + if (!(fieldName in config) || 1.1089 + // These fields are special: We can't retrieve them from the 1.1090 + // supplicant, and often we have a star in our config. In that case, 1.1091 + // we need to avoid overwriting the correct password with a *. 1.1092 + (fieldName === "password" || 1.1093 + fieldName === "wep_key0" || 1.1094 + fieldName === "psk") && 1.1095 + config[fieldName] === '*') { 1.1096 + ++done; 1.1097 + } else { 1.1098 + wifiCommand.setNetworkVariable(netId, fieldName, config[fieldName], function(ok) { 1.1099 + if (!ok) 1.1100 + ++errors; 1.1101 + if (++done == networkConfigurationFields.length) 1.1102 + callback(errors == 0); 1.1103 + }); 1.1104 + } 1.1105 + } 1.1106 + // If config didn't contain any of the fields we want, don't lose the error callback. 1.1107 + if (done == networkConfigurationFields.length) 1.1108 + callback(false); 1.1109 + } 1.1110 + manager.getConfiguredNetworks = function(callback) { 1.1111 + wifiCommand.listNetworks(function (reply) { 1.1112 + var networks = Object.create(null); 1.1113 + var lines = reply ? reply.split("\n") : 0; 1.1114 + if (lines.length <= 1) { 1.1115 + // We need to make sure we call the callback even if there are no 1.1116 + // configured networks. 1.1117 + callback(networks); 1.1118 + return; 1.1119 + } 1.1120 + 1.1121 + var done = 0; 1.1122 + var errors = 0; 1.1123 + for (var n = 1; n < lines.length; ++n) { 1.1124 + var result = lines[n].split("\t"); 1.1125 + var netId = result[0]; 1.1126 + var config = networks[netId] = { netId: netId }; 1.1127 + switch (result[3]) { 1.1128 + case "[CURRENT]": 1.1129 + config.status = "CURRENT"; 1.1130 + break; 1.1131 + case "[DISABLED]": 1.1132 + config.status = "DISABLED"; 1.1133 + break; 1.1134 + default: 1.1135 + config.status = "ENABLED"; 1.1136 + break; 1.1137 + } 1.1138 + manager.getNetworkConfiguration(config, function (ok) { 1.1139 + if (!ok) 1.1140 + ++errors; 1.1141 + if (++done == lines.length - 1) { 1.1142 + if (errors) { 1.1143 + // If an error occured, delete the new netId. 1.1144 + wifiCommand.removeNetwork(netId, function() { 1.1145 + callback(null); 1.1146 + }); 1.1147 + } else { 1.1148 + callback(networks); 1.1149 + } 1.1150 + } 1.1151 + }); 1.1152 + } 1.1153 + }); 1.1154 + } 1.1155 + manager.addNetwork = function(config, callback) { 1.1156 + wifiCommand.addNetwork(function (netId) { 1.1157 + config.netId = netId; 1.1158 + manager.setNetworkConfiguration(config, function (ok) { 1.1159 + if (!ok) { 1.1160 + wifiCommand.removeNetwork(netId, function() { callback(false); }); 1.1161 + return; 1.1162 + } 1.1163 + 1.1164 + callback(ok); 1.1165 + }); 1.1166 + }); 1.1167 + } 1.1168 + manager.updateNetwork = function(config, callback) { 1.1169 + manager.setNetworkConfiguration(config, callback); 1.1170 + } 1.1171 + manager.removeNetwork = function(netId, callback) { 1.1172 + wifiCommand.removeNetwork(netId, callback); 1.1173 + } 1.1174 + 1.1175 + function stringToIp(string) { 1.1176 + let ip = 0; 1.1177 + let start, end = -1; 1.1178 + for (let i = 0; i < 4; i++) { 1.1179 + start = end + 1; 1.1180 + end = string.indexOf(".", start); 1.1181 + if (end == -1) { 1.1182 + end = string.length; 1.1183 + } 1.1184 + let num = parseInt(string.slice(start, end), 10); 1.1185 + if (isNaN(num)) { 1.1186 + return 0; 1.1187 + } 1.1188 + ip |= num << (i * 8); 1.1189 + } 1.1190 + return ip; 1.1191 + } 1.1192 + 1.1193 + function swap32(n) { 1.1194 + return (((n >> 24) & 0xFF) << 0) | 1.1195 + (((n >> 16) & 0xFF) << 8) | 1.1196 + (((n >> 8) & 0xFF) << 16) | 1.1197 + (((n >> 0) & 0xFF) << 24); 1.1198 + } 1.1199 + 1.1200 + function ntohl(n) { 1.1201 + return swap32(n); 1.1202 + } 1.1203 + 1.1204 + function makeMask(len) { 1.1205 + let mask = 0; 1.1206 + for (let i = 0; i < len; ++i) { 1.1207 + mask |= (0x80000000 >> i); 1.1208 + } 1.1209 + return ntohl(mask); 1.1210 + } 1.1211 + 1.1212 + manager.saveConfig = function(callback) { 1.1213 + wifiCommand.saveConfig(callback); 1.1214 + } 1.1215 + manager.enableNetwork = function(netId, disableOthers, callback) { 1.1216 + if (p2pSupported) { 1.1217 + // We have to stop wifi direct scan before associating to an AP. 1.1218 + // Otherwise we will get a "REJECT" wpa supplicant event. 1.1219 + p2pManager.setScanEnabled(false, function(success) {}); 1.1220 + } 1.1221 + wifiCommand.enableNetwork(netId, disableOthers, callback); 1.1222 + } 1.1223 + manager.disableNetwork = function(netId, callback) { 1.1224 + wifiCommand.disableNetwork(netId, callback); 1.1225 + } 1.1226 + manager.getMacAddress = wifiCommand.getMacAddress; 1.1227 + manager.getScanResults = wifiCommand.scanResults; 1.1228 + manager.setScanMode = function(mode, callback) { 1.1229 + setScanMode(mode === "active", callback); // Use our own version. 1.1230 + } 1.1231 + manager.setBackgroundScan = setBackgroundScan; // Use our own version. 1.1232 + manager.scan = scan; // Use our own version. 1.1233 + manager.wpsPbc = wifiCommand.wpsPbc; 1.1234 + manager.wpsPin = wifiCommand.wpsPin; 1.1235 + manager.wpsCancel = wifiCommand.wpsCancel; 1.1236 + manager.setPowerMode = (sdkVersion >= 16) 1.1237 + ? wifiCommand.setPowerModeJB 1.1238 + : wifiCommand.setPowerModeICS; 1.1239 + manager.getHttpProxyNetwork = getHttpProxyNetwork; 1.1240 + manager.setHttpProxy = setHttpProxy; 1.1241 + manager.configureHttpProxy = configureHttpProxy; 1.1242 + manager.setSuspendOptimizations = (sdkVersion >= 16) 1.1243 + ? wifiCommand.setSuspendOptimizationsJB 1.1244 + : wifiCommand.setSuspendOptimizationsICS; 1.1245 + manager.setStaticIpMode = setStaticIpMode; 1.1246 + manager.getRssiApprox = wifiCommand.getRssiApprox; 1.1247 + manager.getLinkSpeed = wifiCommand.getLinkSpeed; 1.1248 + manager.getDhcpInfo = function() { return dhcpInfo; } 1.1249 + manager.getConnectionInfo = (sdkVersion >= 15) 1.1250 + ? wifiCommand.getConnectionInfoICS 1.1251 + : wifiCommand.getConnectionInfoGB; 1.1252 + 1.1253 + manager.isHandShakeState = function(state) { 1.1254 + switch (state) { 1.1255 + case "AUTHENTICATING": 1.1256 + case "ASSOCIATING": 1.1257 + case "ASSOCIATED": 1.1258 + case "FOUR_WAY_HANDSHAKE": 1.1259 + case "GROUP_HANDSHAKE": 1.1260 + return true; 1.1261 + case "DORMANT": 1.1262 + case "COMPLETED": 1.1263 + case "DISCONNECTED": 1.1264 + case "INTERFACE_DISABLED": 1.1265 + case "INACTIVE": 1.1266 + case "SCANNING": 1.1267 + case "UNINITIALIZED": 1.1268 + case "INVALID": 1.1269 + case "CONNECTED": 1.1270 + default: 1.1271 + return false; 1.1272 + } 1.1273 + } 1.1274 + 1.1275 + manager.isWifiEnabled = function(state) { 1.1276 + switch (state) { 1.1277 + case "UNINITIALIZED": 1.1278 + case "DISABLING": 1.1279 + return false; 1.1280 + default: 1.1281 + return true; 1.1282 + } 1.1283 + } 1.1284 + 1.1285 + manager.isWifiTetheringEnabled = function(state) { 1.1286 + switch (state) { 1.1287 + case "UNINITIALIZED": 1.1288 + return false; 1.1289 + default: 1.1290 + return true; 1.1291 + } 1.1292 + } 1.1293 + 1.1294 + manager.syncDebug = syncDebug; 1.1295 + manager.stateOrdinal = function(state) { 1.1296 + return supplicantStatesMap.indexOf(state); 1.1297 + } 1.1298 + manager.supplicantLoopDetection = function(prevState, state) { 1.1299 + var isPrevStateInHandShake = manager.isHandShakeState(prevState); 1.1300 + var isStateInHandShake = manager.isHandShakeState(state); 1.1301 + 1.1302 + if (isPrevStateInHandShake) { 1.1303 + if (isStateInHandShake) { 1.1304 + // Increase the count only if we are in the loop. 1.1305 + if (manager.stateOrdinal(state) > manager.stateOrdinal(prevState)) { 1.1306 + manager.loopDetectionCount++; 1.1307 + } 1.1308 + if (manager.loopDetectionCount > MAX_SUPPLICANT_LOOP_ITERATIONS) { 1.1309 + notify("disconnected", {ssid: manager.connectionInfo.ssid}); 1.1310 + manager.loopDetectionCount = 0; 1.1311 + } 1.1312 + } 1.1313 + } else { 1.1314 + // From others state to HandShake state. Reset the count. 1.1315 + if (isStateInHandShake) { 1.1316 + manager.loopDetectionCount = 0; 1.1317 + } 1.1318 + } 1.1319 + } 1.1320 + 1.1321 + manager.handlePreWifiScan = function() { 1.1322 + if (p2pSupported) { 1.1323 + // Before doing regular wifi scan, we have to disable wifi direct 1.1324 + // scan first. Otherwise we will never get the scan result. 1.1325 + p2pManager.blockScan(); 1.1326 + } 1.1327 + }; 1.1328 + 1.1329 + manager.handlePostWifiScan = function() { 1.1330 + if (p2pSupported) { 1.1331 + // After regular wifi scanning, we should restore the restricted 1.1332 + // wifi direct scan. 1.1333 + p2pManager.unblockScan(); 1.1334 + } 1.1335 + }; 1.1336 + 1.1337 + // 1.1338 + // Public APIs for P2P. 1.1339 + // 1.1340 + 1.1341 + manager.p2pSupported = function() { 1.1342 + return p2pSupported; 1.1343 + }; 1.1344 + 1.1345 + manager.getP2pManager = function() { 1.1346 + return p2pManager; 1.1347 + }; 1.1348 + 1.1349 + manager.enableP2p = function(callback) { 1.1350 + p2pManager.setEnabled(true, { 1.1351 + onSupplicantConnected: function() { 1.1352 + waitForEvent(WifiP2pManager.INTERFACE_NAME); 1.1353 + }, 1.1354 + 1.1355 + onEnabled: function(success) { 1.1356 + callback(success); 1.1357 + } 1.1358 + }); 1.1359 + }; 1.1360 + 1.1361 + manager.getCapabilities = function() { 1.1362 + return capabilities; 1.1363 + } 1.1364 + 1.1365 + return manager; 1.1366 +})(); 1.1367 + 1.1368 +// Get unique key for a network, now the key is created by escape(SSID)+Security. 1.1369 +// So networks of same SSID but different security mode can be identified. 1.1370 +function getNetworkKey(network) 1.1371 +{ 1.1372 + var ssid = "", 1.1373 + encryption = "OPEN"; 1.1374 + 1.1375 + if ("security" in network) { 1.1376 + // manager network object, represents an AP 1.1377 + // object structure 1.1378 + // { 1.1379 + // .ssid : SSID of AP 1.1380 + // .security[] : "WPA-PSK" for WPA-PSK 1.1381 + // "WPA-EAP" for WPA-EAP 1.1382 + // "WEP" for WEP 1.1383 + // "" for OPEN 1.1384 + // other keys 1.1385 + // } 1.1386 + 1.1387 + var security = network.security; 1.1388 + ssid = network.ssid; 1.1389 + 1.1390 + for (let j = 0; j < security.length; j++) { 1.1391 + if (security[j] === "WPA-PSK") { 1.1392 + encryption = "WPA-PSK"; 1.1393 + break; 1.1394 + } else if (security[j] === "WPA-EAP") { 1.1395 + encryption = "WPA-EAP"; 1.1396 + break; 1.1397 + } else if (security[j] === "WEP") { 1.1398 + encryption = "WEP"; 1.1399 + break; 1.1400 + } 1.1401 + } 1.1402 + } else if ("key_mgmt" in network) { 1.1403 + // configure network object, represents a network 1.1404 + // object structure 1.1405 + // { 1.1406 + // .ssid : SSID of network, quoted 1.1407 + // .key_mgmt : Encryption type 1.1408 + // "WPA-PSK" for WPA-PSK 1.1409 + // "WPA-EAP" for WPA-EAP 1.1410 + // "NONE" for WEP/OPEN 1.1411 + // .auth_alg : Encryption algorithm(WEP mode only) 1.1412 + // "OPEN_SHARED" for WEP 1.1413 + // other keys 1.1414 + // } 1.1415 + var key_mgmt = network.key_mgmt, 1.1416 + auth_alg = network.auth_alg; 1.1417 + ssid = dequote(network.ssid); 1.1418 + 1.1419 + if (key_mgmt == "WPA-PSK") { 1.1420 + encryption = "WPA-PSK"; 1.1421 + } else if (key_mgmt == "WPA-EAP") { 1.1422 + encryption = "WPA-EAP"; 1.1423 + } else if (key_mgmt == "NONE" && auth_alg === "OPEN SHARED") { 1.1424 + encryption = "WEP"; 1.1425 + } 1.1426 + } 1.1427 + 1.1428 + // ssid here must be dequoted, and it's safer to esacpe it. 1.1429 + // encryption won't be empty and always be assigned one of the followings : 1.1430 + // "OPEN"/"WEP"/"WPA-PSK"/"WPA-EAP". 1.1431 + // So for a invalid network object, the returned key will be "OPEN". 1.1432 + return escape(ssid) + encryption; 1.1433 +} 1.1434 + 1.1435 +function getKeyManagement(flags) { 1.1436 + var types = []; 1.1437 + if (!flags) 1.1438 + return types; 1.1439 + 1.1440 + if (/\[WPA2?-PSK/.test(flags)) 1.1441 + types.push("WPA-PSK"); 1.1442 + if (/\[WPA2?-EAP/.test(flags)) 1.1443 + types.push("WPA-EAP"); 1.1444 + if (/\[WEP/.test(flags)) 1.1445 + types.push("WEP"); 1.1446 + return types; 1.1447 +} 1.1448 + 1.1449 +function getCapabilities(flags) { 1.1450 + var types = []; 1.1451 + if (!flags) 1.1452 + return types; 1.1453 + 1.1454 + if (/\[WPS/.test(flags)) 1.1455 + types.push("WPS"); 1.1456 + return types; 1.1457 +} 1.1458 + 1.1459 +// These constants shamelessly ripped from WifiManager.java 1.1460 +// strength is the value returned by scan_results. It is nominally in dB. We 1.1461 +// transform it into a percentage for clients looking to simply show a 1.1462 +// relative indication of the strength of a network. 1.1463 +const MIN_RSSI = -100; 1.1464 +const MAX_RSSI = -55; 1.1465 + 1.1466 +function calculateSignal(strength) { 1.1467 + // Some wifi drivers represent their signal strengths as 8-bit integers, so 1.1468 + // in order to avoid negative numbers, they add 256 to the actual values. 1.1469 + // While we don't *know* that this is the case here, we make an educated 1.1470 + // guess. 1.1471 + if (strength > 0) 1.1472 + strength -= 256; 1.1473 + 1.1474 + if (strength <= MIN_RSSI) 1.1475 + return 0; 1.1476 + if (strength >= MAX_RSSI) 1.1477 + return 100; 1.1478 + return Math.floor(((strength - MIN_RSSI) / (MAX_RSSI - MIN_RSSI)) * 100); 1.1479 +} 1.1480 + 1.1481 +function Network(ssid, security, password, capabilities) { 1.1482 + this.ssid = ssid; 1.1483 + this.security = security; 1.1484 + 1.1485 + if (typeof password !== "undefined") 1.1486 + this.password = password; 1.1487 + if (capabilities !== undefined) 1.1488 + this.capabilities = capabilities; 1.1489 + // TODO connected here as well? 1.1490 + 1.1491 + this.__exposedProps__ = Network.api; 1.1492 +} 1.1493 + 1.1494 +Network.api = { 1.1495 + ssid: "r", 1.1496 + security: "r", 1.1497 + capabilities: "r", 1.1498 + known: "r", 1.1499 + 1.1500 + password: "rw", 1.1501 + keyManagement: "rw", 1.1502 + psk: "rw", 1.1503 + identity: "rw", 1.1504 + wep: "rw", 1.1505 + hidden: "rw", 1.1506 + eap: "rw", 1.1507 + pin: "rw", 1.1508 + phase1: "rw", 1.1509 + phase2: "rw" 1.1510 +}; 1.1511 + 1.1512 +// Note: We never use ScanResult.prototype, so the fact that it's unrelated to 1.1513 +// Network.prototype is OK. 1.1514 +function ScanResult(ssid, bssid, flags, signal) { 1.1515 + Network.call(this, ssid, getKeyManagement(flags), undefined, 1.1516 + getCapabilities(flags)); 1.1517 + this.bssid = bssid; 1.1518 + this.signalStrength = signal; 1.1519 + this.relSignalStrength = calculateSignal(Number(signal)); 1.1520 + 1.1521 + this.__exposedProps__ = ScanResult.api; 1.1522 +} 1.1523 + 1.1524 +// XXX This should probably live in the DOM-facing side, but it's hard to do 1.1525 +// there, so we stick this here. 1.1526 +ScanResult.api = { 1.1527 + bssid: "r", 1.1528 + signalStrength: "r", 1.1529 + relSignalStrength: "r", 1.1530 + connected: "r" 1.1531 +}; 1.1532 + 1.1533 +for (let i in Network.api) { 1.1534 + ScanResult.api[i] = Network.api[i]; 1.1535 +} 1.1536 + 1.1537 +function quote(s) { 1.1538 + return '"' + s + '"'; 1.1539 +} 1.1540 + 1.1541 +function dequote(s) { 1.1542 + if (s[0] != '"' || s[s.length - 1] != '"') 1.1543 + throw "Invalid argument, not a quoted string: " + s; 1.1544 + return s.substr(1, s.length - 2); 1.1545 +} 1.1546 + 1.1547 +function isWepHexKey(s) { 1.1548 + if (s.length != 10 && s.length != 26 && s.length != 58) 1.1549 + return false; 1.1550 + return !/[^a-fA-F0-9]/.test(s); 1.1551 +} 1.1552 + 1.1553 + 1.1554 +let WifiNetworkInterface = { 1.1555 + 1.1556 + QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface]), 1.1557 + 1.1558 + registered: false, 1.1559 + 1.1560 + // nsINetworkInterface 1.1561 + 1.1562 + NETWORK_STATE_UNKNOWN: Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN, 1.1563 + NETWORK_STATE_CONNECTING: Ci.nsINetworkInterface.CONNECTING, 1.1564 + NETWORK_STATE_CONNECTED: Ci.nsINetworkInterface.CONNECTED, 1.1565 + NETWORK_STATE_DISCONNECTING: Ci.nsINetworkInterface.DISCONNECTING, 1.1566 + NETWORK_STATE_DISCONNECTED: Ci.nsINetworkInterface.DISCONNECTED, 1.1567 + 1.1568 + state: Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN, 1.1569 + 1.1570 + NETWORK_TYPE_WIFI: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, 1.1571 + NETWORK_TYPE_MOBILE: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE, 1.1572 + NETWORK_TYPE_MOBILE_MMS: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS, 1.1573 + NETWORK_TYPE_MOBILE_SUPL: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL, 1.1574 + 1.1575 + type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, 1.1576 + 1.1577 + name: null, 1.1578 + 1.1579 + ips: [], 1.1580 + 1.1581 + prefixLengths: [], 1.1582 + 1.1583 + dnses: [], 1.1584 + 1.1585 + gateways: [], 1.1586 + 1.1587 + httpProxyHost: null, 1.1588 + 1.1589 + httpProxyPort: null, 1.1590 + 1.1591 + getAddresses: function (ips, prefixLengths) { 1.1592 + ips.value = this.ips.slice(); 1.1593 + prefixLengths.value = this.prefixLengths.slice(); 1.1594 + 1.1595 + return this.ips.length; 1.1596 + }, 1.1597 + 1.1598 + getGateways: function (count) { 1.1599 + if (count) { 1.1600 + count.value = this.gateways.length; 1.1601 + } 1.1602 + return this.gateways.slice(); 1.1603 + }, 1.1604 + 1.1605 + getDnses: function (count) { 1.1606 + if (count) { 1.1607 + count.value = this.dnses.length; 1.1608 + } 1.1609 + return this.dnses.slice(); 1.1610 + } 1.1611 +}; 1.1612 + 1.1613 +function WifiScanResult() {} 1.1614 + 1.1615 +// TODO Make the difference between a DOM-based network object and our 1.1616 +// networks objects much clearer. 1.1617 +let netToDOM; 1.1618 +let netFromDOM; 1.1619 + 1.1620 +function WifiWorker() { 1.1621 + var self = this; 1.1622 + 1.1623 + this._mm = Cc["@mozilla.org/parentprocessmessagemanager;1"] 1.1624 + .getService(Ci.nsIMessageListenerManager); 1.1625 + const messages = ["WifiManager:getNetworks", "WifiManager:getKnownNetworks", 1.1626 + "WifiManager:associate", "WifiManager:forget", 1.1627 + "WifiManager:wps", "WifiManager:getState", 1.1628 + "WifiManager:setPowerSavingMode", 1.1629 + "WifiManager:setHttpProxy", 1.1630 + "WifiManager:setStaticIpMode", 1.1631 + "child-process-shutdown"]; 1.1632 + 1.1633 + messages.forEach((function(msgName) { 1.1634 + this._mm.addMessageListener(msgName, this); 1.1635 + }).bind(this)); 1.1636 + 1.1637 + Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false); 1.1638 + 1.1639 + this.wantScanResults = []; 1.1640 + 1.1641 + this._allowWpaEap = false; 1.1642 + this._needToEnableNetworks = false; 1.1643 + this._highestPriority = -1; 1.1644 + 1.1645 + // Networks is a map from SSID -> a scan result. 1.1646 + this.networks = Object.create(null); 1.1647 + 1.1648 + // ConfiguredNetworks is a map from SSID -> our view of a network. It only 1.1649 + // lists networks known to the wpa_supplicant. The SSID field (and other 1.1650 + // fields) are quoted for ease of use with WifiManager commands. 1.1651 + // Note that we don't have to worry about escaping embedded quotes since in 1.1652 + // all cases, the supplicant will take the last quotation that we pass it as 1.1653 + // the end of the string. 1.1654 + this.configuredNetworks = Object.create(null); 1.1655 + this._addingNetworks = Object.create(null); 1.1656 + 1.1657 + this.currentNetwork = null; 1.1658 + this.ipAddress = ""; 1.1659 + this.macAddress = null; 1.1660 + 1.1661 + this._lastConnectionInfo = null; 1.1662 + this._connectionInfoTimer = null; 1.1663 + this._reconnectOnDisconnect = false; 1.1664 + 1.1665 + // Create p2pObserver and assign to p2pManager. 1.1666 + if (WifiManager.p2pSupported()) { 1.1667 + this._p2pObserver = WifiP2pWorkerObserver(WifiManager.getP2pManager()); 1.1668 + WifiManager.getP2pManager().setObserver(this._p2pObserver); 1.1669 + 1.1670 + // Add DOM message observerd by p2pObserver to the message listener as well. 1.1671 + this._p2pObserver.getObservedDOMMessages().forEach((function(msgName) { 1.1672 + this._mm.addMessageListener(msgName, this); 1.1673 + }).bind(this)); 1.1674 + } 1.1675 + 1.1676 + // Users of instances of nsITimer should keep a reference to the timer until 1.1677 + // it is no longer needed in order to assure the timer is fired. 1.1678 + this._callbackTimer = null; 1.1679 + 1.1680 + // XXX On some phones (Otoro and Unagi) the wifi driver doesn't play nicely 1.1681 + // with the automatic scans that wpa_supplicant does (it appears that the 1.1682 + // driver forgets that it's returned scan results and then refuses to try to 1.1683 + // rescan. In order to detect this case we start a timer when we enter the 1.1684 + // SCANNING state and reset it whenever we either get scan results or leave 1.1685 + // the SCANNING state. If the timer fires, we assume that we are stuck and 1.1686 + // forceably try to unstick the supplican, also turning on background 1.1687 + // scanning to avoid having to constantly poke the supplicant. 1.1688 + 1.1689 + // How long we wait is controlled by the SCAN_STUCK_WAIT constant. 1.1690 + const SCAN_STUCK_WAIT = 12000; 1.1691 + this._scanStuckTimer = null; 1.1692 + this._turnOnBackgroundScan = false; 1.1693 + 1.1694 + function startScanStuckTimer() { 1.1695 + if (WifiManager.schedScanRecovery) { 1.1696 + self._scanStuckTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 1.1697 + self._scanStuckTimer.initWithCallback(scanIsStuck, SCAN_STUCK_WAIT, 1.1698 + Ci.nsITimer.TYPE_ONE_SHOT); 1.1699 + } 1.1700 + } 1.1701 + 1.1702 + function scanIsStuck() { 1.1703 + // Uh-oh, we've waited too long for scan results. Disconnect (which 1.1704 + // guarantees that we leave the SCANNING state and tells wpa_supplicant to 1.1705 + // wait for our next command) ensure that background scanning is on and 1.1706 + // then try again. 1.1707 + debug("Determined that scanning is stuck, turning on background scanning!"); 1.1708 + WifiManager.handlePostWifiScan(); 1.1709 + WifiManager.disconnect(function(ok) {}); 1.1710 + self._turnOnBackgroundScan = true; 1.1711 + } 1.1712 + 1.1713 + // A list of requests to turn wifi on or off. 1.1714 + this._stateRequests = []; 1.1715 + 1.1716 + // Given a connection status network, takes a network from 1.1717 + // self.configuredNetworks and prepares it for the DOM. 1.1718 + netToDOM = function(net) { 1.1719 + var ssid = dequote(net.ssid); 1.1720 + var security = (net.key_mgmt === "NONE" && net.wep_key0) ? ["WEP"] : 1.1721 + (net.key_mgmt && net.key_mgmt !== "NONE") ? [net.key_mgmt] : 1.1722 + []; 1.1723 + var password; 1.1724 + if (("psk" in net && net.psk) || 1.1725 + ("password" in net && net.password) || 1.1726 + ("wep_key0" in net && net.wep_key0)) { 1.1727 + password = "*"; 1.1728 + } 1.1729 + 1.1730 + var pub = new Network(ssid, security, password); 1.1731 + if (net.identity) 1.1732 + pub.identity = dequote(net.identity); 1.1733 + if (net.netId) 1.1734 + pub.known = true; 1.1735 + if (net.scan_ssid === 1) 1.1736 + pub.hidden = true; 1.1737 + return pub; 1.1738 + }; 1.1739 + 1.1740 + netFromDOM = function(net, configured) { 1.1741 + // Takes a network from the DOM and makes it suitable for insertion into 1.1742 + // self.configuredNetworks (that is calling addNetwork will do the right 1.1743 + // thing). 1.1744 + // NB: Modifies net in place: safe since we don't share objects between 1.1745 + // the dom and the chrome code. 1.1746 + 1.1747 + // Things that are useful for the UI but not to us. 1.1748 + delete net.bssid; 1.1749 + delete net.signalStrength; 1.1750 + delete net.relSignalStrength; 1.1751 + delete net.security; 1.1752 + delete net.capabilities; 1.1753 + 1.1754 + if (!configured) 1.1755 + configured = {}; 1.1756 + 1.1757 + net.ssid = quote(net.ssid); 1.1758 + 1.1759 + let wep = false; 1.1760 + if ("keyManagement" in net) { 1.1761 + if (net.keyManagement === "WEP") { 1.1762 + wep = true; 1.1763 + net.keyManagement = "NONE"; 1.1764 + } 1.1765 + 1.1766 + configured.key_mgmt = net.key_mgmt = net.keyManagement; // WPA2-PSK, WPA-PSK, etc. 1.1767 + delete net.keyManagement; 1.1768 + } else { 1.1769 + configured.key_mgmt = net.key_mgmt = "NONE"; 1.1770 + } 1.1771 + 1.1772 + if (net.hidden) { 1.1773 + configured.scan_ssid = net.scan_ssid = 1; 1.1774 + delete net.hidden; 1.1775 + } 1.1776 + 1.1777 + function checkAssign(name, checkStar) { 1.1778 + if (name in net) { 1.1779 + let value = net[name]; 1.1780 + if (!value || (checkStar && value === '*')) { 1.1781 + if (name in configured) 1.1782 + net[name] = configured[name]; 1.1783 + else 1.1784 + delete net[name]; 1.1785 + } else { 1.1786 + configured[name] = net[name] = quote(value); 1.1787 + } 1.1788 + } 1.1789 + } 1.1790 + 1.1791 + checkAssign("psk", true); 1.1792 + checkAssign("identity", false); 1.1793 + checkAssign("password", true); 1.1794 + if (wep && net.wep && net.wep != '*') { 1.1795 + configured.wep_key0 = net.wep_key0 = isWepHexKey(net.wep) ? net.wep : quote(net.wep); 1.1796 + configured.auth_alg = net.auth_alg = "OPEN SHARED"; 1.1797 + } 1.1798 + 1.1799 + if ("pin" in net) { 1.1800 + net.pin = quote(net.pin); 1.1801 + } 1.1802 + 1.1803 + if ("phase1" in net) 1.1804 + net.phase1 = quote(net.phase1); 1.1805 + 1.1806 + if ("phase2" in net) 1.1807 + net.phase2 = quote(net.phase2); 1.1808 + 1.1809 + return net; 1.1810 + }; 1.1811 + 1.1812 + WifiManager.onsupplicantconnection = function() { 1.1813 + debug("Connected to supplicant"); 1.1814 + WifiManager.enabled = true; 1.1815 + self._reloadConfiguredNetworks(function(ok) { 1.1816 + // Prime this.networks. 1.1817 + if (!ok) 1.1818 + return; 1.1819 + 1.1820 + self.waitForScan(function firstScan() {}); 1.1821 + // The select network command we used in associate() disables others networks. 1.1822 + // Enable them here to make sure wpa_supplicant helps to connect to known 1.1823 + // network automatically. 1.1824 + self._enableAllNetworks(); 1.1825 + WifiManager.saveConfig(function() {}) 1.1826 + }); 1.1827 + 1.1828 + try { 1.1829 + self._allowWpaEap = WifiManager.getCapabilities().eapSim; 1.1830 + } catch (e) { 1.1831 + self._allowWpaEap = false; 1.1832 + } 1.1833 + 1.1834 + // Notify everybody, even if they didn't ask us to come up. 1.1835 + WifiManager.getMacAddress(function (mac) { 1.1836 + self.macAddress = mac; 1.1837 + debug("Got mac: " + mac); 1.1838 + self._fireEvent("wifiUp", { macAddress: mac }); 1.1839 + self.requestDone(); 1.1840 + }); 1.1841 + 1.1842 + if (WifiManager.state === "SCANNING") 1.1843 + startScanStuckTimer(); 1.1844 + }; 1.1845 + 1.1846 + WifiManager.onsupplicantlost = function() { 1.1847 + WifiManager.enabled = WifiManager.supplicantStarted = false; 1.1848 + WifiManager.state = "UNINITIALIZED"; 1.1849 + debug("Supplicant died!"); 1.1850 + 1.1851 + // Notify everybody, even if they didn't ask us to come up. 1.1852 + self._fireEvent("wifiDown", {}); 1.1853 + self.requestDone(); 1.1854 + }; 1.1855 + 1.1856 + WifiManager.onpasswordmaybeincorrect = function() { 1.1857 + WifiManager.authenticationFailuresCount++; 1.1858 + }; 1.1859 + 1.1860 + WifiManager.ondisconnected = function() { 1.1861 + // We may fail to establish the connection, re-enable the 1.1862 + // rest of our networks. 1.1863 + if (self._needToEnableNetworks) { 1.1864 + self._enableAllNetworks(); 1.1865 + self._needToEnableNetworks = false; 1.1866 + } 1.1867 + 1.1868 + WifiManager.getCurrentNetworkId(this.ssid, function(netId) { 1.1869 + // Trying to get netId from current network. 1.1870 + if (!netId && 1.1871 + self.currentNetwork && 1.1872 + typeof self.currentNetwork.netId !== "undefined") { 1.1873 + netId = self.currentNetwork.netId; 1.1874 + } 1.1875 + if (netId) { 1.1876 + WifiManager.disableNetwork(netId, function() {}); 1.1877 + } 1.1878 + }); 1.1879 + self._fireEvent("onconnectingfailed", {network: self.currentNetwork}); 1.1880 + } 1.1881 + 1.1882 + WifiManager.onstatechange = function() { 1.1883 + debug("State change: " + this.prevState + " -> " + this.state); 1.1884 + 1.1885 + if (self._connectionInfoTimer && 1.1886 + this.state !== "CONNECTED" && 1.1887 + this.state !== "COMPLETED") { 1.1888 + self._stopConnectionInfoTimer(); 1.1889 + } 1.1890 + 1.1891 + if (this.state !== "SCANNING" && 1.1892 + self._scanStuckTimer) { 1.1893 + self._scanStuckTimer.cancel(); 1.1894 + self._scanStuckTimer = null; 1.1895 + } 1.1896 + 1.1897 + switch (this.state) { 1.1898 + case "DORMANT": 1.1899 + // The dormant state is a bad state to be in since we won't 1.1900 + // automatically connect. Try to knock us out of it. We only 1.1901 + // hit this state when we've failed to run DHCP, so trying 1.1902 + // again isn't the worst thing we can do. Eventually, we'll 1.1903 + // need to detect if we're looping in this state and bail out. 1.1904 + WifiManager.reconnect(function(){}); 1.1905 + break; 1.1906 + case "ASSOCIATING": 1.1907 + // id has not yet been filled in, so we can only report the ssid and 1.1908 + // bssid. 1.1909 + self.currentNetwork = 1.1910 + { bssid: WifiManager.connectionInfo.bssid, 1.1911 + ssid: quote(WifiManager.connectionInfo.ssid) }; 1.1912 + self._fireEvent("onconnecting", { network: netToDOM(self.currentNetwork) }); 1.1913 + break; 1.1914 + case "ASSOCIATED": 1.1915 + if (!self.currentNetwork) { 1.1916 + self.currentNetwork = 1.1917 + { bssid: WifiManager.connectionInfo.bssid, 1.1918 + ssid: quote(WifiManager.connectionInfo.ssid) }; 1.1919 + } 1.1920 + 1.1921 + self.currentNetwork.netId = this.id; 1.1922 + WifiManager.getNetworkConfiguration(self.currentNetwork, function (){}); 1.1923 + break; 1.1924 + case "COMPLETED": 1.1925 + // Now that we've successfully completed the connection, re-enable the 1.1926 + // rest of our networks. 1.1927 + // XXX Need to do this eventually if the user entered an incorrect 1.1928 + // password. For now, we require user interaction to break the loop and 1.1929 + // select a better network! 1.1930 + if (self._needToEnableNetworks) { 1.1931 + self._enableAllNetworks(); 1.1932 + self._needToEnableNetworks = false; 1.1933 + } 1.1934 + 1.1935 + // We get the ASSOCIATED event when we've associated but not connected, so 1.1936 + // wait until the handshake is complete. 1.1937 + if (this.fromStatus || !self.currentNetwork) { 1.1938 + // In this case, we connected to an already-connected wpa_supplicant, 1.1939 + // because of that we need to gather information about the current 1.1940 + // network here. 1.1941 + self.currentNetwork = { ssid: quote(WifiManager.connectionInfo.ssid), 1.1942 + netId: WifiManager.connectionInfo.id }; 1.1943 + WifiManager.getNetworkConfiguration(self.currentNetwork, function(){}); 1.1944 + } 1.1945 + 1.1946 + // Update http proxy when connected to network. 1.1947 + let netConnect = WifiManager.getHttpProxyNetwork(self.currentNetwork); 1.1948 + if (netConnect) 1.1949 + WifiManager.setHttpProxy(netConnect); 1.1950 + 1.1951 + // The full authentication process is completed, reset the count. 1.1952 + WifiManager.authenticationFailuresCount = 0; 1.1953 + WifiManager.loopDetectionCount = 0; 1.1954 + self._startConnectionInfoTimer(); 1.1955 + self._fireEvent("onassociate", { network: netToDOM(self.currentNetwork) }); 1.1956 + break; 1.1957 + case "CONNECTED": 1.1958 + // BSSID is read after connected, update it. 1.1959 + self.currentNetwork.bssid = WifiManager.connectionInfo.bssid; 1.1960 + break; 1.1961 + case "DISCONNECTED": 1.1962 + // wpa_supplicant may give us a "DISCONNECTED" event even if 1.1963 + // we are already in "DISCONNECTED" state. 1.1964 + if ((WifiNetworkInterface.state === 1.1965 + Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED) && 1.1966 + (this.prevState === "INITIALIZING" || 1.1967 + this.prevState === "DISCONNECTED" || 1.1968 + this.prevState === "INTERFACE_DISABLED" || 1.1969 + this.prevState === "INACTIVE" || 1.1970 + this.prevState === "UNINITIALIZED")) { 1.1971 + return; 1.1972 + } 1.1973 + 1.1974 + self._fireEvent("ondisconnect", {}); 1.1975 + 1.1976 + // When disconnected, clear the http proxy setting if it exists. 1.1977 + // Temporarily set http proxy to empty and restore user setting after setHttpProxy. 1.1978 + let netDisconnect = WifiManager.getHttpProxyNetwork(self.currentNetwork); 1.1979 + if (netDisconnect) { 1.1980 + let prehttpProxyHostSetting = netDisconnect.httpProxyHost; 1.1981 + let prehttpProxyPortSetting = netDisconnect.httpProxyPort; 1.1982 + 1.1983 + netDisconnect.httpProxyHost = ""; 1.1984 + netDisconnect.httpProxyPort = 0; 1.1985 + 1.1986 + WifiManager.setHttpProxy(netDisconnect); 1.1987 + 1.1988 + netDisconnect.httpProxyHost = prehttpProxyHostSetting; 1.1989 + netDisconnect.httpProxyPort = prehttpProxyPortSetting; 1.1990 + } 1.1991 + 1.1992 + self.currentNetwork = null; 1.1993 + self.ipAddress = ""; 1.1994 + 1.1995 + if (self._turnOnBackgroundScan) { 1.1996 + self._turnOnBackgroundScan = false; 1.1997 + WifiManager.setBackgroundScan("ON", function(did_something, ok) { 1.1998 + WifiManager.reassociate(function() {}); 1.1999 + }); 1.2000 + } 1.2001 + 1.2002 + WifiManager.connectionDropped(function() { 1.2003 + // We've disconnected from a network because of a call to forgetNetwork. 1.2004 + // Reconnect to the next available network (if any). 1.2005 + if (self._reconnectOnDisconnect) { 1.2006 + self._reconnectOnDisconnect = false; 1.2007 + WifiManager.reconnect(function(){}); 1.2008 + } 1.2009 + }); 1.2010 + 1.2011 + WifiNetworkInterface.state = 1.2012 + Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED; 1.2013 + WifiNetworkInterface.ips = []; 1.2014 + WifiNetworkInterface.prefixLengths = []; 1.2015 + WifiNetworkInterface.gateways = []; 1.2016 + WifiNetworkInterface.dnses = []; 1.2017 + Services.obs.notifyObservers(WifiNetworkInterface, 1.2018 + kNetworkInterfaceStateChangedTopic, 1.2019 + null); 1.2020 + 1.2021 + break; 1.2022 + case "WPS_TIMEOUT": 1.2023 + self._fireEvent("onwpstimeout", {}); 1.2024 + break; 1.2025 + case "WPS_FAIL": 1.2026 + self._fireEvent("onwpsfail", {}); 1.2027 + break; 1.2028 + case "WPS_OVERLAP_DETECTED": 1.2029 + self._fireEvent("onwpsoverlap", {}); 1.2030 + break; 1.2031 + case "SCANNING": 1.2032 + // If we're already scanning in the background, we don't need to worry 1.2033 + // about getting stuck while scanning. 1.2034 + if (!WifiManager.backgroundScanEnabled && WifiManager.enabled) 1.2035 + startScanStuckTimer(); 1.2036 + break; 1.2037 + } 1.2038 + }; 1.2039 + 1.2040 + WifiManager.onnetworkconnected = function() { 1.2041 + if (!this.info || !this.info.ipaddr_str) { 1.2042 + debug("Network information is invalid."); 1.2043 + return; 1.2044 + } 1.2045 + 1.2046 + let maskLength = 1.2047 + netHelpers.getMaskLength(netHelpers.stringToIP(this.info.mask_str)); 1.2048 + if (!maskLength) { 1.2049 + maskLength = 32; // max prefix for IPv4. 1.2050 + } 1.2051 + WifiNetworkInterface.state = 1.2052 + Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED; 1.2053 + WifiNetworkInterface.ips = [this.info.ipaddr_str]; 1.2054 + WifiNetworkInterface.prefixLengths = [maskLength]; 1.2055 + WifiNetworkInterface.gateways = [this.info.gateway_str]; 1.2056 + if (typeof this.info.dns1_str == "string" && 1.2057 + this.info.dns1_str.length) { 1.2058 + WifiNetworkInterface.dnses.push(this.info.dns1_str); 1.2059 + } 1.2060 + if (typeof this.info.dns2_str == "string" && 1.2061 + this.info.dns2_str.length) { 1.2062 + WifiNetworkInterface.dnses.push(this.info.dns2_str); 1.2063 + } 1.2064 + Services.obs.notifyObservers(WifiNetworkInterface, 1.2065 + kNetworkInterfaceStateChangedTopic, 1.2066 + null); 1.2067 + 1.2068 + self.ipAddress = this.info.ipaddr_str; 1.2069 + 1.2070 + // We start the connection information timer when we associate, but 1.2071 + // don't have our IP address until here. Make sure that we fire a new 1.2072 + // connectionInformation event with the IP address the next time the 1.2073 + // timer fires. 1.2074 + self._lastConnectionInfo = null; 1.2075 + self._fireEvent("onconnect", { network: netToDOM(self.currentNetwork) }); 1.2076 + }; 1.2077 + 1.2078 + WifiManager.onscanresultsavailable = function() { 1.2079 + if (self._scanStuckTimer) { 1.2080 + // We got scan results! We must not be stuck for now, try again. 1.2081 + self._scanStuckTimer.cancel(); 1.2082 + self._scanStuckTimer.initWithCallback(scanIsStuck, SCAN_STUCK_WAIT, 1.2083 + Ci.nsITimer.TYPE_ONE_SHOT); 1.2084 + } 1.2085 + 1.2086 + if (self.wantScanResults.length === 0) { 1.2087 + debug("Scan results available, but we don't need them"); 1.2088 + return; 1.2089 + } 1.2090 + 1.2091 + debug("Scan results are available! Asking for them."); 1.2092 + WifiManager.getScanResults(function(r) { 1.2093 + // Failure. 1.2094 + if (!r) { 1.2095 + self.wantScanResults.forEach(function(callback) { callback(null) }); 1.2096 + self.wantScanResults = []; 1.2097 + return; 1.2098 + } 1.2099 + 1.2100 + // Now that we have scan results, there's no more need to continue 1.2101 + // scanning. Ignore any errors from this command. 1.2102 + WifiManager.setScanMode("inactive", function() {}); 1.2103 + let lines = r.split("\n"); 1.2104 + // NB: Skip the header line. 1.2105 + self.networksArray = []; 1.2106 + for (let i = 1; i < lines.length; ++i) { 1.2107 + // bssid / frequency / signal level / flags / ssid 1.2108 + var match = /([\S]+)\s+([\S]+)\s+([\S]+)\s+(\[[\S]+\])?\s(.*)/.exec(lines[i]); 1.2109 + 1.2110 + if (match && match[5]) { 1.2111 + let ssid = match[5], 1.2112 + bssid = match[1], 1.2113 + signalLevel = match[3], 1.2114 + flags = match[4]; 1.2115 + 1.2116 + // Skip ad-hoc networks which aren't supported (bug 811635). 1.2117 + if (flags && flags.indexOf("[IBSS]") >= 0) 1.2118 + continue; 1.2119 + 1.2120 + // If this is the first time that we've seen this SSID in the scan 1.2121 + // results, add it to the list along with any other information. 1.2122 + // Also, we use the highest signal strength that we see. 1.2123 + let network = new ScanResult(ssid, bssid, flags, signalLevel); 1.2124 + 1.2125 + let networkKey = getNetworkKey(network); 1.2126 + let eapIndex = -1; 1.2127 + if (networkKey in self.configuredNetworks) { 1.2128 + let known = self.configuredNetworks[networkKey]; 1.2129 + network.known = true; 1.2130 + 1.2131 + if ("identity" in known && known.identity) 1.2132 + network.identity = dequote(known.identity); 1.2133 + 1.2134 + // Note: we don't hand out passwords here! The * marks that there 1.2135 + // is a password that we're hiding. 1.2136 + if (("psk" in known && known.psk) || 1.2137 + ("password" in known && known.password) || 1.2138 + ("wep_key0" in known && known.wep_key0)) { 1.2139 + network.password = "*"; 1.2140 + } 1.2141 + } else if (!self._allowWpaEap && 1.2142 + (eapIndex = network.security.indexOf("WPA-EAP")) >= 0) { 1.2143 + // Don't offer to connect to WPA-EAP networks unless one has been 1.2144 + // configured through other means (e.g. it was added directly to 1.2145 + // wpa_supplicant.conf). Here, we have an unknown WPA-EAP network, 1.2146 + // so we ignore it entirely if it only supports WPA-EAP, otherwise 1.2147 + // we take EAP out of the list and offer the rest of the 1.2148 + // security. 1.2149 + if (network.security.length === 1) 1.2150 + continue; 1.2151 + 1.2152 + network.security.splice(eapIndex, 1); 1.2153 + } 1.2154 + 1.2155 + self.networksArray.push(network); 1.2156 + if (network.bssid === WifiManager.connectionInfo.bssid) 1.2157 + network.connected = true; 1.2158 + 1.2159 + let signal = calculateSignal(Number(match[3])); 1.2160 + if (signal > network.relSignalStrength) 1.2161 + network.relSignalStrength = signal; 1.2162 + } else if (!match) { 1.2163 + debug("Match didn't find anything for: " + lines[i]); 1.2164 + } 1.2165 + } 1.2166 + 1.2167 + self.wantScanResults.forEach(function(callback) { callback(self.networksArray) }); 1.2168 + self.wantScanResults = []; 1.2169 + }); 1.2170 + }; 1.2171 + 1.2172 + // Read the 'wifi.enabled' setting in order to start with a known 1.2173 + // value at boot time. The handle() will be called after reading. 1.2174 + // 1.2175 + // nsISettingsServiceCallback implementation. 1.2176 + var initWifiEnabledCb = { 1.2177 + handle: function handle(aName, aResult) { 1.2178 + if (aName !== SETTINGS_WIFI_ENABLED) 1.2179 + return; 1.2180 + if (aResult === null) 1.2181 + aResult = true; 1.2182 + self.handleWifiEnabled(aResult); 1.2183 + }, 1.2184 + handleError: function handleError(aErrorMessage) { 1.2185 + debug("Error reading the 'wifi.enabled' setting. Default to wifi on."); 1.2186 + self.handleWifiEnabled(true); 1.2187 + } 1.2188 + }; 1.2189 + 1.2190 + var initWifiDebuggingEnabledCb = { 1.2191 + handle: function handle(aName, aResult) { 1.2192 + if (aName !== SETTINGS_WIFI_DEBUG_ENABLED) 1.2193 + return; 1.2194 + if (aResult === null) 1.2195 + aResult = false; 1.2196 + DEBUG = aResult; 1.2197 + updateDebug(); 1.2198 + }, 1.2199 + handleError: function handleError(aErrorMessage) { 1.2200 + debug("Error reading the 'wifi.debugging.enabled' setting. Default to debugging off."); 1.2201 + DEBUG = false; 1.2202 + updateDebug(); 1.2203 + } 1.2204 + }; 1.2205 + 1.2206 + this.initTetheringSettings(); 1.2207 + 1.2208 + let lock = gSettingsService.createLock(); 1.2209 + lock.get(SETTINGS_WIFI_ENABLED, initWifiEnabledCb); 1.2210 + lock.get(SETTINGS_WIFI_DEBUG_ENABLED, initWifiDebuggingEnabledCb); 1.2211 + 1.2212 + lock.get(SETTINGS_WIFI_SSID, this); 1.2213 + lock.get(SETTINGS_WIFI_SECURITY_TYPE, this); 1.2214 + lock.get(SETTINGS_WIFI_SECURITY_PASSWORD, this); 1.2215 + lock.get(SETTINGS_WIFI_IP, this); 1.2216 + lock.get(SETTINGS_WIFI_PREFIX, this); 1.2217 + lock.get(SETTINGS_WIFI_DHCPSERVER_STARTIP, this); 1.2218 + lock.get(SETTINGS_WIFI_DHCPSERVER_ENDIP, this); 1.2219 + lock.get(SETTINGS_WIFI_DNS1, this); 1.2220 + lock.get(SETTINGS_WIFI_DNS2, this); 1.2221 + lock.get(SETTINGS_WIFI_TETHERING_ENABLED, this); 1.2222 + 1.2223 + lock.get(SETTINGS_USB_DHCPSERVER_STARTIP, this); 1.2224 + lock.get(SETTINGS_USB_DHCPSERVER_ENDIP, this); 1.2225 + 1.2226 + this._wifiTetheringSettingsToRead = [SETTINGS_WIFI_SSID, 1.2227 + SETTINGS_WIFI_SECURITY_TYPE, 1.2228 + SETTINGS_WIFI_SECURITY_PASSWORD, 1.2229 + SETTINGS_WIFI_IP, 1.2230 + SETTINGS_WIFI_PREFIX, 1.2231 + SETTINGS_WIFI_DHCPSERVER_STARTIP, 1.2232 + SETTINGS_WIFI_DHCPSERVER_ENDIP, 1.2233 + SETTINGS_WIFI_DNS1, 1.2234 + SETTINGS_WIFI_DNS2, 1.2235 + SETTINGS_WIFI_TETHERING_ENABLED, 1.2236 + SETTINGS_USB_DHCPSERVER_STARTIP, 1.2237 + SETTINGS_USB_DHCPSERVER_ENDIP]; 1.2238 +} 1.2239 + 1.2240 +function translateState(state) { 1.2241 + switch (state) { 1.2242 + case "INTERFACE_DISABLED": 1.2243 + case "INACTIVE": 1.2244 + case "SCANNING": 1.2245 + case "DISCONNECTED": 1.2246 + default: 1.2247 + return "disconnected"; 1.2248 + 1.2249 + case "AUTHENTICATING": 1.2250 + case "ASSOCIATING": 1.2251 + case "ASSOCIATED": 1.2252 + case "FOUR_WAY_HANDSHAKE": 1.2253 + case "GROUP_HANDSHAKE": 1.2254 + return "connecting"; 1.2255 + 1.2256 + case "COMPLETED": 1.2257 + return WifiManager.getDhcpInfo() ? "connected" : "associated"; 1.2258 + } 1.2259 +} 1.2260 + 1.2261 +WifiWorker.prototype = { 1.2262 + classID: WIFIWORKER_CID, 1.2263 + classInfo: XPCOMUtils.generateCI({classID: WIFIWORKER_CID, 1.2264 + contractID: WIFIWORKER_CONTRACTID, 1.2265 + classDescription: "WifiWorker", 1.2266 + interfaces: [Ci.nsIWorkerHolder, 1.2267 + Ci.nsIWifi, 1.2268 + Ci.nsIObserver]}), 1.2269 + 1.2270 + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWorkerHolder, 1.2271 + Ci.nsIWifi, 1.2272 + Ci.nsISettingsServiceCallback]), 1.2273 + 1.2274 + disconnectedByWifi: false, 1.2275 + 1.2276 + disconnectedByWifiTethering: false, 1.2277 + 1.2278 + _wifiTetheringSettingsToRead: [], 1.2279 + 1.2280 + _oldWifiTetheringEnabledState: null, 1.2281 + 1.2282 + tetheringSettings: {}, 1.2283 + 1.2284 + initTetheringSettings: function initTetheringSettings() { 1.2285 + this.tetheringSettings[SETTINGS_WIFI_TETHERING_ENABLED] = null; 1.2286 + this.tetheringSettings[SETTINGS_WIFI_SSID] = DEFAULT_WIFI_SSID; 1.2287 + this.tetheringSettings[SETTINGS_WIFI_SECURITY_TYPE] = DEFAULT_WIFI_SECURITY_TYPE; 1.2288 + this.tetheringSettings[SETTINGS_WIFI_SECURITY_PASSWORD] = DEFAULT_WIFI_SECURITY_PASSWORD; 1.2289 + this.tetheringSettings[SETTINGS_WIFI_IP] = DEFAULT_WIFI_IP; 1.2290 + this.tetheringSettings[SETTINGS_WIFI_PREFIX] = DEFAULT_WIFI_PREFIX; 1.2291 + this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_STARTIP] = DEFAULT_WIFI_DHCPSERVER_STARTIP; 1.2292 + this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_ENDIP] = DEFAULT_WIFI_DHCPSERVER_ENDIP; 1.2293 + this.tetheringSettings[SETTINGS_WIFI_DNS1] = DEFAULT_DNS1; 1.2294 + this.tetheringSettings[SETTINGS_WIFI_DNS2] = DEFAULT_DNS2; 1.2295 + 1.2296 + this.tetheringSettings[SETTINGS_USB_DHCPSERVER_STARTIP] = DEFAULT_USB_DHCPSERVER_STARTIP; 1.2297 + this.tetheringSettings[SETTINGS_USB_DHCPSERVER_ENDIP] = DEFAULT_USB_DHCPSERVER_ENDIP; 1.2298 + }, 1.2299 + 1.2300 + // Internal methods. 1.2301 + waitForScan: function(callback) { 1.2302 + this.wantScanResults.push(callback); 1.2303 + }, 1.2304 + 1.2305 + // In order to select a specific network, we disable the rest of the 1.2306 + // networks known to us. However, in general, we want the supplicant to 1.2307 + // connect to which ever network it thinks is best, so when we select the 1.2308 + // proper network (or fail to), we need to re-enable the rest. 1.2309 + _enableAllNetworks: function() { 1.2310 + for each (let net in this.configuredNetworks) { 1.2311 + WifiManager.enableNetwork(net.netId, false, function(ok) { 1.2312 + net.disabled = ok ? 1 : 0; 1.2313 + }); 1.2314 + } 1.2315 + }, 1.2316 + 1.2317 + _startConnectionInfoTimer: function() { 1.2318 + if (this._connectionInfoTimer) 1.2319 + return; 1.2320 + 1.2321 + var self = this; 1.2322 + function getConnectionInformation() { 1.2323 + WifiManager.getConnectionInfo(function(connInfo) { 1.2324 + // See comments in calculateSignal for information about this. 1.2325 + if (!connInfo) { 1.2326 + self._lastConnectionInfo = null; 1.2327 + return; 1.2328 + } 1.2329 + 1.2330 + let { rssi, linkspeed } = connInfo; 1.2331 + if (rssi > 0) 1.2332 + rssi -= 256; 1.2333 + if (rssi <= MIN_RSSI) 1.2334 + rssi = MIN_RSSI; 1.2335 + else if (rssi >= MAX_RSSI) 1.2336 + rssi = MAX_RSSI; 1.2337 + 1.2338 + let info = { signalStrength: rssi, 1.2339 + relSignalStrength: calculateSignal(rssi), 1.2340 + linkSpeed: linkspeed, 1.2341 + ipAddress: self.ipAddress }; 1.2342 + let last = self._lastConnectionInfo; 1.2343 + 1.2344 + // Only fire the event if the link speed changed or the signal 1.2345 + // strength changed by more than 10%. 1.2346 + function tensPlace(percent) ((percent / 10) | 0) 1.2347 + 1.2348 + if (last && last.linkSpeed === info.linkSpeed && 1.2349 + tensPlace(last.relSignalStrength) === tensPlace(info.relSignalStrength)) { 1.2350 + return; 1.2351 + } 1.2352 + 1.2353 + self._lastConnectionInfo = info; 1.2354 + debug("Firing connectionInfoUpdate: " + uneval(info)); 1.2355 + self._fireEvent("connectionInfoUpdate", info); 1.2356 + }); 1.2357 + } 1.2358 + 1.2359 + // Prime our _lastConnectionInfo immediately and fire the event at the 1.2360 + // same time. 1.2361 + getConnectionInformation(); 1.2362 + 1.2363 + // Now, set up the timer for regular updates. 1.2364 + this._connectionInfoTimer = 1.2365 + Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 1.2366 + this._connectionInfoTimer.init(getConnectionInformation, 5000, 1.2367 + Ci.nsITimer.TYPE_REPEATING_SLACK); 1.2368 + }, 1.2369 + 1.2370 + _stopConnectionInfoTimer: function() { 1.2371 + if (!this._connectionInfoTimer) 1.2372 + return; 1.2373 + 1.2374 + this._connectionInfoTimer.cancel(); 1.2375 + this._connectionInfoTimer = null; 1.2376 + this._lastConnectionInfo = null; 1.2377 + }, 1.2378 + 1.2379 + _reloadConfiguredNetworks: function(callback) { 1.2380 + WifiManager.getConfiguredNetworks((function(networks) { 1.2381 + if (!networks) { 1.2382 + debug("Unable to get configured networks"); 1.2383 + callback(false); 1.2384 + return; 1.2385 + } 1.2386 + 1.2387 + this._highestPriority = -1; 1.2388 + 1.2389 + // Convert between netId-based and ssid-based indexing. 1.2390 + for (let net in networks) { 1.2391 + let network = networks[net]; 1.2392 + delete networks[net]; 1.2393 + 1.2394 + if (!network.ssid) { 1.2395 + WifiManager.removeNetwork(network.netId, function() {}); 1.2396 + continue; 1.2397 + } 1.2398 + 1.2399 + if (network.priority && network.priority > this._highestPriority) 1.2400 + this._highestPriority = network.priority; 1.2401 + 1.2402 + let networkKey = getNetworkKey(network); 1.2403 + // Accept latest config of same network(same SSID and same security). 1.2404 + if (networks[networkKey]) { 1.2405 + WifiManager.removeNetwork(networks[networkKey].netId, function() {}); 1.2406 + } 1.2407 + networks[networkKey] = network; 1.2408 + } 1.2409 + 1.2410 + this.configuredNetworks = networks; 1.2411 + callback(true); 1.2412 + }).bind(this)); 1.2413 + }, 1.2414 + 1.2415 + // Important side effect: calls WifiManager.saveConfig. 1.2416 + _reprioritizeNetworks: function(callback) { 1.2417 + // First, sort the networks in orer of their priority. 1.2418 + var ordered = Object.getOwnPropertyNames(this.configuredNetworks); 1.2419 + let self = this; 1.2420 + ordered.sort(function(a, b) { 1.2421 + var neta = self.configuredNetworks[a], 1.2422 + netb = self.configuredNetworks[b]; 1.2423 + 1.2424 + // Sort unsorted networks to the end of the list. 1.2425 + if (isNaN(neta.priority)) 1.2426 + return isNaN(netb.priority) ? 0 : 1; 1.2427 + if (isNaN(netb.priority)) 1.2428 + return -1; 1.2429 + return netb.priority - neta.priority; 1.2430 + }); 1.2431 + 1.2432 + // Skip unsorted networks. 1.2433 + let newPriority = 0, i; 1.2434 + for (i = ordered.length - 1; i >= 0; --i) { 1.2435 + if (!isNaN(this.configuredNetworks[ordered[i]].priority)) 1.2436 + break; 1.2437 + } 1.2438 + 1.2439 + // No networks we care about? 1.2440 + if (i < 0) { 1.2441 + WifiManager.saveConfig(callback); 1.2442 + return; 1.2443 + } 1.2444 + 1.2445 + // Now assign priorities from 0 to length, starting with the smallest 1.2446 + // priority and heading towards the highest (note the dependency between 1.2447 + // total and i here). 1.2448 + let done = 0, errors = 0, total = i + 1; 1.2449 + for (; i >= 0; --i) { 1.2450 + let network = this.configuredNetworks[ordered[i]]; 1.2451 + network.priority = newPriority++; 1.2452 + 1.2453 + // Note: networkUpdated declared below since it happens logically after 1.2454 + // this loop. 1.2455 + WifiManager.updateNetwork(network, networkUpdated); 1.2456 + } 1.2457 + 1.2458 + function networkUpdated(ok) { 1.2459 + if (!ok) 1.2460 + ++errors; 1.2461 + if (++done === total) { 1.2462 + if (errors > 0) { 1.2463 + callback(false); 1.2464 + return; 1.2465 + } 1.2466 + 1.2467 + WifiManager.saveConfig(function(ok) { 1.2468 + if (!ok) { 1.2469 + callback(false); 1.2470 + return; 1.2471 + } 1.2472 + 1.2473 + self._reloadConfiguredNetworks(function(ok) { 1.2474 + callback(ok); 1.2475 + }); 1.2476 + }); 1.2477 + } 1.2478 + } 1.2479 + }, 1.2480 + 1.2481 + // nsIWifi 1.2482 + 1.2483 + _domManagers: [], 1.2484 + _fireEvent: function(message, data) { 1.2485 + this._domManagers.forEach(function(manager) { 1.2486 + // Note: We should never have a dead message manager here because we 1.2487 + // observe our child message managers shutting down, below. 1.2488 + manager.sendAsyncMessage("WifiManager:" + message, data); 1.2489 + }); 1.2490 + }, 1.2491 + 1.2492 + _sendMessage: function(message, success, data, msg) { 1.2493 + try { 1.2494 + msg.manager.sendAsyncMessage(message + (success ? ":OK" : ":NO"), 1.2495 + { data: data, rid: msg.rid, mid: msg.mid }); 1.2496 + } catch (e) { 1.2497 + debug("sendAsyncMessage error : " + e); 1.2498 + } 1.2499 + this._splicePendingRequest(msg); 1.2500 + }, 1.2501 + 1.2502 + _domRequest: [], 1.2503 + 1.2504 + _splicePendingRequest: function(msg) { 1.2505 + for (let i = 0; i < this._domRequest.length; i++) { 1.2506 + if (this._domRequest[i].msg === msg) { 1.2507 + this._domRequest.splice(i, 1); 1.2508 + return; 1.2509 + } 1.2510 + } 1.2511 + }, 1.2512 + 1.2513 + _clearPendingRequest: function() { 1.2514 + if (this._domRequest.length === 0) return; 1.2515 + this._domRequest.forEach((function(req) { 1.2516 + this._sendMessage(req.name + ":Return", false, "Wifi is disabled", req.msg); 1.2517 + }).bind(this)); 1.2518 + }, 1.2519 + 1.2520 + receiveMessage: function MessageManager_receiveMessage(aMessage) { 1.2521 + let msg = aMessage.data || {}; 1.2522 + msg.manager = aMessage.target; 1.2523 + 1.2524 + if (WifiManager.p2pSupported()) { 1.2525 + // If p2pObserver returns something truthy, return it! 1.2526 + // Otherwise, continue to do the rest of tasks. 1.2527 + var p2pRet = this._p2pObserver.onDOMMessage(aMessage); 1.2528 + if (p2pRet) { 1.2529 + return p2pRet; 1.2530 + } 1.2531 + } 1.2532 + 1.2533 + // Note: By the time we receive child-process-shutdown, the child process 1.2534 + // has already forgotten its permissions so we do this before the 1.2535 + // permissions check. 1.2536 + if (aMessage.name === "child-process-shutdown") { 1.2537 + let i; 1.2538 + if ((i = this._domManagers.indexOf(msg.manager)) != -1) { 1.2539 + this._domManagers.splice(i, 1); 1.2540 + } 1.2541 + for (i = this._domRequest.length - 1; i >= 0; i--) { 1.2542 + if (this._domRequest[i].msg.manager === msg.manager) { 1.2543 + this._domRequest.splice(i, 1); 1.2544 + } 1.2545 + } 1.2546 + return; 1.2547 + } 1.2548 + 1.2549 + if (!aMessage.target.assertPermission("wifi-manage")) { 1.2550 + return; 1.2551 + } 1.2552 + 1.2553 + // We are interested in DOMRequests only. 1.2554 + if (aMessage.name != "WifiManager:getState") { 1.2555 + this._domRequest.push({name: aMessage.name, msg:msg}); 1.2556 + } 1.2557 + 1.2558 + switch (aMessage.name) { 1.2559 + case "WifiManager:getNetworks": 1.2560 + this.getNetworks(msg); 1.2561 + break; 1.2562 + case "WifiManager:getKnownNetworks": 1.2563 + this.getKnownNetworks(msg); 1.2564 + break; 1.2565 + case "WifiManager:associate": 1.2566 + this.associate(msg); 1.2567 + break; 1.2568 + case "WifiManager:forget": 1.2569 + this.forget(msg); 1.2570 + break; 1.2571 + case "WifiManager:wps": 1.2572 + this.wps(msg); 1.2573 + break; 1.2574 + case "WifiManager:setPowerSavingMode": 1.2575 + this.setPowerSavingMode(msg); 1.2576 + break; 1.2577 + case "WifiManager:setHttpProxy": 1.2578 + this.setHttpProxy(msg); 1.2579 + break; 1.2580 + case "WifiManager:setStaticIpMode": 1.2581 + this.setStaticIpMode(msg); 1.2582 + break; 1.2583 + case "WifiManager:getState": { 1.2584 + let i; 1.2585 + if ((i = this._domManagers.indexOf(msg.manager)) === -1) { 1.2586 + this._domManagers.push(msg.manager); 1.2587 + } 1.2588 + 1.2589 + let net = this.currentNetwork ? netToDOM(this.currentNetwork) : null; 1.2590 + return { network: net, 1.2591 + connectionInfo: this._lastConnectionInfo, 1.2592 + enabled: WifiManager.enabled, 1.2593 + status: translateState(WifiManager.state), 1.2594 + macAddress: this.macAddress }; 1.2595 + } 1.2596 + } 1.2597 + }, 1.2598 + 1.2599 + getNetworks: function(msg) { 1.2600 + const message = "WifiManager:getNetworks:Return"; 1.2601 + if (!WifiManager.enabled) { 1.2602 + this._sendMessage(message, false, "Wifi is disabled", msg); 1.2603 + return; 1.2604 + } 1.2605 + 1.2606 + let sent = false; 1.2607 + let callback = (function (networks) { 1.2608 + if (sent) 1.2609 + return; 1.2610 + sent = true; 1.2611 + this._sendMessage(message, networks !== null, networks, msg); 1.2612 + }).bind(this); 1.2613 + this.waitForScan(callback); 1.2614 + 1.2615 + WifiManager.scan(true, (function(ok) { 1.2616 + // If the scan command succeeded, we're done. 1.2617 + if (ok) 1.2618 + return; 1.2619 + 1.2620 + // Avoid sending multiple responses. 1.2621 + if (sent) 1.2622 + return; 1.2623 + 1.2624 + // Otherwise, let the client know that it failed, it's responsible for 1.2625 + // trying again in a few seconds. 1.2626 + sent = true; 1.2627 + this._sendMessage(message, false, "ScanFailed", msg); 1.2628 + }).bind(this)); 1.2629 + }, 1.2630 + 1.2631 + getWifiScanResults: function(callback) { 1.2632 + var count = 0; 1.2633 + var timer = null; 1.2634 + var self = this; 1.2635 + 1.2636 + self.waitForScan(waitForScanCallback); 1.2637 + doScan(); 1.2638 + function doScan() { 1.2639 + WifiManager.scan(true, (function (ok) { 1.2640 + if (!ok) { 1.2641 + if (!timer) { 1.2642 + count = 0; 1.2643 + timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 1.2644 + } 1.2645 + 1.2646 + if (count++ >= 3) { 1.2647 + timer = null; 1.2648 + self.wantScanResults.splice(self.wantScanResults.indexOf(waitForScanCallback), 1); 1.2649 + callback.onfailure(); 1.2650 + return; 1.2651 + } 1.2652 + 1.2653 + // Else it's still running, continue waiting. 1.2654 + timer.initWithCallback(doScan, 10000, Ci.nsITimer.TYPE_ONE_SHOT); 1.2655 + return; 1.2656 + } 1.2657 + }).bind(this)); 1.2658 + } 1.2659 + 1.2660 + function waitForScanCallback(networks) { 1.2661 + if (networks === null) { 1.2662 + callback.onfailure(); 1.2663 + return; 1.2664 + } 1.2665 + 1.2666 + var wifiScanResults = new Array(); 1.2667 + var net; 1.2668 + for (let net in networks) { 1.2669 + let value = networks[net]; 1.2670 + wifiScanResults.push(transformResult(value)); 1.2671 + } 1.2672 + callback.onready(wifiScanResults.length, wifiScanResults); 1.2673 + } 1.2674 + 1.2675 + function transformResult(element) { 1.2676 + var result = new WifiScanResult(); 1.2677 + result.connected = false; 1.2678 + for (let id in element) { 1.2679 + if (id === "__exposedProps__") { 1.2680 + continue; 1.2681 + } 1.2682 + if (id === "security") { 1.2683 + result[id] = 0; 1.2684 + var security = element[id]; 1.2685 + for (let j = 0; j < security.length; j++) { 1.2686 + if (security[j] === "WPA-PSK") { 1.2687 + result[id] |= Ci.nsIWifiScanResult.WPA_PSK; 1.2688 + } else if (security[j] === "WPA-EAP") { 1.2689 + result[id] |= Ci.nsIWifiScanResult.WPA_EAP; 1.2690 + } else if (security[j] === "WEP") { 1.2691 + result[id] |= Ci.nsIWifiScanResult.WEP; 1.2692 + } else { 1.2693 + result[id] = 0; 1.2694 + } 1.2695 + } 1.2696 + } else { 1.2697 + result[id] = element[id]; 1.2698 + } 1.2699 + } 1.2700 + return result; 1.2701 + } 1.2702 + }, 1.2703 + 1.2704 + getKnownNetworks: function(msg) { 1.2705 + const message = "WifiManager:getKnownNetworks:Return"; 1.2706 + if (!WifiManager.enabled) { 1.2707 + this._sendMessage(message, false, "Wifi is disabled", msg); 1.2708 + return; 1.2709 + } 1.2710 + 1.2711 + this._reloadConfiguredNetworks((function(ok) { 1.2712 + if (!ok) { 1.2713 + this._sendMessage(message, false, "Failed", msg); 1.2714 + return; 1.2715 + } 1.2716 + 1.2717 + var networks = []; 1.2718 + for (let networkKey in this.configuredNetworks) { 1.2719 + networks.push(netToDOM(this.configuredNetworks[networkKey])); 1.2720 + } 1.2721 + 1.2722 + this._sendMessage(message, true, networks, msg); 1.2723 + }).bind(this)); 1.2724 + }, 1.2725 + 1.2726 + _setWifiEnabledCallback: function(status) { 1.2727 + if (status !== 0) { 1.2728 + this.requestDone(); 1.2729 + return; 1.2730 + } 1.2731 + 1.2732 + // If we're enabling ourselves, then wait until we've connected to the 1.2733 + // supplicant to notify. If we're disabling, we take care of this in 1.2734 + // supplicantlost. 1.2735 + if (WifiManager.supplicantStarted) 1.2736 + WifiManager.start(); 1.2737 + }, 1.2738 + 1.2739 + setWifiEnabled: function(enabled, callback) { 1.2740 + // Reply error to pending requests. 1.2741 + if (!enabled) { 1.2742 + this._clearPendingRequest(); 1.2743 + } 1.2744 + 1.2745 + WifiManager.setWifiEnabled(enabled, callback); 1.2746 + }, 1.2747 + 1.2748 + // requestDone() must be called to before callback complete(or error) 1.2749 + // so next queue in the request quene can be executed. 1.2750 + queueRequest: function(data, callback) { 1.2751 + if (!callback) { 1.2752 + throw "Try to enqueue a request without callback"; 1.2753 + } 1.2754 + 1.2755 + let optimizeCommandList = ["setWifiEnabled", "setWifiApEnabled"]; 1.2756 + if (optimizeCommandList.indexOf(data.command) != -1) { 1.2757 + this._stateRequests = this._stateRequests.filter(function(element) { 1.2758 + return element.data.command !== data.command; 1.2759 + }); 1.2760 + } 1.2761 + 1.2762 + this._stateRequests.push({ 1.2763 + data: data, 1.2764 + callback: callback 1.2765 + }); 1.2766 + 1.2767 + this.nextRequest(); 1.2768 + }, 1.2769 + 1.2770 + getWifiTetheringParameters: function getWifiTetheringParameters(enable) { 1.2771 + let ssid; 1.2772 + let securityType; 1.2773 + let securityId; 1.2774 + let interfaceIp; 1.2775 + let prefix; 1.2776 + let wifiDhcpStartIp; 1.2777 + let wifiDhcpEndIp; 1.2778 + let usbDhcpStartIp; 1.2779 + let usbDhcpEndIp; 1.2780 + let dns1; 1.2781 + let dns2; 1.2782 + 1.2783 + ssid = this.tetheringSettings[SETTINGS_WIFI_SSID]; 1.2784 + securityType = this.tetheringSettings[SETTINGS_WIFI_SECURITY_TYPE]; 1.2785 + securityId = this.tetheringSettings[SETTINGS_WIFI_SECURITY_PASSWORD]; 1.2786 + interfaceIp = this.tetheringSettings[SETTINGS_WIFI_IP]; 1.2787 + prefix = this.tetheringSettings[SETTINGS_WIFI_PREFIX]; 1.2788 + wifiDhcpStartIp = this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_STARTIP]; 1.2789 + wifiDhcpEndIp = this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_ENDIP]; 1.2790 + usbDhcpStartIp = this.tetheringSettings[SETTINGS_USB_DHCPSERVER_STARTIP]; 1.2791 + usbDhcpEndIp = this.tetheringSettings[SETTINGS_USB_DHCPSERVER_ENDIP]; 1.2792 + dns1 = this.tetheringSettings[SETTINGS_WIFI_DNS1]; 1.2793 + dns2 = this.tetheringSettings[SETTINGS_WIFI_DNS2]; 1.2794 + 1.2795 + // Check the format to prevent netd from crash. 1.2796 + if (!ssid || ssid == "") { 1.2797 + debug("Invalid SSID value."); 1.2798 + return null; 1.2799 + } 1.2800 + if (securityType != WIFI_SECURITY_TYPE_NONE && 1.2801 + securityType != WIFI_SECURITY_TYPE_WPA_PSK && 1.2802 + securityType != WIFI_SECURITY_TYPE_WPA2_PSK) { 1.2803 + 1.2804 + debug("Invalid security type."); 1.2805 + return null; 1.2806 + } 1.2807 + if (securityType != WIFI_SECURITY_TYPE_NONE && !securityId) { 1.2808 + debug("Invalid security password."); 1.2809 + return null; 1.2810 + } 1.2811 + // Using the default values here until application supports these settings. 1.2812 + if (interfaceIp == "" || prefix == "" || 1.2813 + wifiDhcpStartIp == "" || wifiDhcpEndIp == "" || 1.2814 + usbDhcpStartIp == "" || usbDhcpEndIp == "") { 1.2815 + debug("Invalid subnet information."); 1.2816 + return null; 1.2817 + } 1.2818 + 1.2819 + return { 1.2820 + ssid: ssid, 1.2821 + security: securityType, 1.2822 + key: securityId, 1.2823 + ip: interfaceIp, 1.2824 + prefix: prefix, 1.2825 + wifiStartIp: wifiDhcpStartIp, 1.2826 + wifiEndIp: wifiDhcpEndIp, 1.2827 + usbStartIp: usbDhcpStartIp, 1.2828 + usbEndIp: usbDhcpEndIp, 1.2829 + dns1: dns1, 1.2830 + dns2: dns2, 1.2831 + enable: enable, 1.2832 + mode: enable ? WIFI_FIRMWARE_AP : WIFI_FIRMWARE_STATION, 1.2833 + link: enable ? NETWORK_INTERFACE_UP : NETWORK_INTERFACE_DOWN 1.2834 + }; 1.2835 + }, 1.2836 + 1.2837 + setWifiApEnabled: function(enabled, callback) { 1.2838 + let configuration = this.getWifiTetheringParameters(enabled); 1.2839 + 1.2840 + if (!configuration) { 1.2841 + this.requestDone(); 1.2842 + debug("Invalid Wifi Tethering configuration."); 1.2843 + return; 1.2844 + } 1.2845 + 1.2846 + WifiManager.setWifiApEnabled(enabled, configuration, callback); 1.2847 + }, 1.2848 + 1.2849 + associate: function(msg) { 1.2850 + const MAX_PRIORITY = 9999; 1.2851 + const message = "WifiManager:associate:Return"; 1.2852 + let network = msg.data; 1.2853 + 1.2854 + let privnet = network; 1.2855 + let dontConnect = privnet.dontConnect; 1.2856 + delete privnet.dontConnect; 1.2857 + 1.2858 + if (!WifiManager.enabled) { 1.2859 + this._sendMessage(message, false, "Wifi is disabled", msg); 1.2860 + return; 1.2861 + } 1.2862 + 1.2863 + let self = this; 1.2864 + function networkReady() { 1.2865 + // saveConfig now before we disable most of the other networks. 1.2866 + function selectAndConnect() { 1.2867 + WifiManager.enableNetwork(privnet.netId, true, function (ok) { 1.2868 + if (ok) 1.2869 + self._needToEnableNetworks = true; 1.2870 + if (WifiManager.state === "DISCONNECTED" || 1.2871 + WifiManager.state === "SCANNING") { 1.2872 + WifiManager.reconnect(function (ok) { 1.2873 + self._sendMessage(message, ok, ok, msg); 1.2874 + }); 1.2875 + } else { 1.2876 + self._sendMessage(message, ok, ok, msg); 1.2877 + } 1.2878 + }); 1.2879 + } 1.2880 + 1.2881 + var selectAndConnectOrReturn = dontConnect ? 1.2882 + function() { 1.2883 + self._sendMessage(message, true, "Wifi has been recorded", msg); 1.2884 + } : selectAndConnect; 1.2885 + if (self._highestPriority >= MAX_PRIORITY) { 1.2886 + self._reprioritizeNetworks(selectAndConnectOrReturn); 1.2887 + } else { 1.2888 + WifiManager.saveConfig(selectAndConnectOrReturn); 1.2889 + } 1.2890 + } 1.2891 + 1.2892 + let ssid = privnet.ssid; 1.2893 + let networkKey = getNetworkKey(privnet); 1.2894 + let configured; 1.2895 + 1.2896 + if (networkKey in this._addingNetworks) { 1.2897 + this._sendMessage(message, false, "Racing associates"); 1.2898 + return; 1.2899 + } 1.2900 + 1.2901 + if (networkKey in this.configuredNetworks) 1.2902 + configured = this.configuredNetworks[networkKey]; 1.2903 + 1.2904 + netFromDOM(privnet, configured); 1.2905 + 1.2906 + privnet.priority = ++this._highestPriority; 1.2907 + if (configured) { 1.2908 + privnet.netId = configured.netId; 1.2909 + WifiManager.updateNetwork(privnet, (function(ok) { 1.2910 + if (!ok) { 1.2911 + this._sendMessage(message, false, "Network is misconfigured", msg); 1.2912 + return; 1.2913 + } 1.2914 + 1.2915 + networkReady(); 1.2916 + }).bind(this)); 1.2917 + } else { 1.2918 + // networkReady, above, calls saveConfig. We want to remember the new 1.2919 + // network as being enabled, which isn't the default, so we explicitly 1.2920 + // set it to being "enabled" before we add it and save the 1.2921 + // configuration. 1.2922 + privnet.disabled = 0; 1.2923 + this._addingNetworks[networkKey] = privnet; 1.2924 + WifiManager.addNetwork(privnet, (function(ok) { 1.2925 + delete this._addingNetworks[networkKey]; 1.2926 + 1.2927 + if (!ok) { 1.2928 + this._sendMessage(message, false, "Network is misconfigured", msg); 1.2929 + return; 1.2930 + } 1.2931 + 1.2932 + this.configuredNetworks[networkKey] = privnet; 1.2933 + networkReady(); 1.2934 + }).bind(this)); 1.2935 + } 1.2936 + }, 1.2937 + 1.2938 + forget: function(msg) { 1.2939 + const message = "WifiManager:forget:Return"; 1.2940 + let network = msg.data; 1.2941 + if (!WifiManager.enabled) { 1.2942 + this._sendMessage(message, false, "Wifi is disabled", msg); 1.2943 + return; 1.2944 + } 1.2945 + 1.2946 + this._reloadConfiguredNetworks((function(ok) { 1.2947 + // Give it a chance to remove the network even if reload is failed. 1.2948 + if (!ok) { 1.2949 + debug("Warning !!! Failed to reload the configured networks"); 1.2950 + } 1.2951 + 1.2952 + let ssid = network.ssid; 1.2953 + let networkKey = getNetworkKey(network); 1.2954 + if (!(networkKey in this.configuredNetworks)) { 1.2955 + this._sendMessage(message, false, "Trying to forget an unknown network", msg); 1.2956 + return; 1.2957 + } 1.2958 + 1.2959 + let self = this; 1.2960 + let configured = this.configuredNetworks[networkKey]; 1.2961 + this._reconnectOnDisconnect = (this.currentNetwork && 1.2962 + (this.currentNetwork.ssid === ssid)); 1.2963 + WifiManager.removeNetwork(configured.netId, function(ok) { 1.2964 + if (!ok) { 1.2965 + self._sendMessage(message, false, "Unable to remove the network", msg); 1.2966 + self._reconnectOnDisconnect = false; 1.2967 + return; 1.2968 + } 1.2969 + 1.2970 + WifiManager.saveConfig(function() { 1.2971 + self._reloadConfiguredNetworks(function() { 1.2972 + self._sendMessage(message, true, true, msg); 1.2973 + }); 1.2974 + }); 1.2975 + }); 1.2976 + }).bind(this)); 1.2977 + }, 1.2978 + 1.2979 + wps: function(msg) { 1.2980 + const message = "WifiManager:wps:Return"; 1.2981 + let self = this; 1.2982 + let detail = msg.data; 1.2983 + if (detail.method === "pbc") { 1.2984 + WifiManager.wpsPbc(WifiManager.ifname, function(ok) { 1.2985 + if (ok) 1.2986 + self._sendMessage(message, true, true, msg); 1.2987 + else 1.2988 + self._sendMessage(message, false, "WPS PBC failed", msg); 1.2989 + }); 1.2990 + } else if (detail.method === "pin") { 1.2991 + WifiManager.wpsPin(detail, function(pin) { 1.2992 + if (pin) 1.2993 + self._sendMessage(message, true, pin, msg); 1.2994 + else 1.2995 + self._sendMessage(message, false, "WPS PIN failed", msg); 1.2996 + }); 1.2997 + } else if (detail.method === "cancel") { 1.2998 + WifiManager.wpsCancel(function(ok) { 1.2999 + if (ok) 1.3000 + self._sendMessage(message, true, true, msg); 1.3001 + else 1.3002 + self._sendMessage(message, false, "WPS Cancel failed", msg); 1.3003 + }); 1.3004 + } else { 1.3005 + self._sendMessage(message, false, "Invalid WPS method=" + detail.method, 1.3006 + msg); 1.3007 + } 1.3008 + }, 1.3009 + 1.3010 + setPowerSavingMode: function(msg) { 1.3011 + const message = "WifiManager:setPowerSavingMode:Return"; 1.3012 + let self = this; 1.3013 + let enabled = msg.data; 1.3014 + let mode = enabled ? "AUTO" : "ACTIVE"; 1.3015 + 1.3016 + // Some wifi drivers may not implement this command. Set power mode 1.3017 + // even if suspend optimization command failed. 1.3018 + WifiManager.setSuspendOptimizations(enabled, function(ok) { 1.3019 + WifiManager.setPowerMode(mode, function(ok) { 1.3020 + if (ok) { 1.3021 + self._sendMessage(message, true, true, msg); 1.3022 + } else { 1.3023 + self._sendMessage(message, false, "Set power saving mode failed", msg); 1.3024 + } 1.3025 + }); 1.3026 + }); 1.3027 + }, 1.3028 + 1.3029 + setHttpProxy: function(msg) { 1.3030 + const message = "WifiManager:setHttpProxy:Return"; 1.3031 + let self = this; 1.3032 + let network = msg.data.network; 1.3033 + let info = msg.data.info; 1.3034 + 1.3035 + WifiManager.configureHttpProxy(network, info, function(ok) { 1.3036 + if (ok) { 1.3037 + // If configured network is current connected network 1.3038 + // need update http proxy immediately. 1.3039 + let setNetworkKey = getNetworkKey(network); 1.3040 + let curNetworkKey = self.currentNetwork ? getNetworkKey(self.currentNetwork) : null; 1.3041 + if (setNetworkKey === curNetworkKey) 1.3042 + WifiManager.setHttpProxy(network); 1.3043 + 1.3044 + self._sendMessage(message, true, true, msg); 1.3045 + } else { 1.3046 + self._sendMessage(message, false, "Set http proxy failed", msg); 1.3047 + } 1.3048 + }); 1.3049 + }, 1.3050 + 1.3051 + setStaticIpMode: function(msg) { 1.3052 + const message = "WifiManager:setStaticMode:Return"; 1.3053 + let self = this; 1.3054 + let network = msg.data.network; 1.3055 + let info = msg.data.info; 1.3056 + 1.3057 + // To compatiable with DHCP returned info structure, do translation here 1.3058 + info.ipaddr_str = info.ipaddr; 1.3059 + info.proxy_str = info.proxy; 1.3060 + info.gateway_str = info.gateway; 1.3061 + info.dns1_str = info.dns1; 1.3062 + info.dns2_str = info.dns2; 1.3063 + 1.3064 + WifiManager.setStaticIpMode(network, info, function(ok) { 1.3065 + if (ok) { 1.3066 + self._sendMessage(message, true, true, msg); 1.3067 + } else { 1.3068 + self._sendMessage(message, false, "Set static ip mode failed", msg); 1.3069 + } 1.3070 + }); 1.3071 + }, 1.3072 + 1.3073 + // This is a bit ugly, but works. In particular, this depends on the fact 1.3074 + // that RadioManager never actually tries to get the worker from us. 1.3075 + get worker() { throw "Not implemented"; }, 1.3076 + 1.3077 + shutdown: function() { 1.3078 + debug("shutting down ..."); 1.3079 + this.queueRequest({command: "setWifiEnabled", value: false}, function(data) { 1.3080 + this.setWifiEnabled(false, this._setWifiEnabledCallback.bind(this)); 1.3081 + }.bind(this)); 1.3082 + }, 1.3083 + 1.3084 + requestProcessing: false, // Hold while dequeue and execution a request. 1.3085 + // Released upon the request is fully executed, 1.3086 + // i.e, mostly after callback is done. 1.3087 + requestDone: function requestDone() { 1.3088 + this.requestProcessing = false; 1.3089 + this.nextRequest(); 1.3090 + }, 1.3091 + 1.3092 + nextRequest: function nextRequest() { 1.3093 + // No request to process 1.3094 + if (this._stateRequests.length === 0) { 1.3095 + return; 1.3096 + } 1.3097 + 1.3098 + // Handling request, wait for it. 1.3099 + if (this.requestProcessing) { 1.3100 + return; 1.3101 + } 1.3102 + 1.3103 + // Hold processing lock 1.3104 + this.requestProcessing = true; 1.3105 + 1.3106 + // Find next valid request 1.3107 + let request = this._stateRequests.shift(); 1.3108 + 1.3109 + request.callback(request.data); 1.3110 + }, 1.3111 + 1.3112 + notifyTetheringOn: function notifyTetheringOn() { 1.3113 + // It's really sad that we don't have an API to notify the wifi 1.3114 + // hotspot status. Toggle settings to let gaia know that wifi hotspot 1.3115 + // is enabled. 1.3116 + let self = this; 1.3117 + this.tetheringSettings[SETTINGS_WIFI_TETHERING_ENABLED] = true; 1.3118 + this._oldWifiTetheringEnabledState = true; 1.3119 + gSettingsService.createLock().set( 1.3120 + SETTINGS_WIFI_TETHERING_ENABLED, 1.3121 + true, 1.3122 + { 1.3123 + handle: function(aName, aResult) { 1.3124 + self.requestDone(); 1.3125 + }, 1.3126 + handleError: function(aErrorMessage) { 1.3127 + self.requestDone(); 1.3128 + } 1.3129 + }, 1.3130 + "fromInternalSetting"); 1.3131 + }, 1.3132 + 1.3133 + notifyTetheringOff: function notifyTetheringOff() { 1.3134 + // It's really sad that we don't have an API to notify the wifi 1.3135 + // hotspot status. Toggle settings to let gaia know that wifi hotspot 1.3136 + // is disabled. 1.3137 + let self = this; 1.3138 + this.tetheringSettings[SETTINGS_WIFI_TETHERING_ENABLED] = false; 1.3139 + this._oldWifiTetheringEnabledState = false; 1.3140 + gSettingsService.createLock().set( 1.3141 + SETTINGS_WIFI_TETHERING_ENABLED, 1.3142 + false, 1.3143 + { 1.3144 + handle: function(aName, aResult) { 1.3145 + self.requestDone(); 1.3146 + }, 1.3147 + handleError: function(aErrorMessage) { 1.3148 + self.requestDone(); 1.3149 + } 1.3150 + }, 1.3151 + "fromInternalSetting"); 1.3152 + }, 1.3153 + 1.3154 + handleWifiEnabled: function(enabled) { 1.3155 + // Make sure Wifi hotspot is idle before switching to Wifi mode. 1.3156 + if (enabled) { 1.3157 + this.queueRequest({command: "setWifiApEnabled", value: false}, function(data) { 1.3158 + if (this.tetheringSettings[SETTINGS_WIFI_TETHERING_ENABLED] || 1.3159 + WifiManager.isWifiTetheringEnabled(WifiManager.tetheringState)) { 1.3160 + this.disconnectedByWifi = true; 1.3161 + this.setWifiApEnabled(false, this.notifyTetheringOff.bind(this)); 1.3162 + } else { 1.3163 + this.requestDone(); 1.3164 + } 1.3165 + }.bind(this)); 1.3166 + } 1.3167 + 1.3168 + this.queueRequest({command: "setWifiEnabled", value: enabled}, function(data) { 1.3169 + this.setWifiEnabled(enabled, this._setWifiEnabledCallback.bind(this)); 1.3170 + }.bind(this)); 1.3171 + 1.3172 + if (!enabled) { 1.3173 + this.queueRequest({command: "setWifiApEnabled", value: true}, function(data) { 1.3174 + if (this.disconnectedByWifi) { 1.3175 + this.setWifiApEnabled(true, this.notifyTetheringOn.bind(this)); 1.3176 + } else { 1.3177 + this.requestDone(); 1.3178 + } 1.3179 + this.disconnectedByWifi = false; 1.3180 + }.bind(this)); 1.3181 + } 1.3182 + }, 1.3183 + 1.3184 + handleWifiTetheringEnabled: function(enabled) { 1.3185 + // Make sure Wifi is idle before switching to Wifi hotspot mode. 1.3186 + if (enabled) { 1.3187 + this.queueRequest({command: "setWifiEnabled", value: false}, function(data) { 1.3188 + if (WifiManager.isWifiEnabled(WifiManager.state)) { 1.3189 + this.disconnectedByWifiTethering = true; 1.3190 + this.setWifiEnabled(false, this._setWifiEnabledCallback.bind(this)); 1.3191 + } else { 1.3192 + this.requestDone(); 1.3193 + } 1.3194 + }.bind(this)); 1.3195 + } 1.3196 + 1.3197 + this.queueRequest({command: "setWifiApEnabled", value: enabled}, function(data) { 1.3198 + this.setWifiApEnabled(enabled, this.requestDone.bind(this)); 1.3199 + }.bind(this)); 1.3200 + 1.3201 + if (!enabled) { 1.3202 + this.queueRequest({command: "setWifiEnabled", value: true}, function(data) { 1.3203 + if (this.disconnectedByWifiTethering) { 1.3204 + this.setWifiEnabled(true, this._setWifiEnabledCallback.bind(this)); 1.3205 + } else { 1.3206 + this.requestDone(); 1.3207 + } 1.3208 + this.disconnectedByWifiTethering = false; 1.3209 + }.bind(this)); 1.3210 + } 1.3211 + }, 1.3212 + 1.3213 + // nsIObserver implementation 1.3214 + observe: function observe(subject, topic, data) { 1.3215 + // Note that this function gets called for any and all settings changes, 1.3216 + // so we need to carefully check if we have the one we're interested in. 1.3217 + // The string we're interested in will be a JSON string that looks like: 1.3218 + // {"key":"wifi.enabled","value":"true"}. 1.3219 + if (topic !== kMozSettingsChangedObserverTopic) { 1.3220 + return; 1.3221 + } 1.3222 + 1.3223 + let setting = JSON.parse(data); 1.3224 + // To avoid WifiWorker setting the wifi again, don't need to deal with 1.3225 + // the "mozsettings-changed" event fired from internal setting. 1.3226 + if (setting.message && setting.message === "fromInternalSetting") { 1.3227 + return; 1.3228 + } 1.3229 + 1.3230 + this.handle(setting.key, setting.value); 1.3231 + }, 1.3232 + 1.3233 + handle: function handle(aName, aResult) { 1.3234 + switch(aName) { 1.3235 + case SETTINGS_WIFI_ENABLED: 1.3236 + this.handleWifiEnabled(aResult) 1.3237 + break; 1.3238 + case SETTINGS_WIFI_DEBUG_ENABLED: 1.3239 + if (aResult === null) 1.3240 + aResult = false; 1.3241 + DEBUG = aResult; 1.3242 + updateDebug(); 1.3243 + break; 1.3244 + case SETTINGS_WIFI_TETHERING_ENABLED: 1.3245 + this._oldWifiTetheringEnabledState = this.tetheringSettings[SETTINGS_WIFI_TETHERING_ENABLED]; 1.3246 + // Fall through! 1.3247 + case SETTINGS_WIFI_SSID: 1.3248 + case SETTINGS_WIFI_SECURITY_TYPE: 1.3249 + case SETTINGS_WIFI_SECURITY_PASSWORD: 1.3250 + case SETTINGS_WIFI_IP: 1.3251 + case SETTINGS_WIFI_PREFIX: 1.3252 + case SETTINGS_WIFI_DHCPSERVER_STARTIP: 1.3253 + case SETTINGS_WIFI_DHCPSERVER_ENDIP: 1.3254 + case SETTINGS_WIFI_DNS1: 1.3255 + case SETTINGS_WIFI_DNS2: 1.3256 + case SETTINGS_USB_DHCPSERVER_STARTIP: 1.3257 + case SETTINGS_USB_DHCPSERVER_ENDIP: 1.3258 + if (aResult !== null) { 1.3259 + this.tetheringSettings[aName] = aResult; 1.3260 + } 1.3261 + debug("'" + aName + "'" + " is now " + this.tetheringSettings[aName]); 1.3262 + let index = this._wifiTetheringSettingsToRead.indexOf(aName); 1.3263 + 1.3264 + if (index != -1) { 1.3265 + this._wifiTetheringSettingsToRead.splice(index, 1); 1.3266 + } 1.3267 + 1.3268 + if (this._wifiTetheringSettingsToRead.length) { 1.3269 + debug("We haven't read completely the wifi Tethering data from settings db."); 1.3270 + break; 1.3271 + } 1.3272 + 1.3273 + if (this._oldWifiTetheringEnabledState === this.tetheringSettings[SETTINGS_WIFI_TETHERING_ENABLED]) { 1.3274 + debug("No changes for SETTINGS_WIFI_TETHERING_ENABLED flag. Nothing to do."); 1.3275 + break; 1.3276 + } 1.3277 + 1.3278 + if (this._oldWifiTetheringEnabledState === null && 1.3279 + !this.tetheringSettings[SETTINGS_WIFI_TETHERING_ENABLED]) { 1.3280 + debug("Do nothing when initial settings for SETTINGS_WIFI_TETHERING_ENABLED flag is false."); 1.3281 + break; 1.3282 + } 1.3283 + 1.3284 + this._oldWifiTetheringEnabledState = this.tetheringSettings[SETTINGS_WIFI_TETHERING_ENABLED]; 1.3285 + this.handleWifiTetheringEnabled(aResult) 1.3286 + break; 1.3287 + }; 1.3288 + }, 1.3289 + 1.3290 + handleError: function handleError(aErrorMessage) { 1.3291 + debug("There was an error while reading Tethering settings."); 1.3292 + this.tetheringSettings = {}; 1.3293 + this.tetheringSettings[SETTINGS_WIFI_TETHERING_ENABLED] = false; 1.3294 + }, 1.3295 +}; 1.3296 + 1.3297 +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WifiWorker]); 1.3298 + 1.3299 +let debug; 1.3300 +function updateDebug() { 1.3301 + if (DEBUG) { 1.3302 + debug = function (s) { 1.3303 + dump("-*- WifiWorker component: " + s + "\n"); 1.3304 + }; 1.3305 + } else { 1.3306 + debug = function (s) {}; 1.3307 + } 1.3308 + WifiManager.syncDebug(); 1.3309 +} 1.3310 +updateDebug();