Bug 1038531 - Unify NetworkWorker. r=mrbkap r=fabrice
☠☠ backed out by e934b3bc1fea ☠ ☠
authorHenry Chang <hchang@mozilla.com>
Mon, 18 Aug 2014 11:02:56 +0800
changeset 226388 59611423c368154340dc87981f4e9c92a9a2bb73
parent 226387 780b3083916c30200707779ea6996c05f94166c9
child 226389 a5a343aeaa65f69649dc24b0892e1880371a1de8
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap, fabrice
bugs1038531
milestone35.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
Bug 1038531 - Unify NetworkWorker. r=mrbkap r=fabrice
dom/system/gonk/NetworkManager.js
dom/system/gonk/NetworkService.js
dom/system/gonk/NetworkUtils.cpp
dom/system/gonk/NetworkUtils.h
dom/system/gonk/NetworkWorker.cpp
dom/system/gonk/nsINetworkService.idl
dom/webidl/NetworkOptions.webidl
dom/webidl/WifiOptions.webidl
dom/wifi/WifiNetUtil.jsm
dom/wifi/WifiP2pManager.jsm
dom/wifi/WifiProxyService.cpp
dom/wifi/WifiUtils.cpp
dom/wifi/WifiUtils.h
dom/wifi/WifiWorker.js
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -587,28 +587,28 @@ NetworkManager.prototype = {
     let oldActive = this.active;
 
     if (this._overriddenActive) {
       debug("We have an override for the active network: " +
             this._overriddenActive.name);
       // The override was just set, so reconfigure the network.
       if (this.active != this._overriddenActive) {
         this.active = this._overriddenActive;
-        gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
+        this._setDefaultRouteAndDNS(this.active, oldActive);
         Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
       }
       return;
     }
 
     // The active network is already our preferred type.
     if (this.active &&
         this.active.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED &&
         this.active.type == this._preferredNetworkType) {
       debug("Active network is already our preferred type.");
-      gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
+      this._setDefaultRouteAndDNS(this.active, oldActive);
       return;
     }
 
     // Find a suitable network interface to activate.
     this.active = null;
 #ifdef MOZ_B2G_RIL
     let defaultDataNetwork;
 #endif
@@ -637,17 +637,17 @@ NetworkManager.prototype = {
           this.active.type != this.preferredNetworkType) {
         this.active = defaultDataNetwork;
       }
       // Don't set default route on secondary APN
       if (this.isNetworkTypeSecondaryMobile(this.active.type)) {
         gNetworkService.setDNS(this.active);
       } else {
 #endif // MOZ_B2G_RIL
-        gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
+        this._setDefaultRouteAndDNS(this.active, oldActive);
 #ifdef MOZ_B2G_RIL
       }
 #endif
     }
 
     if (this.active != oldActive) {
       Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
     }
@@ -1244,17 +1244,25 @@ NetworkManager.prototype = {
     if (this._usbTetheringAction === TETHERING_STATE_ONGOING) {
       debug("Postpone the event and handle it when state is idle.");
       this.wantConnectionEvent = callback;
       return;
     }
     this.wantConnectionEvent = null;
 
     callback.call(this);
-  }
+  },
+
+  _setDefaultRouteAndDNS: function(network, oldInterface) {
+    gNetworkService.setDefaultRoute(network, oldInterface, function(success) {
+      gNetworkService.setDNS(network, function(result) {
+        gNetworkService.setNetworkProxy(network);
+      });
+    });
+  },
 };
 
 let CaptivePortalDetectionHelper = (function() {
 
   const EVENT_CONNECT = "Connect";
   const EVENT_DISCONNECT = "Disconnect";
   let _ongoingInterface = null;
   let _available = ("nsICaptivePortalDetector" in Ci);
--- a/dom/system/gonk/NetworkService.js
+++ b/dom/system/gonk/NetworkService.js
@@ -183,17 +183,16 @@ NetworkService.prototype = {
 
     let params = {
       cmd: "setNetworkInterfaceAlarm",
       ifname: networkName,
       threshold: threshold
     };
 
     params.report = true;
-    params.isAsync = true;
 
     this.controlMessage(params, function(result) {
       if (!isError(result.resultCode)) {
         callback.networkUsageAlarmResult(null);
         return;
       }
 
       this._enableNetworkInterfaceAlarm(networkName, threshold, callback);
@@ -205,17 +204,16 @@ NetworkService.prototype = {
 
     let params = {
       cmd: "enableNetworkInterfaceAlarm",
       ifname: networkName,
       threshold: threshold
     };
 
     params.report = true;
-    params.isAsync = true;
 
     this.controlMessage(params, function(result) {
       if (!isError(result.resultCode)) {
         callback.networkUsageAlarmResult(null);
         return;
       }
       callback.networkUsageAlarmResult(result.reason);
     });
@@ -225,34 +223,32 @@ NetworkService.prototype = {
     if(DEBUG) debug("disableNetworkInterfaceAlarm for " + networkName);
 
     let params = {
       cmd: "disableNetworkInterfaceAlarm",
       ifname: networkName,
     };
 
     params.report = true;
-    params.isAsync = true;
 
     this.controlMessage(params, function(result) {
       callback(result);
     });
   },
 
   setWifiOperationMode: function(interfaceName, mode, callback) {
     if(DEBUG) debug("setWifiOperationMode on " + interfaceName + " to " + mode);
 
     let params = {
       cmd: "setWifiOperationMode",
       ifname: interfaceName,
       mode: mode
     };
 
     params.report = true;
-    params.isAsync = true;
 
     this.controlMessage(params, function(result) {
       if (isError(result.resultCode)) {
         callback.wifiOperationModeResult("netd command error");
       } else {
         callback.wifiOperationModeResult(null);
       }
     });
@@ -272,42 +268,42 @@ NetworkService.prototype = {
         ifname: network.name,
         ip: ip,
         prefixLength: prefixLength
       };
       this.controlMessage(options);
     }
   },
 
-  setDNS: function(networkInterface) {
-    if(DEBUG) debug("Going DNS to " + networkInterface.name);
+  setDNS: function(networkInterface, callback) {
+    if (DEBUG) debug("Going DNS to " + networkInterface.name);
     let dnses = networkInterface.getDnses();
     let options = {
       cmd: "setDNS",
       ifname: networkInterface.name,
       domain: "mozilla." + networkInterface.name + ".doman",
       dnses: dnses
     };
-    this.controlMessage(options);
+    this.controlMessage(options, function(result) {
+      callback.setDnsResult(result.success ? null : result.reason);
+    });
   },
 
-  setDefaultRouteAndDNS: function(network, oldInterface) {
-    if(DEBUG) debug("Going to change route and DNS to " + network.name);
+  setDefaultRoute: function(network, oldInterface, callback) {
+    if (DEBUG) debug("Going to change default route to " + network.name);
     let gateways = network.getGateways();
-    let dnses = network.getDnses();
     let options = {
-      cmd: "setDefaultRouteAndDNS",
+      cmd: "setDefaultRoute",
       ifname: network.name,
       oldIfname: (oldInterface && oldInterface !== network) ? oldInterface.name : null,
-      gateways: gateways,
-      domain: "mozilla." + network.name + ".doman",
-      dnses: dnses
+      gateways: gateways
     };
-    this.controlMessage(options);
-    this.setNetworkProxy(network);
+    this.controlMessage(options, function(result) {
+      callback.nativeCommandResult(!result.error);
+    });
   },
 
   removeDefaultRoute: function(network) {
     if(DEBUG) debug("Remove default route for " + network.name);
     let gateways = network.getGateways();
     let options = {
       cmd: "removeDefaultRoute",
       ifname: network.name,
@@ -410,17 +406,16 @@ NetworkService.prototype = {
 
   // Enable/Disable DHCP server.
   setDhcpServer: function(enabled, config, callback) {
     if (null === config) {
       config = {};
     }
 
     config.cmd = "setDhcpServer";
-    config.isAsync = true;
     config.enabled = enabled;
 
     this.controlMessage(config, function setDhcpServerResult(response) {
       if (!response.success) {
         callback.dhcpServerResult('Set DHCP server error');
         return;
       }
       callback.dhcpServerResult(null);
@@ -432,17 +427,16 @@ NetworkService.prototype = {
     // config should've already contained:
     //   .ifname
     //   .internalIfname
     //   .externalIfname
     config.wifictrlinterfacename = WIFI_CTRL_INTERFACE;
     config.cmd = "setWifiTethering";
 
     // The callback function in controlMessage may not be fired immediately.
-    config.isAsync = true;
     this.controlMessage(config, function setWifiTetheringResult(data) {
       let code = data.resultCode;
       let reason = data.resultReason;
       let enable = data.enable;
       let enableString = enable ? "Enable" : "Disable";
 
       if(DEBUG) debug(enableString + " Wifi tethering result: Code " + code + " reason " + reason);
 
@@ -453,17 +447,16 @@ NetworkService.prototype = {
       }
     });
   },
 
   // Enable/disable USB tethering by sending commands to netd.
   setUSBTethering: function(enable, config, callback) {
     config.cmd = "setUSBTethering";
     // The callback function in controlMessage may not be fired immediately.
-    config.isAsync = true;
     this.controlMessage(config, function setUsbTetheringResult(data) {
       let code = data.resultCode;
       let reason = data.resultReason;
       let enable = data.enable;
       let enableString = enable ? "Enable" : "Disable";
 
       if(DEBUG) debug(enableString + " USB tethering result: Code " + code + " reason " + reason);
 
@@ -486,41 +479,99 @@ NetworkService.prototype = {
     // Ask net work to report the result when this value is set to true.
     if (callback) {
       params.report = true;
     } else {
       params.report = false;
     }
 
     // The callback function in controlMessage may not be fired immediately.
-    params.isAsync = true;
     //this._usbTetheringAction = TETHERING_STATE_ONGOING;
     this.controlMessage(params, function(data) {
       callback.enableUsbRndisResult(data.result, data.enable);
     });
   },
 
   updateUpStream: function(previous, current, callback) {
     let params = {
       cmd: "updateUpStream",
-      isAsync: true,
       preInternalIfname: previous.internalIfname,
       preExternalIfname: previous.externalIfname,
       curInternalIfname: current.internalIfname,
       curExternalIfname: current.externalIfname
     };
 
     this.controlMessage(params, function(data) {
       let code = data.resultCode;
       let reason = data.resultReason;
       if(DEBUG) debug("updateUpStream result: Code " + code + " reason " + reason);
       callback.updateUpStreamResult(!isError(code), data.curExternalIfname);
     });
   },
 
+  configureInterface: function(config, callback) {
+    let params = {
+      cmd: "configureInterface",
+      ifname: config.ifname,
+      ipaddr: config.ipaddr,
+      mask: config.mask,
+      gateway_long: config.gateway,
+      dns1_long: config.dns1,
+      dns2_long: config.dns2,
+    };
+
+    this.controlMessage(params, function(result) {
+      callback.nativeCommandResult(!result.error);
+    });
+  },
+
+  dhcpRequest: function(interfaceName, callback) {
+    let params = {
+      cmd: "dhcpRequest",
+      ifname: interfaceName
+    };
+
+    this.controlMessage(params, function(result) {
+      callback.dhcpRequestResult(!result.error, result.error ? null : result);
+    });
+  },
+
+  enableInterface: function(interfaceName, callback) {
+    let params = {
+      cmd: "enableInterface",
+      ifname: interfaceName
+    };
+
+    this.controlMessage(params, function(result) {
+      callback.nativeCommandResult(!result.error);
+    });
+  },
+
+  disableInterface: function(interfaceName, callback) {
+    let params = {
+      cmd: "disableInterface",
+      ifname: interfaceName
+    };
+
+    this.controlMessage(params, function(result) {
+      callback.nativeCommandResult(!result.error);
+    });
+  },
+
+  resetConnections: function(interfaceName, callback) {
+    let params = {
+      cmd: "resetConnections",
+      ifname: interfaceName
+    };
+
+    this.controlMessage(params, function(result) {
+      callback.nativeCommandResult(!result.error);
+    });
+  },
+
   shutdown: false,
 
   observe: function observe(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "xpcom-shutdown":
         debug("NetworkService shutdown");
         this.shutdown = true;
         Services.obs.removeObserver(this, "xpcom-shutdown");
--- a/dom/system/gonk/NetworkUtils.cpp
+++ b/dom/system/gonk/NetworkUtils.cpp
@@ -96,17 +96,24 @@ struct CurrentCommand {
 
 typedef Tuple3<NetdCommand*, CommandChain*, CommandCallback> QueueData;
 
 #define GET_CURRENT_NETD_COMMAND   (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].a)
 #define GET_CURRENT_CHAIN          (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].b)
 #define GET_CURRENT_CALLBACK       (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].c)
 #define GET_CURRENT_COMMAND        (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].a->mData)
 
-#define CNT_OF_ARRAY(a) (sizeof(a) / sizeof(a[0]))
+// A macro for native function call return value check.
+// For native function call, non-zero return value means failure.
+#define RETURN_IF_FAILED(rv) do { \
+  if (SUCCESS != rv) { \
+    return rv; \
+  } \
+} while (0);
+
 
 static NetworkUtils* gNetworkUtils;
 static nsTArray<QueueData> gCommandQueue;
 static CurrentCommand gCurrentCommand;
 static bool gPending = false;
 static nsTArray<nsCString> gReason;
 static NetworkParams *gWifiTetheringParms = 0;
 
@@ -388,16 +395,50 @@ void NetworkUtils::next(CommandChain* aC
   if (!f) {
     delete aChain;
     return;
   }
 
   (*f)(aChain, next, aResult);
 }
 
+CommandResult::CommandResult(int32_t aResultCode)
+  : mIsPending(false)
+{
+  // This is usually not a netd command. We treat the return code
+  // typical linux convention, which uses 0 to indicate success.
+  mResult.mError = (aResultCode == SUCCESS ? false : true);
+  mResult.mResultCode = aResultCode;
+  if (aResultCode != SUCCESS) {
+    // The returned value is sometimes negative, make sure we pass a positive
+    // error number to strerror.
+    enum { STRERROR_R_BUF_SIZE = 1024, };
+    char strerrorBuf[STRERROR_R_BUF_SIZE];
+    strerror_r(abs(aResultCode), strerrorBuf, STRERROR_R_BUF_SIZE);
+    mResult.mReason = NS_ConvertUTF8toUTF16(strerrorBuf);
+  }
+  mResult.mRet = true;
+}
+
+CommandResult::CommandResult(const mozilla::dom::NetworkResultOptions& aResult)
+  : mResult(aResult)
+  , mIsPending(false)
+{
+}
+
+CommandResult::CommandResult(const Pending&)
+  : mIsPending(true)
+{
+}
+
+bool CommandResult::isPending() const
+{
+  return mIsPending;
+}
+
 /**
  * Send command to netd.
  */
 void NetworkUtils::nextNetdCommand()
 {
   if (gCommandQueue.IsEmpty() || gPending) {
     return;
   }
@@ -1025,85 +1066,89 @@ NetworkUtils::NetworkUtils(MessageCallba
 
 NetworkUtils::~NetworkUtils()
 {
 }
 
 #define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aOptions.prop).get()
 #define GET_FIELD(prop) aOptions.prop
 
+// Hoist this type definition to global to avoid template
+// instantiation error on gcc 4.4 used by ICS emulator.
+typedef CommandResult (NetworkUtils::*CommandHandler)(NetworkParams&);
+struct CommandHandlerEntry
+{
+  const char* mCommandName;
+  CommandHandler mCommandHandler;
+};
+
 void NetworkUtils::ExecuteCommand(NetworkParams aOptions)
 {
-  typedef int32_t (NetworkUtils::*CommandHandler)(NetworkParams&);
-
-  const static struct {
-    const char* mCommandName;
-    CommandHandler mCommandHandler;
-  } COMMAND_HANDLER_TABLE[] = {
+  const static CommandHandlerEntry
+    COMMAND_HANDLER_TABLE[] = {
 
     // For command 'testCommand', BUILD_ENTRY(testCommand) will generate
     // {"testCommand", NetworkUtils::testCommand}
     #define BUILD_ENTRY(c) {#c, &NetworkUtils::c}
 
     BUILD_ENTRY(removeNetworkRoute),
     BUILD_ENTRY(setDNS),
-    BUILD_ENTRY(setDefaultRouteAndDNS),
+    BUILD_ENTRY(setDefaultRoute),
     BUILD_ENTRY(removeDefaultRoute),
     BUILD_ENTRY(addHostRoute),
     BUILD_ENTRY(removeHostRoute),
     BUILD_ENTRY(removeHostRoutes),
     BUILD_ENTRY(addSecondaryRoute),
     BUILD_ENTRY(removeSecondaryRoute),
     BUILD_ENTRY(setNetworkInterfaceAlarm),
     BUILD_ENTRY(enableNetworkInterfaceAlarm),
     BUILD_ENTRY(disableNetworkInterfaceAlarm),
     BUILD_ENTRY(setWifiOperationMode),
     BUILD_ENTRY(setDhcpServer),
     BUILD_ENTRY(setWifiTethering),
     BUILD_ENTRY(setUSBTethering),
     BUILD_ENTRY(enableUsbRndis),
     BUILD_ENTRY(updateUpStream),
+    BUILD_ENTRY(configureInterface),
+    BUILD_ENTRY(dhcpRequest),
+    BUILD_ENTRY(enableInterface),
+    BUILD_ENTRY(disableInterface),
+    BUILD_ENTRY(resetConnections),
 
     #undef BUILD_ENTRY
   };
 
   // Loop until we find the command name which matches aOptions.mCmd.
   CommandHandler handler = nullptr;
-  for (size_t i = 0; i < CNT_OF_ARRAY(COMMAND_HANDLER_TABLE); i++) {
+  for (size_t i = 0; i < mozilla::ArrayLength(COMMAND_HANDLER_TABLE); i++) {
     if (aOptions.mCmd.EqualsASCII(COMMAND_HANDLER_TABLE[i].mCommandName)) {
       handler = COMMAND_HANDLER_TABLE[i].mCommandHandler;
       break;
     }
   }
 
   if (!handler) {
     // Command not found in COMMAND_HANDLER_TABLE.
     WARN("unknown message: %s", NS_ConvertUTF16toUTF8(aOptions.mCmd).get());
     return;
   }
 
-  // Command matches! Dispatch to the handler.
-  int32_t ret = 0;
-  ret = (this->*handler)(aOptions);
-
-  if (!aOptions.mIsAsync) {
-    // The requested command is synchronous, which implies the actual result
-    // from netd is not important to the client. So, just notify the
-    // registered callback.
-    NetworkResultOptions result;
-    result.mError = ret == SUCCESS ? false : true;
-    result.mResultCode = ret;
-    if (ret != SUCCESS) {
-      // The returned value is sometimes negative, make sure we pass a positive
-      // error number to strerror.
-      result.mReason = NS_ConvertUTF8toUTF16(strerror(abs(ret)));
-    }
-
-    result.mRet = true;
-    postMessage(aOptions, result);
+  // The handler would return one of the following 3 values
+  // to be wrapped to CommandResult:
+  //
+  //   1) |int32_t| for mostly synchronous native function calls.
+  //   2) |NetworkResultOptions| to populate additional results. (e.g. dhcpRequest)
+  //   3) |CommandResult::Pending| to indicate the result is not
+  //      obtained yet.
+  //
+  // If the handler returns "Pending", the handler should take the
+  // responsibility for posting result to main thread.
+  CommandResult commandResult = (this->*handler)(aOptions);
+  if (!commandResult.isPending()) {
+    postMessage(aOptions, commandResult.mResult);
   }
 }
 
 /**
  * Handle received data from netd.
  */
 void NetworkUtils::onNetdMessage(NetdCommand* aCommand)
 {
@@ -1178,36 +1223,36 @@ void NetworkUtils::onNetdMessage(NetdCom
   if (isComplete(code)) {
     nextNetdCommand();
   }
 }
 
 /**
  * Start/Stop DHCP server.
  */
-int32_t NetworkUtils::setDhcpServer(NetworkParams& aOptions)
+CommandResult NetworkUtils::setDhcpServer(NetworkParams& aOptions)
 {
   if (aOptions.mEnabled) {
     aOptions.mWifiStartIp = aOptions.mStartIp;
     aOptions.mWifiEndIp = aOptions.mEndIp;
     aOptions.mIp = aOptions.mServerIp;
     aOptions.mPrefix = aOptions.mMaskLength;
     aOptions.mLink = NS_ConvertUTF8toUTF16("up");
 
     RUN_CHAIN(aOptions, sStartDhcpServerChain, setDhcpServerFail)
   } else {
     RUN_CHAIN(aOptions, sStopDhcpServerChain, setDhcpServerFail)
   }
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
 /**
  * Set DNS servers for given network interface.
  */
-int32_t NetworkUtils::setDNS(NetworkParams& aOptions)
+CommandResult NetworkUtils::setDNS(NetworkParams& aOptions)
 {
   uint32_t length = aOptions.mDnses.Length();
 
   if (length > 0) {
     for (uint32_t i = 0; i < length; i++) {
       NS_ConvertUTF16toUTF8 autoDns(aOptions.mDnses[i]);
 
       char dns_prop_key[PROPERTY_VALUE_MAX];
@@ -1229,101 +1274,193 @@ int32_t NetworkUtils::setDNS(NetworkPara
 
   char num[PROPERTY_VALUE_MAX];
   snprintf(num, PROPERTY_VALUE_MAX - 1, "%d", atoi(dnschange) + 1);
   property_set("net.dnschange", num);
 
   // DNS needs to be set through netd since JellyBean (4.3).
   if (SDK_VERSION >= 18) {
     RUN_CHAIN(aOptions, sSetDnsChain, setDnsFail)
+    return CommandResult::Pending();
   }
 
   return SUCCESS;
 }
 
+CommandResult NetworkUtils::configureInterface(NetworkParams& aOptions)
+{
+  NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
+  return mNetUtils->do_ifc_configure(
+    autoIfname.get(),
+    aOptions.mIpaddr,
+    aOptions.mMask,
+    aOptions.mGateway_long,
+    aOptions.mDns1_long,
+    aOptions.mDns2_long
+  );
+}
+
+CommandResult NetworkUtils::dhcpRequest(NetworkParams& aOptions) {
+    mozilla::dom::NetworkResultOptions result;
+
+    NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
+    char ipaddr[PROPERTY_VALUE_MAX];
+    char gateway[PROPERTY_VALUE_MAX];
+    uint32_t prefixLength;
+    char dns1[PROPERTY_VALUE_MAX];
+    char dns2[PROPERTY_VALUE_MAX];
+    char server[PROPERTY_VALUE_MAX];
+    uint32_t lease;
+    char vendorinfo[PROPERTY_VALUE_MAX];
+    int32_t ret = mNetUtils->do_dhcp_do_request(autoIfname.get(),
+                                                ipaddr,
+                                                gateway,
+                                                &prefixLength,
+                                                dns1,
+                                                dns2,
+                                                server,
+                                                &lease,
+                                                vendorinfo);
+
+    RETURN_IF_FAILED(ret);
+
+    result.mIpaddr_str = NS_ConvertUTF8toUTF16(ipaddr);
+    result.mGateway_str = NS_ConvertUTF8toUTF16(gateway);
+    result.mDns1_str = NS_ConvertUTF8toUTF16(dns1);
+    result.mDns2_str = NS_ConvertUTF8toUTF16(dns2);
+    result.mServer_str = NS_ConvertUTF8toUTF16(server);
+    result.mVendor_str = NS_ConvertUTF8toUTF16(vendorinfo);
+    result.mLease = lease;
+    result.mMask = makeMask(prefixLength);
+
+    uint32_t inet4; // only support IPv4 for now.
+
+#define INET_PTON(var, field)                                                 \
+  PR_BEGIN_MACRO                                                              \
+    inet_pton(AF_INET, var, &inet4);                                          \
+    result.field = inet4;                                                    \
+  PR_END_MACRO
+
+    INET_PTON(ipaddr, mIpaddr);
+    INET_PTON(gateway, mGateway);
+
+    if (dns1[0] != '\0') {
+      INET_PTON(dns1, mDns1);
+    }
+
+    if (dns2[0] != '\0') {
+      INET_PTON(dns2, mDns2);
+    }
+
+    INET_PTON(server, mServer);
+
+    char inet_str[64];
+    if (inet_ntop(AF_INET, &result.mMask, inet_str, sizeof(inet_str))) {
+      result.mMask_str = NS_ConvertUTF8toUTF16(inet_str);
+    }
+
+    return result;
+}
+
+CommandResult NetworkUtils::enableInterface(NetworkParams& aOptions) {
+  return mNetUtils->do_ifc_enable(
+    NS_ConvertUTF16toUTF8(aOptions.mIfname).get());
+}
+
+CommandResult NetworkUtils::disableInterface(NetworkParams& aOptions) {
+  return mNetUtils->do_ifc_disable(
+    NS_ConvertUTF16toUTF8(aOptions.mIfname).get());
+}
+
+CommandResult NetworkUtils::resetConnections(NetworkParams& aOptions) {
+  NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
+  return mNetUtils->do_ifc_reset_connections(
+    NS_ConvertUTF16toUTF8(aOptions.mIfname).get(),
+    RESET_ALL_ADDRESSES);
+}
+
 /**
  * Set default route and DNS servers for given network interface.
  */
-int32_t NetworkUtils::setDefaultRouteAndDNS(NetworkParams& aOptions)
+CommandResult NetworkUtils::setDefaultRoute(NetworkParams& aOptions)
 {
   NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
 
   if (!aOptions.mOldIfname.IsEmpty()) {
     // Remove IPv4's default route.
-    mNetUtils->do_ifc_remove_default_route(GET_CHAR(mOldIfname));
+    RETURN_IF_FAILED(mNetUtils->do_ifc_remove_default_route(GET_CHAR(mOldIfname)));
     // Remove IPv6's default route.
-    mNetUtils->do_ifc_remove_route(GET_CHAR(mOldIfname), "::", 0, NULL);
+    RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(GET_CHAR(mOldIfname), "::", 0, NULL));
   }
 
   uint32_t length = aOptions.mGateways.Length();
   if (length > 0) {
     for (uint32_t i = 0; i < length; i++) {
       NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateways[i]);
 
       int type = getIpType(autoGateway.get());
       if (type != AF_INET && type != AF_INET6) {
         continue;
       }
 
       if (type == AF_INET6) {
-        mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, autoGateway.get());
+        RETURN_IF_FAILED(mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, autoGateway.get()));
       } else { /* type == AF_INET */
-        mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(autoGateway.get()));
+        RETURN_IF_FAILED(mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(autoGateway.get())));
       }
     }
   } else {
     // Set default froute from system properties.
     char key[PROPERTY_KEY_MAX];
     char gateway[PROPERTY_KEY_MAX];
 
     snprintf(key, sizeof key - 1, "net.%s.gw", autoIfname.get());
     property_get(key, gateway, "");
 
     int type = getIpType(gateway);
     if (type != AF_INET && type != AF_INET6) {
       return EAFNOSUPPORT;
     }
 
     if (type == AF_INET6) {
-      mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, gateway);
+      RETURN_IF_FAILED(mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, gateway));
     } else { /* type == AF_INET */
-      mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(gateway));
+      RETURN_IF_FAILED(mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(gateway)));
     }
   }
 
-  setDNS(aOptions);
   return SUCCESS;
 }
 
 /**
  * Remove default route for given network interface.
  */
-int32_t NetworkUtils::removeDefaultRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::removeDefaultRoute(NetworkParams& aOptions)
 {
   uint32_t length = aOptions.mGateways.Length();
   for (uint32_t i = 0; i < length; i++) {
     NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateways[i]);
 
     int type = getIpType(autoGateway.get());
     if (type != AF_INET && type != AF_INET6) {
       return EAFNOSUPPORT;
     }
 
-    mNetUtils->do_ifc_remove_route(GET_CHAR(mIfname),
-                                   type == AF_INET ? "0.0.0.0" : "::",
-                                   0, autoGateway.get());
+    RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(GET_CHAR(mIfname),
+                                                    type == AF_INET ? "0.0.0.0" : "::",
+                                                    0, autoGateway.get()));
   }
 
   return SUCCESS;
 }
 
 /**
  * Add host route for given network interface.
  */
-int32_t NetworkUtils::addHostRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::addHostRoute(NetworkParams& aOptions)
 {
   NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
   NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp);
   NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateway);
   int type, prefix;
 
   type = getIpType(autoHostname.get());
   if (type != AF_INET && type != AF_INET6) {
@@ -1337,17 +1474,17 @@ int32_t NetworkUtils::addHostRoute(Netwo
   prefix = type == AF_INET ? 32 : 128;
   return mNetUtils->do_ifc_add_route(autoIfname.get(), autoHostname.get(),
                                      prefix, autoGateway.get());
 }
 
 /**
  * Remove host route for given network interface.
  */
-int32_t NetworkUtils::removeHostRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::removeHostRoute(NetworkParams& aOptions)
 {
   NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
   NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp);
   NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateway);
   int type, prefix;
 
   type = getIpType(autoHostname.get());
   if (type != AF_INET && type != AF_INET6) {
@@ -1361,22 +1498,22 @@ int32_t NetworkUtils::removeHostRoute(Ne
   prefix = type == AF_INET ? 32 : 128;
   return mNetUtils->do_ifc_remove_route(autoIfname.get(), autoHostname.get(),
                                         prefix, autoGateway.get());
 }
 
 /**
  * Remove the routes associated with the named interface.
  */
-int32_t NetworkUtils::removeHostRoutes(NetworkParams& aOptions)
+CommandResult NetworkUtils::removeHostRoutes(NetworkParams& aOptions)
 {
   return mNetUtils->do_ifc_remove_host_routes(GET_CHAR(mIfname));
 }
 
-int32_t NetworkUtils::removeNetworkRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::removeNetworkRoute(NetworkParams& aOptions)
 {
   NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
   NS_ConvertUTF16toUTF8 autoIp(aOptions.mIp);
 
   int type = getIpType(autoIp.get());
   if (type != AF_INET && type != AF_INET6) {
     return EAFNOSUPPORT;
   }
@@ -1401,100 +1538,100 @@ int32_t NetworkUtils::removeNetworkRoute
     }
 
     char subnetStr[INET6_ADDRSTRLEN];
     if (!inet_ntop(AF_INET6, &in6, subnetStr, sizeof subnetStr)) {
       return EINVAL;
     }
 
     // Remove default route.
-    mNetUtils->do_ifc_remove_route(autoIfname.get(), "::", 0, NULL);
+    RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), "::", 0, NULL));
 
     // Remove subnet route.
-    mNetUtils->do_ifc_remove_route(autoIfname.get(), subnetStr, prefixLength, NULL);
+    RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), subnetStr, prefixLength, NULL));
     return SUCCESS;
   }
 
   /* type == AF_INET */
   uint32_t ip = inet_addr(autoIp.get());
   uint32_t netmask = makeMask(prefixLength);
   uint32_t subnet = ip & netmask;
   const char* gateway = "0.0.0.0";
   struct in_addr addr;
   addr.s_addr = subnet;
   const char* dst = inet_ntoa(addr);
 
-  mNetUtils->do_ifc_remove_default_route(autoIfname.get());
-  mNetUtils->do_ifc_remove_route(autoIfname.get(), dst, prefixLength, gateway);
+  RETURN_IF_FAILED(mNetUtils->do_ifc_remove_default_route(autoIfname.get()));
+  RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), dst, prefixLength, gateway));
   return SUCCESS;
 }
 
-int32_t NetworkUtils::addSecondaryRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::addSecondaryRoute(NetworkParams& aOptions)
 {
   char command[MAX_COMMAND_SIZE];
   snprintf(command, MAX_COMMAND_SIZE - 1,
            "interface route add %s secondary %s %s %s",
            GET_CHAR(mIfname),
            GET_CHAR(mIp),
            GET_CHAR(mPrefix),
            GET_CHAR(mGateway));
 
   doCommand(command, nullptr, nullptr);
   return SUCCESS;
 }
 
-int32_t NetworkUtils::removeSecondaryRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::removeSecondaryRoute(NetworkParams& aOptions)
 {
   char command[MAX_COMMAND_SIZE];
   snprintf(command, MAX_COMMAND_SIZE - 1,
            "interface route remove %s secondary %s %s %s",
            GET_CHAR(mIfname),
            GET_CHAR(mIp),
            GET_CHAR(mPrefix),
            GET_CHAR(mGateway));
 
   doCommand(command, nullptr, nullptr);
   return SUCCESS;
 }
 
-int32_t NetworkUtils::setNetworkInterfaceAlarm(NetworkParams& aOptions)
+CommandResult NetworkUtils::setNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   DEBUG("setNetworkInterfaceAlarms: %s", GET_CHAR(mIfname));
   RUN_CHAIN(aOptions, sNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail);
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
-int32_t NetworkUtils::enableNetworkInterfaceAlarm(NetworkParams& aOptions)
+CommandResult NetworkUtils::enableNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   DEBUG("enableNetworkInterfaceAlarm: %s", GET_CHAR(mIfname));
   RUN_CHAIN(aOptions, sNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail);
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
-int32_t NetworkUtils::disableNetworkInterfaceAlarm(NetworkParams& aOptions)
+CommandResult NetworkUtils::disableNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   DEBUG("disableNetworkInterfaceAlarms: %s", GET_CHAR(mIfname));
   RUN_CHAIN(aOptions, sNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail);
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
 /**
  * handling main thread's reload Wifi firmware request
  */
-int32_t NetworkUtils::setWifiOperationMode(NetworkParams& aOptions)
+CommandResult NetworkUtils::setWifiOperationMode(NetworkParams& aOptions)
 {
   DEBUG("setWifiOperationMode: %s %s", GET_CHAR(mIfname), GET_CHAR(mMode));
   RUN_CHAIN(aOptions, sWifiOperationModeChain, wifiOperationModeFail);
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
 /**
  * handling main thread's enable/disable WiFi Tethering request
  */
-int32_t NetworkUtils::setWifiTethering(NetworkParams& aOptions)
+CommandResult NetworkUtils::setWifiTethering(NetworkParams& aOptions)
 {
   bool enable = aOptions.mEnable;
   IFProperties interfaceProperties;
   getIFProperties(GET_CHAR(mExternalIfname), interfaceProperties);
 
   if (strcmp(interfaceProperties.dns1, "")) {
     int type = getIpType(interfaceProperties.dns1);
     if (type != AF_INET6) {
@@ -1513,20 +1650,20 @@ int32_t NetworkUtils::setWifiTethering(N
     DEBUG("Starting Wifi Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
     RUN_CHAIN(aOptions, sWifiEnableChain, wifiTetheringFail)
   } else {
     DEBUG("Stopping Wifi Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
     RUN_CHAIN(aOptions, sWifiDisableChain, wifiTetheringFail)
   }
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
-int32_t NetworkUtils::setUSBTethering(NetworkParams& aOptions)
+CommandResult NetworkUtils::setUSBTethering(NetworkParams& aOptions)
 {
   bool enable = aOptions.mEnable;
   IFProperties interfaceProperties;
   getIFProperties(GET_CHAR(mExternalIfname), interfaceProperties);
 
   if (strcmp(interfaceProperties.dns1, "")) {
     int type = getIpType(interfaceProperties.dns1);
     if (type != AF_INET6) {
@@ -1545,61 +1682,59 @@ int32_t NetworkUtils::setUSBTethering(Ne
     DEBUG("Starting USB Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
     RUN_CHAIN(aOptions, sUSBEnableChain, usbTetheringFail)
   } else {
     DEBUG("Stopping USB Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
     RUN_CHAIN(aOptions, sUSBDisableChain, usbTetheringFail)
   }
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
 void NetworkUtils::escapeQuote(nsCString& aString)
 {
   aString.ReplaceSubstring("\\", "\\\\");
   aString.ReplaceSubstring("\"", "\\\"");
 }
 
-void NetworkUtils::checkUsbRndisState(NetworkParams& aOptions)
+CommandResult NetworkUtils::checkUsbRndisState(NetworkParams& aOptions)
 {
   static uint32_t retry = 0;
 
   char currentState[PROPERTY_VALUE_MAX];
   property_get(SYS_USB_STATE_PROPERTY, currentState, nullptr);
 
   nsTArray<nsCString> stateFuncs;
   split(currentState, USB_CONFIG_DELIMIT, stateFuncs);
   bool rndisPresent = stateFuncs.Contains(nsCString(USB_FUNCTION_RNDIS));
 
   if (aOptions.mEnable == rndisPresent) {
     NetworkResultOptions result;
     result.mEnable = aOptions.mEnable;
     result.mResult = true;
-    postMessage(aOptions, result);
     retry = 0;
-    return;
+    return result;
   }
   if (retry < USB_FUNCTION_RETRY_TIMES) {
     retry++;
     usleep(USB_FUNCTION_RETRY_INTERVAL * 1000);
-    checkUsbRndisState(aOptions);
-    return;
+    return checkUsbRndisState(aOptions);
   }
 
   NetworkResultOptions result;
   result.mResult = false;
-  postMessage(aOptions, result);
   retry = 0;
+  return result;
 }
 
 /**
  * Modify usb function's property to turn on USB RNDIS function
  */
-int32_t NetworkUtils::enableUsbRndis(NetworkParams& aOptions)
+CommandResult NetworkUtils::enableUsbRndis(NetworkParams& aOptions)
 {
   bool report = aOptions.mReport;
 
   // For some reason, rndis doesn't play well with diag,modem,nmea.
   // So when turning rndis on, we set sys.usb.config to either "rndis"
   // or "rndis,adb". When turning rndis off, we go back to
   // persist.sys.usb.config.
   //
@@ -1645,28 +1780,28 @@ int32_t NetworkUtils::enableUsbRndis(Net
   join(configFuncs, USB_CONFIG_DELIMIT, PROPERTY_VALUE_MAX, newConfig);
   if (strcmp(currentConfig, newConfig)) {
     property_set(SYS_USB_CONFIG_PROPERTY, newConfig);
   }
 
   // Trigger the timer to check usb state and report the result to NetworkManager.
   if (report) {
     usleep(USB_FUNCTION_RETRY_INTERVAL * 1000);
-    checkUsbRndisState(aOptions);
+    return checkUsbRndisState(aOptions);
   }
   return SUCCESS;
 }
 
 /**
  * handling upstream interface change event.
  */
-int32_t NetworkUtils::updateUpStream(NetworkParams& aOptions)
+CommandResult NetworkUtils::updateUpStream(NetworkParams& aOptions)
 {
   RUN_CHAIN(aOptions, sUpdateUpStreamChain, updateUpStreamFail)
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
 void NetworkUtils::sendBroadcastMessage(uint32_t code, char* reason)
 {
   NetworkResultOptions result;
   switch(code) {
     case NETD_COMMAND_INTERFACE_CHANGE:
       result.mTopic = NS_ConvertUTF8toUTF16("netd-interface-change");
--- a/dom/system/gonk/NetworkUtils.h
+++ b/dom/system/gonk/NetworkUtils.h
@@ -23,58 +23,16 @@ typedef void (*ErrorCallback)(NetworkPar
                               mozilla::dom::NetworkResultOptions& aResult);
 
 class NetworkParams
 {
 public:
   NetworkParams() {
   }
 
-  NetworkParams(const NetworkParams& aOther) {
-    mIp = aOther.mIp;
-    mCmd = aOther.mCmd;
-    mDomain = aOther.mDomain;
-    mGateway = aOther.mGateway;
-    mGateways = aOther.mGateways;
-    mId = aOther.mId;
-    mIfname = aOther.mIfname;
-    mPrefixLength = aOther.mPrefixLength;
-    mOldIfname = aOther.mOldIfname;
-    mMode = aOther.mMode;
-    mReport = aOther.mReport;
-    mIsAsync = aOther.mIsAsync;
-    mEnabled = aOther.mEnabled;
-    mWifictrlinterfacename = aOther.mWifictrlinterfacename;
-    mInternalIfname = aOther.mInternalIfname;
-    mExternalIfname = aOther.mExternalIfname;
-    mEnable = aOther.mEnable;
-    mSsid = aOther.mSsid;
-    mSecurity = aOther.mSecurity;
-    mKey = aOther.mKey;
-    mPrefix = aOther.mPrefix;
-    mLink = aOther.mLink;
-    mInterfaceList = aOther.mInterfaceList;
-    mWifiStartIp = aOther.mWifiStartIp;
-    mWifiEndIp = aOther.mWifiEndIp;
-    mUsbStartIp = aOther.mUsbStartIp;
-    mUsbEndIp = aOther.mUsbEndIp;
-    mDns1 = aOther.mDns1;
-    mDns2 = aOther.mDns2;
-    mDnses = aOther.mDnses;
-    mStartIp = aOther.mStartIp;
-    mEndIp = aOther.mEndIp;
-    mServerIp = aOther.mServerIp;
-    mMaskLength = aOther.mMaskLength;
-    mPreInternalIfname = aOther.mPreInternalIfname;
-    mPreExternalIfname = aOther.mPreExternalIfname;
-    mCurInternalIfname = aOther.mCurInternalIfname;
-    mCurExternalIfname = aOther.mCurExternalIfname;
-    mThreshold = aOther.mThreshold;
-  }
-
   NetworkParams(const mozilla::dom::NetworkCommandOptions& aOther) {
 
 #define COPY_SEQUENCE_FIELD(prop, type)                                                      \
     if (aOther.prop.WasPassed()) {                                                           \
       mozilla::dom::Sequence<type > const & currentValue = aOther.prop.InternalValue();      \
       uint32_t length = currentValue.Length();                                               \
       for (uint32_t idx = 0; idx < length; idx++) {                                          \
         prop.AppendElement(currentValue[idx]);                                               \
@@ -107,17 +65,16 @@ public:
     COPY_OPT_STRING_FIELD(mGateway, EmptyString())
     COPY_SEQUENCE_FIELD(mGateways, nsString)
     COPY_OPT_STRING_FIELD(mIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mIp, EmptyString())
     COPY_OPT_FIELD(mPrefixLength, 0)
     COPY_OPT_STRING_FIELD(mOldIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mMode, EmptyString())
     COPY_OPT_FIELD(mReport, false)
-    COPY_OPT_FIELD(mIsAsync, false)
     COPY_OPT_FIELD(mEnabled, false)
     COPY_OPT_STRING_FIELD(mWifictrlinterfacename, EmptyString())
     COPY_OPT_STRING_FIELD(mInternalIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mExternalIfname, EmptyString())
     COPY_OPT_FIELD(mEnable, false)
     COPY_OPT_STRING_FIELD(mSsid, EmptyString())
     COPY_OPT_STRING_FIELD(mSecurity, EmptyString())
     COPY_OPT_STRING_FIELD(mKey, EmptyString())
@@ -135,16 +92,21 @@ public:
     COPY_OPT_STRING_FIELD(mEndIp, EmptyString())
     COPY_OPT_STRING_FIELD(mServerIp, EmptyString())
     COPY_OPT_STRING_FIELD(mMaskLength, EmptyString())
     COPY_OPT_STRING_FIELD(mPreInternalIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mPreExternalIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mCurInternalIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mCurExternalIfname, EmptyString())
     COPY_OPT_FIELD(mThreshold, -1)
+    COPY_OPT_FIELD(mIpaddr, 0)
+    COPY_OPT_FIELD(mMask, 0)
+    COPY_OPT_FIELD(mGateway_long, 0)
+    COPY_OPT_FIELD(mDns1_long, 0)
+    COPY_OPT_FIELD(mDns2_long, 0)
 
 #undef COPY_SEQUENCE_FIELD
 #undef COPY_OPT_STRING_FIELD
 #undef COPY_OPT_FIELD
 #undef COPY_FIELD
   }
 
   int32_t mId;
@@ -153,17 +115,16 @@ public:
   nsString mGateway;
   nsTArray<nsString> mGateways;
   nsString mIfname;
   nsString mIp;
   uint32_t mPrefixLength;
   nsString mOldIfname;
   nsString mMode;
   bool mReport;
-  bool mIsAsync;
   bool mEnabled;
   nsString mWifictrlinterfacename;
   nsString mInternalIfname;
   nsString mExternalIfname;
   bool mEnable;
   nsString mSsid;
   nsString mSecurity;
   nsString mKey;
@@ -181,16 +142,21 @@ public:
   nsString mEndIp;
   nsString mServerIp;
   nsString mMaskLength;
   nsString mPreInternalIfname;
   nsString mPreExternalIfname;
   nsString mCurInternalIfname;
   nsString mCurExternalIfname;
   long mThreshold;
+  long mIpaddr;
+  long mMask;
+  long mGateway_long;
+  long mDns1_long;
+  long mDns2_long;
 };
 
 // CommandChain store the necessary information to execute command one by one.
 // Including :
 // 1. Command parameters.
 // 2. Command list.
 // 3. Error callback function.
 // 4. Index of current execution command.
@@ -230,49 +196,73 @@ public:
 private:
   uint32_t mIndex;
   NetworkParams mParams;
   CommandFunc* mCommands;
   uint32_t mLength;
   ErrorCallback mError;
 };
 
+// A helper class to easily construct a resolved
+// or a pending result for command execution.
+class CommandResult
+{
+public:
+  struct Pending {};
+
+public:
+  CommandResult(int32_t aResultCode);
+  CommandResult(const mozilla::dom::NetworkResultOptions& aResult);
+  CommandResult(const Pending&);
+  bool isPending() const;
+
+  mozilla::dom::NetworkResultOptions mResult;
+
+private:
+  bool mIsPending;
+};
+
 class NetworkUtils MOZ_FINAL
 {
 public:
   NetworkUtils(MessageCallback aCallback);
   ~NetworkUtils();
 
   void ExecuteCommand(NetworkParams aOptions);
   void onNetdMessage(mozilla::ipc::NetdCommand* aCommand);
 
   MessageCallback getMessageCallback() { return mMessageCallback; }
 
 private:
   /**
    * Commands supported by NetworkUtils.
    */
-  int32_t setDNS(NetworkParams& aOptions);
-  int32_t setDefaultRouteAndDNS(NetworkParams& aOptions);
-  int32_t addHostRoute(NetworkParams& aOptions);
-  int32_t removeDefaultRoute(NetworkParams& aOptions);
-  int32_t removeHostRoute(NetworkParams& aOptions);
-  int32_t removeHostRoutes(NetworkParams& aOptions);
-  int32_t removeNetworkRoute(NetworkParams& aOptions);
-  int32_t addSecondaryRoute(NetworkParams& aOptions);
-  int32_t removeSecondaryRoute(NetworkParams& aOptions);
-  int32_t setNetworkInterfaceAlarm(NetworkParams& aOptions);
-  int32_t enableNetworkInterfaceAlarm(NetworkParams& aOptions);
-  int32_t disableNetworkInterfaceAlarm(NetworkParams& aOptions);
-  int32_t setWifiOperationMode(NetworkParams& aOptions);
-  int32_t setDhcpServer(NetworkParams& aOptions);
-  int32_t setWifiTethering(NetworkParams& aOptions);
-  int32_t setUSBTethering(NetworkParams& aOptions);
-  int32_t enableUsbRndis(NetworkParams& aOptions);
-  int32_t updateUpStream(NetworkParams& aOptions);
+  CommandResult configureInterface(NetworkParams& aOptions);
+  CommandResult dhcpRequest(NetworkParams& aOptions);
+  CommandResult enableInterface(NetworkParams& aOptions);
+  CommandResult disableInterface(NetworkParams& aOptions);
+  CommandResult resetConnections(NetworkParams& aOptions);
+  CommandResult setDefaultRoute(NetworkParams& aOptions);
+  CommandResult addHostRoute(NetworkParams& aOptions);
+  CommandResult removeDefaultRoute(NetworkParams& aOptions);
+  CommandResult removeHostRoute(NetworkParams& aOptions);
+  CommandResult removeHostRoutes(NetworkParams& aOptions);
+  CommandResult removeNetworkRoute(NetworkParams& aOptions);
+  CommandResult setDNS(NetworkParams& aOptions);
+  CommandResult addSecondaryRoute(NetworkParams& aOptions);
+  CommandResult removeSecondaryRoute(NetworkParams& aOptions);
+  CommandResult setNetworkInterfaceAlarm(NetworkParams& aOptions);
+  CommandResult enableNetworkInterfaceAlarm(NetworkParams& aOptions);
+  CommandResult disableNetworkInterfaceAlarm(NetworkParams& aOptions);
+  CommandResult setWifiOperationMode(NetworkParams& aOptions);
+  CommandResult setDhcpServer(NetworkParams& aOptions);
+  CommandResult setWifiTethering(NetworkParams& aOptions);
+  CommandResult setUSBTethering(NetworkParams& aOptions);
+  CommandResult enableUsbRndis(NetworkParams& aOptions);
+  CommandResult updateUpStream(NetworkParams& aOptions);
 
   /**
    * function pointer array holds all netd commands should be executed
    * in sequence to accomplish a given command by other module.
    */
   static CommandFunc sWifiEnableChain[];
   static CommandFunc sWifiDisableChain[];
   static CommandFunc sWifiFailChain[];
@@ -355,17 +345,17 @@ private:
   /**
    * Notify broadcast message to main thread.
    */
   void sendBroadcastMessage(uint32_t code, char* reason);
 
   /**
    * Utility functions.
    */
-  void checkUsbRndisState(NetworkParams& aOptions);
+  CommandResult checkUsbRndisState(NetworkParams& aOptions);
   void dumpParams(NetworkParams& aOptions, const char* aType);
 
   static void escapeQuote(nsCString& aString);
   inline uint32_t netdResponseType(uint32_t code);
   inline bool isBroadcastMessage(uint32_t code);
   inline bool isError(uint32_t code);
   inline bool isComplete(uint32_t code);
   inline bool isProceeding(uint32_t code);
--- a/dom/system/gonk/NetworkWorker.cpp
+++ b/dom/system/gonk/NetworkWorker.cpp
@@ -28,34 +28,19 @@ StaticRefPtr<NetworkWorker> gNetworkWork
 // The singleton networkutils class, that can be used on any thread.
 static nsAutoPtr<NetworkUtils> gNetworkUtils;
 
 // Runnable used dispatch command result on the main thread.
 class NetworkResultDispatcher : public nsRunnable
 {
 public:
   NetworkResultDispatcher(const NetworkResultOptions& aResult)
+    : mResult(aResult)
   {
     MOZ_ASSERT(!NS_IsMainThread());
-
-#define COPY_FIELD(prop) mResult.prop = aResult.prop;
-    COPY_FIELD(mId)
-    COPY_FIELD(mRet)
-    COPY_FIELD(mBroadcast)
-    COPY_FIELD(mTopic)
-    COPY_FIELD(mReason)
-    COPY_FIELD(mResultCode)
-    COPY_FIELD(mResultReason)
-    COPY_FIELD(mError)
-    COPY_FIELD(mEnable)
-    COPY_FIELD(mResult)
-    COPY_FIELD(mSuccess)
-    COPY_FIELD(mCurExternalIfname)
-    COPY_FIELD(mCurInternalIfname)
-#undef COPY_FIELD
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (gNetworkWorker) {
       gNetworkWorker->DispatchNetworkResult(mResult);
--- a/dom/system/gonk/nsINetworkService.idl
+++ b/dom/system/gonk/nsINetworkService.idl
@@ -96,20 +96,75 @@ interface nsIUpdateUpStreamCallback : ns
    * @param success
    *        Boolean to indicate the operation is successful or not.
    * @param externalIfname
    *        The external interface name.
    */
   void updateUpStreamResult(in boolean success, in DOMString externalIfname);
 };
 
+[scriptable, function, uuid(eedca6c0-1310-11e4-9191-0800200c9a66)]
+interface nsISetDnsCallback : nsISupports
+{
+  /**
+   * Callback function used to report the result of setting DNS server.
+   *
+   * @param error
+   *        An error message if the operation wasn't successful,
+   *        or `null` if it was.
+   */
+  void setDnsResult(in jsval error);
+};
+
+[scriptable, function, uuid(5d0e1a60-1187-11e4-9191-0800200c9a66)]
+interface nsINativeCommandCallback : nsISupports
+{
+  /**
+   * Callback function used to report the result of a network native command.
+   *
+   * @param success
+   *        Boolean to indicate the operation is successful or not.
+   */
+  void nativeCommandResult(in boolean success);
+};
+
+[scriptable, function, uuid(694abb80-1187-11e4-9191-0800200c9a66)]
+interface nsIDhcpRequestCallback : nsISupports
+{
+  /**
+   * Callback function used to report the result of DHCP client request.
+   *
+   * @param success
+   *        Boolean to indicate the operation is successful or not.
+   *
+   * @param dhcpInfo
+   *        An object to represent the successful DHCP request:
+   *
+   *          - gateway_str: string
+   *          - dns1_str:    string
+   *          - dns2_str:    string
+   *          - mask_str:    string
+   *          - server_str:  string
+   *          - vendor_str:  string
+   *          - lease:       long
+   *          - mask:        long
+   *          - ipaddr:      long
+   *          - gateway:     long
+   *          - dns1:        long
+   *          - dns2:        long
+   *          - server:      long
+   */
+  void dhcpRequestResult(in boolean success, in jsval dhcpInfo);
+};
+
+
 /**
  * Provide network services.
  */
-[scriptable, uuid(ddb38428-0cf2-4c6a-a3c9-5e2f00fc54db)]
+[scriptable, uuid(9f1d78e0-1314-11e4-9191-0800200c9a66)]
 interface nsINetworkService : nsISupports
 {
   /**
    * Enable or disable Wifi Tethering
    *
    * @param enabled
    *        Boolean that indicates whether tethering should be enabled (true) or disabled (false).
    * @param config
@@ -224,29 +279,36 @@ interface nsINetworkService : nsISupport
    */
   void resetRoutingTable(in nsINetworkInterface networkInterface);
 
   /**
    * Set DNS.
    *
    * @param networkInterface
    *        The network interface which contains the DNS we want to set.
+   *
+   * @param callback
+   *        Callback to notify the result of setting DNS server.
    */
-  void setDNS(in nsINetworkInterface networkInterface);
+  void setDNS(in nsINetworkInterface networkInterface,
+              in nsISetDnsCallback callback);
 
   /**
-   * Set default route and DNS.
+   * Set default route.
    *
    * @param networkInterface
-   *        The network interface we want to set to the default route and dns.
+   *        The network interface we want to set to the default route.
    * @param oldInterface
    *        The previous network interface.
+   * @param callback
+   *        Callback to notify the result of setting default route.
    */
-  void setDefaultRouteAndDNS(in nsINetworkInterface networkInterface,
-                             in nsINetworkInterface oldInterface);
+  void setDefaultRoute(in nsINetworkInterface networkInterface,
+                       in nsINetworkInterface oldInterface,
+                       in nsINativeCommandCallback callback);
 
   /**
    * Remove default route.
    *
    * @param networkInterface
    *        The network interface we want remove from the default route.
    */
   void removeDefaultRoute(in nsINetworkInterface networkInterface);
@@ -336,9 +398,76 @@ interface nsINetworkService : nsISupport
    * @param current
    *        The current internal and external interface.
    * @param callback
    *        Callback function to report the result.
    */
   void updateUpStream(in jsval previous,
                       in jsval current,
                       in nsIUpdateUpStreamCallback callback);
+
+  /**
+   * Configure a network interface.
+   *
+   * @param config
+   *        An object containing the detail that we want to configure the interface:
+   *
+   *          - ifname:  string
+   *          - ipaddr:  long
+   *          - mask:    long
+   *          - gateway: long
+   *          - dns1:    long
+   *          - dns2:    long
+   *
+   * @param callback
+   *        Callback to notify the result of configurating network interface.
+   */
+  void configureInterface(in jsval config,
+                          in nsINativeCommandCallback callback);
+
+  /**
+   * Issue a DHCP client request.
+   *
+   * @param networkInterface
+   *        The network interface which we wnat to do the DHCP request on.
+   *
+   * @param callback
+   *        Callback to notify the result of the DHCP request.
+   */
+  void dhcpRequest(in DOMString interfaceName,
+                   in nsIDhcpRequestCallback callback);
+
+  /**
+   * Enable a network interface.
+   *
+   * @param networkInterface
+   *        The network interface name which we want to enable.
+   *
+   * @param callback
+   *        Callback to notify the result of disabling network interface.
+   */
+  void enableInterface(in DOMString interfaceName,
+                       in nsINativeCommandCallback callback);
+
+  /**
+   * Disable a network interface.
+   *
+   * @param networkInterface
+   *        The network interface name which we want to disable.
+   *
+   * @param callback
+   *        Callback to notify the result of disabling network interface.
+   */
+  void disableInterface(in DOMString interfaceName,
+                        in nsINativeCommandCallback callback);
+
+  /**
+   * Reset all connections
+   *
+   * @param networkInterface
+   *        The network interface name which we want to reset.
+   *
+   * @param callback
+   *        Callback to notify the result of resetting connections.
+   */
+  void resetConnections(in DOMString interfaceName,
+                        in nsINativeCommandCallback callback);
 };
--- a/dom/webidl/NetworkOptions.webidl
+++ b/dom/webidl/NetworkOptions.webidl
@@ -17,17 +17,16 @@ dictionary NetworkCommandOptions
   unsigned long prefixLength;         // for "removeNetworkRoute".
   DOMString domain;                   // for "setDNS"
   sequence<DOMString> dnses;          // for "setDNS", "setDefaultRouteAndDNS".
   DOMString oldIfname;                // for "setDefaultRouteAndDNS".
   DOMString gateway;                  // for "addSecondaryRoute", "removeSecondaryRoute".
   sequence<DOMString> gateways;       // for "setDefaultRouteAndDNS", "removeDefaultRoute".
   DOMString mode;                     // for "setWifiOperationMode".
   boolean report;                     // for "setWifiOperationMode".
-  boolean isAsync;                    // for "setWifiOperationMode".
   boolean enabled;                    // for "setDhcpServer".
   DOMString wifictrlinterfacename;    // for "setWifiTethering".
   DOMString internalIfname;           // for "setWifiTethering".
   DOMString externalIfname;           // for "setWifiTethering".
   boolean enable;                     // for "setWifiTethering".
   DOMString ssid;                     // for "setWifiTethering".
   DOMString security;                 // for "setWifiTethering".
   DOMString key;                      // for "setWifiTethering".
@@ -45,16 +44,22 @@ dictionary NetworkCommandOptions
   DOMString startIp;                  // for "setDhcpServer".
   DOMString endIp;                    // for "setDhcpServer".
   DOMString serverIp;                 // for "setDhcpServer".
   DOMString maskLength;               // for "setDhcpServer".
   DOMString preInternalIfname;        // for "updateUpStream".
   DOMString preExternalIfname;        // for "updateUpStream".
   DOMString curInternalIfname;        // for "updateUpStream".
   DOMString curExternalIfname;        // for "updateUpStream".
+
+  long ipaddr;                        // for "ifc_configure".
+  long mask;                          // for "ifc_configure".
+  long gateway_long;                  // for "ifc_configure".
+  long dns1_long;                     // for "ifc_configure".
+  long dns2_long;                     // for "ifc_configure".
 };
 
 /**
 * This dictionary holds the parameters sent back to NetworkService.js.
 */
 dictionary NetworkResultOptions
 {
   long id = 0;                        // opaque id.
@@ -68,9 +73,27 @@ dictionary NetworkResultOptions
   boolean error = false;              // for all commands.
 
   boolean enable = false;             // for "setWifiTethering", "setUSBTethering"
                                       //     "enableUsbRndis".
   boolean result = false;             // for "enableUsbRndis".
   boolean success = false;            // for "setDhcpServer".
   DOMString curExternalIfname = "";   // for "updateUpStream".
   DOMString curInternalIfname = "";   // for "updateUpStream".
+
+  DOMString reply = "";               // for "command".
+  DOMString route = "";               // for "ifc_get_default_route".
+  DOMString ipaddr_str = "";          // The following are for the result of
+                                      // dhcp_do_request.
+  DOMString gateway_str = "";
+  DOMString dns1_str = "";
+  DOMString dns2_str = "";
+  DOMString mask_str = "";
+  DOMString server_str = "";
+  DOMString vendor_str = "";
+  long      lease = 0;
+  long      mask = 0;
+  long      ipaddr = 0;
+  long      gateway = 0;
+  long      dns1 = 0;
+  long      dns2 = 0;
+  long      server = 0;
 };
--- a/dom/webidl/WifiOptions.webidl
+++ b/dom/webidl/WifiOptions.webidl
@@ -5,61 +5,27 @@
 /**
   * This dictionnary holds the parameters sent to the wifi service.
   */
 dictionary WifiCommandOptions
 {
   long      id = 0;       // opaque id.
   DOMString cmd = "";     // the command name.
   DOMString request;      // for "command"
-  DOMString ifname;       // for "ifc_reset_connections", "ifc_enable",
-                          // "ifc_disable", "ifc_remove_host_routes",
-                          // "ifc_remove_default_route", "dhcp_stop",
-                          // "dhcp_release_lease", "ifc_get_default_route",
-                          // "ifc_add_host_route", "ifc_set_default_route",
-                          // "ifc_configure", "dhcp_do_request",
-                          // "dhcp_do_request_renew".
-  long route;             // for "ifc_add_host_route", "ifc_set_default_route".
-  long ipaddr;            // for "ifc_configure".
-  long mask;              // for "ifc_configure".
-  long gateway;           // for "ifc_configure".
-  long dns1;              // for "ifc_configure".
-  long dns2;              // for "ifc_configure".
-  DOMString key;          // for "property_get", "property_set".
-  DOMString value;        // for "property_set".
-  DOMString defaultValue; // for "property_get".
 };
 
 /**
   * This dictionnary holds the parameters sent back to WifiWorker.js
   */
 dictionary WifiResultOptions
 {
   long      id = 0;             // opaque id.
   long      status = 0;         // the return status of the command.
                                 // Used by most commands.
   DOMString reply = "";         // for "command".
-  DOMString route = "";         // for "ifc_get_default_route".
-  DOMString error = "";         // for "dhcp_get_errmsg".
-  DOMString value = "";         // for "property_get".
-  DOMString ipaddr_str = "";    // The following are for the result of
-                                // dhcp_do_request.
-  DOMString gateway_str = "";
-  DOMString dns1_str = "";
-  DOMString dns2_str = "";
-  DOMString mask_str = "";
-  DOMString server_str = "";
-  DOMString vendor_str = "";
-  long      lease = 0;
-  long      mask = 0;
-  long      ipaddr = 0;
-  long      gateway = 0;
-  long      dns1 = 0;
-  long      dns2 = 0;
-  long      server = 0;
 };
 
 
 /**
   * This dictionary holds the callback parameter sent back from WifiCertService
   * to WifiWorker, and should only be passed around in chrome process.
   */
 dictionary WifiCertServiceResultOptions
--- a/dom/wifi/WifiNetUtil.jsm
+++ b/dom/wifi/WifiNetUtil.jsm
@@ -25,126 +25,45 @@ this.WifiNetUtil = function(controlMessa
   function debug(msg) {
     if (DEBUG) {
       dump('-------------- NetUtil: ' + msg);
     }
   }
 
   var util = {};
 
-  util.configureInterface = function(cfg, callback) {
-    let message = { cmd:     "ifc_configure",
-                    ifname:  cfg.ifname,
-                    ipaddr:  cfg.ipaddr,
-                    mask:    cfg.mask,
-                    gateway: cfg.gateway,
-                    dns1:    cfg.dns1,
-                    dns2:    cfg.dns2 };
-
-    controlMessage(message, function(data) {
-      callback(!data.status);
-    });
-  };
-
   util.runDhcp = function (ifname, callback) {
-    controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
-      var dhcpInfo = data.status ? null : data;
+    gNetworkService.dhcpRequest(ifname, function(success, dhcpInfo) {
       util.runIpConfig(ifname, dhcpInfo, callback);
     });
   };
 
   util.stopDhcp = function (ifname, callback) {
     // This function does exactly what dhcp_stop does. Unforunately, if we call
     // this function twice before the previous callback is returned. We may block
     // our self waiting for the callback. It slows down the wifi startup procedure.
     // Therefore, we have to roll our own version here.
     let dhcpService = DHCP_PROP + "_" + ifname;
     let suffix = (ifname.substr(0, 3) === "p2p") ? "p2p" : ifname;
     let processName = DHCP + "_" + suffix;
     stopProcess(dhcpService, processName, callback);
   };
 
-  util.enableInterface = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_enable", ifname: ifname }, function (data) {
-      callback(!data.status);
-    });
-  };
-
-  util.disableInterface = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_disable", ifname: ifname }, function (data) {
-      callback(!data.status);
-    });
-  };
-
   util.startDhcpServer = function (config, callback) {
     gNetworkService.setDhcpServer(true, config, function (error) {
       callback(!error);
     });
   };
 
   util.stopDhcpServer = function (callback) {
     gNetworkService.setDhcpServer(false, null, function (error) {
       callback(!error);
     });
   };
 
-  util.addHostRoute = function (ifname, route, callback) {
-    controlMessage({ cmd: "ifc_add_host_route", ifname: ifname, route: route }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.removeHostRoutes = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_remove_host_routes", ifname: ifname }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.setDefaultRoute = function (ifname, route, callback) {
-    controlMessage({ cmd: "ifc_set_default_route", ifname: ifname, route: route }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.getDefaultRoute = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_get_default_route", ifname: ifname }, function(data) {
-      callback(!data.route);
-    });
-  };
-
-  util.removeDefaultRoute = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_remove_default_route", ifname: ifname }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.resetConnections = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_reset_connections", ifname: ifname }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.releaseDhcpLease = function (ifname, callback) {
-    controlMessage({ cmd: "dhcp_release_lease", ifname: ifname }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.getDhcpError = function (callback) {
-    controlMessage({ cmd: "dhcp_get_errmsg" }, function(data) {
-      callback(data.error);
-    });
-  };
-
-  util.runDhcpRenew = function (ifname, callback) {
-    controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
-      callback(data.status ? null : data);
-    });
-  };
-
   util.runIpConfig = function (name, data, callback) {
     if (!data) {
       debug("IP config failed to run");
       callback({ info: data });
       return;
     }
 
     setProperty("net." + name + ".dns1", ipToString(data.dns1),
--- a/dom/wifi/WifiP2pManager.jsm
+++ b/dom/wifi/WifiP2pManager.jsm
@@ -16,16 +16,20 @@ Cu.import("resource://gre/modules/system
 XPCOMUtils.defineLazyServiceGetter(this, "gSysMsgr",
                                    "@mozilla.org/system-message-internal;1",
                                    "nsISystemMessagesInternal");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
                                    "@mozilla.org/network/manager;1",
                                    "nsINetworkManager");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
+                                   "@mozilla.org/network/service;1",
+                                   "nsINetworkService");
+
 this.EXPORTED_SYMBOLS = ["WifiP2pManager"];
 
 const EVENT_IGNORED                      = -1;
 const EVENT_UNKNOWN                      = -2;
 
 // Events from supplicant for p2p.
 const EVENT_P2P_DEVICE_FOUND             = 0;
 const EVENT_P2P_DEVICE_LOST              = 1;
@@ -642,17 +646,17 @@ function P2pStateMachine(aP2pCommand, aN
             onFailure();
             return;
           }
 
           debug('P2P is enabled! Enabling net interface...');
 
           // Step 4: Enable p2p0 net interface. wpa_supplicant may have
           //         already done it for us.
-          aNetUtil.enableInterface(P2P_INTERFACE_NAME, function (success) {
+          gNetworkService.enableInterface(P2P_INTERFACE_NAME, function (success) {
             onSuccess();
           });
         });
       });
     },
 
     handleEvent: function(aEvent) {
       // We won't receive any event since all of them will be blocked.
@@ -1313,17 +1317,17 @@ function P2pStateMachine(aP2pCommand, aN
     enter: function() {
       _sm.pause();
       aNetUtil.stopDhcpServer(function (success) { // Stopping DHCP server is harmless.
         debug('Stop DHCP server result: ' + success);
         aP2pCommand.p2pDisable(function(success) {
           debug('P2P function disabled');
           aP2pCommand.closeSupplicantConnection(function (status) {
             debug('Supplicant connection closed');
-            aNetUtil.disableInterface(P2P_INTERFACE_NAME, function (success){
+            gNetworkService.disableInterface(P2P_INTERFACE_NAME, function (success){
               debug('Disabled interface: ' + P2P_INTERFACE_NAME);
               _onDisabled(true);
               _sm.gotoState(stateDisabled);
             });
           });
         });
       });
     },
--- a/dom/wifi/WifiProxyService.cpp
+++ b/dom/wifi/WifiProxyService.cpp
@@ -84,46 +84,20 @@ private:
   nsCString mInterface;
 };
 
 // Runnable used dispatch the Command result on the main thread.
 class WifiResultDispatcher : public nsRunnable
 {
 public:
   WifiResultDispatcher(WifiResultOptions& aResult, const nsACString& aInterface)
-    : mInterface(aInterface)
+    : mResult(aResult)
+    , mInterface(aInterface)
   {
     MOZ_ASSERT(!NS_IsMainThread());
-
-    // XXX: is there a better way to copy webidl dictionnaries?
-    // the copy constructor is private.
-#define COPY_FIELD(prop) mResult.prop = aResult.prop;
-
-    COPY_FIELD(mId)
-    COPY_FIELD(mStatus)
-    COPY_FIELD(mReply)
-    COPY_FIELD(mRoute)
-    COPY_FIELD(mError)
-    COPY_FIELD(mValue)
-    COPY_FIELD(mIpaddr_str)
-    COPY_FIELD(mGateway_str)
-    COPY_FIELD(mDns1_str)
-    COPY_FIELD(mDns2_str)
-    COPY_FIELD(mMask_str)
-    COPY_FIELD(mServer_str)
-    COPY_FIELD(mVendor_str)
-    COPY_FIELD(mLease)
-    COPY_FIELD(mMask)
-    COPY_FIELD(mIpaddr)
-    COPY_FIELD(mGateway)
-    COPY_FIELD(mDns1)
-    COPY_FIELD(mDns2)
-    COPY_FIELD(mServer)
-
-#undef COPY_FIELD
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
     gWifiProxyService->DispatchWifiResult(mResult, mInterface);
     return NS_OK;
   }
--- a/dom/wifi/WifiUtils.cpp
+++ b/dom/wifi/WifiUtils.cpp
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WifiUtils.h"
 #include <dlfcn.h>
 #include <errno.h>
 #include <cutils/properties.h>
 #include "prinit.h"
 #include "js/CharacterEncoding.h"
-#include "mozilla/dom/network/NetUtils.h"
 
 using namespace mozilla::dom;
 
 #define BUFFER_SIZE        4096
 #define COMMAND_SIZE       256
 #define PROPERTY_VALUE_MAX 80
 
 // Intentionally not trying to dlclose() this handle. That's playing
@@ -375,24 +374,27 @@ public:
     USE_DLFUNC(wifi_command)
     return wifi_command(command, buf, len);
   }
 };
 
 // Concrete class to use to access the wpa supplicant.
 WpaSupplicant::WpaSupplicant()
 {
-  if (NetUtils::SdkVersion() < 16) {
+  char propVersion[PROPERTY_VALUE_MAX];
+  property_get("ro.build.version.sdk", propVersion, "0");
+  mSdkVersion = strtol(propVersion, nullptr, 10);
+
+  if (mSdkVersion < 16) {
     mImpl = new ICSWpaSupplicantImpl();
-  } else if (NetUtils::SdkVersion() < 19) {
+  } else if (mSdkVersion < 19) {
     mImpl = new JBWpaSupplicantImpl();
   } else {
     mImpl = new KKWpaSupplicantImpl();
   }
-  mNetUtils = new NetUtils();
   mWifiHotspotUtils = new WifiHotspotUtils();
 };
 
 void WpaSupplicant::WaitForEvent(nsAString& aEvent, const nsCString& aInterface)
 {
   CHECK_HWLIB()
 
   char buffer[BUFFER_SIZE];
@@ -413,19 +415,16 @@ uint32_t WpaSupplicant::MakeMask(uint32_
   return ntohl(mask);
 }
 
 bool WpaSupplicant::ExecuteCommand(CommandOptions aOptions,
                                    WifiResultOptions& aResult,
                                    const nsCString& aInterface)
 {
   CHECK_HWLIB(false)
-  if (!mNetUtils->GetSharedLibrary()) {
-    return false;
-  }
 
   if (!mWifiHotspotUtils->GetSharedLibrary()) {
     return false;
   }
 
   // Always correlate the opaque ids.
   aResult.mId = aOptions.mId;
 
@@ -450,91 +449,16 @@ bool WpaSupplicant::ExecuteCommand(Comma
   } else if (aOptions.mCmd.EqualsLiteral("unload_driver")) {
     aResult.mStatus = mImpl->do_wifi_unload_driver();
   } else if (aOptions.mCmd.EqualsLiteral("start_supplicant")) {
     aResult.mStatus = mImpl->do_wifi_start_supplicant(GetWifiP2pSupported() ? 1 : 0);
   } else if (aOptions.mCmd.EqualsLiteral("stop_supplicant")) {
     aResult.mStatus = mImpl->do_wifi_stop_supplicant(0);
   } else if (aOptions.mCmd.EqualsLiteral("connect_to_supplicant")) {
     aResult.mStatus = mImpl->do_wifi_connect_to_supplicant(aInterface.get());
-  } else if (aOptions.mCmd.EqualsLiteral("ifc_enable")) {
-    aResult.mStatus = mNetUtils->do_ifc_enable(GET_CHAR(mIfname));
-  } else if (aOptions.mCmd.EqualsLiteral("ifc_disable")) {
-    aResult.mStatus = mNetUtils->do_ifc_disable(GET_CHAR(mIfname));
-  } else if (aOptions.mCmd.EqualsLiteral("ifc_configure")) {
-    aResult.mStatus = mNetUtils->do_ifc_configure(
-      GET_CHAR(mIfname), aOptions.mIpaddr, aOptions.mMask,
-      aOptions.mGateway, aOptions.mDns1, aOptions.mDns2
-    );
-  } else if (aOptions.mCmd.EqualsLiteral("ifc_reset_connections")) {
-    aResult.mStatus = mNetUtils->do_ifc_reset_connections(
-      GET_CHAR(mIfname), RESET_ALL_ADDRESSES
-    );
-  } else if (aOptions.mCmd.EqualsLiteral("dhcp_stop")) {
-    aResult.mStatus = mNetUtils->do_dhcp_stop(GET_CHAR(mIfname));
-  } else if (aOptions.mCmd.EqualsLiteral("dhcp_do_request")) {
-    char ipaddr[PROPERTY_VALUE_MAX];
-    char gateway[PROPERTY_VALUE_MAX];
-    uint32_t prefixLength;
-    char dns1[PROPERTY_VALUE_MAX];
-    char dns2[PROPERTY_VALUE_MAX];
-    char server[PROPERTY_VALUE_MAX];
-    uint32_t lease;
-    char vendorinfo[PROPERTY_VALUE_MAX];
-    aResult.mStatus =
-      mNetUtils->do_dhcp_do_request(GET_CHAR(mIfname),
-                                    ipaddr,
-                                    gateway,
-                                    &prefixLength,
-                                    dns1,
-                                    dns2,
-                                    server,
-                                    &lease,
-                                    vendorinfo);
-
-    if (aResult.mStatus == -1) {
-      // Early return since we failed.
-      return true;
-    }
-
-    aResult.mIpaddr_str = NS_ConvertUTF8toUTF16(ipaddr);
-    aResult.mGateway_str = NS_ConvertUTF8toUTF16(gateway);
-    aResult.mDns1_str = NS_ConvertUTF8toUTF16(dns1);
-    aResult.mDns2_str = NS_ConvertUTF8toUTF16(dns2);
-    aResult.mServer_str = NS_ConvertUTF8toUTF16(server);
-    aResult.mVendor_str = NS_ConvertUTF8toUTF16(vendorinfo);
-    aResult.mLease = lease;
-    aResult.mMask = MakeMask(prefixLength);
-
-    uint32_t inet4; // only support IPv4 for now.
-
-#define INET_PTON(var, field)                                                 \
-  PR_BEGIN_MACRO                                                              \
-    inet_pton(AF_INET, var, &inet4);                                          \
-    aResult.field = inet4;                                                    \
-  PR_END_MACRO
-
-    INET_PTON(ipaddr, mIpaddr);
-    INET_PTON(gateway, mGateway);
-
-    if (dns1[0] != '\0') {
-      INET_PTON(dns1, mDns1);
-    }
-
-    if (dns2[0] != '\0') {
-      INET_PTON(dns2, mDns2);
-    }
-
-    INET_PTON(server, mServer);
-
-    //aResult.mask_str = netHelpers.ipToString(obj.mask);
-    char inet_str[64];
-    if (inet_ntop(AF_INET, &aResult.mMask, inet_str, sizeof(inet_str))) {
-      aResult.mMask_str = NS_ConvertUTF8toUTF16(inet_str);
-    }
   } else if (aOptions.mCmd.EqualsLiteral("hostapd_command")) {
     size_t len = BUFFER_SIZE - 1;
     char buffer[BUFFER_SIZE];
     NS_ConvertUTF16toUTF8 request(aOptions.mRequest);
     aResult.mStatus = mWifiHotspotUtils->do_wifi_hostapd_command(request.get(),
                                                                  buffer,
                                                                  &len);
     nsString value;
@@ -590,17 +514,17 @@ void
 WpaSupplicant::CheckBuffer(char* buffer, int32_t length,
                            nsAString& aEvent)
 {
   if (length <= 0 || length >= (BUFFER_SIZE - 1)) {
     NS_WARNING("WpaSupplicant::CheckBuffer: Invalid buffer length");
     return;
   }
 
-  if (NetUtils::SdkVersion() < 18) {
+  if (mSdkVersion < 18) {
     buffer[length] = 0;
     LossyConvertUTF8toUTF16(buffer, length, aEvent);
     return;
   }
 
   // After Android JB4.3, the SSIDs have been converted into printable form.
   // In most of cases, SSIDs do not use unprintable characters, but IEEE 802.11
   // standard does not limit the used character set, so anything could be used
--- a/dom/wifi/WifiUtils.h
+++ b/dom/wifi/WifiUtils.h
@@ -8,81 +8,44 @@
  */
 
 #ifndef WifiUtils_h
 #define WifiUtils_h
 
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "mozilla/dom/WifiOptionsBinding.h"
-#include "mozilla/dom/network/NetUtils.h"
 #include "WifiHotspotUtils.h"
 
 // Needed to add a copy constructor to WifiCommandOptions.
 struct CommandOptions
 {
 public:
-  CommandOptions(const CommandOptions& aOther) {
-    mId = aOther.mId;
-    mCmd = aOther.mCmd;
-    mRequest = aOther.mRequest;
-    mIfname = aOther.mIfname;
-    mRoute = aOther.mRoute;
-    mIpaddr = aOther.mIpaddr;
-    mMask = aOther.mMask;
-    mGateway = aOther.mGateway;
-    mDns1 = aOther.mDns1;
-    mDns2 = aOther.mDns2;
-    mKey = aOther.mKey;
-    mValue = aOther.mValue;
-    mDefaultValue = aOther.mDefaultValue;
-  }
-
   CommandOptions(const mozilla::dom::WifiCommandOptions& aOther) {
 
 #define COPY_OPT_FIELD(prop, defaultValue)            \
     if (aOther.prop.WasPassed()) {                    \
       prop = aOther.prop.Value();                     \
     } else {                                          \
       prop = defaultValue;                            \
     }
 
 #define COPY_FIELD(prop) prop = aOther.prop;
     COPY_FIELD(mId)
     COPY_FIELD(mCmd)
     COPY_OPT_FIELD(mRequest, EmptyString())
-    COPY_OPT_FIELD(mIfname, EmptyString())
-    COPY_OPT_FIELD(mIpaddr, 0)
-    COPY_OPT_FIELD(mRoute, 0)
-    COPY_OPT_FIELD(mMask, 0)
-    COPY_OPT_FIELD(mGateway, 0)
-    COPY_OPT_FIELD(mDns1, 0)
-    COPY_OPT_FIELD(mDns2, 0)
-    COPY_OPT_FIELD(mKey, EmptyString())
-    COPY_OPT_FIELD(mValue, EmptyString())
-    COPY_OPT_FIELD(mDefaultValue, EmptyString())
 
 #undef COPY_OPT_FIELD
 #undef COPY_FIELD
   }
 
   // All the fields, not Optional<> anymore to get copy constructors.
   nsString mCmd;
-  nsString mDefaultValue;
-  int32_t mDns1;
-  int32_t mDns2;
-  int32_t mGateway;
   int32_t mId;
-  nsString mIfname;
-  int32_t mIpaddr;
-  nsString mKey;
-  int32_t mMask;
   nsString mRequest;
-  int32_t mRoute;
-  nsString mValue;
 };
 
 // Abstract class that exposes libhardware_legacy functions we need for
 // wifi management.
 // We use the ICS signatures here since they are likely more future-proof.
 class WpaSupplicantImpl
 {
 public:
@@ -125,17 +88,18 @@ public:
   // conversion
   void WaitForEvent(nsAString& aEvent, const nsCString& aInterface);
   bool ExecuteCommand(CommandOptions aOptions,
                       mozilla::dom::WifiResultOptions& result,
                       const nsCString& aInterface);
 
 private:
   nsAutoPtr<WpaSupplicantImpl> mImpl;
-  nsAutoPtr<NetUtils> mNetUtils;
   nsAutoPtr<WifiHotspotUtils> mWifiHotspotUtils;
 
+  uint32_t mSdkVersion;
+
 protected:
   void CheckBuffer(char* buffer, int32_t length, nsAString& aEvent);
   uint32_t MakeMask(uint32_t len);
 };
 
 #endif // WifiUtils_h
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -410,18 +410,18 @@ var WifiManager = (function() {
 
       // 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.
-        netUtil.disableInterface(manager.ifname, function (ok) {
-          netUtil.enableInterface(manager.ifname, function (ok) {
+        gNetworkService.disableInterface(manager.ifname, function (ok) {
+          gNetworkService.enableInterface(manager.ifname, function (ok) {
           });
         });
       }
     });
   }
 
   var dhcpInfo = null;
 
@@ -437,22 +437,22 @@ var WifiManager = (function() {
     staticIpInfo = staticIpConfig[key];
 
     // Stop dhcpd when use static IP
     if (dhcpInfo != null) {
       netUtil.stopDhcp(manager.ifname, function() {});
     }
 
     // Set ip, mask length, gateway, dns to network interface
-    netUtil.configureInterface( { ifname: ifname,
-                                  ipaddr: staticIpInfo.ipaddr,
-                                  mask: staticIpInfo.maskLength,
-                                  gateway: staticIpInfo.gateway,
-                                  dns1: staticIpInfo.dns1,
-                                  dns2: staticIpInfo.dns2 }, function (data) {
+    gNetworkService.configureInterface( { ifname: ifname,
+                                          ipaddr: staticIpInfo.ipaddr,
+                                          mask: staticIpInfo.maskLength,
+                                          gateway: staticIpInfo.gateway,
+                                          dns1: staticIpInfo.dns1,
+                                          dns2: staticIpInfo.dns2 }, function (data) {
       netUtil.runIpConfig(ifname, staticIpInfo, function(data) {
         dhcpInfo = data.info;
         notify("networkconnected", data);
       });
     });
   }
 
   var suppressEvents = false;
@@ -582,27 +582,27 @@ var WifiManager = (function() {
 
     retryTimer = null;
     connectTries = 0;
     notify("supplicantlost", { success: false });
   }
 
   manager.connectionDropped = function(callback) {
     // Reset network interface when connection drop
-    netUtil.configureInterface( { ifname: manager.ifname,
-                                  ipaddr: 0,
-                                  mask: 0,
-                                  gateway: 0,
-                                  dns1: 0,
-                                  dns2: 0 }, function (data) {
+    gNetworkService.configureInterface( { ifname: manager.ifname,
+                                          ipaddr: 0,
+                                          mask: 0,
+                                          gateway: 0,
+                                          dns1: 0,
+                                          dns2: 0 }, function (data) {
     });
 
     // If we got disconnected, kill the DHCP client in preparation for
     // reconnection.
-    netUtil.resetConnections(manager.ifname, function() {
+    gNetworkService.resetConnections(manager.ifname, function() {
       netUtil.stopDhcp(manager.ifname, function() {
         callback();
       });
     });
   }
 
   manager.start = function() {
     debug("detected SDK version " + sdkVersion);
@@ -884,17 +884,17 @@ var WifiManager = (function() {
     function tryStopSupplicant () {
       let status = libcutils.property_get(SUPP_PROP);
       if (status !== "running") {
         callback();
         return;
       }
       suppressEvents = true;
       wifiCommand.killSupplicant(function() {
-        netUtil.disableInterface(manager.ifname, function (ok) {
+        gNetworkService.disableInterface(manager.ifname, function (ok) {
           suppressEvents = false;
           callback();
         });
       });
     }
   }
 
   // Initial state.
@@ -991,17 +991,17 @@ var WifiManager = (function() {
                   unloadDriver(WIFI_FIRMWARE_STATION, function() {
                     callback(status);
                   });
                   manager.state = "UNINITIALIZED";
                   return;
                 }
 
                 manager.supplicantStarted = true;
-                netUtil.enableInterface(manager.ifname, function (ok) {
+                gNetworkService.enableInterface(manager.ifname, function (ok) {
                   callback(ok ? 0 : -1);
                 });
               });
             }
 
             function doStartSupplicant() {
               cancelWaitForDriverReadyTimer();
 
@@ -1035,17 +1035,17 @@ var WifiManager = (function() {
       // supplicant gracefully, then we need to continue telling it to die
       // until it does.
       let doDisableWifi = function() {
         manager.stopSupplicantCallback = (function () {
           wifiCommand.stopSupplicant(function (status) {
             wifiCommand.closeSupplicantConnection(function() {
               manager.connectToSupplicant = false;
               manager.state = "UNINITIALIZED";
-              netUtil.disableInterface(manager.ifname, function (ok) {
+              gNetworkService.disableInterface(manager.ifname, function (ok) {
                 unloadDriver(WIFI_FIRMWARE_STATION, callback);
               });
             });
           });
         }).bind(this);
 
         let terminateEventCallback = (function() {
           handleEvent("CTRL-EVENT-TERMINATING");