Merge birch and m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 24 Jun 2013 14:01:24 -0400
changeset 147760 d839f8a7f95660fc071eac3cf9d859aeb4cb7532
parent 147747 fe684609e72a21a24d4ddc66d3fda7ea8a5d168f (current diff)
parent 147759 de94eeba93c12252758b3d715c1c67dff20d487c (diff)
child 147761 53d6355ec4b73ca59406275a6ee88b0e382e8236
child 147762 3cb980ee5440c791999e0193a282b9f3f550b6b5
child 148561 8b4591ef3b24dfe9ae82799bc4d6d7175ffeb52f
child 148593 58a8b09df970d0d5db89b638e4e61fd9173dd411
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge birch and m-c.
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "d816bb323b9c9d7e59b3c8dfc2c62d3901864b46", 
+    "revision": "c18a9987518a11d34217823633aace14f0384322", 
     "repo_path": "/integration/gaia-central"
 }
--- a/dom/alarm/AlarmService.jsm
+++ b/dom/alarm/AlarmService.jsm
@@ -503,17 +503,27 @@ this.AlarmService = {
   observe: function(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "profile-change-teardown":
         this.uninit();
         break;
       case "webapps-clear-data":
         let params =
           aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
+        if (!params) {
+          debug("Error! Fail to remove alarms for an uninstalled app.");
+          return;
+        }
+
         let manifestURL = appsService.getManifestURLByLocalId(params.appId);
+        if (!manifestURL) {
+          debug("Error! Fail to remove alarms for an uninstalled app.");
+          return;
+        }
+
         this._db.getAll(
           manifestURL,
           function getAllSuccessCb(aAlarms) {
             aAlarms.forEach(function removeAlarm(aAlarm) {
               this.remove(aAlarm.id, manifestURL);
             }, this);
           }.bind(this),
           function getAllErrorCb(aErrorMsg) {
--- a/dom/messages/SystemMessageManager.js
+++ b/dom/messages/SystemMessageManager.js
@@ -22,19 +22,25 @@ XPCOMUtils.defineLazyServiceGetter(this,
 
 function debug(aMsg) {
    // dump("-- SystemMessageManager " + Date.now() + " : " + aMsg + "\n");
 }
 
 // Implementation of the DOM API for system messages
 
 function SystemMessageManager() {
-  // Message handlers for this page.
-  // We can have only one handler per message type.
-  this._handlers = {};
+  // If we have a system message handler registered for messages of type
+  // |type|, this._dispatchers[type] equals {handler, messages, isHandling},
+  // where
+  //  - |handler| is the message handler that the page registered,
+  //  - |messages| is a list of messages which we've received while
+  //    dispatching messages to the handler, but haven't yet sent, and
+  //  - |isHandling| indicates whether we're currently dispatching messages
+  //    to this handler.
+  this._dispatchers = {};
 
   // Pending messages for this page, keyed by message type.
   this._pendings = {};
 
   // Flag to specify if this process has already registered manifest.
   this._registerManifestReady = false;
 
   // Flag to determine this process is a parent or child process.
@@ -47,17 +53,31 @@ function SystemMessageManager() {
   if (this._isParentProcess) {
     Services.obs.addObserver(this, kSystemMessageInternalReady, false);
   }
 }
 
 SystemMessageManager.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
-  _dispatchMessage: function sysMessMgr_dispatchMessage(aType, aHandler, aMessage) {
+  _dispatchMessage: function sysMessMgr_dispatchMessage(aType, aDispatcher, aMessage) {
+    if (aDispatcher.isHandling) {
+      // Queue up the incomming message if we're currently dispatching a
+      // message; we'll send the message once we finish with the current one.
+      //
+      // _dispatchMethod is reentrant because a page can spin up a nested
+      // event loop from within a system message handler (e.g. via alert()),
+      // and we can then try to send the page another message while it's
+      // inside this nested event loop.
+      aDispatcher.messages.push(aMessage);
+      return;
+    }
+
+    aDispatcher.isHandling = true;
+
     // We get a json blob, but in some cases we want another kind of object
     // to be dispatched.
     // To do so, we check if we have a with a contract ID of
     // "@mozilla.org/dom/system-messages/wrapper/TYPE;1" component implementing
     // nsISystemMessageWrapper.
     debug("Dispatching " + JSON.stringify(aMessage) + "\n");
     let contractID = "@mozilla.org/dom/system-messages/wrapper/" + aType + ";1";
     let wrapped = false;
@@ -67,44 +87,58 @@ SystemMessageManager.prototype = {
       let wrapper = Cc[contractID].createInstance(Ci.nsISystemMessagesWrapper);
       if (wrapper) {
         aMessage = wrapper.wrapMessage(aMessage, this._window);
         wrapped = true;
         debug("wrapped = " + aMessage);
       }
     }
 
-    aHandler.handleMessage(wrapped ? aMessage
-                                   : ObjectWrapper.wrap(aMessage, this._window));
+    aDispatcher.handler
+      .handleMessage(wrapped ? aMessage
+                             : ObjectWrapper.wrap(aMessage, this._window));
+
+    // We need to notify the parent one of the system messages has been handled,
+    // so the parent can release the CPU wake lock it took on our behalf.
+    cpmm.sendAsyncMessage("SystemMessageManager:HandleMessagesDone",
+                          { type: aType,
+                            manifest: this._manifest,
+                            uri: this._uri,
+                            handledCount: 1 });
+
+    aDispatcher.isHandling = false;
+    if (aDispatcher.messages.length > 0) {
+      this._dispatchMessage(aType, aDispatcher, aDispatcher.messages.shift());
+    }
   },
 
   mozSetMessageHandler: function sysMessMgr_setMessageHandler(aType, aHandler) {
     debug("set message handler for [" + aType + "] " + aHandler);
 
     if (this._isInBrowserElement) {
       debug("the app loaded in the browser cannot set message handler");
       // Don't throw there, but ignore the registration.
       return;
     }
 
     if (!aType) {
       // Just bail out if we have no type.
       return;
     }
 
-    let handlers = this._handlers;
+    let dispatchers = this._dispatchers;
     if (!aHandler) {
-      // Setting the handler to null means we don't want to receive messages
-      // of this type anymore.
-      delete handlers[aType];
+      // Setting the dispatcher to null means we don't want to handle messages
+      // for this type anymore.
+      delete dispatchers[aType];
       return;
     }
 
     // Last registered handler wins.
-    handlers[aType] = aHandler;
+    dispatchers[aType] = { handler: aHandler, messages: [], isHandling: false };
 
     // Ask for the list of currently pending messages.
     cpmm.sendAsyncMessage("SystemMessageManager:GetPendingMessages",
                           { type: aType,
                             uri: this._uri,
                             manifest: this._manifest });
   },
 
@@ -113,28 +147,28 @@ SystemMessageManager.prototype = {
 
     if (this._isInBrowserElement) {
       debug("the app loaded in the browser cannot ask pending message");
       // Don't throw there, but pretend to have no messages available.
       return false;
     }
 
     // If we have a handler for this type, we can't have any pending message.
-    if (aType in this._handlers) {
+    if (aType in this._dispatchers) {
       return false;
     }
 
     return cpmm.sendSyncMessage("SystemMessageManager:HasPendingMessages",
                                 { type: aType,
                                   uri: this._uri,
                                   manifest: this._manifest })[0];
   },
 
   uninit: function sysMessMgr_uninit()  {
-    this._handlers = null;
+    this._dispatchers = null;
     this._pendings = null;
 
     if (this._isParentProcess) {
       Services.obs.removeObserver(this, kSystemMessageInternalReady);
     }
 
     if (this._isInBrowserElement) {
       debug("the app loaded in the browser doesn't need to unregister " +
@@ -182,35 +216,38 @@ SystemMessageManager.prototype = {
                               msgID: msg.msgID });
     }
 
     let messages = (aMessage.name == "SystemMessageManager:Message")
                    ? [msg.msg]
                    : msg.msgQueue;
 
     // We only dispatch messages when a handler is registered.
-    let handler = this._handlers[msg.type];
-    if (handler) {
+    let dispatcher = this._dispatchers[msg.type];
+    if (dispatcher) {
       messages.forEach(function(aMsg) {
-        this._dispatchMessage(msg.type, handler, aMsg);
+        this._dispatchMessage(msg.type, dispatcher, aMsg);
       }, this);
+    } else {
+      // We need to notify the parent that all the queued system messages have
+      // been handled (notice |handledCount: messages.length|), so the parent
+      // can release the CPU wake lock it took on our behalf.
+      cpmm.sendAsyncMessage("SystemMessageManager:HandleMessagesDone",
+                            { type: msg.type,
+                              manifest: this._manifest,
+                              uri: this._uri,
+                              handledCount: messages.length });
     }
 
-    // We need to notify the parent the system messages have been handled,
-    // even if there are no handlers registered for them, so the parent can
-    // release the CPU wake lock it took on our behalf.
-    cpmm.sendAsyncMessage("SystemMessageManager:HandleMessagesDone",
-                          { type: msg.type,
-                            manifest: this._manifest,
-                            uri: this._uri,
-                            handledCount: messages.length });
-
-    Services.obs.notifyObservers(/* aSubject */ null,
-                                 "handle-system-messages-done",
-                                 /* aData */ null);
+    if (!dispatcher || !dispatcher.isHandling) {
+      // TODO: Bug 874353 - Remove SystemMessageHandledListener in ContentParent
+      Services.obs.notifyObservers(/* aSubject */ null,
+                                   "handle-system-messages-done",
+                                   /* aData */ null);
+    }
   },
 
   // nsIDOMGlobalPropertyInitializer implementation.
   init: function sysMessMgr_init(aWindow) {
     debug("init");
     this.initHelper(aWindow, ["SystemMessageManager:Message",
                               "SystemMessageManager:GetPendingMessages:Return"]);
 
@@ -267,16 +304,17 @@ SystemMessageManager.prototype = {
   },
 
   classID: Components.ID("{bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMNavigatorSystemMessages,
                                          Ci.nsIDOMGlobalPropertyInitializer,
                                          Ci.nsIObserver]),
 
-  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2}"),
-                                    contractID: "@mozilla.org/system-message-manager;1",
-                                    interfaces: [Ci.nsIDOMNavigatorSystemMessages],
-                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
-                                    classDescription: "System Messages"})
+  classInfo: XPCOMUtils.generateCI({
+    classID: Components.ID("{bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2}"),
+    contractID: "@mozilla.org/system-message-manager;1",
+    interfaces: [Ci.nsIDOMNavigatorSystemMessages],
+    flags: Ci.nsIClassInfo.DOM_OBJECT,
+    classDescription: "System Messages"})
 }
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SystemMessageManager]);
--- a/dom/mobilemessage/src/ril/MmsService.js
+++ b/dom/mobilemessage/src/ril/MmsService.js
@@ -1449,17 +1449,17 @@ MmsService.prototype = {
     return message;
   },
 
   // nsIMmsService
 
   send: function send(aParams, aRequest) {
     if (DEBUG) debug("send: aParams: " + JSON.stringify(aParams));
     if (aParams.receivers.length == 0) {
-      aRequest.notifySendMmsMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
+      aRequest.notifySendMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
       return;
     }
 
     let self = this;
 
     let sendTransactionCb = function sendTransactionCb(aRecordId, aErrorCode) {
       if (DEBUG) debug("The error code of sending transaction: " + aErrorCode);
       let isSentSuccess = (aErrorCode == Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR);
@@ -1492,24 +1492,24 @@ MmsService.prototype = {
 
     let savableMessage = this.createSavableFromParams(aParams);
     gMobileMessageDatabaseService
       .saveSendingMessage(savableMessage,
                           function notifySendingResult(aRv, aDomMessage) {
       if (DEBUG) debug("Saving sending message is done. Start to send.");
 
       // For radio disabled error.
-      if(gMmsConnection.radioDisabled) {
+      if (gMmsConnection.radioDisabled) {
         if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
         sendTransactionCb(aDomMessage.id, Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR);
         return;
       }
 
       // For SIM card is not ready.
-      if(gRIL.rilContext.cardState != "ready") {
+      if (gRIL.rilContext.cardState != "ready") {
         if (DEBUG) debug("Error! SIM card is not ready when sending MMS.");
         sendTransactionCb(aDomMessage.id, Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR);
         return;
       }
 
       // TODO bug 832140 handle !Components.isSuccessCode(aRv)
       Services.obs.notifyObservers(aDomMessage, kSmsSendingObserverTopic, null);
       let sendTransaction;
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -2835,16 +2835,40 @@ RadioInterfaceLayer.prototype = {
 
     let id = gMobileMessageDatabaseService.saveSendingMessage(
       sendingMessage,
       function notifyResult(rv, domMessage) {
 
         // TODO bug 832140 handle !Components.isSuccessCode(rv)
         Services.obs.notifyObservers(domMessage, kSmsSendingObserverTopic, null);
 
+        // If the radio is disabled or the SIM card is not ready, just directly
+        // return with the corresponding error code.
+        let errorCode;
+        if (!this._radioEnabled) {
+          debug("Error! Radio is disabled when sending SMS.");
+          errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
+        } else if (this.rilContext.cardState != "ready") {
+          debug("Error! SIM card is not ready when sending SMS.");
+          errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
+        }
+        if (errorCode) {
+          gMobileMessageDatabaseService
+            .setMessageDelivery(domMessage.id,
+                                null,
+                                DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
+                                RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
+                                function notifyResult(rv, domMessage) {
+            // TODO bug 832140 handle !Components.isSuccessCode(rv)
+            request.notifySendMessageFailed(errorCode);
+            Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
+          });
+          return;
+        }
+
         // Keep current SMS message info for sent/delivered notifications
         options.envelopeId = this.createSmsEnvelope({
           request: request,
           sms: domMessage,
           requestStatusReport: options.requestStatusReport
         });
 
         if (PhoneNumberUtils.isPlainPhoneNumber(options.number)) {
--- a/dom/wifi/DOMWifiManager.js
+++ b/dom/wifi/DOMWifiManager.js
@@ -80,16 +80,17 @@ DOMWifiManager.prototype = {
     this._lastConnectionInfo = null;
 
     const messages = ["WifiManager:getNetworks:Return:OK", "WifiManager:getNetworks:Return:NO",
                       "WifiManager:getKnownNetworks:Return:OK", "WifiManager:getKnownNetworks:Return:NO",
                       "WifiManager:associate:Return:OK", "WifiManager:associate:Return:NO",
                       "WifiManager:forget:Return:OK", "WifiManager:forget:Return:NO",
                       "WifiManager:wps:Return:OK", "WifiManager:wps:Return:NO",
                       "WifiManager:setPowerSavingMode:Return:OK", "WifiManager:setPowerSavingMode:Return:NO",
+                      "WifiManager:setStaticIpMode:Return:OK", "WifiManager:setStaticIpMode:Return:NO",
                       "WifiManager:wifiDown", "WifiManager:wifiUp",
                       "WifiManager:onconnecting", "WifiManager:onassociate",
                       "WifiManager:onconnect", "WifiManager:ondisconnect",
                       "WifiManager:onwpstimeout", "WifiManager:onwpsfail",
                       "WifiManager:onwpsoverlap", "WifiManager:connectionInfoUpdate",
                       "WifiManager:onconnectingfailed"];
     this.initHelper(aWindow, messages);
     this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
@@ -186,16 +187,26 @@ DOMWifiManager.prototype = {
         Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
         break;
 
       case "WifiManager:setPowerSavingMode:Return:NO":
         request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
+      case "WifiManager:setStaticIpMode:Return:OK":
+        request = this.takeRequest(msg.rid);
+        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        break;
+
+      case "WifiManager:setStaticIpMode:Return:NO":
+        request = this.takeRequest(msg.rid);
+        Services.DOMRequest.fireError(request, msg.data);
+        break;
+
       case "WifiManager:wifiDown":
         this._enabled = false;
         this._currentNetwork = null;
         this._fireEnabledOrDisabled(false);
         break;
 
       case "WifiManager:wifiUp":
         this._enabled = true;
@@ -342,16 +353,24 @@ DOMWifiManager.prototype = {
   setPowerSavingMode: function nsIDOMWifiManager_setPowerSavingMode(enabled) {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:setPowerSavingMode", enabled, request);
     return request;
   },
 
+  setStaticIpMode: function nsIDOMWifiManager_setStaticIpMode(network, info) {
+    if (!this._hasPrivileges)
+      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+    var request = this.createRequest();
+    this._sendMessageForRequest("WifiManager:setStaticIpMode", {network: network,info: info}, request);
+    return request;
+  },
+
   get enabled() {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     return this._enabled;
   },
 
   get macAddress() {
     if (!this._hasPrivileges)
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -6,17 +6,17 @@
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
-var DEBUG = false; // set to true to show debug messages
+var DEBUG = false; // set to true to show debug messages.
 
 const WIFIWORKER_CONTRACTID = "@mozilla.org/wifi/worker;1";
 const WIFIWORKER_CID        = Components.ID("{a14e8977-d259-433a-a88d-58dd44657e5b}");
 
 const WIFIWORKER_WORKER     = "resource://gre/modules/wifi_worker.js";
 
 const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
 const kMozSettingsChangedObserverTopic   = "mozsettings-changed";
@@ -132,26 +132,26 @@ var WifiManager = (function() {
       callback(data);
       delete controlCallbacks[id];
     }
   };
 
   // Polling the status worker
   var recvErrors = 0;
   eventWorker.onmessage = function(e) {
-    // process the event and tell the event worker to listen for more events
+    // Process the event and tell the event worker to listen for more events.
     if (handleEvent(e.data.event))
       waitForEvent();
   };
 
   function waitForEvent() {
     eventWorker.postMessage({ cmd: "wait_for_event" });
   }
 
-  // Commands to the control worker
+  // Commands to the control worker.
 
   function voidControlMessage(cmd, callback) {
     controlMessage({ cmd: cmd }, function (data) {
       callback(data.status);
     });
   }
 
   var driverLoaded = false;
@@ -611,21 +611,87 @@ var WifiManager = (function() {
   }
 
   function resetConnections(ifname, callback) {
     controlMessage({ cmd: "ifc_reset_connections", ifname: ifname }, function(data) {
       callback(!data.status);
     });
   }
 
+  var staticIpConfig = Object.create(null);
+  function setStaticIpMode(network, info, callback) {
+    let setNetworkKey = getNetworkKey(network);
+    let curNetworkKey = null;
+    let currentNetwork = Object.create(null);
+    currentNetwork.netId = manager.connectionInfo.id;
+
+    manager.getNetworkConfiguration(currentNetwork, function (){
+      curNetworkKey = getNetworkKey(currentNetwork);
+
+      // Add additional information to static ip configuration
+      // It is used to compatiable with information dhcp callback.
+      info.ipaddr = stringToIp(info.ipaddr_str);
+      info.gateway = stringToIp(info.gateway_str);
+      info.mask_str = makeMask(info.maskLength);
+
+      // Optional
+      info.dns1 = stringToIp("dns1_str" in info ? info.dns1_str : "");
+      info.dns2 = stringToIp("dns2_str" in info ? info.dns2_str : "");
+      info.proxy = stringToIp("proxy_str" in info ? info.proxy_str : "");
+
+      staticIpConfig[setNetworkKey] = info;
+
+      // If the ssid of current connection is the same as configured ssid
+      // It means we need update current connection to use static IP address.
+      if (setNetworkKey == curNetworkKey) {
+        // Use configureInterface directly doesn't work, the network iterface
+        // and routing table is changed but still cannot connect to network
+        // so the workaround here is disable interface the enable again to
+        // trigger network reconnect with static ip.
+        disableInterface(manager.ifname, function (ok) {
+          enableInterface(manager.ifname, function (ok) {
+          });
+        });
+      }
+    });
+  }
+
   var dhcpInfo = null;
-  function runDhcp(ifname, callback) {
+  function runDhcp(ifname) {
+    debug("Run Dhcp");
     controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
       dhcpInfo = data.status ? null : data;
-      callback(dhcpInfo);
+      runIpConfig(ifname, dhcpInfo);
+    });
+  }
+
+  function runStaticIp(ifname, key) {
+    debug("Run static ip");
+
+    // Read static ip information from settings.
+    let staticIpInfo;
+
+    if (!(key in staticIpConfig))
+      return;
+
+    staticIpInfo = staticIpConfig[key];
+
+    // Stop dhcpd when use static IP
+    if (dhcpInfo != null) {
+      stopDhcp(manager.ifname, function() {});
+    }
+
+    // Set ip, mask length, gateway, dns to network interface
+    configureInterface(ifname,
+                       staticIpInfo.ipaddr,
+                       staticIpInfo.maskLength,
+                       staticIpInfo.gateway,
+                       staticIpInfo.dns1,
+                       staticIpInfo.dns2, function (data) {
+      runIpConfig(ifname, staticIpInfo);
     });
   }
 
   function stopDhcp(ifname, callback) {
     controlMessage({ cmd: "dhcp_stop", ifname: ifname }, function(data) {
       dhcpInfo = null;
       notify("dhcplost");
       callback(!data.status);
@@ -762,17 +828,17 @@ var WifiManager = (function() {
   function connectCallback(ok) {
     if (ok === 0) {
       // Tell the event worker to start waiting for events.
       retryTimer = null;
       didConnectSupplicant(function(){});
       return;
     }
     if (connectTries++ < 3) {
-      // try again in 5 seconds
+      // Try again in 5 seconds.
       if (!retryTimer)
         retryTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 
       retryTimer.initWithCallback(function(timer) {
         connectToSupplicant(connectCallback);
       }, 5000, Ci.nsITimer.TYPE_ONE_SHOT);
       return;
     }
@@ -798,42 +864,58 @@ var WifiManager = (function() {
   manager.start = function() {
     debug("detected SDK version " + sdkVersion);
     connectToSupplicant(connectCallback);
   }
 
   function onconnected() {
     // For now we do our own DHCP. In the future, this should be handed
     // off to the Network Manager.
-    runDhcp(manager.ifname, function (data) {
-      if (!data) {
-        debug("DHCP failed to run");
-        notify("dhcpconnected", { info: data });
+    let currentNetwork = Object.create(null);
+    currentNetwork.netId = manager.connectionInfo.id;
+
+    manager.getNetworkConfiguration(currentNetwork, function (){
+      let key = getNetworkKey(currentNetwork);
+      if (staticIpConfig  &&
+          (key in staticIpConfig) &&
+          staticIpConfig[key].enabled) {
+          debug("Run static ip");
+          runStaticIp(manager.ifname, key);
+          return;
+      }
+      runDhcp(manager.ifname);
+    });
+  }
+
+  function runIpConfig(name, data) {
+    if (!data) {
+      debug("IP config failed to run");
+      notify("networkconnected", { info: data });
+      return;
+    }
+
+    setProperty("net." + name + ".dns1", ipToString(data.dns1),
+                function(ok) {
+      if (!ok) {
+        debug("Unable to set net.<ifname>.dns1");
         return;
       }
-      setProperty("net." + manager.ifname + ".dns1", ipToString(data.dns1),
+      setProperty("net." + name + ".dns2", ipToString(data.dns2),
                   function(ok) {
         if (!ok) {
-          debug("Unable to set net.<ifname>.dns1");
+          debug("Unable to set net.<ifname>.dns2");
           return;
         }
-        setProperty("net." + manager.ifname + ".dns2", ipToString(data.dns2),
+        setProperty("net." + name + ".gw", ipToString(data.gateway),
                     function(ok) {
           if (!ok) {
-            debug("Unable to set net.<ifname>.dns2");
+            debug("Unable to set net.<ifname>.gw");
             return;
           }
-          setProperty("net." + manager.ifname + ".gw", ipToString(data.gateway),
-                      function(ok) {
-            if (!ok) {
-              debug("Unable to set net.<ifname>.gw");
-              return;
-            }
-            notify("dhcpconnected", { info: data });
-          });
+          notify("networkconnected", { info: data });
         });
       });
     });
   }
 
   var supplicantStatesMap = (sdkVersion >= 15) ?
     ["DISCONNECTED", "INTERFACE_DISABLED", "INACTIVE", "SCANNING",
      "AUTHENTICATING", "ASSOCIATING", "ASSOCIATED", "FOUR_WAY_HANDSHAKE",
@@ -860,17 +942,17 @@ var WifiManager = (function() {
             (ssid && ssid === dequote(network.ssid))) {
           return callback(net);
         }
       }
       callback(null);
     });
   }
 
-  // handle events sent to us by the event worker
+  // Handle events sent to us by the event worker.
   function handleEvent(event) {
     debug("Event coming in: " + event);
     if (event.indexOf("CTRL-EVENT-") !== 0 && event.indexOf("WPS") !== 0) {
       // Handle connection fail exception on WEP-128, while password length
       // is not 5 nor 13 bytes.
       if (event.indexOf("Association request to the driver failed") !== -1) {
         notify("passwordmaybeincorrect");
         if (manager.authenticationFailuresCount > MAX_RETRIES_ON_AUTHENTICATION_FAILURE) {
@@ -893,17 +975,17 @@ var WifiManager = (function() {
         manager.connectionInfo.ssid = match[1];
       }
       return true;
     }
 
     var space = event.indexOf(" ");
     var eventData = event.substr(0, space + 1);
     if (eventData.indexOf("CTRL-EVENT-STATE-CHANGE") === 0) {
-      // Parse the event data
+      // Parse the event data.
       var fields = {};
       var tokens = event.substr(space + 1).split(" ");
       for (var n = 0; n < tokens.length; ++n) {
         var kv = tokens[n].split("=");
         if (kv.length === 2)
           fields[kv[0]] = kv[1];
       }
       if (!("state" in fields))
@@ -933,17 +1015,17 @@ var WifiManager = (function() {
       // simply exit here (we don't have to notify about having lost
       // the connection).
       if (eventData.indexOf("connection closed") !== -1) {
         notify("supplicantlost", { success: true });
         return false;
       }
 
       // As long we haven't seen too many recv errors yet, we
-      // will keep going for a bit longer
+      // will keep going for a bit longer.
       if (eventData.indexOf("recv error") !== -1 && ++recvErrors < 10)
         return true;
 
       notifyStateChange({ state: "DISCONNECTED", BSSID: null, id: -1 });
       notify("supplicantlost", { success: true });
       return false;
     }
     if (eventData.indexOf("CTRL-EVENT-DISCONNECTED") === 0) {
@@ -971,18 +1053,21 @@ var WifiManager = (function() {
       if (event.indexOf("EAP authentication failed") !== -1) {
         notify("passwordmaybeincorrect");
       }
       return true;
     }
     if (eventData.indexOf("CTRL-EVENT-CONNECTED") === 0) {
       // Format: CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=]
       var bssid = event.split(" ")[4];
-      var id = event.substr(event.indexOf("id=")).split(" ")[0];
+
+      var keyword = "id=";
+      var id = event.substr(event.indexOf(keyword) + keyword.length).split(" ")[0];
       // Read current BSSID here, it will always being provided.
+      manager.connectionInfo.id = id;
       manager.connectionInfo.bssid = bssid;
       return true;
     }
     if (eventData.indexOf("CTRL-EVENT-SCAN-RESULTS") === 0) {
       debug("Notifying of scan results available");
       if (reEnableBackgroundScan) {
         reEnableBackgroundScan = false;
         setBackgroundScan("ON", function() {});
@@ -997,17 +1082,17 @@ var WifiManager = (function() {
     if (eventData.indexOf("WPS-FAIL") === 0) {
       notifyStateChange({ state: "WPS_FAIL", BSSID: null, id: -1 });
       return true;
     }
     if (eventData.indexOf("WPS-OVERLAP-DETECTED") === 0) {
       notifyStateChange({ state: "WPS_OVERLAP_DETECTED", BSSID: null, id: -1 });
       return true;
     }
-    // unknown event
+    // Unknown event.
     return true;
   }
 
   const SUPP_PROP = "init.svc.wpa_supplicant";
   function killSupplicant(callback) {
     // It is interesting to note that this function does exactly what
     // wifi_stop_supplicant does. Unforunately, on the Galaxy S2, Samsung
     // changed that function in a way that means that it doesn't recognize
@@ -1060,17 +1145,17 @@ var WifiManager = (function() {
         disableInterface(manager.ifname, function (ok) {
           suppressEvents = false;
           callback();
         });
       });
     });
   }
 
-  // Initial state
+  // Initial state.
   manager.state = "UNINITIALIZED";
   manager.tetheringState = "UNINITIALIZED";
   manager.enabled = false;
   manager.supplicantStarted = false;
   manager.connectionInfo = { ssid: null, bssid: null, id: -1 };
   manager.authenticationFailuresCount = 0;
   manager.loopDetectionCount = 0;
 
@@ -1084,17 +1169,17 @@ var WifiManager = (function() {
   };
   function createWaitForDriverReadyTimer(onTimeout) {
     waitForDriverReadyTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     waitForDriverReadyTimer.initWithCallback(onTimeout,
                                              DRIVER_READY_WAIT,
                                              Ci.nsITimer.TYPE_ONE_SHOT);
   };
 
-  // Public interface of the wifi service
+  // Public interface of the wifi service.
   manager.setWifiEnabled = function(enable, callback) {
     if (enable === manager.enabled) {
       callback("no change");
       return;
     }
 
     if (enable) {
       manager.state = "INITIALIZING";
@@ -1236,17 +1321,17 @@ var WifiManager = (function() {
 
   manager.disconnect = disconnectCommand;
   manager.reconnect = reconnectCommand;
   manager.reassociate = reassociateCommand;
 
   var networkConfigurationFields = [
     "ssid", "bssid", "psk", "wep_key0", "wep_key1", "wep_key2", "wep_key3",
     "wep_tx_keyidx", "priority", "key_mgmt", "scan_ssid", "disabled",
-    "identity", "password", "auth_alg"
+    "identity", "password", "auth_alg", "phase1", "phase2", "eap"
   ];
 
   manager.getNetworkConfiguration = function(config, callback) {
     var netId = config.netId;
     var done = 0;
     for (var n = 0; n < networkConfigurationFields.length; ++n) {
       let fieldName = networkConfigurationFields[n];
       getNetworkVariableCommand(netId, fieldName, function(value) {
@@ -1276,17 +1361,17 @@ var WifiManager = (function() {
         setNetworkVariableCommand(netId, fieldName, config[fieldName], function(ok) {
           if (!ok)
             ++errors;
           if (++done == networkConfigurationFields.length)
             callback(errors == 0);
         });
       }
     }
-    // If config didn't contain any of the fields we want, don't lose the error callback
+    // If config didn't contain any of the fields we want, don't lose the error callback.
     if (done == networkConfigurationFields.length)
       callback(false);
   }
   manager.getConfiguredNetworks = function(callback) {
     listNetworksCommand(function (reply) {
       var networks = Object.create(null);
       var lines = reply.split("\n");
       if (lines.length === 1) {
@@ -1313,17 +1398,17 @@ var WifiManager = (function() {
           config.status = "ENABLED";
           break;
         }
         manager.getNetworkConfiguration(config, function (ok) {
             if (!ok)
               ++errors;
             if (++done == lines.length - 1) {
               if (errors) {
-                // If an error occured, delete the new netId
+                // If an error occured, delete the new netId.
                 removeNetworkCommand(netId, function() {
                   callback(null);
                 });
               } else {
                 callback(networks);
               }
             }
         });
@@ -1352,16 +1437,53 @@ var WifiManager = (function() {
 
   function ipToString(n) {
     return String((n >>  0) & 0xFF) + "." +
                  ((n >>  8) & 0xFF) + "." +
                  ((n >> 16) & 0xFF) + "." +
                  ((n >> 24) & 0xFF);
   }
 
+  function stringToIp(string) {
+    let ip = 0;
+    let start, end = -1;
+    for (let i = 0; i < 4; i++) {
+      start = end + 1;
+      end = string.indexOf(".", start);
+      if (end == -1) {
+        end = string.length;
+      }
+      let num = parseInt(string.slice(start, end), 10);
+      if (isNaN(num)) {
+        return 0;
+      }
+      ip |= num << (i * 8);
+    }
+    return ip;
+  }
+
+  function swap32(n) {
+    return (((n >> 24) & 0xFF) <<  0) |
+           (((n >> 16) & 0xFF) <<  8) |
+           (((n >>  8) & 0xFF) << 16) |
+           (((n >>  0) & 0xFF) << 24);
+  }
+
+  function ntohl(n) {
+    return swap32(n);
+  }
+
+  function makeMask(len) {
+    let mask = 0;
+    for (let i = 0; i < len; ++i) {
+      mask |= (0x80000000 >> i);
+    }
+    return ntohl(mask);
+  }
+
   manager.saveConfig = function(callback) {
     saveConfigCommand(callback);
   }
   manager.enableNetwork = function(netId, disableOthers, callback) {
     enableNetworkCommand(netId, disableOthers, callback);
   }
   manager.disableNetwork = function(netId, callback) {
     disableNetworkCommand(netId, callback);
@@ -1373,16 +1495,17 @@ var WifiManager = (function() {
   }
   manager.setBackgroundScan = setBackgroundScan;
   manager.scan = scanCommand;
   manager.wpsPbc = wpsPbcCommand;
   manager.wpsPin = wpsPinCommand;
   manager.wpsCancel = wpsCancelCommand;
   manager.setPowerMode = setPowerModeCommand;
   manager.setSuspendOptimizations = setSuspendOptimizationsCommand;
+  manager.setStaticIpMode = setStaticIpMode;
   manager.getRssiApprox = getRssiApproxCommand;
   manager.getLinkSpeed = getLinkSpeedCommand;
   manager.getDhcpInfo = function() { return dhcpInfo; }
   manager.getConnectionInfo = (sdkVersion >= 15)
                               ? getConnectionInfoICS
                               : getConnectionInfoGB;
 
   manager.isHandShakeState = function(state) {
@@ -1494,17 +1617,17 @@ function getNetworkKey(network)
     } else if (key_mgmt == "NONE" && auth_alg === "OPEN SHARED") {
       encryption = "WEP";
     }
   }
 
   // ssid here must be dequoted, and it's safer to esacpe it.
   // encryption won't be empty and always be assigned one of the followings :
   // "OPEN"/"WEP"/"WPA-PSK"/"WPA-EAP".
-  // So for a invalid network object, the returned key will be "OPEN"
+  // So for a invalid network object, the returned key will be "OPEN".
   return escape(ssid) + encryption;
 }
 
 function getKeyManagement(flags) {
   var types = [];
   if (!flags)
     return types;
 
@@ -1555,17 +1678,20 @@ Network.api = {
   capabilities: "r",
   known: "r",
 
   password: "rw",
   keyManagement: "rw",
   psk: "rw",
   identity: "rw",
   wep: "rw",
-  hidden: "rw"
+  hidden: "rw",
+  eap: "rw",
+  phase1: "rw",
+  phase2: "rw"
 };
 
 // Note: We never use ScanResult.prototype, so the fact that it's unrelated to
 // Network.prototype is OK.
 function ScanResult(ssid, bssid, flags, signal) {
   Network.call(this, ssid, getKeyManagement(flags));
   this.bssid = bssid;
   this.signalStrength = signal;
@@ -1660,34 +1786,35 @@ function WifiWorker() {
   var self = this;
 
   this._mm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
                .getService(Ci.nsIMessageListenerManager);
   const messages = ["WifiManager:getNetworks", "WifiManager:getKnownNetworks",
                     "WifiManager:associate", "WifiManager:forget",
                     "WifiManager:wps", "WifiManager:getState",
                     "WifiManager:setPowerSavingMode",
+                    "WifiManager:setStaticIpMode",
                     "child-process-shutdown"];
 
   messages.forEach((function(msgName) {
     this._mm.addMessageListener(msgName, this);
   }).bind(this));
 
   Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
 
   this.wantScanResults = [];
 
   this._allowWpaEap = false;
   this._needToEnableNetworks = false;
   this._highestPriority = -1;
 
-  // networks is a map from SSID -> a scan result.
+  // Networks is a map from SSID -> a scan result.
   this.networks = Object.create(null);
 
-  // configuredNetworks is a map from SSID -> our view of a network. It only
+  // ConfiguredNetworks is a map from SSID -> our view of a network. It only
   // lists networks known to the wpa_supplicant. The SSID field (and other
   // fields) are quoted for ease of use with WifiManager commands.
   // Note that we don't have to worry about escaping embedded quotes since in
   // all cases, the supplicant will take the last quotation that we pass it as
   // the end of the string.
   this.configuredNetworks = Object.create(null);
   this._addingNetworks = Object.create(null);
 
@@ -1816,16 +1943,22 @@ function WifiWorker() {
     checkAssign("psk", true);
     checkAssign("identity", false);
     checkAssign("password", true);
     if (wep && net.wep && net.wep != '*') {
       configured.wep_key0 = net.wep_key0 = isWepHexKey(net.wep) ? net.wep : quote(net.wep);
       configured.auth_alg = net.auth_alg = "OPEN SHARED";
     }
 
+    if ("phase1" in net)
+      net.phase1 = quote(net.phase1);
+
+    if ("phase2" in net)
+      net.phase2 = quote(net.phase2);
+
     return net;
   };
 
   WifiManager.onsupplicantconnection = function() {
     debug("Connected to supplicant");
     WifiManager.enabled = true;
     self._reloadConfiguredNetworks(function(ok) {
       // Prime this.networks.
@@ -2019,17 +2152,17 @@ function WifiWorker() {
         // If we're already scanning in the background, we don't need to worry
         // about getting stuck while scanning.
         if (!WifiManager.backgroundScanEnabled && WifiManager.enabled)
           startScanStuckTimer();
         break;
     }
   };
 
-  WifiManager.ondhcpconnected = function() {
+  WifiManager.onnetworkconnected = function() {
     if (this.info) {
       WifiNetworkInterface.state =
         Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED;
       WifiNetworkInterface.ip = this.info.ipaddr_str;
       WifiNetworkInterface.netmask = this.info.mask_str;
       WifiNetworkInterface.broadcast = this.info.broadcast_str;
       WifiNetworkInterface.gateway = this.info.gateway_str;
       WifiNetworkInterface.dns1 = this.info.dns1_str;
@@ -2147,17 +2280,17 @@ function WifiWorker() {
       self.wantScanResults.forEach(function(callback) { callback(self.networksArray) });
       self.wantScanResults = [];
     });
   };
 
   // Read the 'wifi.enabled' setting in order to start with a known
   // value at boot time. The handle() will be called after reading.
   //
-  // nsISettingsServiceCallback implementation
+  // nsISettingsServiceCallback implementation.
   var initWifiEnabledCb = {
     handle: function handle(aName, aResult) {
       if (aName !== SETTINGS_WIFI_ENABLED)
         return;
       if (aResult === null)
         aResult = true;
       self.handleWifiEnabled(aResult);
     },
@@ -2496,16 +2629,19 @@ WifiWorker.prototype = {
         this.forget(msg);
         break;
       case "WifiManager:wps":
         this.wps(msg);
         break;
       case "WifiManager:setPowerSavingMode":
         this.setPowerSavingMode(msg);
         break;
+      case "WifiManager:setStaticIpMode":
+        this.setStaticIpMode(msg);
+        break;
       case "WifiManager:getState": {
         let i;
         if ((i = this._domManagers.indexOf(msg.manager)) === -1) {
           this._domManagers.push(msg.manager);
         }
 
         let net = this.currentNetwork ? netToDOM(this.currentNetwork) : null;
         return { network: net,
@@ -2965,16 +3101,40 @@ WifiWorker.prototype = {
           self._sendMessage(message, true, true, msg);
         } else {
           self._sendMessage(message, false, "Set power saving mode failed", msg);
         }
       });
     });
   },
 
+  setStaticIpMode: function(msg) {
+    const message = "WifiManager:setStaticMode:Return";
+    let self = this;
+    let network = msg.data.network;
+    let info = msg.data.info;
+
+    netFromDOM(network, null);
+
+    // To compatiable with DHCP returned info structure, do translation here
+    info.ipaddr_str = info.ipaddr;
+    info.proxy_str = info.proxy;
+    info.gateway_str = info.gateway;
+    info.dns1_str = info.dns1;
+    info.dns2_str = info.dns2;
+
+    WifiManager.setStaticIpMode(network, info, function(ok) {
+      if (ok) {
+        self._sendMessage(message, true, true, msg);
+      } else {
+        self._sendMessage(message, false, "Set static ip mode failed", msg);
+      }
+    });
+  },
+
   // This is a bit ugly, but works. In particular, this depends on the fact
   // that RadioManager never actually tries to get the worker from us.
   get worker() { throw "Not implemented"; },
 
   shutdown: function() {
     debug("shutting down ...");
     this.setWifiEnabled({enabled: false});
   },
--- a/dom/wifi/nsIWifi.idl
+++ b/dom/wifi/nsIWifi.idl
@@ -54,17 +54,17 @@ interface nsIWifi : nsISupports
      * currently configured networks.
      *
      * On success a callback is notified with the list of networks.
      * On failure after 3 scan retry attempts a callback is notified of failure.
      */
     void getWifiScanResults(in nsIWifiScanResultsReady callback);
 };
 
-[scriptable, uuid(caa76ee3-8ffe-4ea5-bc59-3b53a9df0d07)]
+[scriptable, uuid(3f21012d-6e75-4632-b87c-acdd7c57fbf3)]
 interface nsIDOMWifiManager : nsISupports
 {
     /**
      * Returns the list of currently available networks.
      * onsuccess: We have obtained the current list of networks. request.value
      *            is an object whose property names are SSIDs and values are
      *            network objects.
      * onerror: We were unable to obtain a list of property names.
@@ -122,16 +122,33 @@ interface nsIDOMWifiManager : nsISupport
      * Turn on/off wifi power saving mode.
      * @param enabled true or false.
      * onsuccess: We have successfully turn on/off wifi power saving mode.
      * onerror: We have failed to turn on/off wifi power saving mode.
      */
     nsIDOMDOMRequest setPowerSavingMode(in boolean enabled);
 
     /**
+     * Given a network, configure using static IP instead of running DHCP
+     * @param network A network object with the SSID of the network to set static ip.
+     * @param info info should have following field:
+     *        - enabled True to enable static IP, false to use DHCP
+     *        - ipaddr configured static IP address
+     *        - proxy configured proxy server address
+     *        - maskLength configured mask length
+     *        - gateway configured gateway address
+     *        - dns1 configured first DNS server address
+     *        - dns2 configured seconf DNS server address
+     * onsuccess: We have successfully configure the static ip mode.
+     * onerror: We have failed to configure the static ip mode.
+     */
+    nsIDOMDOMRequest setStaticIpMode(in jsval network,
+                                     in jsval info);
+
+    /**
      * Returns whether or not wifi is currently enabled.
      */
     readonly attribute boolean enabled;
 
     /**
      * Returns the MAC address of the wifi adapter.
      */
     readonly attribute DOMString macAddress;