dom/wifi/WifiCommand.jsm

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

michael@0 1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 "use strict";
michael@0 8
michael@0 9 this.EXPORTED_SYMBOLS = ["WifiCommand"];
michael@0 10
michael@0 11 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
michael@0 12
michael@0 13 Cu.import("resource://gre/modules/systemlibs.js");
michael@0 14
michael@0 15 const SUPP_PROP = "init.svc.wpa_supplicant";
michael@0 16 const WPA_SUPPLICANT = "wpa_supplicant";
michael@0 17 const DEBUG = false;
michael@0 18
michael@0 19 this.WifiCommand = function(aControlMessage, aInterface) {
michael@0 20 function debug(msg) {
michael@0 21 if (DEBUG) {
michael@0 22 dump('-------------- WifiCommand: ' + msg);
michael@0 23 }
michael@0 24 }
michael@0 25
michael@0 26 var command = {};
michael@0 27
michael@0 28 //-------------------------------------------------
michael@0 29 // General commands.
michael@0 30 //-------------------------------------------------
michael@0 31
michael@0 32 command.loadDriver = function (callback) {
michael@0 33 voidControlMessage("load_driver", function(status) {
michael@0 34 callback(status);
michael@0 35 });
michael@0 36 };
michael@0 37
michael@0 38 command.unloadDriver = function (callback) {
michael@0 39 voidControlMessage("unload_driver", function(status) {
michael@0 40 callback(status);
michael@0 41 });
michael@0 42 };
michael@0 43
michael@0 44 command.startSupplicant = function (callback) {
michael@0 45 voidControlMessage("start_supplicant", callback);
michael@0 46 };
michael@0 47
michael@0 48 command.killSupplicant = function (callback) {
michael@0 49 // It is interesting to note that this function does exactly what
michael@0 50 // wifi_stop_supplicant does. Unforunately, on the Galaxy S2, Samsung
michael@0 51 // changed that function in a way that means that it doesn't recognize
michael@0 52 // wpa_supplicant as already running. Therefore, we have to roll our own
michael@0 53 // version here.
michael@0 54 stopProcess(SUPP_PROP, WPA_SUPPLICANT, callback);
michael@0 55 };
michael@0 56
michael@0 57 command.terminateSupplicant = function (callback) {
michael@0 58 doBooleanCommand("TERMINATE", "OK", callback);
michael@0 59 };
michael@0 60
michael@0 61 command.stopSupplicant = function (callback) {
michael@0 62 voidControlMessage("stop_supplicant", callback);
michael@0 63 };
michael@0 64
michael@0 65 command.listNetworks = function (callback) {
michael@0 66 doStringCommand("LIST_NETWORKS", callback);
michael@0 67 };
michael@0 68
michael@0 69 command.addNetwork = function (callback) {
michael@0 70 doIntCommand("ADD_NETWORK", callback);
michael@0 71 };
michael@0 72
michael@0 73 command.setNetworkVariable = function (netId, name, value, callback) {
michael@0 74 doBooleanCommand("SET_NETWORK " + netId + " " + name + " " +
michael@0 75 value, "OK", callback);
michael@0 76 };
michael@0 77
michael@0 78 command.getNetworkVariable = function (netId, name, callback) {
michael@0 79 doStringCommand("GET_NETWORK " + netId + " " + name, callback);
michael@0 80 };
michael@0 81
michael@0 82 command.removeNetwork = function (netId, callback) {
michael@0 83 doBooleanCommand("REMOVE_NETWORK " + netId, "OK", callback);
michael@0 84 };
michael@0 85
michael@0 86 command.enableNetwork = function (netId, disableOthers, callback) {
michael@0 87 doBooleanCommand((disableOthers ? "SELECT_NETWORK " : "ENABLE_NETWORK ") +
michael@0 88 netId, "OK", callback);
michael@0 89 };
michael@0 90
michael@0 91 command.disableNetwork = function (netId, callback) {
michael@0 92 doBooleanCommand("DISABLE_NETWORK " + netId, "OK", callback);
michael@0 93 };
michael@0 94
michael@0 95 command.status = function (callback) {
michael@0 96 doStringCommand("STATUS", callback);
michael@0 97 };
michael@0 98
michael@0 99 command.ping = function (callback) {
michael@0 100 doBooleanCommand("PING", "PONG", callback);
michael@0 101 };
michael@0 102
michael@0 103 command.scanResults = function (callback) {
michael@0 104 doStringCommand("SCAN_RESULTS", callback);
michael@0 105 };
michael@0 106
michael@0 107 command.disconnect = function (callback) {
michael@0 108 doBooleanCommand("DISCONNECT", "OK", callback);
michael@0 109 };
michael@0 110
michael@0 111 command.reconnect = function (callback) {
michael@0 112 doBooleanCommand("RECONNECT", "OK", callback);
michael@0 113 };
michael@0 114
michael@0 115 command.reassociate = function (callback) {
michael@0 116 doBooleanCommand("REASSOCIATE", "OK", callback);
michael@0 117 };
michael@0 118
michael@0 119 command.setBackgroundScan = function (enable, callback) {
michael@0 120 doBooleanCommand("SET pno " + (enable ? "1" : "0"),
michael@0 121 "OK",
michael@0 122 function(ok) {
michael@0 123 callback(true, ok);
michael@0 124 });
michael@0 125 };
michael@0 126
michael@0 127 command.doSetScanMode = function (setActive, callback) {
michael@0 128 doBooleanCommand(setActive ?
michael@0 129 "DRIVER SCAN-ACTIVE" :
michael@0 130 "DRIVER SCAN-PASSIVE", "OK", callback);
michael@0 131 };
michael@0 132
michael@0 133 command.scan = function (callback) {
michael@0 134 doBooleanCommand("SCAN", "OK", callback);
michael@0 135 };
michael@0 136
michael@0 137 command.setLogLevel = function (level, callback) {
michael@0 138 doBooleanCommand("LOG_LEVEL " + level, "OK", callback);
michael@0 139 };
michael@0 140
michael@0 141 command.getLogLevel = function (callback) {
michael@0 142 doStringCommand("LOG_LEVEL", callback);
michael@0 143 };
michael@0 144
michael@0 145 command.wpsPbc = function (iface, callback) {
michael@0 146 doBooleanCommand("WPS_PBC" + (iface ? (" interface=" + iface) : ""),
michael@0 147 "OK", callback);
michael@0 148 };
michael@0 149
michael@0 150 command.wpsPin = function (detail, callback) {
michael@0 151 doStringCommand("WPS_PIN " +
michael@0 152 (detail.bssid === undefined ? "any" : detail.bssid) +
michael@0 153 (detail.pin === undefined ? "" : (" " + detail.pin)) +
michael@0 154 (detail.iface ? (" interface=" + detail.iface) : ""),
michael@0 155 callback);
michael@0 156 };
michael@0 157
michael@0 158 command.wpsCancel = function (callback) {
michael@0 159 doBooleanCommand("WPS_CANCEL", "OK", callback);
michael@0 160 };
michael@0 161
michael@0 162 command.startDriver = function (callback) {
michael@0 163 doBooleanCommand("DRIVER START", "OK");
michael@0 164 };
michael@0 165
michael@0 166 command.stopDriver = function (callback) {
michael@0 167 doBooleanCommand("DRIVER STOP", "OK");
michael@0 168 };
michael@0 169
michael@0 170 command.startPacketFiltering = function (callback) {
michael@0 171 var commandChain = ["DRIVER RXFILTER-ADD 0",
michael@0 172 "DRIVER RXFILTER-ADD 1",
michael@0 173 "DRIVER RXFILTER-ADD 3",
michael@0 174 "DRIVER RXFILTER-START"];
michael@0 175
michael@0 176 doBooleanCommandChain(commandChain, callback);
michael@0 177 };
michael@0 178
michael@0 179 command.stopPacketFiltering = function (callback) {
michael@0 180 var commandChain = ["DRIVER RXFILTER-STOP",
michael@0 181 "DRIVER RXFILTER-REMOVE 3",
michael@0 182 "DRIVER RXFILTER-REMOVE 1",
michael@0 183 "DRIVER RXFILTER-REMOVE 0"];
michael@0 184
michael@0 185 doBooleanCommandChain(commandChain, callback);
michael@0 186 };
michael@0 187
michael@0 188 command.doGetRssi = function (cmd, callback) {
michael@0 189 doCommand(cmd, function(data) {
michael@0 190 var rssi = -200;
michael@0 191
michael@0 192 if (!data.status) {
michael@0 193 // If we are associating, the reply is "OK".
michael@0 194 var reply = data.reply;
michael@0 195 if (reply !== "OK") {
michael@0 196 // Format is: <SSID> rssi XX". SSID can contain spaces.
michael@0 197 var offset = reply.lastIndexOf("rssi ");
michael@0 198 if (offset !== -1) {
michael@0 199 rssi = reply.substr(offset + 5) | 0;
michael@0 200 }
michael@0 201 }
michael@0 202 }
michael@0 203 callback(rssi);
michael@0 204 });
michael@0 205 };
michael@0 206
michael@0 207 command.getRssi = function (callback) {
michael@0 208 command.doGetRssi("DRIVER RSSI", callback);
michael@0 209 };
michael@0 210
michael@0 211 command.getRssiApprox = function (callback) {
michael@0 212 command.doGetRssi("DRIVER RSSI-APPROX", callback);
michael@0 213 };
michael@0 214
michael@0 215 command.getLinkSpeed = function (callback) {
michael@0 216 doStringCommand("DRIVER LINKSPEED", function(reply) {
michael@0 217 if (reply) {
michael@0 218 reply = reply.split(" ")[1] | 0; // Format: LinkSpeed XX
michael@0 219 }
michael@0 220 callback(reply);
michael@0 221 });
michael@0 222 };
michael@0 223
michael@0 224 command.getConnectionInfoICS = function (callback) {
michael@0 225 doStringCommand("SIGNAL_POLL", function(reply) {
michael@0 226 if (!reply) {
michael@0 227 callback(null);
michael@0 228 return;
michael@0 229 }
michael@0 230
michael@0 231 let rval = {};
michael@0 232 var lines = reply.split("\n");
michael@0 233 for (let i = 0; i < lines.length; ++i) {
michael@0 234 let [key, value] = lines[i].split("=");
michael@0 235 switch (key.toUpperCase()) {
michael@0 236 case "RSSI":
michael@0 237 rval.rssi = value | 0;
michael@0 238 break;
michael@0 239 case "LINKSPEED":
michael@0 240 rval.linkspeed = value | 0;
michael@0 241 break;
michael@0 242 default:
michael@0 243 // Ignore.
michael@0 244 }
michael@0 245 }
michael@0 246
michael@0 247 callback(rval);
michael@0 248 });
michael@0 249 };
michael@0 250
michael@0 251 command.getMacAddress = function (callback) {
michael@0 252 doStringCommand("DRIVER MACADDR", function(reply) {
michael@0 253 if (reply) {
michael@0 254 reply = reply.split(" ")[2]; // Format: Macaddr = XX.XX.XX.XX.XX.XX
michael@0 255 }
michael@0 256 callback(reply);
michael@0 257 });
michael@0 258 };
michael@0 259
michael@0 260 command.setPowerModeICS = function (mode, callback) {
michael@0 261 doBooleanCommand("DRIVER POWERMODE " + (mode === "AUTO" ? 0 : 1), "OK", callback);
michael@0 262 };
michael@0 263
michael@0 264 command.setPowerModeJB = function (mode, callback) {
michael@0 265 doBooleanCommand("SET ps " + (mode === "AUTO" ? 1 : 0), "OK", callback);
michael@0 266 };
michael@0 267
michael@0 268 command.getPowerMode = function (callback) {
michael@0 269 doStringCommand("DRIVER GETPOWER", function(reply) {
michael@0 270 if (reply) {
michael@0 271 reply = (reply.split()[2]|0); // Format: powermode = XX
michael@0 272 }
michael@0 273 callback(reply);
michael@0 274 });
michael@0 275 };
michael@0 276
michael@0 277 command.setNumAllowedChannels = function (numChannels, callback) {
michael@0 278 doBooleanCommand("DRIVER SCAN-CHANNELS " + numChannels, "OK", callback);
michael@0 279 };
michael@0 280
michael@0 281 command.getNumAllowedChannels = function (callback) {
michael@0 282 doStringCommand("DRIVER SCAN-CHANNELS", function(reply) {
michael@0 283 if (reply) {
michael@0 284 reply = (reply.split()[2]|0); // Format: Scan-Channels = X
michael@0 285 }
michael@0 286 callback(reply);
michael@0 287 });
michael@0 288 };
michael@0 289
michael@0 290 command.setBluetoothCoexistenceMode = function (mode, callback) {
michael@0 291 doBooleanCommand("DRIVER BTCOEXMODE " + mode, "OK", callback);
michael@0 292 };
michael@0 293
michael@0 294 command.setBluetoothCoexistenceScanMode = function (mode, callback) {
michael@0 295 doBooleanCommand("DRIVER BTCOEXSCAN-" + (mode ? "START" : "STOP"),
michael@0 296 "OK", callback);
michael@0 297 };
michael@0 298
michael@0 299 command.saveConfig = function (callback) {
michael@0 300 // Make sure we never write out a value for AP_SCAN other than 1.
michael@0 301 doBooleanCommand("AP_SCAN 1", "OK", function(ok) {
michael@0 302 doBooleanCommand("SAVE_CONFIG", "OK", callback);
michael@0 303 });
michael@0 304 };
michael@0 305
michael@0 306 command.reloadConfig = function (callback) {
michael@0 307 doBooleanCommand("RECONFIGURE", "OK", callback);
michael@0 308 };
michael@0 309
michael@0 310 command.setScanResultHandling = function (mode, callback) {
michael@0 311 doBooleanCommand("AP_SCAN " + mode, "OK", callback);
michael@0 312 };
michael@0 313
michael@0 314 command.addToBlacklist = function (bssid, callback) {
michael@0 315 doBooleanCommand("BLACKLIST " + bssid, "OK", callback);
michael@0 316 };
michael@0 317
michael@0 318 command.clearBlacklist = function (callback) {
michael@0 319 doBooleanCommand("BLACKLIST clear", "OK", callback);
michael@0 320 };
michael@0 321
michael@0 322 command.setSuspendOptimizationsICS = function (enabled, callback) {
michael@0 323 doBooleanCommand("DRIVER SETSUSPENDOPT " + (enabled ? 0 : 1),
michael@0 324 "OK", callback);
michael@0 325 };
michael@0 326
michael@0 327 command.setSuspendOptimizationsJB = function (enabled, callback) {
michael@0 328 doBooleanCommand("DRIVER SETSUSPENDMODE " + (enabled ? 1 : 0),
michael@0 329 "OK", callback);
michael@0 330 };
michael@0 331
michael@0 332 command.connectToSupplicant = function(callback) {
michael@0 333 voidControlMessage("connect_to_supplicant", callback);
michael@0 334 };
michael@0 335
michael@0 336 command.closeSupplicantConnection = function(callback) {
michael@0 337 voidControlMessage("close_supplicant_connection", callback);
michael@0 338 };
michael@0 339
michael@0 340 command.getMacAddress = function(callback) {
michael@0 341 doStringCommand("DRIVER MACADDR", function(reply) {
michael@0 342 if (reply) {
michael@0 343 reply = reply.split(" ")[2]; // Format: Macaddr = XX.XX.XX.XX.XX.XX
michael@0 344 }
michael@0 345 callback(reply);
michael@0 346 });
michael@0 347 };
michael@0 348
michael@0 349 command.setDeviceName = function(deviceName, callback) {
michael@0 350 doBooleanCommand("SET device_name " + deviceName, "OK", callback);
michael@0 351 };
michael@0 352
michael@0 353 //-------------------------------------------------
michael@0 354 // P2P commands.
michael@0 355 //-------------------------------------------------
michael@0 356
michael@0 357 command.p2pProvDiscovery = function(address, wpsMethod, callback) {
michael@0 358 var command = "P2P_PROV_DISC " + address + " " + wpsMethod;
michael@0 359 doBooleanCommand(command, "OK", callback);
michael@0 360 };
michael@0 361
michael@0 362 command.p2pConnect = function(config, callback) {
michael@0 363 var command = "P2P_CONNECT " + config.address + " " + config.wpsMethodWithPin + " ";
michael@0 364 if (config.joinExistingGroup) {
michael@0 365 command += "join";
michael@0 366 } else {
michael@0 367 command += "go_intent=" + config.goIntent;
michael@0 368 }
michael@0 369
michael@0 370 debug('P2P connect command: ' + command);
michael@0 371 doBooleanCommand(command, "OK", callback);
michael@0 372 };
michael@0 373
michael@0 374 command.p2pGroupRemove = function(iface, callback) {
michael@0 375 debug("groupRemove()");
michael@0 376 doBooleanCommand("P2P_GROUP_REMOVE " + iface, "OK", callback);
michael@0 377 };
michael@0 378
michael@0 379 command.p2pEnable = function(detail, callback) {
michael@0 380 var commandChain = ["SET device_name " + detail.deviceName,
michael@0 381 "SET device_type " + detail.deviceType,
michael@0 382 "SET config_methods " + detail.wpsMethods,
michael@0 383 "P2P_SET conc_pref sta",
michael@0 384 "P2P_FLUSH"];
michael@0 385
michael@0 386 doBooleanCommandChain(commandChain, callback);
michael@0 387 };
michael@0 388
michael@0 389 command.p2pDisable = function(callback) {
michael@0 390 doBooleanCommand("P2P_SET disabled 1", "OK", callback);
michael@0 391 };
michael@0 392
michael@0 393 command.p2pEnableScan = function(timeout, callback) {
michael@0 394 doBooleanCommand("P2P_FIND " + timeout, "OK", callback);
michael@0 395 };
michael@0 396
michael@0 397 command.p2pDisableScan = function(callback) {
michael@0 398 doBooleanCommand("P2P_STOP_FIND", "OK", callback);
michael@0 399 };
michael@0 400
michael@0 401 command.p2pGetGroupCapab = function(address, callback) {
michael@0 402 command.p2pPeer(address, function(reply) {
michael@0 403 debug('p2p_peer reply: ' + reply);
michael@0 404 if (!reply) {
michael@0 405 callback(0);
michael@0 406 return;
michael@0 407 }
michael@0 408 var capab = /group_capab=0x([0-9a-fA-F]+)/.exec(reply)[1];
michael@0 409 if (!capab) {
michael@0 410 callback(0);
michael@0 411 } else {
michael@0 412 callback(parseInt(capab, 16));
michael@0 413 }
michael@0 414 });
michael@0 415 };
michael@0 416
michael@0 417 command.p2pPeer = function(address, callback) {
michael@0 418 doStringCommand("P2P_PEER " + address, callback);
michael@0 419 };
michael@0 420
michael@0 421 command.p2pGroupAdd = function(netId, callback) {
michael@0 422 doBooleanCommand("P2P_GROUP_ADD persistent=" + netId, callback);
michael@0 423 };
michael@0 424
michael@0 425 command.p2pReinvoke = function(netId, address, callback) {
michael@0 426 doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + address, "OK", callback);
michael@0 427 };
michael@0 428
michael@0 429 //----------------------------------------------------------
michael@0 430 // Private stuff.
michael@0 431 //----------------------------------------------------------
michael@0 432
michael@0 433 function voidControlMessage(cmd, callback) {
michael@0 434 aControlMessage({ cmd: cmd, iface: aInterface }, function (data) {
michael@0 435 callback(data.status);
michael@0 436 });
michael@0 437 }
michael@0 438
michael@0 439 function doCommand(request, callback) {
michael@0 440 var msg = { cmd: "command",
michael@0 441 request: request,
michael@0 442 iface: aInterface };
michael@0 443
michael@0 444 aControlMessage(msg, callback);
michael@0 445 }
michael@0 446
michael@0 447 function doIntCommand(request, callback) {
michael@0 448 doCommand(request, function(data) {
michael@0 449 callback(data.status ? -1 : (data.reply|0));
michael@0 450 });
michael@0 451 }
michael@0 452
michael@0 453 function doBooleanCommand(request, expected, callback) {
michael@0 454 doCommand(request, function(data) {
michael@0 455 callback(data.status ? false : (data.reply === expected));
michael@0 456 });
michael@0 457 }
michael@0 458
michael@0 459 function doStringCommand(request, callback) {
michael@0 460 doCommand(request, function(data) {
michael@0 461 callback(data.status ? null : data.reply);
michael@0 462 });
michael@0 463 }
michael@0 464
michael@0 465 function doBooleanCommandChain(commandChain, callback, i) {
michael@0 466 if (undefined === i) {
michael@0 467 i = 0;
michael@0 468 }
michael@0 469
michael@0 470 doBooleanCommand(commandChain[i], "OK", function(ok) {
michael@0 471 if (!ok) {
michael@0 472 return callback(false);
michael@0 473 }
michael@0 474 i++;
michael@0 475 if (i === commandChain.length || !commandChain[i]) {
michael@0 476 // Reach the end or empty command.
michael@0 477 return callback(true);
michael@0 478 }
michael@0 479 doBooleanCommandChain(commandChain, callback, i);
michael@0 480 });
michael@0 481 }
michael@0 482
michael@0 483 //--------------------------------------------------
michael@0 484 // Helper functions.
michael@0 485 //--------------------------------------------------
michael@0 486
michael@0 487 function stopProcess(service, process, callback) {
michael@0 488 var count = 0;
michael@0 489 var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
michael@0 490 function tick() {
michael@0 491 let result = libcutils.property_get(service);
michael@0 492 if (result === null) {
michael@0 493 callback();
michael@0 494 return;
michael@0 495 }
michael@0 496 if (result === "stopped" || ++count >= 5) {
michael@0 497 // Either we succeeded or ran out of time.
michael@0 498 timer = null;
michael@0 499 callback();
michael@0 500 return;
michael@0 501 }
michael@0 502
michael@0 503 // Else it's still running, continue waiting.
michael@0 504 timer.initWithCallback(tick, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
michael@0 505 }
michael@0 506
michael@0 507 setProperty("ctl.stop", process, tick);
michael@0 508 }
michael@0 509
michael@0 510 // Wrapper around libcutils.property_set that returns true if setting the
michael@0 511 // value was successful.
michael@0 512 // Note that the callback is not called asynchronously.
michael@0 513 function setProperty(key, value, callback) {
michael@0 514 let ok = true;
michael@0 515 try {
michael@0 516 libcutils.property_set(key, value);
michael@0 517 } catch(e) {
michael@0 518 ok = false;
michael@0 519 }
michael@0 520 callback(ok);
michael@0 521 }
michael@0 522
michael@0 523 return command;
michael@0 524 };

mercurial