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.

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

mercurial