Merge b2g-inbound to m-c on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 29 Jan 2014 15:37:19 -0500
changeset 181860 73eefb421e2afe6cc34a66d5bbb1896dbea13728
parent 181806 90bfbf075f3f4f2e49cfe4b7155289b00f2a05c8 (current diff)
parent 181859 27ab0949047e2fd6b28e19cdd0a0d00aaa03b348 (diff)
child 181861 67fcec5a2779eb6c553f13e30e4a978a8be04f31
child 181882 c45c9d81123bcce09b795c4337ee18afd177abf1
child 181939 9441e41f5f29712bbbc073aeb7acc38395bdda65
child 182090 3f021e06a878823693d2ede45804bca1bab92e1a
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone29.0a1
first release with
nightly linux32
73eefb421e2a / 29.0a1 / 20140130030202 / files
nightly linux64
73eefb421e2a / 29.0a1 / 20140130030202 / files
nightly mac
73eefb421e2a / 29.0a1 / 20140130030202 / files
nightly win32
73eefb421e2a / 29.0a1 / 20140130030202 / files
nightly win64
73eefb421e2a / 29.0a1 / 20140130030202 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge b2g-inbound to m-c on a CLOSED TREE.
dom/system/gonk/net_worker.js
dom/wifi/NetUtils.cpp
dom/wifi/NetUtils.h
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -7,17 +7,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea7971a9f5bbf63a3977161f09ce7138202c7c62"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0bc0e703df197d46dfffb9ac65cb85d2e3e10c4a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -6,17 +6,17 @@
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="317f25e0a4cb3e8e86e2b76c37a14081372f0307">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea7971a9f5bbf63a3977161f09ce7138202c7c62"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0bc0e703df197d46dfffb9ac65cb85d2e3e10c4a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -7,17 +7,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea7971a9f5bbf63a3977161f09ce7138202c7c62"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0bc0e703df197d46dfffb9ac65cb85d2e3e10c4a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "9e678fbbf8a8d15376fa1e9ec84d5d91ef10cc58", 
+    "revision": "621040ee199cdde3bdd2aeaf2a016ff7806875bb", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -6,17 +6,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea7971a9f5bbf63a3977161f09ce7138202c7c62"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0bc0e703df197d46dfffb9ac65cb85d2e3e10c4a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -5,17 +5,17 @@
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea7971a9f5bbf63a3977161f09ce7138202c7c62"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0bc0e703df197d46dfffb9ac65cb85d2e3e10c4a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -7,17 +7,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea7971a9f5bbf63a3977161f09ce7138202c7c62"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0bc0e703df197d46dfffb9ac65cb85d2e3e10c4a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -6,17 +6,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea7971a9f5bbf63a3977161f09ce7138202c7c62"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0bc0e703df197d46dfffb9ac65cb85d2e3e10c4a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -6,17 +6,17 @@
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="317f25e0a4cb3e8e86e2b76c37a14081372f0307">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea7971a9f5bbf63a3977161f09ce7138202c7c62"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0bc0e703df197d46dfffb9ac65cb85d2e3e10c4a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -113,17 +113,17 @@
   <project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
   <project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
   <project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
   <!-- Nexus 4 specific things -->
-  <project name="device-mako" path="device/lge/mako" remote="b2g" revision="59877c64bb3665441547f9e7a9a990394393bffc"/>
+  <project name="device-mako" path="device/lge/mako" remote="b2g" revision="55a5f7def3310ba245102a97270daf1c052c058d"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
   <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="f995ccdb7c023b7edd8064c9d06fbea8f7108c45"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
   <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -6,17 +6,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea7971a9f5bbf63a3977161f09ce7138202c7c62"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0bc0e703df197d46dfffb9ac65cb85d2e3e10c4a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/content/media/encoder/OmxTrackEncoder.cpp
+++ b/content/media/encoder/OmxTrackEncoder.cpp
@@ -202,18 +202,16 @@ OmxAudioTrackEncoder::AppendEncodedFrame
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!frameData.IsEmpty()) {
     bool isCSD = false;
     if (outFlags & OMXCodecWrapper::BUFFER_CODEC_CONFIG) { // codec specific data
       isCSD = true;
     } else if (outFlags & OMXCodecWrapper::BUFFER_EOS) { // last frame
       mEncodingComplete = true;
-    } else {
-      MOZ_ASSERT(frameData.Length() == OMXCodecWrapper::kAACFrameSize);
     }
 
     nsRefPtr<EncodedFrame> audiodata = new EncodedFrame();
     audiodata->SetFrameType(isCSD ?
       EncodedFrame::AAC_CSD : EncodedFrame::AUDIO_FRAME);
     audiodata->SetTimeStamp(outTimeUs);
     audiodata->SetFrameData(&frameData);
     aContainer.AppendEncodedFrame(audiodata);
@@ -238,24 +236,36 @@ OmxAudioTrackEncoder::GetEncodedTrack(En
 
     if (mCanceled || mEncodingComplete) {
       return NS_ERROR_FAILURE;
     }
 
     segment.AppendFrom(&mRawSegment);
   }
 
-  if (!mEosSetInEncoder) {
-    if (mEndOfStream) {
+  nsresult rv;
+  if (segment.GetDuration() == 0) {
+    // Notify EOS at least once, even if segment is empty.
+    if (mEndOfStream && !mEosSetInEncoder) {
       mEosSetInEncoder = true;
-    }
-    if (segment.GetDuration() > 0 || mEndOfStream) {
-      // Notify EOS at least once, even when segment is empty.
-      nsresult rv = mEncoder->Encode(segment,
-                                mEndOfStream ? OMXCodecWrapper::BUFFER_EOS : 0);
+      rv = mEncoder->Encode(segment, OMXCodecWrapper::BUFFER_EOS);
       NS_ENSURE_SUCCESS(rv, rv);
     }
+    // Nothing to encode but encoder could still have encoded data for earlier
+    // input.
+    return AppendEncodedFrames(aData);
   }
 
-  return AppendEncodedFrames(aData);
+  // OMX encoder has limited input buffers only so we have to feed input and get
+  // output more than once if there are too many samples pending in segment.
+  while (segment.GetDuration() > 0) {
+    rv = mEncoder->Encode(segment,
+                          mEndOfStream ? OMXCodecWrapper::BUFFER_EOS : 0);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = AppendEncodedFrames(aData);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
 }
 
 }
--- a/content/media/omx/OMXCodecWrapper.cpp
+++ b/content/media/omx/OMXCodecWrapper.cpp
@@ -415,52 +415,63 @@ private:
   Vector<sp<ABuffer> >& mBuffers;
   size_t mIndex;
   uint8_t* mData;
   size_t mCapicity;
   size_t mOffset;
 };
 
 nsresult
-OMXAudioEncoder::Encode(const AudioSegment& aSegment, int aInputFlags)
+OMXAudioEncoder::Encode(AudioSegment& aSegment, int aInputFlags)
 {
 #ifndef MOZ_SAMPLE_TYPE_S16
 #error MediaCodec accepts only 16-bit PCM data.
 #endif
 
   MOZ_ASSERT(mStarted, "Configure() should be called before Encode().");
 
   size_t numSamples = aSegment.GetDuration();
 
   // Get input buffer.
   InputBufferHelper buffer(mCodec, mInputBufs);
   status_t result = buffer.Dequeue();
+  if (result == -EAGAIN) {
+    // All input buffers are full. Caller can try again later after consuming
+    // some output buffers.
+    return NS_OK;
+  }
   NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
 
   size_t samplesCopied = 0; // Number of copied samples.
 
   if (numSamples > 0) {
     // Copy input PCM data to input buffer until queue is empty.
     AudioSegment::ChunkIterator iter(const_cast<AudioSegment&>(aSegment));
     while (!iter.IsEnded()) {
       AudioChunk chunk = *iter;
       size_t samplesToCopy = chunk.GetDuration(); // Number of samples to copy.
       size_t bytesToCopy = samplesToCopy * mChannels * sizeof(AudioDataValue);
 
       if (bytesToCopy > buffer.AvailableSize()) {
         // Not enough space left in input buffer. Send it to encoder and get a
         // new one.
-        // Don't signal EOS since there is more data to copy.
         result = buffer.Enqueue(mTimestamp, aInputFlags & ~BUFFER_EOS);
         NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
 
+        result = buffer.Dequeue();
+        if (result == -EAGAIN) {
+          // All input buffers are full. Caller can try again later after
+          // consuming some output buffers.
+          aSegment.RemoveLeading(samplesCopied);
+          return NS_OK;
+        }
+
         mTimestamp += samplesCopied * mSampleDuration;
         samplesCopied = 0;
 
-        result = buffer.Dequeue();
         NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
       }
 
       AudioDataValue* dst = reinterpret_cast<AudioDataValue*>(buffer.GetPointer());
       if (!chunk.IsNull()) {
         // Append the interleaved data to input buffer.
         AudioTrackEncoder::InterleaveTrackData(chunk, samplesToCopy, mChannels,
                                                dst);
@@ -468,27 +479,35 @@ OMXAudioEncoder::Encode(const AudioSegme
         // Silence.
         memset(dst, 0, bytesToCopy);
       }
 
       samplesCopied += samplesToCopy;
       buffer.IncreaseOffset(bytesToCopy);
       iter.Next();
     }
+    if (samplesCopied > 0) {
+      aSegment.RemoveLeading(samplesCopied);
+    }
   } else if (aInputFlags & BUFFER_EOS) {
     // No audio data left in segment but we still have to feed something to
     // MediaCodec in order to notify EOS.
     size_t bytesToCopy = mChannels * sizeof(AudioDataValue);
     memset(buffer.GetPointer(), 0, bytesToCopy);
     buffer.IncreaseOffset(bytesToCopy);
     samplesCopied = 1;
   }
 
   if (samplesCopied > 0) {
-    result = buffer.Enqueue(mTimestamp, aInputFlags);
+    int flags = aInputFlags;
+    if (aSegment.GetDuration() > 0) {
+      // Don't signal EOS until source segment is empty.
+      flags &= ~BUFFER_EOS;
+    }
+    result = buffer.Enqueue(mTimestamp, flags);
     NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
 
     mTimestamp += samplesCopied * mSampleDuration;
   }
 
   return NS_OK;
 }
 
--- a/content/media/omx/OMXCodecWrapper.h
+++ b/content/media/omx/OMXCodecWrapper.h
@@ -172,19 +172,21 @@ public:
   /**
    * Configure audio codec parameters and start media codec. It must be called
    * before calling Encode() and GetNextEncodedFrame().
    */
   nsresult Configure(int aChannelCount, int aSampleRate);
 
   /**
    * Encode 16-bit PCM audio samples stored in aSegment. To notify end of
-   * stream, set aInputFlags to BUFFER_EOS.
+   * stream, set aInputFlags to BUFFER_EOS. Since encoder has limited buffers,
+   * this function might not be able to encode all chunks in one call, however
+   * it will remove chunks it consumes from aSegment.
    */
-  nsresult Encode(const mozilla::AudioSegment& aSegment, int aInputFlags = 0);
+  nsresult Encode(mozilla::AudioSegment& aSegment, int aInputFlags = 0);
 
 protected:
   virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
                                        ABuffer* aData) MOZ_OVERRIDE;
 
 private:
   // Hide these. User should always use creator functions to get a media codec.
   OMXAudioEncoder() MOZ_DELETE;
--- a/content/media/test/test_mediarecorder_avoid_recursion.html
+++ b/content/media/test/test_mediarecorder_avoid_recursion.html
@@ -12,24 +12,27 @@ a Bug 897776</a>
 <script class="testbody" type="text/javascript">
 function startTest() {
   navigator.mozGetUserMedia({audio: true, fake: true}, function(stream) {
     var mediaRecorder = new MediaRecorder(stream);
     var count = 0;
     mediaRecorder.start();
     info("mediaRecorder start");
     mediaRecorder.ondataavailable = function (e) {
-      if (count++ == 30) {
+      ++count;
+      info("got ondataavailable data size = " + e.data.size);
+      // no more requestData() to prevent busy main thread from starving
+      // the encoding thread
+      if (count == 30) {
+        info("stream.stop");
         stream.stop();
-      }
-      if (mediaRecorder.state == 'recording') {
-        info("get data again");
+      } else if (count < 30 && mediaRecorder.state == 'recording') {
+        info("requestData again");
         mediaRecorder.requestData();
       }
-      info("got ondataavailable data size = " + e.data.size);
     }
     mediaRecorder.requestData();
     info("mediaRecorder requestData");
     mediaRecorder.onstop = function () {
       ok(true, "requestData within ondataavailable successfully avoided infinite recursion");
       SimpleTest.finish();
     }
   }, function(err) {
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -386,24 +386,29 @@ ContactManager.prototype = {
         cpmm.sendAsyncMessage("Contacts:GetAll:SendNow", { cursorId: aCursorId });
       }
     } else {
       if (DEBUG) debug("waiting for contact");
       data.waitingForNext = true;
     }
   },
 
-  remove: function removeContact(aRecord) {
+  remove: function removeContact(aRecordOrId) {
     let request = this.createRequest();
-    if (!aRecord || !aRecord.id) {
+    let id;
+    if (typeof aRecordOrId === "string") {
+      id = aRecordOrId;
+    } else if (!aRecordOrId || !aRecordOrId.id) {
       Services.DOMRequest.fireErrorAsync(request, true);
       return request;
+    } else {
+      id = aRecordOrId.id;
     }
 
-    let options = { id: aRecord.id };
+    let options = { id: id };
     let allowCallback = function() {
       cpmm.sendAsyncMessage("Contact:Remove", {requestID: this.getRequestId({request: request, reason: "remove"}), options: options});
     }.bind(this);
     this.askPermission("remove", request, allowCallback);
     return request;
   },
 
   clear: function() {
--- a/dom/contacts/tests/test_contacts_basics2.html
+++ b/dom/contacts/tests/test_contacts_basics2.html
@@ -795,16 +795,38 @@ var steps = [
   function() {
     ok(true, "mozContact.init resets properties");
     var c = new mozContact({jobTitle: ["Software Engineer"]});
     c.init({nickname: ["Jobless Johnny"]});
     ise(c.nickname[0], "Jobless Johnny", "Same nickname");
     ok(!c.jobTitle, "jobTitle is not set");
     next();
   },
+  function() {
+    ok(true, "mozContacts.remove with an ID works");
+    var c = new mozContact({name: ["Ephemeral Jimmy"]});
+    req = navigator.mozContacts.save(c);
+    req.onsuccess = function() {
+      req = navigator.mozContacts.remove(c.id);
+      req.onsuccess = function() {
+        req = navigator.mozContacts.find({
+          filterBy: ["id"],
+          filterOp: "equals",
+          filterValue: c.id
+        });
+        req.onsuccess = function() {
+          ise(req.result.length, 0, "Successfully removed contact by ID");
+          next();
+        };
+        req.onerror = onFailure;
+      };
+      req.onerror = onFailure;
+    };
+    req.onerror = onFailure;
+  },
   function () {
     ok(true, "all done!\n");
     SimpleTest.finish();
   }
 ];
 
 function next() {
   ok(true, "Begin!");
--- a/dom/icc/interfaces/nsIIccProvider.idl
+++ b/dom/icc/interfaces/nsIIccProvider.idl
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMDOMRequest;
 interface nsIDOMMozIccInfo;
 interface nsIDOMWindow;
 
-[scriptable, uuid(87e9ad03-e8e2-40d1-bf28-a6d287c31b93)]
+[scriptable, uuid(7c0ada3d-d8d4-493e-9243-fa3df39855e4)]
 interface nsIIccListener : nsISupports
 {
   void notifyStkCommand(in DOMString aMessage);
   void notifyStkSessionEnd();
   void notifyCardStateChanged();
   void notifyIccInfoChanged();
 };
 
@@ -98,9 +98,17 @@ interface nsIIccProvider : nsISupports
   nsIDOMDOMRequest iccExchangeAPDU(in unsigned long clientId,
                                    in nsIDOMWindow window,
                                    in long channel,
                                    in jsval apdu);
 
   nsIDOMDOMRequest iccCloseChannel(in unsigned long clientId,
                                    in nsIDOMWindow window,
                                    in long channel);
+
+  /**
+   * Helpers
+   */
+  nsIDOMDOMRequest matchMvno(in unsigned long clientId,
+                             in nsIDOMWindow window,
+                             in DOMString mvnoType,
+                             in DOMString mvnoData);
 };
--- a/dom/icc/src/Icc.cpp
+++ b/dom/icc/src/Icc.cpp
@@ -352,8 +352,30 @@ Icc::IccCloseChannel(int32_t aChannel, E
                                            getter_AddRefs(request));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
+
+already_AddRefed<nsISupports>
+Icc::MatchMvno(const nsAString& aMvnoType,
+               const nsAString& aMvnoData,
+               ErrorResult& aRv)
+{
+  if (!mProvider) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<nsIDOMDOMRequest> request;
+  nsresult rv = mProvider->MatchMvno(mClientId, GetOwner(),
+                                     aMvnoType, aMvnoData,
+                                     getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
+
+  return request.forget();
+}
--- a/dom/icc/src/Icc.h
+++ b/dom/icc/src/Icc.h
@@ -93,16 +93,20 @@ public:
 
   already_AddRefed<nsISupports>
   IccExchangeAPDU(const JSContext* aCx, int32_t aChannel,
                   JS::Handle<JS::Value> aApdu, ErrorResult& aRv);
 
   already_AddRefed<nsISupports>
   IccCloseChannel(int32_t aChannel, ErrorResult& aRv);
 
+  already_AddRefed<nsISupports>
+  MatchMvno(const nsAString& aMvnoType, const nsAString& aMatchData,
+            ErrorResult& aRv);
+
   IMPL_EVENT_HANDLER(iccinfochange)
   IMPL_EVENT_HANDLER(cardstatechange)
   IMPL_EVENT_HANDLER(stkcommand)
   IMPL_EVENT_HANDLER(stksessionend)
 
 private:
   bool mLive;
   uint32_t mClientId;
--- a/dom/icc/tests/marionette/manifest.ini
+++ b/dom/icc/tests/marionette/manifest.ini
@@ -21,8 +21,9 @@ qemu = true
 [test_stk_get_inkey.js]
 [test_stk_get_input.js]
 [test_stk_select_item.js]
 [test_stk_setup_menu.js]
 [test_stk_setup_idle_mode_text.js]
 [test_stk_bip_command.js]
 [test_icc_access_invalid_object.js]
 [test_icc_detected_undetected_event.js]
+[test_icc_match_mvno.js]
new file mode 100644
--- /dev/null
+++ b/dom/icc/tests/marionette/test_icc_match_mvno.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 30000;
+MARIONETTE_HEAD_JS = "icc_header.js";
+
+// Emulator's hard coded IMSI: 310260000000000
+let testCases = [
+  // mvno type, mvno data, request success, expected result
+  ["imsi", "3102600",            true, true               ],
+  // x and X means skip the comparison.
+  ["imsi", "31026xx0",           true, true               ],
+  ["imsi", "310260x0x",          true, true               ],
+  ["imsi", "310260X00",          true, true               ],
+  ["imsi", "310260XX1",          true, false              ],
+  ["imsi", "31026012",           true, false              ],
+  ["imsi", "310260000000000",    true, true               ],
+  ["imsi", "310260000000000123", true, false              ],
+  ["imsi", "",                   false, "InvalidParameter"],
+  // Currently we only support imsi match.
+  ["spn",  "Android",            false, "ModeNotSupported"]
+];
+
+function matchMvno(mvnoType, mvnoData, success, expectedResult) {
+  log("matchMvno: " + mvnoType + ", " + mvnoData);
+  let request = icc.matchMvno(mvnoType, mvnoData);
+  request.onsuccess = function onsuccess() {
+    log("onsuccess: " + request.result);
+    ok(success, "onsuccess while error expected");
+    is(request.result, expectedResult);
+    testMatchMvno();
+  }
+  request.onerror = function onerror() {
+    log("onerror: " + request.error.name);
+    ok(!success, "onerror while success expected");
+    is(request.error.name, expectedResult);
+    testMatchMvno();
+  }
+}
+
+function testMatchMvno() {
+  let testCase = testCases.shift();
+  if (!testCase) {
+    taskHelper.runNext();
+    return;
+  }
+  matchMvno(testCase[0], testCase[1], testCase[2], testCase[3]);
+}
+
+taskHelper.push(
+  testMatchMvno
+);
+
+// Start test
+taskHelper.runNext();
+
--- a/dom/mobileconnection/tests/marionette/manifest.ini
+++ b/dom/mobileconnection/tests/marionette/manifest.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 b2g = true
 browser = false
 qemu = true
 
 [test_mobile_networks.js]
 disabled = Bug 808783
 [test_mobile_voice_state.js]
+[test_mobile_voice_location.js]
 [test_mobile_operator_names.js]
 [test_mobile_preferred_network_type.js]
 [test_mobile_preferred_network_type_by_setting.js]
 disabled = Bug 808783
 [test_mobile_data_connection.js]
 [test_mobile_data_location.js]
 [test_mobile_data_state.js]
 [test_mobile_mmi.js]
new file mode 100644
--- /dev/null
+++ b/dom/mobileconnection/tests/marionette/mobile_header.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+SpecialPowers.addPermission("mobileconnection", true, document);
+
+// In single sim scenario, there is only one mobileConnection, we can always use
+// the first instance.
+let mobileConnection = window.navigator.mozMobileConnections[0];
+ok(mobileConnection instanceof MozMobileConnection,
+   "mobileConnection is instanceof " + mobileConnection.constructor);
+
+/* Remove permission and execute finish() */
+let cleanUp = function() {
+  SpecialPowers.removePermission("mobileconnection", document);
+  finish();
+};
+
+/* Helper for tasks */
+let taskHelper = {
+  tasks: [],
+
+  push: function(task) {
+    this.tasks.push(task);
+  },
+
+  runNext: function() {
+    let task = this.tasks.shift();
+    if (!task) {
+      cleanUp();
+      return;
+    }
+
+    if (typeof task === "function") {
+      task();
+    }
+  },
+};
+
+/* Helper for emulator console command */
+let emulatorHelper = {
+  pendingCommandCount: 0,
+
+  sendCommand: function(cmd, callback) {
+    this.pendingCommandCount++;
+    runEmulatorCmd(cmd, function(results) {
+      this.pendingCommandCount--;
+
+      let result = results[results.length - 1];
+      is(result, "OK", "'"+ cmd +"' returns '" + result + "'");
+
+      if (callback && typeof callback === "function") {
+        callback(results);
+      }
+    });
+  },
+};
--- a/dom/mobileconnection/tests/marionette/test_mobile_data_state.js
+++ b/dom/mobileconnection/tests/marionette/test_mobile_data_state.js
@@ -1,123 +1,172 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 30000;
-
-SpecialPowers.addPermission("mobileconnection", true, document);
-
-// Permission changes can't change existing Navigator.prototype
-// objects, so grab our objects from a new Navigator
-let ifr = document.createElement("iframe");
-let mobileConnection;
-ifr.onload = function() {
-  mobileConnection = ifr.contentWindow.navigator.mozMobileConnections[0];
+MARIONETTE_HEAD_JS = "mobile_header.js";
 
-  // Start the test
-  verifyInitialState();
-};
-document.body.appendChild(ifr);
-
-function verifyInitialState() {
-  log("Verifying initial state.");
-  ok(mobileConnection instanceof MozMobileConnection,
-      "mobileConnection is instanceof " + mobileConnection.constructor);
-  // Want to start test with mobileConnection.data.state 'registered'
-  // This is the default state; if it is not currently this value then set it
-  log("Starting mobileConnection.data.state is: '"
-      + mobileConnection.data.state + "'.");
-  if (mobileConnection.data.state != "registered") {
-    changeDataStateAndVerify("home", "registered", testUnregistered);
-  } else {
-    testUnregistered();
-  }
+function setEmulatorDataState(state) {
+  emulatorHelper.sendCommand("gsm data " + state);
 }
 
-function changeDataStateAndVerify(dataState, expected, nextFunction) {
-  let gotCallback = false;
-
-  // Change the mobileConnection.data.state via 'gsm data' command
-  log("Changing emulator data state to '" + dataState
-      + "' and waiting for 'ondatachange' event.");
-
-  // Setup 'ondatachange' event handler
+function waitForDataChangeEvent(callback) {
   mobileConnection.addEventListener("datachange", function ondatachange() {
     mobileConnection.removeEventListener("datachange", ondatachange);
-    log("Received 'ondatachange' event.");
-    log("mobileConnection.data.state is now '"
-        + mobileConnection.data.state + "'.");
-    is(mobileConnection.data.state, expected, "data.state");
-    waitFor(nextFunction, function() {
-      return(gotCallback);
-    });
-  });
 
-  // Change the emulator data state
-  gotCallback = false;
-  runEmulatorCmd("gsm data " + dataState, function(result) {
-    is(result[0], "OK");
-    log("Emulator callback complete.");
-    gotCallback = true;
+    if (callback && typeof callback === "function") {
+      callback();
+    }
   });
 }
 
-function testUnregistered() {
-  log("Test 1: Unregistered.");
-  // Set emulator data state to 'unregistered' and verify
-  // Expect mobileConnection.data.state to be 'notsearching'
-  changeDataStateAndVerify("unregistered", "notSearching", testRoaming);
-}
+/* Test Initial Connection Info */
+taskHelper.push(function testInitialDataInfo() {
+  log("Test initial data connection info");
+
+  let data = mobileConnection.data;
+  // |data.connected| reports true only if the "default" data connection is
+  // established.
+  is(data.connected, false, "check data.connected");
+  is(data.state, "registered", "check data.state");
+  is(data.emergencyCallsOnly, false, "check data.emergencyCallsOnly");
+  is(data.roaming, false, "check data.roaming");
+  // Android emulator initializes the signal strength to -99 dBm
+  is(data.signalStrength, -99, "check data.signalStrength");
+  is(data.relSignalStrength, 44, "check data.relSignalStrength");
 
-function testRoaming() {
-  log("Test 2: Roaming.");
-  // Set emulator data state to 'roaming' and verify
-  // Expect mobileConnection.data.state to be 'registered'
-  changeDataStateAndVerify("roaming", "registered", testOff);
-}
+  let cell = data.cell;
+  ok(data.cell, "location available");
+  // Initial LAC/CID. Android emulator initializes both value to
+  // 0xffff/0xffffffff.
+  is(cell.gsmLocationAreaCode, 65535, "check data.cell.gsmLocationAreaCode");
+  is(cell.gsmCellId, 268435455, "check data.cell.gsmCellId");
+  is(cell.cdmaBaseStationId, -1, "check data.cell.cdmaBaseStationId");
+  is(cell.cdmaBaseStationLatitude, -2147483648,
+     "check data.cell.cdmaBaseStationLatitude");
+  is(cell.cdmaBaseStationLongitude, -2147483648,
+     "check data.cell.cdmaBaseStationLongitude");
+  is(cell.cdmaSystemId, -1, "check data.cell.cdmaSystemId");
+  is(cell.cdmaNetworkId, -1, "check data.cell.cdmaNetworkId");
+
+  taskHelper.runNext();
+});
 
-function testOff() {
-  log("Test 3: Off.");
-  // Set emulator data state to 'off' and verify
-  // Expect mobileConnection.data.state to be 'notsearching'
-  changeDataStateAndVerify("off", "notSearching", testSearching);
-}
+/* Test Data State Changed */
+taskHelper.push(function testDataStateUpdate() {
+  // Set emulator's lac/cid and wait for 'ondatachange' event.
+  function doTestDataState(state, expect, callback) {
+    log("Test data info with state='" + state + "'");
+
+    waitForDataChangeEvent(function() {
+      let data = mobileConnection.data;
+      is(data.state, expect.state, "check data.state");
+      is(data.connected, expect.connected, "check data.connected");
+      is(data.emergencyCallsOnly, expect.emergencyCallsOnly,
+         "check data.emergencyCallsOnly");
+      is(data.roaming, expect.roaming, "check data.roaming");
+      is(data.signalStrength, expect.signalStrength,
+         "check data.signalStrength");
+      is(data.relSignalStrength, expect.relSignalStrength,
+         "check data.relSignalStrength");
 
-function testSearching() {
-  log("Test 4: Searching.");
-  // Set emulator data state to 'searching' and verify
-  // Expect mobileConnection.data.state to be 'searching'
-  changeDataStateAndVerify("searching", "searching", testDenied);
-}
+      let cell = data.cell;
+      if (!expect.cell) {
+        ok(!cell, "check data.cell");
+      } else {
+        is(cell.gsmLocationAreaCode, expect.cell.gsmLocationAreaCode,
+           "check data.cell.gsmLocationAreaCode");
+        is(cell.gsmCellId, expect.cell.gsmCellId, "check data.cell.gsmCellId");
+        is(cell.cdmaBaseStationId, -1, "check data.cell.cdmaBaseStationId");
+        is(cell.cdmaBaseStationLatitude, -2147483648,
+           "check data.cell.cdmaBaseStationLatitude");
+        is(cell.cdmaBaseStationLongitude, -2147483648,
+           "check data.cell.cdmaBaseStationLongitude");
+        is(cell.cdmaSystemId, -1, "check data.cell.cdmaSystemId");
+        is(cell.cdmaNetworkId, -1, "check data.cell.cdmaNetworkId");
+      }
+
+      if (callback && typeof callback === "function") {
+        callback();
+      }
+    });
+
+    setEmulatorDataState(state);
+  }
 
-function testDenied() {
-  log("Test 5: Denied.");
-  // Set emulator data state to 'denied' and verify
-  // Expect mobileConnection.data.state to be 'denied'
-  changeDataStateAndVerify("denied", "denied", testOn);
-}
-
-function testOn() {
-  log("Test 6: On.");
-  // Set emulator data state to 'on' and verify
-  // Expect mobileConnection.data.state to be 'registered'
-  changeDataStateAndVerify("on", "registered", testOffAgain);
-}
+  let testData = [
+    // Test state becomes to "unregistered"
+    {state: "unregistered",
+     expect: {
+      state: "notSearching",
+      connected: false,
+      emergencyCallsOnly: true,
+      roaming: false,
+      signalStrength: null,
+      relSignalStrength: null,
+      cell: null
+    }},
+    // Test state becomes to "searching"
+    {state: "searching",
+     expect: {
+      state: "searching",
+      connected: false,
+      emergencyCallsOnly: true,
+      roaming: false,
+      signalStrength: null,
+      relSignalStrength: null,
+      cell: null
+    }},
+    // Test state becomes to "denied"
+    {state: "denied",
+     expect: {
+      state: "denied",
+      connected: false,
+      emergencyCallsOnly: true,
+      roaming: false,
+      signalStrength: null,
+      relSignalStrength: null,
+      cell: null
+    }},
+    // Test state becomes to "roaming"
+    // Set emulator's data state to "roaming" won't change the operator's
+    // long_name/short_name/mcc/mnc, so that the |data.roaming| will still
+    // report false. Please see bug 787967.
+    {state: "roaming",
+     expect: {
+      state: "registered",
+      connected: false,
+      emergencyCallsOnly: false,
+      roaming: false,
+      signalStrength: -99,
+      relSignalStrength: 44,
+      cell: {
+        gsmLocationAreaCode: 65535,
+        gsmCellId: 268435455
+    }}},
+    // Reset state to default value.
+    {state: "home",
+     expect: {
+      state: "registered",
+      connected: false,
+      emergencyCallsOnly: false,
+      roaming: false,
+      signalStrength: -99,
+      relSignalStrength: 44,
+      cell: {
+        gsmLocationAreaCode: 65535,
+        gsmCellId: 268435455
+    }}}
+  ];
 
-function testOffAgain() {
-  log("Test 7: Off again.");
-  // Set emulator data state to 'off' and verify
-  // Expect mobileConnection.data.state to be 'notsearching'
-  changeDataStateAndVerify("off", "notSearching", testHome);
-}
+  // Run all test data.
+  (function do_call() {
+    let next = testData.shift();
+    if (!next) {
+      taskHelper.runNext();
+      return;
+    }
+    doTestDataState(next.state, next.expect, do_call);
+  })();
+});
 
-function testHome() {
-  log("Test 8: Home.");
-  // Set emulator data state to 'home' and verify
-  // Expect mobileConnection.data.state to be 'registered'
-  changeDataStateAndVerify("home", "registered", cleanUp);
-}
-
-function cleanUp() {
-  mobileConnection.ondatachange = null;
-  SpecialPowers.removePermission("mobileconnection", document);
-  finish();
-}
+// Start test
+taskHelper.runNext();
new file mode 100644
--- /dev/null
+++ b/dom/mobileconnection/tests/marionette/test_mobile_voice_location.js
@@ -0,0 +1,88 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 20000;
+MARIONETTE_HEAD_JS = "mobile_header.js";
+
+function setEmulatorGsmLocation(lac, cid) {
+  emulatorHelper.sendCommand("gsm location " + lac + " " + cid);
+}
+
+function waitForVoiceChangeEvent(callback) {
+  mobileConnection.addEventListener("voicechange", function onvoicechange() {
+    mobileConnection.removeEventListener("voicechange", onvoicechange);
+
+    if (callback && typeof callback === "function") {
+      callback();
+    }
+  });
+}
+
+/* Test Initial Voice Cell Location Info */
+taskHelper.push(function testInitialVoiceCellLocationInfo() {
+  log("Test initial voice location info");
+
+  let cell = mobileConnection.voice.cell;
+  ok(cell, "location available");
+  // Initial LAC/CID. Android emulator initializes both value to
+  // 0xffff/0xffffffff.
+  is(cell.gsmLocationAreaCode, 65535, "check voice.cell.gsmLocationAreaCode");
+  is(cell.gsmCellId, 268435455, "check voice.cell.gsmCellId");
+  is(cell.cdmaBaseStationId, -1, "check voice.cell.cdmaBaseStationId");
+  is(cell.cdmaBaseStationLatitude, -2147483648,
+     "check voice.cell.cdmaBaseStationLatitude");
+  is(cell.cdmaBaseStationLongitude, -2147483648,
+     "check voice.cell.cdmaBaseStationLongitude");
+  is(cell.cdmaSystemId, -1, "check voice.cell.cdmaSystemId");
+  is(cell.cdmaNetworkId, -1, "check voice.cell.cdmaNetworkId");
+
+  taskHelper.runNext();
+});
+
+/* Test Voice Cell Location Info Change */
+taskHelper.push(function testVoiceCellLocationUpdate() {
+  // Set emulator's lac/cid and wait for 'onvoicechange' event.
+  function doTestVoiceCellLocation(lac, cid, callback) {
+    log("Test cell location with lac=" + lac + " and cid=" + cid);
+
+    waitForVoiceChangeEvent(function() {
+      let cell = mobileConnection.voice.cell;
+      is(cell.gsmLocationAreaCode, lac, "check voice.cell.gsmLocationAreaCode");
+      is(cell.gsmCellId, cid, "check voice.cell.gsmCellId");
+      // cdma information won't change.
+      is(cell.cdmaBaseStationId, -1, "check voice.cell.cdmaBaseStationId");
+      is(cell.cdmaBaseStationLatitude, -2147483648,
+         "check voice.cell.cdmaBaseStationLatitude");
+      is(cell.cdmaBaseStationLongitude, -2147483648,
+         "check voice.cell.cdmaBaseStationLongitude");
+      is(cell.cdmaSystemId, -1, "check voice.cell.cdmaSystemId");
+      is(cell.cdmaNetworkId, -1, "check voice.cell.cdmaNetworkId");
+
+      if (callback && typeof callback === "function") {
+        callback();
+      }
+    });
+
+    setEmulatorGsmLocation(lac, cid);
+  }
+
+  let testData = [
+    {lac: 100, cid: 100},
+    {lac: 2000, cid: 2000},
+    // Reset lac/cid to default value.
+    {lac: 65535, cid: 268435455}
+  ];
+
+  // Run all test data.
+  (function do_call() {
+    let next = testData.shift();
+    if (!next) {
+      taskHelper.runNext();
+      return;
+    }
+    doTestVoiceCellLocation(next.lac, next.cid, do_call);
+  })();
+});
+
+// Start test
+taskHelper.runNext();
--- a/dom/mobileconnection/tests/marionette/test_mobile_voice_state.js
+++ b/dom/mobileconnection/tests/marionette/test_mobile_voice_state.js
@@ -1,189 +1,167 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 30000;
-
-SpecialPowers.addPermission("mobileconnection", true, document);
+MARIONETTE_HEAD_JS = "mobile_header.js";
 
-// Permission changes can't change existing Navigator.prototype
-// objects, so grab our objects from a new Navigator
-let ifr = document.createElement("iframe");
-let connection;
-ifr.onload = function() {
-  connection = ifr.contentWindow.navigator.mozMobileConnections[0];
-  ok(connection instanceof ifr.contentWindow.MozMobileConnection,
-     "connection is instanceof " + connection.constructor);
-  testConnectionInfo();
-};
-document.body.appendChild(ifr);
-
-let emulatorCmdPendingCount = 0;
 function setEmulatorVoiceState(state) {
-  emulatorCmdPendingCount++;
-  runEmulatorCmd("gsm voice " + state, function(result) {
-    emulatorCmdPendingCount--;
-    is(result[0], "OK");
-  });
+  emulatorHelper.sendCommand("gsm voice " + state);
 }
 
-function setEmulatorGsmLocation(lac, cid) {
-  emulatorCmdPendingCount++;
-  runEmulatorCmd("gsm location " + lac + " " + cid, function(result) {
-    emulatorCmdPendingCount--;
-    is(result[0], "OK");
+function waitForVoiceChangeEvent(callback) {
+  mobileConnection.addEventListener("voicechange", function onvoicechange() {
+    mobileConnection.removeEventListener("voicechange", onvoicechange);
+
+    if (callback && typeof callback === "function") {
+      callback();
+    }
   });
 }
 
-function testConnectionInfo() {
-  let voice = connection.voice;
-  is(voice.connected, true);
-  is(voice.state, "registered");
-  is(voice.emergencyCallsOnly, false);
-  is(voice.roaming, false);
-
-  testCellLocation();
-}
-
-function testCellLocation() {
-  let cell = connection.voice.cell;
+/* Test Initial Connection Info */
+taskHelper.push(function testInitialVoiceInfo() {
+  log("Test initial voice connection info");
 
-  // Emulator always reports valid lac/cid value because its AT command parser
-  // insists valid value for every complete response. See source file
-  // hardare/ril/reference-ril/at_tok.c, function at_tok_nexthexint().
-  ok(cell, "location available");
-
-  // Initial LAC/CID. Android emulator initializes both value to 0xffff/0xffffffff.
-  is(cell.gsmLocationAreaCode, 65535);
-  is(cell.gsmCellId, 268435455);
-  is(cell.cdmaBaseStationId, -1);
-  is(cell.cdmaBaseStationLatitude, -2147483648);
-  is(cell.cdmaBaseStationLongitude, -2147483648);
-  is(cell.cdmaSystemId, -1);
-  is(cell.cdmaNetworkId, -1);
-
-  connection.addEventListener("voicechange", function onvoicechange() {
-    connection.removeEventListener("voicechange", onvoicechange);
+  let voice = mobileConnection.voice;
+  is(voice.state, "registered", "check voice.state");
+  is(voice.connected, true, "check voice.connected");
+  is(voice.emergencyCallsOnly, false, "check voice.emergencyCallsOnly");
+  is(voice.roaming, false, "check voice.roaming");
+  // Android emulator initializes the signal strength to -99 dBm
+  is(voice.signalStrength, -99, "check voice.signalStrength");
+  is(voice.relSignalStrength, 44, "check voice.relSignalStrength");
 
-    is(cell.gsmLocationAreaCode, 100);
-    is(cell.gsmCellId, 100);
-    is(cell.cdmaBaseStationId, -1);
-    is(cell.cdmaBaseStationLatitude, -2147483648);
-    is(cell.cdmaBaseStationLongitude, -2147483648);
-    is(cell.cdmaSystemId, -1);
-    is(cell.cdmaNetworkId, -1);
-
-    testSignalStrength();
-  });
-
-  setEmulatorGsmLocation(100, 100);
-}
-
-function testSignalStrength() {
-  // Android emulator initializes the signal strength to -99 dBm
-  is(connection.voice.signalStrength, -99);
-  is(connection.voice.relSignalStrength, 44);
+  let cell = voice.cell;
+  ok(cell, "location available");
+  // Initial LAC/CID. Android emulator initializes both value to
+  // 0xffff/0xffffffff.
+  is(cell.gsmLocationAreaCode, 65535, "check voice.cell.gsmLocationAreaCode");
+  is(cell.gsmCellId, 268435455, "check voice.cell.gsmCellId");
+  is(cell.cdmaBaseStationId, -1, "check voice.cell.cdmaBaseStationId");
+  is(cell.cdmaBaseStationLatitude, -2147483648,
+     "check voice.cell.cdmaBaseStationLatitude");
+  is(cell.cdmaBaseStationLongitude, -2147483648,
+     "check voice.cell.cdmaBaseStationLongitude");
+  is(cell.cdmaSystemId, -1, "check voice.cell.cdmaSystemId");
+  is(cell.cdmaNetworkId, -1, "check voice.cell.cdmaNetworkId");
 
-  testUnregistered();
-}
-
-function testUnregistered() {
-  setEmulatorVoiceState("unregistered");
-
-  connection.addEventListener("voicechange", function onvoicechange() {
-    connection.removeEventListener("voicechange", onvoicechange);
-
-    is(connection.voice.connected, false);
-    is(connection.voice.state, "notSearching");
-    is(connection.voice.emergencyCallsOnly, true);
-    is(connection.voice.roaming, false);
-    is(connection.voice.cell, null);
-    is(connection.voice.signalStrength, null);
-    is(connection.voice.relSignalStrength, null);
-
-    testSearching();
-  });
-}
-
-function testSearching() {
-  setEmulatorVoiceState("searching");
+  taskHelper.runNext();
+});
 
-  connection.addEventListener("voicechange", function onvoicechange() {
-    connection.removeEventListener("voicechange", onvoicechange);
-
-    is(connection.voice.connected, false);
-    is(connection.voice.state, "searching");
-    is(connection.voice.emergencyCallsOnly, true);
-    is(connection.voice.roaming, false);
-    is(connection.voice.cell, null);
-    is(connection.voice.signalStrength, null);
-    is(connection.voice.relSignalStrength, null);
-
-    testDenied();
-  });
-}
-
-function testDenied() {
-  setEmulatorVoiceState("denied");
+/* Test Voice State Changed */
+taskHelper.push(function testVoiceStateUpdate() {
+  // Set emulator's lac/cid and wait for 'onvoicechange' event.
+  function doTestVoiceState(state, expect, callback) {
+    log("Test voice info with state='" + state + "'");
 
-  connection.addEventListener("voicechange", function onvoicechange() {
-    connection.removeEventListener("voicechange", onvoicechange);
-
-    is(connection.voice.connected, false);
-    is(connection.voice.state, "denied");
-    is(connection.voice.emergencyCallsOnly, true);
-    is(connection.voice.roaming, false);
-    is(connection.voice.cell, null);
-    is(connection.voice.signalStrength, null);
-    is(connection.voice.relSignalStrength, null);
-
-    testRoaming();
-  });
-}
-
-function testRoaming() {
-  setEmulatorVoiceState("roaming");
+    waitForVoiceChangeEvent(function() {
+      let voice = mobileConnection.voice;
+      is(voice.state, expect.state, "check voice.state");
+      is(voice.connected, expect.connected, "check voice.connected");
+      is(voice.emergencyCallsOnly, expect.emergencyCallsOnly,
+         "check voice.emergencyCallsOnly");
+      is(voice.roaming, expect.roaming, "check voice.roaming");
+      is(voice.signalStrength, expect.signalStrength,
+         "check voice.signalStrength");
+      is(voice.relSignalStrength, expect.relSignalStrength,
+         "check voice.relSignalStrength");
 
-  connection.addEventListener("voicechange", function onvoicechange() {
-    connection.removeEventListener("voicechange", onvoicechange);
-
-    is(connection.voice.connected, true);
-    is(connection.voice.state, "registered");
-    is(connection.voice.emergencyCallsOnly, false);
-    is(connection.voice.roaming, true);
-
-    // Android emulator initializes the signal strength to -99 dBm
-    is(connection.voice.signalStrength, -99);
-    is(connection.voice.relSignalStrength, 44);
-
-    testHome();
-  });
-}
-
-function testHome() {
-  setEmulatorVoiceState("home");
+      let cell = voice.cell;
+      if (!expect.cell) {
+        ok(!cell, "check voice.cell");
+      } else {
+        is(cell.gsmLocationAreaCode, expect.cell.gsmLocationAreaCode,
+           "check voice.cell.gsmLocationAreaCode");
+        is(cell.gsmCellId, expect.cell.gsmCellId, "check voice.cell.gsmCellId");
+        is(cell.cdmaBaseStationId, -1, "check voice.cell.cdmaBaseStationId");
+        is(cell.cdmaBaseStationLatitude, -2147483648,
+           "check voice.cell.cdmaBaseStationLatitude");
+        is(cell.cdmaBaseStationLongitude, -2147483648,
+           "check voice.cell.cdmaBaseStationLongitude");
+        is(cell.cdmaSystemId, -1, "check voice.cell.cdmaSystemId");
+        is(cell.cdmaNetworkId, -1, "check voice.cell.cdmaNetworkId");
+      }
 
-  connection.addEventListener("voicechange", function onvoicechange() {
-    connection.removeEventListener("voicechange", onvoicechange);
-
-    is(connection.voice.connected, true);
-    is(connection.voice.state, "registered");
-    is(connection.voice.emergencyCallsOnly, false);
-    is(connection.voice.roaming, false);
+      if (callback && typeof callback === "function") {
+        callback();
+      }
+    });
 
-    // Android emulator initializes the signal strength to -99 dBm
-    is(connection.voice.signalStrength, -99);
-    is(connection.voice.relSignalStrength, 44);
-
-    cleanUp();
-  });
-}
-
-function cleanUp() {
-  if (emulatorCmdPendingCount > 0) {
-    setTimeout(cleanUp, 100);
-    return;
+    setEmulatorVoiceState(state);
   }
 
-  SpecialPowers.removePermission("mobileconnection", document);
-  finish();
-}
+  let testData = [
+    // Test state becomes to "unregistered"
+    {state: "unregistered",
+     expect: {
+      state: "notSearching",
+      connected: false,
+      emergencyCallsOnly: true,
+      roaming: false,
+      signalStrength: null,
+      relSignalStrength: null,
+      cell: null
+    }},
+    // Test state becomes to "searching"
+    {state: "searching",
+     expect: {
+      state: "searching",
+      connected: false,
+      emergencyCallsOnly: true,
+      roaming: false,
+      signalStrength: null,
+      relSignalStrength: null,
+      cell: null
+    }},
+    // Test state becomes to "denied"
+    {state: "denied",
+     expect: {
+      state: "denied",
+      connected: false,
+      emergencyCallsOnly: true,
+      roaming: false,
+      signalStrength: null,
+      relSignalStrength: null,
+      cell: null
+    }},
+    // Test state becomes to "roaming"
+    {state: "roaming",
+     expect: {
+      state: "registered",
+      connected: true,
+      emergencyCallsOnly: false,
+      roaming: true,
+      signalStrength: -99,
+      relSignalStrength: 44,
+      cell: {
+        gsmLocationAreaCode: 65535,
+        gsmCellId: 268435455
+    }}},
+    // Reset state to default value.
+    {state: "home",
+     expect: {
+      state: "registered",
+      connected: true,
+      emergencyCallsOnly: false,
+      roaming: false,
+      signalStrength: -99,
+      relSignalStrength: 44,
+      cell: {
+        gsmLocationAreaCode: 65535,
+        gsmCellId: 268435455
+    }}}
+  ];
+
+  // Run all test data.
+  (function do_call() {
+    let next = testData.shift();
+    if (!next) {
+      taskHelper.runNext();
+      return;
+    }
+    doTestVoiceState(next.state, next.expect, do_call);
+  })();
+});
+
+// Start test
+taskHelper.runNext();
new file mode 100644
--- /dev/null
+++ b/dom/network/src/NetUtils.cpp
@@ -0,0 +1,181 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "NetUtils.h"
+#include <dlfcn.h>
+#include <errno.h>
+#include <cutils/properties.h>
+#include "prinit.h"
+#include "mozilla/Assertions.h"
+#include "nsDebug.h"
+
+static void* sNetUtilsLib;
+static PRCallOnceType sInitNetUtilsLib;
+
+static PRStatus
+InitNetUtilsLib()
+{
+  sNetUtilsLib = dlopen("/system/lib/libnetutils.so", RTLD_LAZY);
+  // We might fail to open the hardware lib. That's OK.
+  return PR_SUCCESS;
+}
+
+static void*
+GetNetUtilsLibHandle()
+{
+  PR_CallOnce(&sInitNetUtilsLib, InitNetUtilsLib);
+  return sNetUtilsLib;
+}
+
+// static
+void*
+NetUtils::GetSharedLibrary()
+{
+  void* netLib = GetNetUtilsLibHandle();
+  if (!netLib) {
+    NS_WARNING("No /system/lib/libnetutils.so");
+  }
+  return netLib;
+}
+
+// static
+int32_t
+NetUtils::SdkVersion()
+{
+  char propVersion[PROPERTY_VALUE_MAX];
+  property_get("ro.build.version.sdk", propVersion, "0");
+  int32_t version = strtol(propVersion, nullptr, 10);
+  return version;
+}
+
+DEFINE_DLFUNC(ifc_enable, int32_t, const char*)
+DEFINE_DLFUNC(ifc_disable, int32_t, const char*)
+DEFINE_DLFUNC(ifc_configure, int32_t, const char*, in_addr_t, uint32_t,
+              in_addr_t, in_addr_t, in_addr_t)
+DEFINE_DLFUNC(ifc_reset_connections, int32_t, const char*, const int32_t)
+DEFINE_DLFUNC(ifc_set_default_route, int32_t, const char*, in_addr_t)
+DEFINE_DLFUNC(ifc_add_route, int32_t, const char*, const char*, uint32_t, const char*)
+DEFINE_DLFUNC(ifc_remove_route, int32_t, const char*, const char*, uint32_t, const char*)
+DEFINE_DLFUNC(ifc_remove_host_routes, int32_t, const char*)
+DEFINE_DLFUNC(ifc_remove_default_route, int32_t, const char*)
+DEFINE_DLFUNC(dhcp_stop, int32_t, const char*)
+
+int32_t NetUtils::do_ifc_enable(const char *ifname)
+{
+  USE_DLFUNC(ifc_enable)
+  return ifc_enable(ifname);
+}
+
+int32_t NetUtils::do_ifc_disable(const char *ifname)
+{
+  USE_DLFUNC(ifc_disable)
+  return ifc_disable(ifname);
+}
+
+int32_t NetUtils::do_ifc_configure(const char *ifname,
+                                       in_addr_t address,
+                                       uint32_t prefixLength,
+                                       in_addr_t gateway,
+                                       in_addr_t dns1,
+                                       in_addr_t dns2)
+{
+  USE_DLFUNC(ifc_configure)
+  int32_t ret = ifc_configure(ifname, address, prefixLength, gateway, dns1, dns2);
+  return ret;
+}
+
+int32_t NetUtils::do_ifc_reset_connections(const char *ifname,
+                                               const int32_t resetMask)
+{
+  USE_DLFUNC(ifc_reset_connections)
+  return ifc_reset_connections(ifname, resetMask);
+}
+
+int32_t NetUtils::do_ifc_set_default_route(const char *ifname,
+                                           in_addr_t gateway)
+{
+  USE_DLFUNC(ifc_set_default_route)
+  return ifc_set_default_route(ifname, gateway);
+}
+
+int32_t NetUtils::do_ifc_add_route(const char *ifname,
+                                   const char *dst,
+                                   uint32_t prefixLength,
+                                   const char *gateway)
+{
+  USE_DLFUNC(ifc_add_route)
+  return ifc_add_route(ifname, dst, prefixLength, gateway);
+}
+
+int32_t NetUtils::do_ifc_remove_route(const char *ifname,
+                                      const char *dst,
+                                      uint32_t prefixLength,
+                                      const char *gateway)
+{
+  USE_DLFUNC(ifc_remove_route)
+  return ifc_remove_route(ifname, dst, prefixLength, gateway);
+}
+
+int32_t NetUtils::do_ifc_remove_host_routes(const char *ifname)
+{
+  USE_DLFUNC(ifc_remove_host_routes)
+  return ifc_remove_host_routes(ifname);
+}
+
+int32_t NetUtils::do_ifc_remove_default_route(const char *ifname)
+{
+  USE_DLFUNC(ifc_remove_default_route)
+  return ifc_remove_default_route(ifname);
+}
+
+int32_t NetUtils::do_dhcp_stop(const char *ifname)
+{
+  USE_DLFUNC(dhcp_stop)
+  return dhcp_stop(ifname);
+}
+
+int32_t NetUtils::do_dhcp_do_request(const char *ifname,
+                                         char *ipaddr,
+                                         char *gateway,
+                                         uint32_t *prefixLength,
+                                         char *dns1,
+                                         char *dns2,
+                                         char *server,
+                                         uint32_t  *lease,
+                                         char* vendorinfo)
+{
+  int32_t ret = -1;
+  uint32_t sdkVersion = SdkVersion();
+
+  if (sdkVersion == 15) {
+    // ICS
+    // http://androidxref.com/4.0.4/xref/system/core/libnetutils/dhcp_utils.c#149
+    DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*,  uint32_t*, char*, char*, char*, uint32_t*)
+    USE_DLFUNC(dhcp_do_request)
+    vendorinfo[0] = '\0';
+
+    ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns1, dns2,
+                          server, lease);
+  } else if (sdkVersion == 16 || sdkVersion == 17) {
+    // JB 4.1 and 4.2
+    // http://androidxref.com/4.1.2/xref/system/core/libnetutils/dhcp_utils.c#175
+    // http://androidxref.com/4.2.2_r1/xref/system/core/include/netutils/dhcp.h#26
+    DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*,  uint32_t*, char*, char*, char*, uint32_t*, char*)
+    USE_DLFUNC(dhcp_do_request)
+    ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns1, dns2,
+                          server, lease, vendorinfo);
+  } else if (sdkVersion == 18) {
+    // JB 4.3
+    // http://androidxref.com/4.3_r2.1/xref/system/core/libnetutils/dhcp_utils.c#181
+    DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*,  uint32_t*, char**, char*, uint32_t*, char*, char*)
+    USE_DLFUNC(dhcp_do_request)
+    char *dns[3] = {dns1, dns2, nullptr};
+    char domains[PROPERTY_VALUE_MAX];
+    ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns,
+                          server, lease, vendorinfo, domains);
+  } else {
+    NS_WARNING("Unable to perform do_dhcp_request: unsupported sdk version!");
+  }
+  return ret;
+}
new file mode 100644
--- /dev/null
+++ b/dom/network/src/NetUtils.h
@@ -0,0 +1,71 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Abstraction on top of the network support from libnetutils that we
+ * use to set up network connections.
+ */
+
+#ifndef NetUtils_h
+#define NetUtils_h
+
+#include "arpa/inet.h"
+
+// Copied from ifc.h
+#define RESET_IPV4_ADDRESSES 0x01
+#define RESET_IPV6_ADDRESSES 0x02
+#define RESET_ALL_ADDRESSES  (RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES)
+
+// Implements netutils functions. No need for an abstract class here since we
+// only have a one sdk specific method (dhcp_do_request)
+class NetUtils
+{
+public:
+  static void* GetSharedLibrary();
+
+  int32_t do_ifc_enable(const char *ifname);
+  int32_t do_ifc_disable(const char *ifname);
+  int32_t do_ifc_configure(const char *ifname,
+                           in_addr_t address,
+                           uint32_t prefixLength,
+                           in_addr_t gateway,
+                           in_addr_t dns1,
+                           in_addr_t dns2);
+  int32_t do_ifc_reset_connections(const char *ifname, const int32_t resetMask);
+  int32_t do_ifc_set_default_route(const char *ifname, in_addr_t gateway);
+  int32_t do_ifc_add_route(const char *ifname,
+                           const char *dst,
+                           uint32_t prefixLength,
+                           const char *gateway);
+  int32_t do_ifc_remove_route(const char *ifname,
+                              const char *dst,
+                              uint32_t prefixLength,
+                              const char *gateway);
+  int32_t do_ifc_remove_host_routes(const char *ifname);
+  int32_t do_ifc_remove_default_route(const char *ifname);
+  int32_t do_dhcp_stop(const char *ifname);
+  int32_t do_dhcp_do_request(const char *ifname,
+                             char *ipaddr,
+                             char *gateway,
+                             uint32_t *prefixLength,
+                             char *dns1,
+                             char *dns2,
+                             char *server,
+                             uint32_t  *lease,
+                             char* vendorinfo);
+
+  static int32_t SdkVersion();
+};
+
+// Defines a function type with the right arguments and return type.
+#define DEFINE_DLFUNC(name, ret, args...) typedef ret (*FUNC##name)(args);
+
+// Set up a dlsymed function ready to use.
+#define USE_DLFUNC(name)                                                      \
+  FUNC##name name = (FUNC##name) dlsym(GetSharedLibrary(), #name);            \
+  if (!name) {                                                                \
+    MOZ_ASSUME_UNREACHABLE("Symbol not found in shared library : " #name);    \
+  }
+
+#endif // NetUtils_h
--- a/dom/network/src/moz.build
+++ b/dom/network/src/moz.build
@@ -44,16 +44,22 @@ EXTRA_PP_COMPONENTS += [
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     EXTRA_COMPONENTS += [
         'NetworkStatsManager.js',
         'NetworkStatsManager.manifest',
         'NetworkStatsServiceProxy.js',
         'NetworkStatsServiceProxy.manifest',
     ]
+    EXPORTS.mozilla.dom.network += [
+        'NetUtils.h',
+    ]
+    UNIFIED_SOURCES += [
+        'NetUtils.cpp',
+    ]
 
 IPDL_SOURCES += [
     'PTCPServerSocket.ipdl',
     'PTCPSocket.ipdl',
     'PUDPSocket.ipdl',
 ]
 
 FAIL_ON_WARNINGS = True
--- a/dom/system/gonk/NetworkService.js
+++ b/dom/system/gonk/NetworkService.js
@@ -9,16 +9,20 @@ const {classes: Cc, interfaces: Ci, util
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 
 const NETWORKSERVICE_CONTRACTID = "@mozilla.org/network/service;1";
 const NETWORKSERVICE_CID = Components.ID("{c14cabaf-bb8e-470d-a2f1-2cb6de6c5e5c}");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gNetworkWorker",
+                                   "@mozilla.org/network/worker;1",
+                                   "nsINetworkWorker");
+
 // 1xx - Requested action is proceeding
 const NETD_COMMAND_PROCEEDING   = 100;
 // 2xx - Requested action has been successfully completed
 const NETD_COMMAND_OKAY         = 200;
 // 4xx - The command is accepted but the requested action didn't
 // take place.
 const NETD_COMMAND_FAIL         = 400;
 // 5xx - The command syntax or parameters error
@@ -46,27 +50,33 @@ function debug(msg) {
 }
 
 /**
  * This component watches for network interfaces changing state and then
  * adjusts routes etc. accordingly.
  */
 function NetworkService() {
   if(DEBUG) debug("Starting net_worker.");
-  this.worker = new ChromeWorker("resource://gre/modules/net_worker.js");
-  this.worker.onmessage = this.handleWorkerMessage.bind(this);
-  this.worker.onerror = function onerror(event) {
-    if(DEBUG) debug("Received error from worker: " + event.filename +
-                    ":" + event.lineno + ": " + event.message + "\n");
-    // Prevent the event from bubbling any further.
-    event.preventDefault();
-  };
+
+  let self = this;
 
+  if (gNetworkWorker) {
+    let networkListener = {
+      onEvent: function(event) {
+        self.handleWorkerMessage(event);
+      }
+    };
+    this.worker = gNetworkWorker;
+    gNetworkWorker.start(networkListener);
+  }
   // Callbacks to invoke when a reply arrives from the net_worker.
   this.controlCallbacks = Object.create(null);
+
+  this.shutdown = false;
+  Services.obs.addObserver(this, "xpcom-shutdown", false);
 }
 
 NetworkService.prototype = {
   classID:   NETWORKSERVICE_CID,
   classInfo: XPCOMUtils.generateCI({classID: NETWORKSERVICE_CID,
                                     contractID: NETWORKSERVICE_CONTRACTID,
                                     classDescription: "Network Service",
                                     interfaces: [Ci.nsINetworkService]}),
@@ -77,45 +87,54 @@ NetworkService.prototype = {
   // nsIWorkerHolder
 
   worker: null,
 
   // Helpers
 
   idgen: 0,
   controlMessage: function(params, callback) {
+    if (this.shutdown) {
+      return;
+    }
+
     if (callback) {
       let id = this.idgen++;
       params.id = id;
       this.controlCallbacks[id] = callback;
     }
-    this.worker.postMessage(params);
+    if (gNetworkWorker) {
+      gNetworkWorker.postMessage(params);
+    }
   },
 
-  handleWorkerMessage: function(e) {
-    if(DEBUG) debug("NetworkManager received message from worker: " + JSON.stringify(e.data));
-    let response = e.data;
+  handleWorkerMessage: function(response) {
+    if(DEBUG) debug("NetworkManager received message from worker: " + JSON.stringify(response));
     let id = response.id;
-    if (id === 'broadcast') {
+    if (response.broadcast === true) {
       Services.obs.notifyObservers(null, response.topic, response.reason);
       return;
     }
     let callback = this.controlCallbacks[id];
     if (callback) {
       callback.call(this, response);
       delete this.controlCallbacks[id];
     }
   },
 
   // nsINetworkService
 
   getNetworkInterfaceStats: function(networkName, callback) {
     if(DEBUG) debug("getNetworkInterfaceStats for " + networkName);
+
+    if (this.shutdown) {
+      return;
+    }
+
     let file = new FileUtils.File("/proc/net/dev");
-
     if (!file) {
       callback.networkStatsAvailable(false, -1, -1, new Date());
       return;
     }
 
     NetUtil.asyncFetch(file, function(inputStream, status) {
       let result = {
         success: true,  // netd always return success even interface doesn't exist.
@@ -154,17 +173,17 @@ NetworkService.prototype = {
       this._disableNetworkInterfaceAlarm(networkName, callback);
       return;
     }
 
     this._setNetworkInterfaceAlarm(networkName, threshold, callback);
   },
 
   _setNetworkInterfaceAlarm: function(networkName, threshold, callback) {
-    debug("setNetworkInterfaceAlarm for " + networkName + " at " + threshold + "bytes");
+    if(DEBUG) debug("setNetworkInterfaceAlarm for " + networkName + " at " + threshold + "bytes");
 
     let params = {
       cmd: "setNetworkInterfaceAlarm",
       ifname: networkName,
       threshold: threshold
     };
 
     params.report = true;
@@ -176,17 +195,17 @@ NetworkService.prototype = {
         return;
       }
 
       this._enableNetworkInterfaceAlarm(networkName, threshold, callback);
     });
   },
 
   _enableNetworkInterfaceAlarm: function(networkName, threshold, callback) {
-    debug("enableNetworkInterfaceAlarm for " + networkName + " at " + threshold + "bytes");
+    if(DEBUG) debug("enableNetworkInterfaceAlarm for " + networkName + " at " + threshold + "bytes");
 
     let params = {
       cmd: "enableNetworkInterfaceAlarm",
       ifname: networkName,
       threshold: threshold
     };
 
     params.report = true;
@@ -197,17 +216,17 @@ NetworkService.prototype = {
         callback.networkUsageAlarmResult(null);
         return;
       }
       callback.networkUsageAlarmResult(result.reason);
     });
   },
 
   _disableNetworkInterfaceAlarm: function(networkName, callback) {
-    debug("disableNetworkInterfaceAlarm for " + networkName);
+    if(DEBUG) debug("disableNetworkInterfaceAlarm for " + networkName);
 
     let params = {
       cmd: "disableNetworkInterfaceAlarm",
       ifname: networkName,
     };
 
     params.report = true;
     params.isAsync = true;
@@ -248,104 +267,104 @@ NetworkService.prototype = {
       return;
     }
     let options = {
       cmd: "removeNetworkRoute",
       ifname: network.name,
       ip: network.ip,
       netmask: network.netmask
     };
-    this.worker.postMessage(options);
+    this.controlMessage(options, function() {});
   },
 
   setDNS: function(networkInterface) {
     if(DEBUG) debug("Going DNS to " + networkInterface.name);
     let options = {
       cmd: "setDNS",
       ifname: networkInterface.name,
       dns1_str: networkInterface.dns1,
       dns2_str: networkInterface.dns2
     };
-    this.worker.postMessage(options);
+    this.controlMessage(options, function() {});
   },
 
   setDefaultRouteAndDNS: function(network, oldInterface) {
     if(DEBUG) debug("Going to change route and DNS to " + network.name);
     let options = {
       cmd: "setDefaultRouteAndDNS",
       ifname: network.name,
       oldIfname: (oldInterface && oldInterface !== network) ? oldInterface.name : null,
       gateway_str: network.gateway,
       dns1_str: network.dns1,
       dns2_str: network.dns2
     };
-    this.worker.postMessage(options);
+    this.controlMessage(options, function() {});
     this.setNetworkProxy(network);
   },
 
   removeDefaultRoute: function(ifname) {
     if(DEBUG) debug("Remove default route for " + ifname);
     let options = {
       cmd: "removeDefaultRoute",
       ifname: ifname
     };
-    this.worker.postMessage(options);
+    this.controlMessage(options, function() {});
   },
 
   addHostRoute: function(network) {
     if(DEBUG) debug("Going to add host route on " + network.name);
     let options = {
       cmd: "addHostRoute",
       ifname: network.name,
       gateway: network.gateway,
       hostnames: [network.dns1, network.dns2, network.httpProxyHost]
     };
-    this.worker.postMessage(options);
+    this.controlMessage(options, function() {});
   },
 
   removeHostRoute: function(network) {
     if(DEBUG) debug("Going to remove host route on " + network.name);
     let options = {
       cmd: "removeHostRoute",
       ifname: network.name,
       gateway: network.gateway,
       hostnames: [network.dns1, network.dns2, network.httpProxyHost]
     };
-    this.worker.postMessage(options);
+    this.controlMessage(options, function() {});
   },
 
   removeHostRoutes: function(ifname) {
     if(DEBUG) debug("Going to remove all host routes on " + ifname);
     let options = {
       cmd: "removeHostRoutes",
       ifname: ifname,
     };
-    this.worker.postMessage(options);
+    this.controlMessage(options, function() {});
   },
 
   addHostRouteWithResolve: function(network, hosts) {
     if(DEBUG) debug("Going to add host route after dns resolution on " + network.name);
     let options = {
       cmd: "addHostRoute",
       ifname: network.name,
       gateway: network.gateway,
       hostnames: hosts
     };
-    this.worker.postMessage(options);
+    this.controlMessage(options, function() {});
   },
 
   removeHostRouteWithResolve: function(network, hosts) {
     if(DEBUG) debug("Going to remove host route after dns resolution on " + network.name);
     let options = {
       cmd: "removeHostRoute",
       ifname: network.name,
       gateway: network.gateway,
       hostnames: hosts
     };
-    this.worker.postMessage(options);
+    this.controlMessage(options, function() {});
   },
 
   setNetworkProxy: function(network) {
     try {
       if (!network.httpProxyHost || network.httpProxyHost === "") {
         // Sets direct connection to internet.
         Services.prefs.clearUserPref("network.proxy.type");
         Services.prefs.clearUserPref("network.proxy.share_proxy_settings");
@@ -473,11 +492,23 @@ NetworkService.prototype = {
 
     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.current.externalIfname);
     });
   },
+
+  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");
+        break;
+    }
+  },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkService]);
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/NetworkUtils.cpp
@@ -0,0 +1,1400 @@
+/* Copyright 2012 Mozilla Foundation and Mozilla contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NetworkUtils.h"
+
+#include <android/log.h>
+#include <cutils/properties.h>
+#include "mozilla/dom/network/NetUtils.h"
+
+#define _DEBUG 0
+
+#define WARN(args...)   __android_log_print(ANDROID_LOG_WARN,  "NetworlUtils", ## args)
+#define ERROR(args...)  __android_log_print(ANDROID_LOG_ERROR,  "NetworkUtils", ## args)
+
+#if _DEBUG
+#define DEBUG(args...)  __android_log_print(ANDROID_LOG_DEBUG, "NetworkUtils" , ## args)
+#else
+#define DEBUG(args...)
+#endif
+
+using namespace mozilla::dom;
+using namespace mozilla::ipc;
+
+static const char* PERSIST_SYS_USB_CONFIG_PROPERTY = "persist.sys.usb.config";
+static const char* SYS_USB_CONFIG_PROPERTY         = "sys.usb.config";
+static const char* SYS_USB_STATE_PROPERTY          = "sys.usb.state";
+
+static const char* USB_FUNCTION_RNDIS  = "rndis";
+static const char* USB_FUNCTION_ADB    = "adb";
+
+// Use this command to continue the function chain.
+static const char* DUMMY_COMMAND = "tether status";
+
+// Retry 20 times (2 seconds) for usb state transition.
+static const uint32_t USB_FUNCTION_RETRY_TIMES = 20;
+// Check "sys.usb.state" every 100ms.
+static const uint32_t USB_FUNCTION_RETRY_INTERVAL = 100;
+
+// 1xx - Requested action is proceeding
+static const uint32_t NETD_COMMAND_PROCEEDING   = 100;
+// 2xx - Requested action has been successfully completed
+static const uint32_t NETD_COMMAND_OKAY         = 200;
+// 4xx - The command is accepted but the requested action didn't
+// take place.
+static const uint32_t NETD_COMMAND_FAIL         = 400;
+// 5xx - The command syntax or parameters error
+static const uint32_t NETD_COMMAND_ERROR        = 500;
+// 6xx - Unsolicited broadcasts
+static const uint32_t NETD_COMMAND_UNSOLICITED  = 600;
+
+// Broadcast messages
+static const uint32_t NETD_COMMAND_INTERFACE_CHANGE     = 600;
+static const uint32_t NETD_COMMAND_BANDWIDTH_CONTROLLER = 601;
+
+static const char* INTERFACE_DELIMIT = "\0";
+static const char* USB_CONFIG_DELIMIT = ",";
+static const char* NETD_MESSAGE_DELIMIT = " ";
+
+static const uint32_t BUF_SIZE = 1024;
+
+static uint32_t SDK_VERSION;
+
+struct IFProperties {
+  char gateway[PROPERTY_VALUE_MAX];
+  char dns1[PROPERTY_VALUE_MAX];
+  char dns2[PROPERTY_VALUE_MAX];
+};
+
+struct CurrentCommand {
+  CommandChain* chain;
+  CommandCallback callback;
+  char command[MAX_COMMAND_SIZE];
+};
+
+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)
+
+static NetworkUtils* gNetworkUtils;
+static nsTArray<QueueData> gCommandQueue;
+static CurrentCommand gCurrentCommand;
+static bool gPending = false;
+static nsTArray<nsCString> gReason;
+
+CommandFunc NetworkUtils::sWifiEnableChain[] = {
+  NetworkUtils::wifiFirmwareReload,
+  NetworkUtils::startAccessPointDriver,
+  NetworkUtils::setAccessPoint,
+  NetworkUtils::startSoftAP,
+  NetworkUtils::setInterfaceUp,
+  NetworkUtils::tetherInterface,
+  NetworkUtils::setIpForwardingEnabled,
+  NetworkUtils::tetheringStatus,
+  NetworkUtils::startTethering,
+  NetworkUtils::setDnsForwarders,
+  NetworkUtils::enableNat,
+  NetworkUtils::wifiTetheringSuccess
+};
+
+CommandFunc NetworkUtils::sWifiDisableChain[] = {
+  NetworkUtils::stopSoftAP,
+  NetworkUtils::stopAccessPointDriver,
+  NetworkUtils::wifiFirmwareReload,
+  NetworkUtils::untetherInterface,
+  NetworkUtils::preTetherInterfaceList,
+  NetworkUtils::postTetherInterfaceList,
+  NetworkUtils::disableNat,
+  NetworkUtils::setIpForwardingEnabled,
+  NetworkUtils::stopTethering,
+  NetworkUtils::wifiTetheringSuccess
+};
+
+CommandFunc NetworkUtils::sWifiFailChain[] = {
+  NetworkUtils::stopSoftAP,
+  NetworkUtils::setIpForwardingEnabled,
+  NetworkUtils::stopTethering
+};
+
+CommandFunc NetworkUtils::sWifiOperationModeChain[] = {
+  NetworkUtils::wifiFirmwareReload,
+  NetworkUtils::wifiOperationModeSuccess
+};
+
+CommandFunc NetworkUtils::sUSBEnableChain[] = {
+  NetworkUtils::setInterfaceUp,
+  NetworkUtils::enableNat,
+  NetworkUtils::setIpForwardingEnabled,
+  NetworkUtils::tetherInterface,
+  NetworkUtils::tetheringStatus,
+  NetworkUtils::startTethering,
+  NetworkUtils::setDnsForwarders,
+  NetworkUtils::usbTetheringSuccess
+};
+
+CommandFunc NetworkUtils::sUSBDisableChain[] = {
+  NetworkUtils::untetherInterface,
+  NetworkUtils::preTetherInterfaceList,
+  NetworkUtils::postTetherInterfaceList,
+  NetworkUtils::disableNat,
+  NetworkUtils::setIpForwardingEnabled,
+  NetworkUtils::stopTethering,
+  NetworkUtils::usbTetheringSuccess
+};
+
+CommandFunc NetworkUtils::sUSBFailChain[] = {
+  NetworkUtils::stopSoftAP,
+  NetworkUtils::setIpForwardingEnabled,
+  NetworkUtils::stopTethering
+};
+
+CommandFunc NetworkUtils::sUpdateUpStreamChain[] = {
+  NetworkUtils::cleanUpStream,
+  NetworkUtils::createUpStream,
+  NetworkUtils::updateUpStreamSuccess
+};
+
+CommandFunc NetworkUtils::sStartDhcpServerChain[] = {
+  NetworkUtils::setInterfaceUp,
+  NetworkUtils::startTethering,
+  NetworkUtils::setDhcpServerSuccess
+};
+
+CommandFunc NetworkUtils::sStopDhcpServerChain[] = {
+  NetworkUtils::stopTethering,
+  NetworkUtils::setDhcpServerSuccess
+};
+
+CommandFunc NetworkUtils::sNetworkInterfaceStatsChain[] = {
+  NetworkUtils::getRxBytes,
+  NetworkUtils::getTxBytes,
+  NetworkUtils::networkInterfaceStatsSuccess
+};
+
+CommandFunc NetworkUtils::sNetworkInterfaceEnableAlarmChain[] = {
+  NetworkUtils::enableAlarm,
+  NetworkUtils::setQuota,
+  NetworkUtils::setAlarm,
+  NetworkUtils::networkInterfaceAlarmSuccess
+};
+
+CommandFunc NetworkUtils::sNetworkInterfaceDisableAlarmChain[] = {
+  NetworkUtils::removeQuota,
+  NetworkUtils::disableAlarm,
+  NetworkUtils::networkInterfaceAlarmSuccess
+};
+
+CommandFunc NetworkUtils::sNetworkInterfaceSetAlarmChain[] = {
+  NetworkUtils::setAlarm,
+  NetworkUtils::networkInterfaceAlarmSuccess
+};
+
+/**
+ * Helper function to get the bit length from given mask.
+ */
+static uint32_t getMaskLength(const uint32_t mask)
+{
+  uint32_t netmask = ntohl(mask);
+  uint32_t len = 0;
+  while (netmask & 0x80000000) {
+    len++;
+    netmask = netmask << 1;
+  }
+  return len;
+}
+
+/**
+ * Helper function to split string by seperator, store split result as an nsTArray.
+ */
+static void split(char* str, const char* sep, nsTArray<nsCString>& result)
+{
+  char *s = strtok(str, sep);
+  while (s != nullptr) {
+    result.AppendElement(s);
+    s = strtok(nullptr, sep);
+  }
+}
+
+/**
+ * Helper function that implement join function.
+ */
+static void join(nsTArray<nsCString>& array, const char* sep, const uint32_t maxlen, char* result)
+{
+#define CHECK_LENGTH(len, add, max)  len += add;          \
+                                     if (len > max - 1)   \
+                                       return;            \
+
+  uint32_t len = 0;
+  uint32_t seplen = strlen(sep);
+
+  if (array.Length() > 0) {
+    CHECK_LENGTH(len, strlen(array[0].get()), maxlen)
+    strcpy(result, array[0].get());
+
+    for (uint32_t i = 1; i < array.Length(); i++) {
+      CHECK_LENGTH(len, seplen, maxlen)
+      strcat(result, sep);
+
+      CHECK_LENGTH(len, strlen(array[i].get()), maxlen)
+      strcat(result, array[i].get());
+    }
+  }
+
+#undef CHECK_LEN
+}
+
+/**
+ * Helper function to get network interface properties from the system property table.
+ */
+static void getIFProperties(const char* ifname, IFProperties& prop)
+{
+  char key[PROPERTY_KEY_MAX];
+  snprintf(key, PROPERTY_KEY_MAX - 1, "net.%s.gw", ifname);
+  property_get(key, prop.gateway, "");
+  snprintf(key, PROPERTY_KEY_MAX - 1, "net.%s.dns1", ifname);
+  property_get(key, prop.dns1, "");
+  snprintf(key, PROPERTY_KEY_MAX - 1, "net.%s.dns2", ifname);
+  property_get(key, prop.dns2, "");
+}
+
+static void postMessage(NetworkResultOptions& aResult)
+{
+  MOZ_ASSERT(gNetworkUtils);
+  MOZ_ASSERT(gNetworkUtils->getMessageCallback());
+
+  if (*(gNetworkUtils->getMessageCallback()))
+    (*(gNetworkUtils->getMessageCallback()))(aResult);
+}
+
+static void postMessage(NetworkParams& aOptions, NetworkResultOptions& aResult)
+{
+  MOZ_ASSERT(gNetworkUtils);
+  MOZ_ASSERT(gNetworkUtils->getMessageCallback());
+
+  aResult.mId = aOptions.mId;
+
+  if (*(gNetworkUtils->getMessageCallback()))
+    (*(gNetworkUtils->getMessageCallback()))(aResult);
+}
+
+void NetworkUtils::next(CommandChain* aChain, bool aError, NetworkResultOptions& aResult)
+{
+  if (aError) {
+    ErrorCallback onError = aChain->getErrorCallback();
+    if(onError) {
+      aResult.mError = true;
+      (*onError)(aChain->getParams(), aResult);
+    }
+    delete aChain;
+    return;
+  }
+  CommandFunc f = aChain->getNextCommand();
+  if (!f) {
+    delete aChain;
+    return;
+  }
+
+  (*f)(aChain, next, aResult);
+}
+
+/**
+ * Send command to netd.
+ */
+void NetworkUtils::nextNetdCommand()
+{
+  if (gCommandQueue.IsEmpty() || gPending) {
+    return;
+  }
+
+  gCurrentCommand.chain = GET_CURRENT_CHAIN;
+  gCurrentCommand.callback = GET_CURRENT_CALLBACK;
+  snprintf(gCurrentCommand.command, MAX_COMMAND_SIZE - 1, "%s", GET_CURRENT_COMMAND);
+
+  DEBUG("Sending \'%s\' command to netd.", gCurrentCommand.command);
+  SendNetdCommand(GET_CURRENT_NETD_COMMAND);
+
+  gCommandQueue.RemoveElementAt(0);
+  gPending = true;
+}
+
+/**
+ * Composite NetdCommand sent to netd
+ *
+ * @param aCommand  Command sent to netd to execute.
+ * @param aChain    Store command chain data, ex. command parameter.
+ * @param aCallback Callback function to be executed when the result of
+ *                  this command is returned from netd.
+ */
+void NetworkUtils::doCommand(const char* aCommand, CommandChain* aChain, CommandCallback aCallback)
+{
+  DEBUG("Preparing to send \'%s\' command...", aCommand);
+
+  NetdCommand* netdCommand = new NetdCommand();
+
+  // Android JB version adds sequence number to netd command.
+  if (SDK_VERSION >= 16) {
+    snprintf((char*)netdCommand->mData, MAX_COMMAND_SIZE - 1, "0 %s", aCommand);
+  } else {
+    snprintf((char*)netdCommand->mData, MAX_COMMAND_SIZE - 1, "%s", aCommand);
+  }
+  netdCommand->mSize = strlen((char*)netdCommand->mData) + 1;
+
+  gCommandQueue.AppendElement(QueueData(netdCommand, aChain, aCallback));
+
+  nextNetdCommand();
+}
+
+/*
+ * Netd command function
+ */
+#define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aChain->getParams().prop).get()
+#define GET_FIELD(prop) aChain->getParams().prop
+
+void NetworkUtils::wifiFirmwareReload(CommandChain* aChain,
+                                      CommandCallback aCallback,
+                                      NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "softap fwreload %s %s", GET_CHAR(mIfname), GET_CHAR(mMode));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::startAccessPointDriver(CommandChain* aChain,
+                                          CommandCallback aCallback,
+                                          NetworkResultOptions& aResult)
+{
+  // Skip the command for sdk version >= 16.
+  if (SDK_VERSION >= 16) {
+    aResult.mResultCode = 0;
+    aResult.mResultReason = NS_ConvertUTF8toUTF16("");
+    aCallback(aChain, false, aResult);
+    return;
+  }
+
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "softap start %s", GET_CHAR(mIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::stopAccessPointDriver(CommandChain* aChain,
+                                         CommandCallback aCallback,
+                                         NetworkResultOptions& aResult)
+{
+  // Skip the command for sdk version >= 16.
+  if (SDK_VERSION >= 16) {
+    aResult.mResultCode = 0;
+    aResult.mResultReason = NS_ConvertUTF8toUTF16("");
+    aCallback(aChain, false, aResult);
+    return;
+  }
+
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "softap stop %s", GET_CHAR(mIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+/**
+ * Command format for sdk version < 16
+ *   Arguments:
+ *     argv[2] - wlan interface
+ *     argv[3] - SSID
+ *     argv[4] - Security
+ *     argv[5] - Key
+ *     argv[6] - Channel
+ *     argv[7] - Preamble
+ *     argv[8] - Max SCB
+ *
+ * Command format for sdk version >= 16
+ *   Arguments:
+ *     argv[2] - wlan interface
+ *     argv[3] - SSID
+ *     argv[4] - Security
+ *     argv[5] - Key
+ */
+void NetworkUtils::setAccessPoint(CommandChain* aChain,
+                                  CommandCallback aCallback,
+                                  NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  if (SDK_VERSION >= 16) {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "softap set %s \"%s\" %s \"%s\"",
+                     GET_CHAR(mIfname),
+                     GET_CHAR(mSsid),
+                     GET_CHAR(mSecurity),
+                     GET_CHAR(mKey));
+  } else {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "softap set %s %s \"%s\" %s \"%s\" 6 0 8",
+                     GET_CHAR(mIfname),
+                     GET_CHAR(mWifictrlinterfacename),
+                     GET_CHAR(mSsid),
+                     GET_CHAR(mSecurity),
+                     GET_CHAR(mKey));
+  }
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::cleanUpStream(CommandChain* aChain,
+                                 CommandCallback aCallback,
+                                 NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "nat disable %s %s 0", GET_CHAR(mPreInternalIfname), GET_CHAR(mPreExternalIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::createUpStream(CommandChain* aChain,
+                                  CommandCallback aCallback,
+                                  NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "nat enable %s %s 0", GET_CHAR(mCurInternalIfname), GET_CHAR(mCurExternalIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::startSoftAP(CommandChain* aChain,
+                               CommandCallback aCallback,
+                               NetworkResultOptions& aResult)
+{
+  const char* command= "softap startap";
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::stopSoftAP(CommandChain* aChain,
+                              CommandCallback aCallback,
+                              NetworkResultOptions& aResult)
+{
+  const char* command= "softap stopap";
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::getRxBytes(CommandChain* aChain,
+                              CommandCallback aCallback,
+                              NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "interface readrxcounter %s", GET_CHAR(mIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::getTxBytes(CommandChain* aChain,
+                              CommandCallback aCallback,
+                              NetworkResultOptions& aResult)
+{
+  NetworkParams& options = aChain->getParams();
+  options.mRxBytes = atof(NS_ConvertUTF16toUTF8(aResult.mResultReason).get());
+
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "interface readtxcounter %s", GET_CHAR(mIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::enableAlarm(CommandChain* aChain,
+                               CommandCallback aCallback,
+                               NetworkResultOptions& aResult)
+{
+  const char* command= "bandwidth enable";
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::disableAlarm(CommandChain* aChain,
+                                CommandCallback aCallback,
+                                NetworkResultOptions& aResult)
+{
+  const char* command= "bandwidth disable";
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::setQuota(CommandChain* aChain,
+                            CommandCallback aCallback,
+                            NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth setiquota %s %lld", GET_CHAR(mIfname), atoll("0xffffffffffffffff"));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::removeQuota(CommandChain* aChain,
+                               CommandCallback aCallback,
+                               NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth removeiquota %s", GET_CHAR(mIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::setAlarm(CommandChain* aChain,
+                            CommandCallback aCallback,
+                            NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth setinterfacealert %s %ld", GET_CHAR(mIfname), GET_FIELD(mThreshold));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::setInterfaceUp(CommandChain* aChain,
+                                  CommandCallback aCallback,
+                                  NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  if (SDK_VERSION >= 16) {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "interface setcfg %s %s %s %s",
+                     GET_CHAR(mIfname),
+                     GET_CHAR(mIp),
+                     GET_CHAR(mPrefix),
+                     GET_CHAR(mLink));
+  } else {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "interface setcfg %s %s %s [%s]",
+                     GET_CHAR(mIfname),
+                     GET_CHAR(mIp),
+                     GET_CHAR(mPrefix),
+                     GET_CHAR(mLink));
+  }
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::tetherInterface(CommandChain* aChain,
+                                   CommandCallback aCallback,
+                                   NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface add %s", GET_CHAR(mIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::preTetherInterfaceList(CommandChain* aChain,
+                                          CommandCallback aCallback,
+                                          NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  if (SDK_VERSION >= 16) {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface list");
+  } else {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface list 0");
+  }
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::postTetherInterfaceList(CommandChain* aChain,
+                                           CommandCallback aCallback,
+                                           NetworkResultOptions& aResult)
+{
+  // Send the dummy command to continue the function chain.
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND);
+
+  char buf[BUF_SIZE];
+  const char* reason = NS_ConvertUTF16toUTF8(aResult.mResultReason).get();
+  memcpy(buf, reason, strlen(reason));
+  split(buf, INTERFACE_DELIMIT, GET_FIELD(mInterfaceList));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::setIpForwardingEnabled(CommandChain* aChain,
+                                          CommandCallback aCallback,
+                                          NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+
+  if (GET_FIELD(mEnable)) {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "ipfwd enable");
+  } else {
+    // Don't disable ip forwarding because others interface still need it.
+    // Send the dummy command to continue the function chain.
+    if (GET_FIELD(mInterfaceList).Length() > 1) {
+      snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND);
+    } else {
+      snprintf(command, MAX_COMMAND_SIZE - 1, "ipfwd disable");
+    }
+  }
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::tetheringStatus(CommandChain* aChain,
+                                   CommandCallback aCallback,
+                                   NetworkResultOptions& aResult)
+{
+  const char* command= "tether status";
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::stopTethering(CommandChain* aChain,
+                                 CommandCallback aCallback,
+                                 NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+
+  // Don't stop tethering because others interface still need it.
+  // Send the dummy to continue the function chain.
+  if (GET_FIELD(mInterfaceList).Length() > 1) {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND);
+  } else {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "tether stop");
+  }
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::startTethering(CommandChain* aChain,
+                                  CommandCallback aCallback,
+                                  NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+
+  // We don't need to start tethering again.
+  // Send the dummy command to continue the function chain.
+  if (aResult.mResultReason.Find("started") != kNotFound) {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND);
+  } else {
+    snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s", GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp));
+
+    // If usbStartIp/usbEndIp is not valid, don't append them since
+    // the trailing white spaces will be parsed to extra empty args
+    // See: http://androidxref.com/4.3_r2.1/xref/system/core/libsysutils/src/FrameworkListener.cpp#78
+    if (!GET_FIELD(mUsbStartIp).IsEmpty() && !GET_FIELD(mUsbEndIp).IsEmpty()) {
+      snprintf(command, MAX_COMMAND_SIZE - 1, "%s %s %s", command, GET_CHAR(mUsbStartIp), GET_CHAR(mUsbEndIp));
+    }
+  }
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::untetherInterface(CommandChain* aChain,
+                                     CommandCallback aCallback,
+                                     NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface remove %s", GET_CHAR(mIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::setDnsForwarders(CommandChain* aChain,
+                                    CommandCallback aCallback,
+                                    NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "tether dns set %s %s", GET_CHAR(mDns1), GET_CHAR(mDns2));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::enableNat(CommandChain* aChain,
+                             CommandCallback aCallback,
+                             NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "nat enable %s %s 0", GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::disableNat(CommandChain* aChain,
+                              CommandCallback aCallback,
+                              NetworkResultOptions& aResult)
+{
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "nat disable %s %s 0", GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
+
+  doCommand(command, aChain, aCallback);
+}
+
+#undef GET_CHAR
+#undef GET_FIELD
+
+/*
+ * Netd command success/fail function
+ */
+#define ASSIGN_FIELD(prop)  aResult.prop = aChain->getParams().prop;
+#define ASSIGN_FIELD_VALUE(prop, value)  aResult.prop = value;
+
+#define RUN_CHAIN(param, cmds, err)                                \
+  uint32_t size = sizeof(cmds) / sizeof(CommandFunc);              \
+  CommandChain* chain = new CommandChain(param, cmds, size, err);  \
+  NetworkResultOptions result;                                     \
+  next(chain, false, result);
+
+void NetworkUtils::wifiTetheringFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
+{
+  // Notify the main thread.
+  postMessage(aOptions, aResult);
+
+  // If one of the stages fails, we try roll back to ensure
+  // we don't leave the network systems in limbo.
+  ASSIGN_FIELD_VALUE(mEnable, false)
+  RUN_CHAIN(aOptions, sWifiFailChain, nullptr)
+}
+
+void NetworkUtils::wifiTetheringSuccess(CommandChain* aChain,
+                                        CommandCallback aCallback,
+                                        NetworkResultOptions& aResult)
+{
+  ASSIGN_FIELD(mEnable)
+  postMessage(aChain->getParams(), aResult);
+}
+
+void NetworkUtils::usbTetheringFail(NetworkParams& aOptions,
+                                    NetworkResultOptions& aResult)
+{
+  // Notify the main thread.
+  postMessage(aOptions, aResult);
+  // Try to roll back to ensure
+  // we don't leave the network systems in limbo.
+  // This parameter is used to disable ipforwarding.
+  {
+    aOptions.mEnable = false;
+    RUN_CHAIN(aOptions, sUSBFailChain, nullptr)
+  }
+
+  // Disable usb rndis function.
+  {
+    NetworkParams options;
+    options.mEnable = false;
+    options.mReport = false;
+    gNetworkUtils->enableUsbRndis(options);
+  }
+}
+
+void NetworkUtils::usbTetheringSuccess(CommandChain* aChain,
+                                       CommandCallback aCallback,
+                                       NetworkResultOptions& aResult)
+{
+  ASSIGN_FIELD(mEnable)
+  postMessage(aChain->getParams(), aResult);
+}
+
+void NetworkUtils::networkInterfaceStatsFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
+{
+  postMessage(aOptions, aResult);
+}
+
+void NetworkUtils::networkInterfaceStatsSuccess(CommandChain* aChain,
+                                                CommandCallback aCallback,
+                                                NetworkResultOptions& aResult)
+{
+  ASSIGN_FIELD(mRxBytes)
+  ASSIGN_FIELD_VALUE(mTxBytes, atof(NS_ConvertUTF16toUTF8(aResult.mResultReason).get()))
+  postMessage(aChain->getParams(), aResult);
+}
+
+void NetworkUtils::networkInterfaceAlarmFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
+{
+  postMessage(aOptions, aResult);
+}
+
+void NetworkUtils::networkInterfaceAlarmSuccess(CommandChain* aChain,
+                                                CommandCallback aCallback,
+                                                NetworkResultOptions& aResult)
+{
+  // TODO : error is not used , and it is conflict with boolean type error.
+  // params.error = parseFloat(params.resultReason);
+  postMessage(aChain->getParams(), aResult);
+}
+
+void NetworkUtils::updateUpStreamFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
+{
+  postMessage(aOptions, aResult);
+}
+
+void NetworkUtils::updateUpStreamSuccess(CommandChain* aChain,
+                                         CommandCallback aCallback,
+                                         NetworkResultOptions& aResult)
+{
+  ASSIGN_FIELD(mCurExternalIfname)
+  ASSIGN_FIELD(mCurInternalIfname)
+  postMessage(aChain->getParams(), aResult);
+}
+
+void NetworkUtils::setDhcpServerFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
+{
+  aResult.mSuccess = false;
+  postMessage(aOptions, aResult);
+}
+
+void NetworkUtils::setDhcpServerSuccess(CommandChain* aChain, CommandCallback aCallback, NetworkResultOptions& aResult)
+{
+  aResult.mSuccess = true;
+  postMessage(aChain->getParams(), aResult);
+}
+
+void NetworkUtils::wifiOperationModeFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
+{
+  postMessage(aOptions, aResult);
+}
+
+void NetworkUtils::wifiOperationModeSuccess(CommandChain* aChain,
+                                            CommandCallback aCallback,
+                                            NetworkResultOptions& aResult)
+{
+  postMessage(aChain->getParams(), aResult);
+}
+
+#undef ASSIGN_FIELD
+#undef ASSIGN_FIELD_VALUE
+
+NetworkUtils::NetworkUtils(MessageCallback aCallback)
+ : mMessageCallback(aCallback)
+{
+  mNetUtils = new NetUtils();
+
+  char value[PROPERTY_VALUE_MAX];
+  property_get("ro.build.version.sdk", value, nullptr);
+  SDK_VERSION = atoi(value);
+
+  gNetworkUtils = this;
+}
+
+NetworkUtils::~NetworkUtils()
+{
+}
+
+#define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aOptions.prop).get()
+
+void NetworkUtils::ExecuteCommand(NetworkParams aOptions)
+{
+  bool ret = true;
+
+  if (aOptions.mCmd.EqualsLiteral("removeNetworkRoute")) {
+    removeNetworkRoute(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("setDNS")) {
+    setDNS(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("setDefaultRouteAndDNS")) {
+    setDefaultRouteAndDNS(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("removeDefaultRoute")) {
+    removeDefaultRoute(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("addHostRoute")) {
+    addHostRoute(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("removeHostRoute")) {
+    removeHostRoute(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("removeHostRoutes")) {
+    removeHostRoutes(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("getNetworkInterfaceStats")) {
+    getNetworkInterfaceStats(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("setNetworkInterfaceAlarm")) {
+    setNetworkInterfaceAlarm(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("enableNetworkInterfaceAlarm")) {
+    enableNetworkInterfaceAlarm(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("disableNetworkInterfaceAlarm")) {
+    disableNetworkInterfaceAlarm(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("setWifiOperationMode")) {
+    setWifiOperationMode(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("setDhcpServer")) {
+    setDhcpServer(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("setWifiTethering")) {
+    setWifiTethering(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("setUSBTethering")) {
+    setUSBTethering(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("enableUsbRndis")) {
+    enableUsbRndis(aOptions);
+  } else if (aOptions.mCmd.EqualsLiteral("updateUpStream")) {
+    updateUpStream(aOptions);
+  } else {
+    WARN("unknon message");
+    return;
+  }
+
+  if (!aOptions.mIsAsync) {
+    NetworkResultOptions result;
+    result.mRet = ret;
+    postMessage(aOptions, result);
+  }
+}
+
+/**
+ * Handle received data from netd.
+ */
+void NetworkUtils::onNetdMessage(NetdCommand* aCommand)
+{
+  char* data = (char*)aCommand->mData;
+
+  // get code & reason.
+  char* result = strtok(data, NETD_MESSAGE_DELIMIT);
+
+  if (!result) {
+    nextNetdCommand();
+    return;
+  }
+  uint32_t code = atoi(result);
+
+  if (!isBroadcastMessage(code) && SDK_VERSION >= 16) {
+    strtok(nullptr, NETD_MESSAGE_DELIMIT);
+  }
+
+  char* reason = strtok(nullptr, "\0");
+
+  if (isBroadcastMessage(code)) {
+    DEBUG("Receiving broadcast message from netd.");
+    DEBUG("          ==> Code: %d  Reason: %s", code, reason);
+    sendBroadcastMessage(code, reason);
+    nextNetdCommand();
+    return;
+  }
+
+   // Set pending to false before we handle next command.
+  DEBUG("Receiving \"%s\" command response from netd.", gCurrentCommand.command);
+  DEBUG("          ==> Code: %d  Reason: %s", code, reason);
+
+  gReason.AppendElement(nsCString(reason));
+
+  // 1xx response code regards as command is proceeding, we need to wait for
+  // final response code such as 2xx, 4xx and 5xx before sending next command.
+  if (isProceeding(code)) {
+    return;
+  }
+
+  if (isComplete(code)) {
+    gPending = false;
+  }
+
+  if (gCurrentCommand.callback) {
+    char buf[BUF_SIZE];
+    join(gReason, INTERFACE_DELIMIT, BUF_SIZE, buf);
+
+    NetworkResultOptions result;
+    result.mResultCode = code;
+    result.mResultReason = NS_ConvertUTF8toUTF16(buf);
+    join(gReason, INTERFACE_DELIMIT, BUF_SIZE, buf);
+    (*gCurrentCommand.callback)(gCurrentCommand.chain, isError(code), result);
+    gReason.Clear();
+  }
+
+  // Handling pending commands if any.
+  if (isComplete(code)) {
+    nextNetdCommand();
+  }
+}
+
+/**
+ * Start/Stop DHCP server.
+ */
+bool 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 true;
+}
+
+/**
+ * Set DNS servers for given network interface.
+ */
+bool NetworkUtils::setDNS(NetworkParams& aOptions)
+{
+  IFProperties interfaceProperties;
+  getIFProperties(GET_CHAR(mIfname), interfaceProperties);
+
+  if (aOptions.mDns1_str.IsEmpty()) {
+    property_set("net.dns1", interfaceProperties.dns1);
+  } else {
+    property_set("net.dns1", GET_CHAR(mDns1_str));
+  }
+
+  if (aOptions.mDns2_str.IsEmpty()) {
+    property_set("net.dns2", interfaceProperties.dns2);
+  } else {
+    property_set("net.dns2", GET_CHAR(mDns2_str));
+  }
+
+  // Bump the DNS change property.
+  char dnschange[PROPERTY_VALUE_MAX];
+  property_get("net.dnschange", dnschange, "0");
+
+  char num[PROPERTY_VALUE_MAX];
+  snprintf(num, PROPERTY_VALUE_MAX - 1, "%d", atoi(dnschange) + 1);
+  property_set("net.dnschange", num);
+
+  return true;
+}
+
+/**
+ * Set default route and DNS servers for given network interface.
+ */
+bool NetworkUtils::setDefaultRouteAndDNS(NetworkParams& aOptions)
+{
+  if (!aOptions.mOldIfname.IsEmpty()) {
+    mNetUtils->do_ifc_remove_default_route(GET_CHAR(mOldIfname));
+  }
+
+  IFProperties ifprops;
+  getIFProperties(GET_CHAR(mIfname), ifprops);
+
+  if (aOptions.mGateway_str.IsEmpty()) {
+    mNetUtils->do_ifc_set_default_route(GET_CHAR(mIfname), inet_addr(ifprops.gateway));
+  } else {
+    mNetUtils->do_ifc_set_default_route(GET_CHAR(mIfname), inet_addr(GET_CHAR(mGateway_str)));
+  }
+
+  setDNS(aOptions);
+  return true;
+}
+
+/**
+ * Remove default route for given network interface.
+ */
+bool NetworkUtils::removeDefaultRoute(NetworkParams& aOptions)
+{
+  mNetUtils->do_ifc_remove_default_route(GET_CHAR(mIfname));
+  return true;
+}
+
+/**
+ * Add host route for given network interface.
+ */
+bool NetworkUtils::addHostRoute(NetworkParams& aOptions)
+{
+  uint32_t length = aOptions.mHostnames.Length();
+  for (uint32_t i = 0; i < length; i++) {
+    mNetUtils->do_ifc_add_route(GET_CHAR(mIfname), GET_CHAR(mHostnames[i]), 32, GET_CHAR(mGateway));
+  }
+  return true;
+}
+
+/**
+ * Remove host route for given network interface.
+ */
+bool NetworkUtils::removeHostRoute(NetworkParams& aOptions)
+{
+  uint32_t length = aOptions.mHostnames.Length();
+  for (uint32_t i = 0; i < length; i++) {
+    mNetUtils->do_ifc_remove_route(GET_CHAR(mIfname), GET_CHAR(mHostnames[i]), 32, GET_CHAR(mGateway));
+  }
+  return true;
+}
+
+/**
+ * Remove the routes associated with the named interface.
+ */
+bool NetworkUtils::removeHostRoutes(NetworkParams& aOptions)
+{
+  mNetUtils->do_ifc_remove_host_routes(GET_CHAR(mIfname));
+  return true;
+}
+
+bool NetworkUtils::removeNetworkRoute(NetworkParams& aOptions)
+{
+  uint32_t ip = inet_addr(GET_CHAR(mIp));
+  uint32_t netmask = inet_addr(GET_CHAR(mNetmask));
+  uint32_t subnet = ip & netmask;
+  uint32_t prefixLength = getMaskLength(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(GET_CHAR(mIfname));
+  mNetUtils->do_ifc_remove_route(GET_CHAR(mIfname), dst, prefixLength, gateway);
+  return true;
+}
+
+bool NetworkUtils::getNetworkInterfaceStats(NetworkParams& aOptions)
+{
+  DEBUG("getNetworkInterfaceStats: %s", GET_CHAR(mIfname));
+  aOptions.mRxBytes = -1;
+  aOptions.mTxBytes = -1;
+
+  RUN_CHAIN(aOptions, sNetworkInterfaceStatsChain, networkInterfaceStatsFail);
+  return  true;
+}
+
+bool NetworkUtils::setNetworkInterfaceAlarm(NetworkParams& aOptions)
+{
+  DEBUG("setNetworkInterfaceAlarms: %s", GET_CHAR(mIfname));
+  RUN_CHAIN(aOptions, sNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail);
+  return true;
+}
+
+bool NetworkUtils::enableNetworkInterfaceAlarm(NetworkParams& aOptions)
+{
+  DEBUG("enableNetworkInterfaceAlarm: %s", GET_CHAR(mIfname));
+  RUN_CHAIN(aOptions, sNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail);
+  return true;
+}
+
+bool NetworkUtils::disableNetworkInterfaceAlarm(NetworkParams& aOptions)
+{
+  DEBUG("disableNetworkInterfaceAlarms: %s", GET_CHAR(mIfname));
+  RUN_CHAIN(aOptions, sNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail);
+  return true;
+}
+
+/**
+ * handling main thread's reload Wifi firmware request
+ */
+bool NetworkUtils::setWifiOperationMode(NetworkParams& aOptions)
+{
+  DEBUG("setWifiOperationMode: %s %s", GET_CHAR(mIfname), GET_CHAR(mMode));
+  RUN_CHAIN(aOptions, sWifiOperationModeChain, wifiOperationModeFail);
+  return true;
+}
+
+/**
+ * handling main thread's enable/disable WiFi Tethering request
+ */
+bool NetworkUtils::setWifiTethering(NetworkParams& aOptions)
+{
+  bool enable = aOptions.mEnable;
+  IFProperties interfaceProperties;
+  getIFProperties(GET_CHAR(mExternalIfname), interfaceProperties);
+
+  if (strcmp(interfaceProperties.dns1, "")) {
+    aOptions.mDns1 = NS_ConvertUTF8toUTF16(interfaceProperties.dns1);
+  }
+  if (strcmp(interfaceProperties.dns2, "")) {
+    aOptions.mDns2 = NS_ConvertUTF8toUTF16(interfaceProperties.dns2);
+  }
+  dumpParams(aOptions, "WIFI");
+
+  if (enable) {
+    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 true;
+}
+
+bool NetworkUtils::setUSBTethering(NetworkParams& aOptions)
+{
+  bool enable = aOptions.mEnable;
+  IFProperties interfaceProperties;
+  getIFProperties(GET_CHAR(mExternalIfname), interfaceProperties);
+
+  if (strcmp(interfaceProperties.dns1, "")) {
+    aOptions.mDns1 = NS_ConvertUTF8toUTF16(interfaceProperties.dns1);
+  }
+  if (strcmp(interfaceProperties.dns2, "")) {
+    aOptions.mDns2 = NS_ConvertUTF8toUTF16(interfaceProperties.dns2);
+  }
+  dumpParams(aOptions, "USB");
+
+  if (enable) {
+    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 true;
+}
+
+void 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;
+  }
+  if (retry < USB_FUNCTION_RETRY_TIMES) {
+    retry++;
+    usleep(USB_FUNCTION_RETRY_INTERVAL * 1000);
+    checkUsbRndisState(aOptions);
+    return;
+  }
+
+  NetworkResultOptions result;
+  result.mResult = false;
+  postMessage(aOptions, result);
+  retry = 0;
+}
+
+/**
+ * Modify usb function's property to turn on USB RNDIS function
+ */
+bool 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.
+  //
+  // On the otoro/unagi, persist.sys.usb.config should be one of:
+  //
+  //    diag,modem,nmea,mass_storage
+  //    diag,modem,nmea,mass_storage,adb
+  //
+  // When rndis is enabled, sys.usb.config should be one of:
+  //
+  //    rdnis
+  //    rndis,adb
+  //
+  // and when rndis is disabled, it should revert to persist.sys.usb.config
+
+  char currentConfig[PROPERTY_VALUE_MAX];
+  property_get(SYS_USB_CONFIG_PROPERTY, currentConfig, nullptr);
+
+  nsTArray<nsCString> configFuncs;
+  split(currentConfig, USB_CONFIG_DELIMIT, configFuncs);
+
+  char persistConfig[PROPERTY_VALUE_MAX];
+  property_get(PERSIST_SYS_USB_CONFIG_PROPERTY, persistConfig, nullptr);
+
+  nsTArray<nsCString> persistFuncs;
+  split(persistConfig, USB_CONFIG_DELIMIT, persistFuncs);
+
+  if (aOptions.mEnable) {
+    configFuncs.Clear();
+    configFuncs.AppendElement(nsCString(USB_FUNCTION_RNDIS));
+    if (persistFuncs.Contains(nsCString(USB_FUNCTION_ADB))) {
+      configFuncs.AppendElement(nsCString(USB_FUNCTION_ADB));
+    }
+  } else {
+    // We're turning rndis off, revert back to the persist setting.
+    // adb will already be correct there, so we don't need to do any
+    // further adjustments.
+    configFuncs = persistFuncs;
+  }
+
+  char newConfig[PROPERTY_VALUE_MAX] = "";
+  property_get(SYS_USB_CONFIG_PROPERTY, currentConfig, nullptr);
+  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 true;
+}
+
+/**
+ * handling upstream interface change event.
+ */
+bool NetworkUtils::updateUpStream(NetworkParams& aOptions)
+{
+  RUN_CHAIN(aOptions, sUpdateUpStreamChain, updateUpStreamFail)
+  return true;
+}
+
+void NetworkUtils::sendBroadcastMessage(uint32_t code, char* reason)
+{
+  NetworkResultOptions result;
+  switch(code) {
+    case NETD_COMMAND_INTERFACE_CHANGE:
+      result.mTopic = NS_ConvertUTF8toUTF16("netd-interface-change");
+      break;
+    case NETD_COMMAND_BANDWIDTH_CONTROLLER:
+      result.mTopic = NS_ConvertUTF8toUTF16("netd-bandwidth-control");
+      break;
+    default:
+      return;
+  }
+
+  result.mBroadcast = true;
+  result.mReason = NS_ConvertUTF8toUTF16(reason);
+  postMessage(result);
+}
+
+inline uint32_t NetworkUtils::netdResponseType(uint32_t code)
+{
+  return (code / 100) * 100;
+}
+
+inline bool NetworkUtils::isBroadcastMessage(uint32_t code)
+{
+  uint32_t type = netdResponseType(code);
+  return type == NETD_COMMAND_UNSOLICITED;
+}
+
+inline bool NetworkUtils::isError(uint32_t code)
+{
+  uint32_t type = netdResponseType(code);
+  return type != NETD_COMMAND_PROCEEDING && type != NETD_COMMAND_OKAY;
+}
+
+inline bool NetworkUtils::isComplete(uint32_t code)
+{
+  uint32_t type = netdResponseType(code);
+  return type != NETD_COMMAND_PROCEEDING;
+}
+
+inline bool NetworkUtils::isProceeding(uint32_t code)
+{
+  uint32_t type = netdResponseType(code);
+  return type == NETD_COMMAND_PROCEEDING;
+}
+
+void NetworkUtils::dumpParams(NetworkParams& aOptions, const char* aType)
+{
+#ifdef _DEBUG
+  DEBUG("Dump params:");
+  DEBUG("     ifname: %s", GET_CHAR(mIfname));
+  DEBUG("     ip: %s", GET_CHAR(mIp));
+  DEBUG("     link: %s", GET_CHAR(mLink));
+  DEBUG("     prefix: %s", GET_CHAR(mPrefix));
+  DEBUG("     wifiStartIp: %s", GET_CHAR(mWifiStartIp));
+  DEBUG("     wifiEndIp: %s", GET_CHAR(mWifiEndIp));
+  DEBUG("     usbStartIp: %s", GET_CHAR(mUsbStartIp));
+  DEBUG("     usbEndIp: %s", GET_CHAR(mUsbEndIp));
+  DEBUG("     dnsserver1: %s", GET_CHAR(mDns1));
+  DEBUG("     dnsserver2: %s", GET_CHAR(mDns2));
+  DEBUG("     internalIfname: %s", GET_CHAR(mInternalIfname));
+  DEBUG("     externalIfname: %s", GET_CHAR(mExternalIfname));
+  if (!strcmp(aType, "WIFI")) {
+    DEBUG("     wifictrlinterfacename: %s", GET_CHAR(mWifictrlinterfacename));
+    DEBUG("     ssid: %s", GET_CHAR(mSsid));
+    DEBUG("     security: %s", GET_CHAR(mSecurity));
+    DEBUG("     key: %s", GET_CHAR(mKey));
+  }
+#endif
+}
+
+#undef GET_CHAR
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/NetworkUtils.h
@@ -0,0 +1,389 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef NetworkUtils_h
+#define NetworkUtils_h
+
+#include "nsString.h"
+#include "mozilla/dom/NetworkOptionsBinding.h"
+#include "mozilla/dom/network/NetUtils.h"
+#include "mozilla/ipc/Netd.h"
+#include "nsTArray.h"
+
+class NetworkParams;
+class CommandChain;
+
+using namespace mozilla::dom;
+
+typedef void (*CommandCallback)(CommandChain*, bool, NetworkResultOptions& aResult);
+typedef void (*CommandFunc)(CommandChain*, CommandCallback, NetworkResultOptions& aResult);
+typedef void (*MessageCallback)(NetworkResultOptions& aResult);
+typedef void (*ErrorCallback)(NetworkParams& aOptions, NetworkResultOptions& aResult);
+
+class NetworkParams
+{
+public:
+  NetworkParams() {
+  }
+
+  NetworkParams(const NetworkParams& aOther) {
+    mIp = aOther.mIp;
+    mCmd = aOther.mCmd;
+    mDns1_str = aOther.mDns1_str;
+    mDns2_str = aOther.mDns2_str;
+    mGateway = aOther.mGateway;
+    mGateway_str = aOther.mGateway_str;
+    mHostnames = aOther.mHostnames;
+    mId = aOther.mId;
+    mIfname = aOther.mIfname;
+    mNetmask = aOther.mNetmask;
+    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;
+    mRxBytes = aOther.mRxBytes;
+    mTxBytes = aOther.mTxBytes;
+    mDate = aOther.mDate;
+    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 NetworkCommandOptions& aOther) {
+
+#define COPY_SEQUENCE_FIELD(prop)                                                            \
+    if (aOther.prop.WasPassed()) {                                                           \
+      mozilla::dom::Sequence<nsString > const & currentValue = aOther.prop.InternalValue();  \
+      uint32_t length = currentValue.Length();                                               \
+      for (uint32_t idx = 0; idx < length; idx++) {                                          \
+        mHostnames.AppendElement(currentValue[idx]);                                         \
+      }                                                                                      \
+    }
+
+#define COPY_OPT_STRING_FIELD(prop, defaultValue)       \
+    if (aOther.prop.WasPassed()) {                      \
+      if (aOther.prop.Value().EqualsLiteral("null")) {  \
+        prop = defaultValue;                            \
+      } else {                                          \
+        prop = aOther.prop.Value();                     \
+      }                                                 \
+    } else {                                            \
+      prop = defaultValue;                              \
+    }
+
+#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_STRING_FIELD(mDns1_str, EmptyString())
+    COPY_OPT_STRING_FIELD(mDns2_str, EmptyString())
+    COPY_OPT_STRING_FIELD(mGateway, EmptyString())
+    COPY_OPT_STRING_FIELD(mGateway_str, EmptyString())
+    COPY_SEQUENCE_FIELD(mHostnames)
+    COPY_OPT_STRING_FIELD(mIfname, EmptyString())
+    COPY_OPT_STRING_FIELD(mIp, EmptyString())
+    COPY_OPT_STRING_FIELD(mNetmask, EmptyString())
+    COPY_OPT_STRING_FIELD(mOldIfname, EmptyString())
+    COPY_OPT_STRING_FIELD(mMode, EmptyString())
+    COPY_OPT_FIELD(mReport, false)
+    COPY_OPT_FIELD(mIsAsync, true)
+    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())
+    COPY_OPT_STRING_FIELD(mPrefix, EmptyString())
+    COPY_OPT_STRING_FIELD(mLink, EmptyString())
+    COPY_SEQUENCE_FIELD(mInterfaceList)
+    COPY_OPT_STRING_FIELD(mWifiStartIp, EmptyString())
+    COPY_OPT_STRING_FIELD(mWifiEndIp, EmptyString())
+    COPY_OPT_STRING_FIELD(mUsbStartIp, EmptyString())
+    COPY_OPT_STRING_FIELD(mUsbEndIp, EmptyString())
+    COPY_OPT_STRING_FIELD(mDns1, EmptyString())
+    COPY_OPT_STRING_FIELD(mDns2, EmptyString())
+    COPY_OPT_FIELD(mRxBytes, -1)
+    COPY_OPT_FIELD(mTxBytes, -1)
+    COPY_OPT_STRING_FIELD(mDate, EmptyString())
+    COPY_OPT_STRING_FIELD(mStartIp, EmptyString())
+    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)
+
+#undef COPY_SEQUENCE_FIELD
+#undef COPY_OPT_STRING_FIELD
+#undef COPY_OPT_FIELD
+#undef COPY_FIELD
+  }
+
+  int32_t mId;
+  nsString mCmd;
+  nsString mDns1_str;
+  nsString mDns2_str;
+  nsString mGateway;
+  nsString mGateway_str;
+  nsTArray<nsString> mHostnames;
+  nsString mIfname;
+  nsString mIp;
+  nsString mNetmask;
+  nsString mOldIfname;
+  nsString mMode;
+  bool mReport;
+  bool mIsAsync;
+  bool mEnabled;
+  nsString mWifictrlinterfacename;
+  nsString mInternalIfname;
+  nsString mExternalIfname;
+  bool mEnable;
+  nsString mSsid;
+  nsString mSecurity;
+  nsString mKey;
+  nsString mPrefix;
+  nsString mLink;
+  nsTArray<nsCString> mInterfaceList;
+  nsString mWifiStartIp;
+  nsString mWifiEndIp;
+  nsString mUsbStartIp;
+  nsString mUsbEndIp;
+  nsString mDns1;
+  nsString mDns2;
+  float mRxBytes;
+  float mTxBytes;
+  nsString mDate;
+  nsString mStartIp;
+  nsString mEndIp;
+  nsString mServerIp;
+  nsString mMaskLength;
+  nsString mPreInternalIfname;
+  nsString mPreExternalIfname;
+  nsString mCurInternalIfname;
+  nsString mCurExternalIfname;
+  long mThreshold;
+};
+
+// 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.
+class CommandChain MOZ_FINAL
+{
+public:
+  CommandChain(const NetworkParams& aParams,
+               CommandFunc aCmds[],
+               uint32_t aLength,
+               ErrorCallback aError)
+  : mIndex(-1)
+  , mParams(aParams)
+  , mCommands(aCmds)
+  , mLength(aLength)
+  , mError(aError) {
+  }
+
+  NetworkParams&
+  getParams()
+  {
+    return mParams;
+  };
+
+  CommandFunc
+  getNextCommand()
+  {
+    mIndex++;
+    return mIndex < mLength ? mCommands[mIndex] : nullptr;
+  };
+
+  ErrorCallback
+  getErrorCallback() const
+  {
+    return mError;
+  };
+
+private:
+  uint32_t mIndex;
+  NetworkParams mParams;
+  CommandFunc* mCommands;
+  uint32_t mLength;
+  ErrorCallback mError;
+};
+
+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.
+   */
+  bool setDNS(NetworkParams& aOptions);
+  bool setDefaultRouteAndDNS(NetworkParams& aOptions);
+  bool addHostRoute(NetworkParams& aOptions);
+  bool removeDefaultRoute(NetworkParams& aOptions);
+  bool removeHostRoute(NetworkParams& aOptions);
+  bool removeHostRoutes(NetworkParams& aOptions);
+  bool removeNetworkRoute(NetworkParams& aOptions);
+  bool getNetworkInterfaceStats(NetworkParams& aOptions);
+  bool setNetworkInterfaceAlarm(NetworkParams& aOptions);
+  bool enableNetworkInterfaceAlarm(NetworkParams& aOptions);
+  bool disableNetworkInterfaceAlarm(NetworkParams& aOptions);
+  bool setWifiOperationMode(NetworkParams& aOptions);
+  bool setDhcpServer(NetworkParams& aOptions);
+  bool setWifiTethering(NetworkParams& aOptions);
+  bool setUSBTethering(NetworkParams& aOptions);
+  bool enableUsbRndis(NetworkParams& aOptions);
+  bool 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[];
+  static CommandFunc sWifiOperationModeChain[];
+  static CommandFunc sUSBEnableChain[];
+  static CommandFunc sUSBDisableChain[];
+  static CommandFunc sUSBFailChain[];
+  static CommandFunc sUpdateUpStreamChain[];
+  static CommandFunc sStartDhcpServerChain[];
+  static CommandFunc sStopDhcpServerChain[];
+  static CommandFunc sNetworkInterfaceStatsChain[];
+  static CommandFunc sNetworkInterfaceEnableAlarmChain[];
+  static CommandFunc sNetworkInterfaceDisableAlarmChain[];
+  static CommandFunc sNetworkInterfaceSetAlarmChain[];
+
+  /**
+   * Individual netd command stored in command chain.
+   */
+#define PARAMS CommandChain* aChain, CommandCallback aCallback, NetworkResultOptions& aResult
+  static void wifiFirmwareReload(PARAMS);
+  static void startAccessPointDriver(PARAMS);
+  static void stopAccessPointDriver(PARAMS);
+  static void setAccessPoint(PARAMS);
+  static void cleanUpStream(PARAMS);
+  static void createUpStream(PARAMS);
+  static void startSoftAP(PARAMS);
+  static void stopSoftAP(PARAMS);
+  static void getRxBytes(PARAMS);
+  static void getTxBytes(PARAMS);
+  static void enableAlarm(PARAMS);
+  static void disableAlarm(PARAMS);
+  static void setQuota(PARAMS);
+  static void removeQuota(PARAMS);
+  static void setAlarm(PARAMS);
+  static void setInterfaceUp(PARAMS);
+  static void tetherInterface(PARAMS);
+  static void preTetherInterfaceList(PARAMS);
+  static void postTetherInterfaceList(PARAMS);
+  static void setIpForwardingEnabled(PARAMS);
+  static void tetheringStatus(PARAMS);
+  static void stopTethering(PARAMS);
+  static void startTethering(PARAMS);
+  static void untetherInterface(PARAMS);
+  static void setDnsForwarders(PARAMS);
+  static void enableNat(PARAMS);
+  static void disableNat(PARAMS);
+  static void wifiTetheringSuccess(PARAMS);
+  static void usbTetheringSuccess(PARAMS);
+  static void networkInterfaceStatsSuccess(PARAMS);
+  static void networkInterfaceAlarmSuccess(PARAMS);
+  static void updateUpStreamSuccess(PARAMS);
+  static void setDhcpServerSuccess(PARAMS);
+  static void wifiOperationModeSuccess(PARAMS);
+#undef PARAMS
+
+  /**
+   * Error callback function executed when a command is fail.
+   */
+#define PARAMS NetworkParams& aOptions, NetworkResultOptions& aResult
+  static void wifiTetheringFail(PARAMS);
+  static void wifiOperationModeFail(PARAMS);
+  static void usbTetheringFail(PARAMS);
+  static void updateUpStreamFail(PARAMS);
+  static void setDhcpServerFail(PARAMS);
+  static void networkInterfaceStatsFail(PARAMS);
+  static void networkInterfaceAlarmFail(PARAMS);
+#undef PARAMS
+
+  /**
+   * Command chain processing functions.
+   */
+  static void next(CommandChain* aChain, bool aError, NetworkResultOptions& aResult);
+  static void nextNetdCommand();
+  static void doCommand(const char* aCommand, CommandChain* aChain, CommandCallback aCallback);
+
+  /**
+   * Notify broadcast message to main thread.
+   */
+  void sendBroadcastMessage(uint32_t code, char* reason);
+
+  /**
+   * Utility functions.
+   */
+  void checkUsbRndisState(NetworkParams& aOptions);
+  void dumpParams(NetworkParams& aOptions, const char* aType);
+
+  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);
+  void Shutdown();
+  /**
+   * Callback function to send netd result to main thread.
+   */
+  MessageCallback mMessageCallback;
+
+  /*
+   * Utility class to access libnetutils.
+   */
+  nsAutoPtr<NetUtils> mNetUtils;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/NetworkWorker.cpp
@@ -0,0 +1,263 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "NetworkWorker.h"
+#include "NetworkUtils.h"
+#include <nsThreadUtils.h>
+#include "mozilla/ModuleUtils.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "nsXULAppAPI.h"
+#include "nsCxPusher.h"
+
+#define NS_NETWORKWORKER_CID \
+  { 0x6df093e1, 0x8127, 0x4fa7, {0x90, 0x13, 0xa3, 0xaa, 0xa7, 0x79, 0xbb, 0xdd} }
+
+using namespace mozilla;
+using namespace mozilla::dom;
+using namespace mozilla::ipc;
+
+namespace mozilla {
+
+// The singleton network worker, to be used on the main thread.
+StaticRefPtr<NetworkWorker> gNetworkWorker;
+
+// 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)
+  {
+    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(mRxBytes)
+    COPY_FIELD(mTxBytes)
+    COPY_FIELD(mDate)
+    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);
+    }
+    return NS_OK;
+  }
+private:
+  NetworkResultOptions mResult;
+};
+
+// Runnable used dispatch netd command on the worker thread.
+class NetworkCommandDispatcher : public nsRunnable
+{
+public:
+  NetworkCommandDispatcher(const NetworkParams& aParams)
+    : mParams(aParams)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+  }
+
+  NS_IMETHOD Run()
+  {
+    if (gNetworkUtils) {
+      gNetworkUtils->ExecuteCommand(mParams);
+    }
+    return NS_OK;
+  }
+private:
+  NetworkParams mParams;
+};
+
+// Runnable used dispatch netd result on the worker thread.
+class NetdEventRunnable : public nsRunnable
+{
+public:
+  NetdEventRunnable(NetdCommand* aCommand)
+    : mCommand(aCommand)
+  { }
+
+  NS_IMETHOD Run()
+  {
+    if (gNetworkUtils) {
+      gNetworkUtils->onNetdMessage(mCommand);
+    }
+    return NS_OK;
+  }
+
+private:
+  nsAutoPtr<NetdCommand> mCommand;
+};
+
+NS_IMPL_ISUPPORTS1(NetworkWorker, nsINetworkWorker)
+
+NetworkWorker::NetworkWorker()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!gNetworkWorker);
+}
+
+NetworkWorker::~NetworkWorker()
+{
+  MOZ_ASSERT(!gNetworkWorker);
+}
+
+already_AddRefed<NetworkWorker>
+NetworkWorker::FactoryCreate()
+{
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return nullptr;
+  }
+
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!gNetworkWorker) {
+    gNetworkWorker = new NetworkWorker();
+    ClearOnShutdown(&gNetworkWorker);
+
+    gNetworkUtils = new NetworkUtils(NetworkWorker::NotifyResult);
+    ClearOnShutdown(&gNetworkUtils);
+  }
+
+  nsRefPtr<NetworkWorker> worker = gNetworkWorker.get();
+  return worker.forget();
+}
+
+NS_IMETHODIMP
+NetworkWorker::Start(nsINetworkEventListener* aListener)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aListener);
+
+  nsresult rv;
+
+  if (gNetworkWorker) {
+    StartNetd(gNetworkWorker);
+  }
+
+  rv = NS_NewThread(getter_AddRefs(mWorkerThread));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Can't create network control thread");
+    Shutdown();
+    return NS_ERROR_FAILURE;
+  }
+
+  mListener = aListener;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+NetworkWorker::Shutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  StopNetd();
+
+  if (mWorkerThread) {
+    mWorkerThread->Shutdown();
+    mWorkerThread = nullptr;
+  }
+  mListener = nullptr;
+  return NS_OK;
+}
+
+// Receive command from main thread (NetworkService.js).
+NS_IMETHODIMP
+NetworkWorker::PostMessage(JS::Handle<JS::Value> aOptions, JSContext* aCx)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  NetworkCommandOptions options;
+  if (!options.Init(aCx, aOptions)) {
+    NS_WARNING("Bad dictionary passed to NetworkWorker::SendCommand");
+    return NS_ERROR_FAILURE;
+  }
+
+  // Dispatch the command to the control thread.
+  NetworkParams NetworkParams(options);
+  nsCOMPtr<nsIRunnable> runnable = new NetworkCommandDispatcher(NetworkParams);
+  if (mWorkerThread) {
+    mWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
+  }
+  return NS_OK;
+}
+
+void
+NetworkWorker::DispatchNetworkResult(const NetworkResultOptions& aOptions)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mozilla::AutoSafeJSContext cx;
+  JS::RootedValue val(cx);
+
+  if (!aOptions.ToObject(cx, JS::NullPtr(), &val)) {
+    return;
+  }
+
+  // Call the listener with a JS value.
+  if (mListener) {
+    mListener->OnEvent(val);
+  }
+}
+
+// Callback function from Netd, dispatch result to network worker thread.
+void
+NetworkWorker::MessageReceived(NetdCommand* aCommand)
+{
+  nsCOMPtr<nsIRunnable> runnable = new NetdEventRunnable(aCommand);
+  if (mWorkerThread) {
+    mWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
+  }
+}
+
+// Callback function from network worker thread to update result on main thread.
+void
+NetworkWorker::NotifyResult(NetworkResultOptions& aResult)
+{
+  nsCOMPtr<nsIRunnable> runnable = new NetworkResultDispatcher(aResult);
+  NS_DispatchToMainThread(runnable);
+}
+
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(NetworkWorker,
+                                         NetworkWorker::FactoryCreate)
+
+NS_DEFINE_NAMED_CID(NS_NETWORKWORKER_CID);
+
+static const mozilla::Module::CIDEntry kNetworkWorkerCIDs[] = {
+  { &kNS_NETWORKWORKER_CID, false, nullptr, NetworkWorkerConstructor },
+  { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kNetworkWorkerContracts[] = {
+  { "@mozilla.org/network/worker;1", &kNS_NETWORKWORKER_CID },
+  { nullptr }
+};
+
+static const mozilla::Module kNetworkWorkerModule = {
+  mozilla::Module::kVersion,
+  kNetworkWorkerCIDs,
+  kNetworkWorkerContracts,
+  nullptr
+};
+
+} // namespace mozilla
+
+NSMODULE_DEFN(NetworkWorkerModule) = &kNetworkWorkerModule;
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/NetworkWorker.h
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef NetworkWorker_h
+#define NetworkWorker_h
+
+#include "mozilla/dom/NetworkOptionsBinding.h"
+#include "mozilla/ipc/Netd.h"
+#include "nsINetworkWorker.h"
+#include "nsCOMPtr.h"
+#include "nsThread.h"
+
+namespace mozilla {
+
+class NetworkWorker MOZ_FINAL : public nsINetworkWorker,
+                                public mozilla::ipc::NetdConsumer
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSINETWORKWORKER
+
+  static already_AddRefed<NetworkWorker> FactoryCreate();
+
+  void DispatchNetworkResult(const mozilla::dom::NetworkResultOptions& aOptions);
+  void MessageReceived(mozilla::ipc::NetdCommand* aMessage);
+
+private:
+  NetworkWorker();
+  ~NetworkWorker();
+
+  static void NotifyResult(mozilla::dom::NetworkResultOptions& aResult);
+
+  nsCOMPtr<nsIThread> mWorkerThread;
+  nsCOMPtr<nsINetworkEventListener> mListener;
+};
+
+} // namespace mozilla
+
+#endif  // NetworkWorker_h
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -102,17 +102,18 @@ const RIL_IPC_MSG_NAMES = [
   "RIL:UpdateIccContact",
   "RIL:SetRoamingPreference",
   "RIL:GetRoamingPreference",
   "RIL:ExitEmergencyCbMode",
   "RIL:SetRadioEnabled",
   "RIL:RadioStateChanged",
   "RIL:SetVoicePrivacyMode",
   "RIL:GetVoicePrivacyMode",
-  "RIL:OtaStatusChanged"
+  "RIL:OtaStatusChanged",
+  "RIL:MatchMvno"
 ];
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsISyncMessageSender");
 
 XPCOMUtils.defineLazyGetter(this, "gNumRadioInterfaces", function() {
   let appInfo = Cc["@mozilla.org/xre/app-info;1"];
@@ -631,16 +632,36 @@ RILContentHelper.prototype = {
     return context && context.iccInfo;
   },
 
   getCardState: function(clientId) {
     let context = this.getRilContext(clientId);
     return context && context.cardState;
   },
 
+  matchMvno: function(clientId, window, mvnoType, mvnoData) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+
+    let request = Services.DOMRequest.createRequest(window);
+    let requestId = this.getRequestId(request);
+
+    cpmm.sendAsyncMessage("RIL:MatchMvno", {
+      clientId: clientId,
+      data: {
+        requestId: requestId,
+        mvnoType: mvnoType,
+        mvnoData: mvnoData
+      }
+    });
+    return request;
+  },
+
   /**
    * nsIMobileConnectionProvider
    */
 
   getLastKnownNetwork: function(clientId) {
     return cpmm.sendSyncMessage("RIL:GetLastKnownNetwork", {
       clientId: clientId
     })[0];
@@ -1779,16 +1800,19 @@ RILContentHelper.prototype = {
         this.handleIccExchangeAPDU(data);
         break;
       case "RIL:ReadIccContacts":
         this.handleReadIccContacts(data);
         break;
       case "RIL:UpdateIccContact":
         this.handleUpdateIccContact(data);
         break;
+      case "RIL:MatchMvno":
+        this.handleSimpleRequest(data.requestId, data.errorMsg, data.result);
+        break;
       case "RIL:DataError":
         this.updateConnectionInfo(data, this.rilContexts[clientId].dataConnectionInfo);
         this._deliverEvent(clientId, "_mobileConnectionListeners", "notifyDataError",
                            [data.errorMsg]);
         break;
       case "RIL:GetCallForwardingOptions":
         this.handleGetCallForwardingOptions(data);
         break;
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -139,17 +139,18 @@ const RIL_IPC_ICCMANAGER_MSG_NAMES = [
   "RIL:UnlockCardLock",
   "RIL:SetCardLock",
   "RIL:GetCardLockRetryCount",
   "RIL:IccOpenChannel",
   "RIL:IccExchangeAPDU",
   "RIL:IccCloseChannel",
   "RIL:ReadIccContacts",
   "RIL:UpdateIccContact",
-  "RIL:RegisterIccMsg"
+  "RIL:RegisterIccMsg",
+  "RIL:MatchMvno"
 ];
 
 const RIL_IPC_VOICEMAIL_MSG_NAMES = [
   "RIL:RegisterVoicemailMsg",
   "RIL:GetVoicemailInfo"
 ];
 
 const RIL_IPC_CELLBROADCAST_MSG_NAMES = [
@@ -838,17 +839,17 @@ RadioInterfaceLayer.prototype = {
         let network = subject.QueryInterface(Ci.nsINetworkInterface);
         // DSDS: setup pending data connection when switching the default id
         // for data call. We can not use network.type to tell if it's
         // NETWORK_TYPE_MOBILE, since the type is removed from
         // RILNetworkInterface.connectedTypes on disconnect().
         if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN) {
           let oldRadioInterface =
             this.radioInterfaces[this._currentDataClientId];
-          if (!oldRadioInterface.anyDataConnected() &&
+          if (oldRadioInterface.allDataDisconnected() &&
               typeof this._pendingDataCallRequest === "function") {
             if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
               oldRadioInterface.setDataRegistration(false);
             }
             if (DEBUG) debug("All data calls disconnected, setup pending data call.");
             this._pendingDataCallRequest();
             this._pendingDataCallRequest = null;
           }
@@ -1393,16 +1394,19 @@ RadioInterface.prototype = {
         this.workerMessenger.sendWithIPCMessage(msg, "iccExchangeAPDU");
         break;
       case "RIL:ReadIccContacts":
         this.workerMessenger.sendWithIPCMessage(msg, "readICCContacts");
         break;
       case "RIL:UpdateIccContact":
         this.workerMessenger.sendWithIPCMessage(msg, "updateICCContact");
         break;
+      case "RIL:MatchMvno":
+        this.matchMvno(msg.target, msg.json.data);
+        break;
       case "RIL:SetCallForwardingOptions":
         this.setCallForwardingOptions(msg.target, msg.json.data);
         break;
       case "RIL:GetCallForwardingOptions":
         this.workerMessenger.sendWithIPCMessage(msg, "queryCallForwardStatus");
         break;
       case "RIL:SetCallBarringOptions":
         this.workerMessenger.sendWithIPCMessage(msg, "setCallBarring");
@@ -1634,16 +1638,62 @@ RadioInterface.prototype = {
     // See bug 808220
     if (iccId === undefined || iccId === "undefined") {
       return null;
     }
 
     return iccId;
   },
 
+  // Matches the mvnoData pattern with imsi. Characters 'x' and 'X' are skipped
+  // and not compared. E.g., if the mvnoData passed is '310260x10xxxxxx',
+  // then the function returns true only if imsi has the same first 6 digits,
+  // 8th and 9th digit.
+  isImsiMatches: function(mvnoData) {
+    let imsi = this.rilContext.imsi;
+
+    // This should not be an error, but a mismatch.
+    if (mvnoData.length > imsi.length) {
+      return false;
+    }
+
+    for (let i = 0; i < mvnoData.length; i++) {
+      let c = mvnoData[i];
+      if ((c !== 'x') && (c !== 'X') && (c !== imsi[i])) {
+        return false;
+      }
+    }
+    return true;
+  },
+
+  matchMvno: function(target, message) {
+    if (DEBUG) this.debug("matchMvno: " + JSON.stringify(message));
+
+    if (!message || !message.mvnoType || !message.mvnoData) {
+      message.errorMsg = RIL.GECKO_ERROR_INVALID_PARAMETER;
+    }
+    // Currently we only support imsi matching.
+    if (message.mvnoType != "imsi") {
+      message.errorMsg = RIL.GECKO_ERROR_MODE_NOT_SUPPORTED;
+    }
+    // Fire error if mvnoType is imsi but imsi is not available.
+    if (!this.rilContext.imsi) {
+      message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
+    }
+
+    if (!message.errorMsg) {
+      message.result = this.isImsiMatches(message.mvnoData);
+    }
+
+    target.sendAsyncMessage("RIL:MatchMvno", {
+      clientId: this.clientId,
+      data: message
+    });
+  },
+
   updateNetworkInfo: function(message) {
     let voiceMessage = message[RIL.NETWORK_INFO_VOICE_REGISTRATION_STATE];
     let dataMessage = message[RIL.NETWORK_INFO_DATA_REGISTRATION_STATE];
     let operatorMessage = message[RIL.NETWORK_INFO_OPERATOR];
     let selectionMessage = message[RIL.NETWORK_INFO_NETWORK_SELECTION_MODE];
     let signalMessage = message[RIL.NETWORK_INFO_SIGNAL];
 
     // Batch the *InfoChanged messages together
@@ -1687,22 +1737,25 @@ RadioInterface.prototype = {
     * Fix the roaming. RIL can report roaming in some case it is not
     * really the case. See bug 787967
     *
     * @param registration  The voiceMessage or dataMessage from which the
     *                      roaming state will be changed (maybe, if needed).
     */
   checkRoamingBetweenOperators: function(registration) {
     let iccInfo = this.rilContext.iccInfo;
-    if (!iccInfo || !registration.connected) {
+    let operator = registration.network;
+    let state = registration.state;
+
+    if (!iccInfo || !operator ||
+        state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
       return;
     }
 
     let spn = iccInfo.spn && iccInfo.spn.toLowerCase();
-    let operator = registration.network;
     let longName = operator.longName && operator.longName.toLowerCase();
     let shortName = operator.shortName && operator.shortName.toLowerCase();
 
     let equalsLongName = longName && (spn == longName);
     let equalsShortName = shortName && (spn == shortName);
     let equalsMcc = iccInfo.mcc == operator.mcc;
 
     registration.roaming = registration.roaming &&
@@ -2029,40 +2082,63 @@ RadioInterface.prototype = {
 
     // No data calls exist. It's safe to proceed the pending radio power off
     // request.
     if (gRadioEnabledController.isDeactivatingDataCalls() && !dataDisconnecting) {
       gRadioEnabledController.finishDeactivatingDataCalls(this.clientId);
     }
   },
 
+  updateApnSettings: function(allApnSettings) {
+    let simApnSettings = allApnSettings[this.clientId];
+    if (!simApnSettings) {
+      return;
+    }
+    if (this._pendingApnSettings) {
+      // Change of apn settings in process, just update to the newest.
+      this._pengingApnSettings = simApnSettings;
+      return;
+    }
+
+    let isDeactivatingDataCalls = false;
+    // Clear all existing connections based on APN types.
+    for each (let apnSetting in this.apnSettings.byApn) {
+      for each (let type in apnSetting.types) {
+        if (this.getDataCallStateByType(type) ==
+            RIL.GECKO_NETWORK_STATE_CONNECTED) {
+          this.deactivateDataCallByType(type);
+          isDeactivatingDataCalls = true;
+        }
+      }
+    }
+    if (isDeactivatingDataCalls) {
+      // Defer apn settings setup until all data calls are cleared.
+      this._pendingApnSettings = simApnSettings;
+      return;
+    }
+    this.setupApnSettings(simApnSettings);
+  },
+
   /**
    * This function will do the following steps:
    *   1. Clear the cached APN settings in the RIL.
    *   2. Combine APN, user name, and password as the key of |byApn| object to
    *      refer to the corresponding APN setting.
    *   3. Use APN type as the index of |byType| object to refer to the
    *      corresponding APN setting.
    *   4. Create RilNetworkInterface for each APN setting created at step 2.
    */
-  updateApnSettings: function(allApnSettings) {
-    let simApnSettings = allApnSettings[this.clientId];
+  setupApnSettings: function(simApnSettings) {
     if (!simApnSettings) {
       return;
     }
-
-    // Clear the cached APN settings in the RIL.
+    if (DEBUG) this.debug("setupApnSettings: " + JSON.stringify(simApnSettings));
+
+    // Unregister anything from iface and delete it.
     for each (let apnSetting in this.apnSettings.byApn) {
-      // Clear all existing connections based on APN types.
-      for each (let type in apnSetting.types) {
-        if (this.getDataCallStateByType(type) ==
-            RIL.GECKO_NETWORK_STATE_CONNECTED) {
-          this.deactivateDataCallByType(type);
-        }
-      }
       if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
         gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
       }
       this.unregisterDataCallCallback(apnSetting.iface);
       delete apnSetting.iface;
     }
     this.apnSettings.byApn = {};
     this.apnSettings.byType = {};
@@ -2095,23 +2171,32 @@ RadioInterface.prototype = {
     }
 
     // Create RilNetworkInterface for each APN setting that just cached.
     for each (let apnSetting in this.apnSettings.byApn) {
       apnSetting.iface = new RILNetworkInterface(this, apnSetting);
     }
   },
 
+  allDataDisconnected: function() {
+    for each (let apnSetting in this.apnSettings.byApn) {
+      let iface = apnSetting.iface;
+      if (iface && iface.state != RIL.GECKO_NETWORK_STATE_UNKNOWN &&
+          iface.state != RIL.GECKO_NETWORK_STATE_DISCONNECTED) {
+        return false;
+      }
+    }
+    return true;
+  },
+
   anyDataConnected: function() {
     for each (let apnSetting in this.apnSettings.byApn) {
-      for each (let type in apnSetting.types) {
-        if (this.getDataCallStateByType(type) ==
-            RIL.GECKO_NETWORK_STATE_CONNECTED) {
-          return true;
-        }
+      let iface = apnSetting.iface;
+      if (iface && iface.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
+        return true;
       }
     }
     return false;
   },
 
   /**
    * Check if we get all necessary APN data.
    */
@@ -2206,16 +2291,20 @@ RadioInterface.prototype = {
     if (dataInfo.roaming && !this.dataCallSettings.roamingEnabled) {
       if (DEBUG) this.debug("We're roaming, but data roaming is disabled.");
       return;
     }
     if (wifi_active) {
       if (DEBUG) this.debug("Don't connect data call when Wifi is connected.");
       return;
     }
+    if (this._pendingApnSettings) {
+      if (DEBUG) this.debug("We're changing apn settings, ignore any changes.");
+      return;
+    }
 
     let detailedRadioState = this.rilContext.detailedRadioState;
     if (gRadioEnabledController.isDeactivatingDataCalls() ||
         detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_ENABLING ||
         detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_DISABLING) {
       // We're changing the radio power currently, ignore any changes.
       return;
     }
@@ -2492,33 +2581,28 @@ RadioInterface.prototype = {
     }
 
     this._deliverDataCallCallback("dataCallStateChanged",
                                   [datacall]);
 
     // Process pending radio power off request after all data calls
     // are disconnected.
     if (datacall.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
-        gRadioEnabledController.isDeactivatingDataCalls()) {
-      let anyDataConnected = false;
-      for each (let apnSetting in this.apnSettings.byApn) {
-        for each (let type in apnSetting.types) {
-          if (this.getDataCallStateByType(type) == RIL.GECKO_NETWORK_STATE_CONNECTED) {
-            anyDataConnected = true;
-            break;
-          }
-        }
-        if (anyDataConnected) {
-          break;
-        }
-      }
-      if (!anyDataConnected) {
+        this.allDataDisconnected()) {
+      if (gRadioEnabledController.isDeactivatingDataCalls()) {
         if (DEBUG) this.debug("All data connections are disconnected.");
         gRadioEnabledController.finishDeactivatingDataCalls(this.clientId);
       }
+
+      if (this._pendingApnSettings) {
+        if (DEBUG) this.debug("Setup pending apn settings.");
+        this.setupApnSettings(this._pendingApnSettings);
+        this._pendingApnSettings = null;
+        this.updateRILNetworkInterface();
+      }
     }
   },
 
   /**
    * Handle data call list.
    */
   handleDataCallList: function(message) {
     this._deliverDataCallCallback("receiveDataCallList",
@@ -2776,16 +2860,19 @@ RadioInterface.prototype = {
 
   supportedNetworkTypes: null,
 
   // Data calls setting.
   dataCallSettings: null,
 
   apnSettings: null,
 
+  // Apn settings to be setup after data call are cleared.
+  _pendingApnSettings: null,
+
   // Flag to determine whether to update system clock automatically. It
   // corresponds to the "time.clock.automatic-update.enabled" setting.
   _clockAutoUpdateEnabled: null,
 
   // Flag to determine whether to update system timezone automatically. It
   // corresponds to the "time.clock.automatic-update.enabled" setting.
   _timezoneAutoUpdateEnabled: null,
 
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -19,17 +19,16 @@
 
 #include "nsINetworkService.h"
 #include "nsIWifi.h"
 #include "nsIWorkerHolder.h"
 #include "nsIXPConnect.h"
 
 #include "jsfriendapi.h"
 #include "mozilla/dom/workers/Workers.h"
-#include "mozilla/ipc/Netd.h"
 #include "AutoMounter.h"
 #include "TimeZoneSettingObserver.h"
 #include "AudioManager.h"
 #ifdef MOZ_B2G_RIL
 #include "mozilla/ipc/Ril.h"
 #endif
 #ifdef MOZ_NFC
 #include "mozilla/ipc/Nfc.h"
@@ -52,161 +51,16 @@ using namespace mozilla::system;
 namespace {
 
 NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID);
 NS_DEFINE_CID(kNetworkServiceCID, NS_INETWORKSERVICE_IID);
 
 // Doesn't carry a reference, we're owned by services.
 SystemWorkerManager *gInstance = nullptr;
 
-bool
-DoNetdCommand(JSContext *cx, unsigned argc, JS::Value *vp)
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
-
-  if (argc != 1) {
-    JS_ReportError(cx, "Expecting a single argument with the Netd message");
-    return false;
-  }
-
-  JS::Value v = JS_ARGV(cx, vp)[0];
-
-  JSAutoByteString abs;
-  void *data;
-  size_t size;
-  if (JSVAL_IS_STRING(v)) {
-    JSString *str = JSVAL_TO_STRING(v);
-    if (!abs.encodeUtf8(cx, str)) {
-      return false;
-    }
-
-    size = abs.length();
-    if (!size) {
-      JS_ReportError(cx, "Command length is zero");
-      return false;
-    }
-
-    data = abs.ptr();
-    if (!data) {
-      JS_ReportError(cx, "Command string is empty");
-      return false;
-    }
-  } else if (!JSVAL_IS_PRIMITIVE(v)) {
-    JSObject *obj = JSVAL_TO_OBJECT(v);
-    if (!JS_IsTypedArrayObject(obj)) {
-      JS_ReportError(cx, "Object passed in wasn't a typed array");
-      return false;
-    }
-
-    uint32_t type = JS_GetArrayBufferViewType(obj);
-    if (type != js::ArrayBufferView::TYPE_INT8 &&
-        type != js::ArrayBufferView::TYPE_UINT8 &&
-        type != js::ArrayBufferView::TYPE_UINT8_CLAMPED) {
-      JS_ReportError(cx, "Typed array data is not octets");
-      return false;
-    }
-
-    size = JS_GetTypedArrayByteLength(obj);
-    if (!size) {
-      JS_ReportError(cx, "Typed array byte length is zero");
-      return false;
-    }
-
-    data = JS_GetArrayBufferViewData(obj);
-    if (!data) {
-      JS_ReportError(cx, "Array buffer view data is NULL");
-      return false;
-    }
-  } else {
-    JS_ReportError(cx,
-                   "Incorrect argument. Expecting a string or a typed array");
-    return false;
-  }
-
-  // Reserve one space for '\0'.
-  if (size > MAX_COMMAND_SIZE - 1 || size <= 0) {
-    JS_ReportError(cx, "Passed-in data size is invalid");
-    return false;
-  }
-
-  NetdCommand* command = new NetdCommand();
-
-  memcpy(command->mData, data, size);
-  // Include the null terminate to the command to make netd happy.
-  command->mData[size] = 0;
-  command->mSize = size + 1;
-  SendNetdCommand(command);
-  return true;
-}
-
-class ConnectWorkerToNetd : public WorkerTask
-{
-public:
-  virtual bool RunTask(JSContext *aCx);
-};
-
-bool
-ConnectWorkerToNetd::RunTask(JSContext *aCx)
-{
-  // Set up the DoNetdCommand on the function for worker <--> Netd process
-  // communication.
-  NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
-  NS_ASSERTION(!JS_IsRunning(aCx), "Are we being called somehow?");
-  JS::Rooted<JSObject*> workerGlobal(aCx, JS::CurrentGlobalOrNull(aCx));
-  return !!JS_DefineFunction(aCx, workerGlobal, "postNetdCommand",
-                             DoNetdCommand, 1, 0);
-}
-
-class NetdReceiver : public NetdConsumer
-{
-  class DispatchNetdEvent : public WorkerTask
-  {
-  public:
-    DispatchNetdEvent(NetdCommand *aMessage)
-      : mMessage(aMessage)
-    { }
-
-    virtual bool RunTask(JSContext *aCx);
-
-  private:
-    nsAutoPtr<NetdCommand> mMessage;
-  };
-
-public:
-  NetdReceiver(WorkerCrossThreadDispatcher *aDispatcher)
-    : mDispatcher(aDispatcher)
-  { }
-
-  virtual void MessageReceived(NetdCommand *aMessage) {
-    nsRefPtr<DispatchNetdEvent> dre(new DispatchNetdEvent(aMessage));
-    if (!mDispatcher->PostTask(dre)) {
-      NS_WARNING("Failed to PostTask to net worker");
-    }
-  }
-
-private:
-  nsRefPtr<WorkerCrossThreadDispatcher> mDispatcher;
-};
-
-bool
-NetdReceiver::DispatchNetdEvent::RunTask(JSContext *aCx)
-{
-  JSObject *obj = JS::CurrentGlobalOrNull(aCx);
-
-  JSObject *array = JS_NewUint8Array(aCx, mMessage->mSize);
-  if (!array) {
-    return false;
-  }
-
-  memcpy(JS_GetUint8ArrayData(array), mMessage->mData, mMessage->mSize);
-  JS::Value argv[] = { OBJECT_TO_JSVAL(array) };
-  return JS_CallFunctionName(aCx, obj, "onNetdMessage", NS_ARRAY_LENGTH(argv),
-                             argv, argv);
-}
-
 } // anonymous namespace
 
 SystemWorkerManager::SystemWorkerManager()
   : mShutdown(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!gInstance, "There should only be one instance!");
 }
@@ -273,17 +127,16 @@ SystemWorkerManager::Shutdown()
 #ifdef MOZ_B2G_RIL
   RilConsumer::Shutdown();
 #endif
 
 #ifdef MOZ_NFC
   NfcConsumer::Shutdown();
 #endif
 
-  StopNetd();
   mNetdWorker = nullptr;
 
   nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker));
   if (wifi) {
     wifi->Shutdown();
     wifi = nullptr;
   }
   mWifiWorker = nullptr;
@@ -386,40 +239,16 @@ SystemWorkerManager::RegisterNfcWorker(J
 #endif // MOZ_NFC
 }
 
 nsresult
 SystemWorkerManager::InitNetd(JSContext *cx)
 {
   nsCOMPtr<nsIWorkerHolder> worker = do_GetService(kNetworkServiceCID);
   NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
-
-  JS::Rooted<JS::Value> workerval(cx);
-  nsresult rv = worker->GetWorker(&workerval);
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(workerval.isObject(), NS_ERROR_UNEXPECTED);
-
-  JSAutoCompartment ac(cx, &workerval.toObject());
-
-  WorkerCrossThreadDispatcher *wctd =
-    GetWorkerCrossThreadDispatcher(cx, workerval);
-  if (!wctd) {
-    NS_WARNING("Failed to GetWorkerCrossThreadDispatcher for netd");
-    return NS_ERROR_FAILURE;
-  }
-
-  nsRefPtr<ConnectWorkerToNetd> connection = new ConnectWorkerToNetd();
-  if (!wctd->PostTask(connection)) {
-    NS_WARNING("Failed to connect worker to netd");
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  // Now that we're set up, connect ourselves to the Netd process.
-  mozilla::RefPtr<NetdReceiver> receiver = new NetdReceiver(wctd);
-  StartNetd(receiver);
   mNetdWorker = worker;
   return NS_OK;
 }
 
 nsresult
 SystemWorkerManager::InitWifi(JSContext *cx)
 {
   nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID);
--- a/dom/system/gonk/moz.build
+++ b/dom/system/gonk/moz.build
@@ -14,16 +14,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 XPIDL_SOURCES += [
     'nsIAudioManager.idl',
     'nsINetworkInterfaceListService.idl',
     'nsINetworkManager.idl',
     'nsINetworkService.idl',
+    'nsINetworkWorker.idl',
     'nsISystemWorkerManager.idl',
     'nsIVolume.idl',
     'nsIVolumeMountLock.idl',
     'nsIVolumeService.idl',
     'nsIVolumeStat.idl',
     'nsIWorkerHolder.idl',
 ]
 
@@ -35,16 +36,18 @@ EXPORTS += [
     'nsVolumeService.h',
 ]
 SOURCES += [
     'AudioChannelManager.cpp',
     'AudioManager.cpp',
     'AutoMounter.cpp',
     'AutoMounterSetting.cpp',
     'GonkGPSGeolocationProvider.cpp',
+    'NetworkUtils.cpp',
+    'NetworkWorker.cpp',
     'nsVolume.cpp',
     'nsVolumeMountLock.cpp',
     'nsVolumeService.cpp',
     'nsVolumeStat.cpp',
     'OpenFileFinder.cpp',
     'SystemWorkerManager.cpp',
     'TimeZoneSettingObserver.cpp',
     'Volume.cpp',
@@ -63,17 +66,16 @@ EXTRA_COMPONENTS += [
     'NetworkManager.manifest',
     'NetworkService.manifest',
 ]
 EXTRA_PP_COMPONENTS += [
     'NetworkManager.js',
     'NetworkService.js',
 ]
 EXTRA_JS_MODULES += [
-    'net_worker.js',
     'systemlibs.js',
 ]
 
 if CONFIG['MOZ_B2G_RIL']:
     XPIDL_SOURCES += [
         'nsIRadioInterfaceLayer.idl',
     ]
     EXTRA_COMPONENTS += [
deleted file mode 100644
--- a/dom/system/gonk/net_worker.js
+++ /dev/null
@@ -1,964 +0,0 @@
-/* Copyright 2012 Mozilla Foundation and Mozilla contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-"use strict";
-
-const DEBUG = false;
-
-const PERSIST_SYS_USB_CONFIG_PROPERTY = "persist.sys.usb.config";
-const SYS_USB_CONFIG_PROPERTY         = "sys.usb.config";
-const SYS_USB_STATE_PROPERTY          = "sys.usb.state";
-
-const USB_FUNCTION_RNDIS  = "rndis";
-const USB_FUNCTION_ADB    = "adb";
-
-const kNetdInterfaceChangedTopic = "netd-interface-change";
-const kNetdBandwidthControlTopic = "netd-bandwidth-control";
-
-// Use this command to continue the function chain.
-const DUMMY_COMMAND = "tether status";
-
-// Retry 20 times (2 seconds) for usb state transition.
-const USB_FUNCTION_RETRY_TIMES = 20;
-// Check "sys.usb.state" every 100ms.
-const USB_FUNCTION_RETRY_INTERVAL = 100;
-
-// 1xx - Requested action is proceeding
-const NETD_COMMAND_PROCEEDING   = 100;
-// 2xx - Requested action has been successfully completed
-const NETD_COMMAND_OKAY         = 200;
-// 4xx - The command is accepted but the requested action didn't
-// take place.
-const NETD_COMMAND_FAIL         = 400;
-// 5xx - The command syntax or parameters error
-const NETD_COMMAND_ERROR        = 500;
-// 6xx - Unsolicited broadcasts
-const NETD_COMMAND_UNSOLICITED  = 600;
-
-// Broadcast messages
-const NETD_COMMAND_INTERFACE_CHANGE     = 600;
-const NETD_COMMAND_BANDWIDTH_CONTROLLER = 601;
-
-const INTERFACE_DELIMIT = "\0";
-
-importScripts("systemlibs.js");
-
-const SDK_VERSION = libcutils.property_get("ro.build.version.sdk", "0");
-
-function netdResponseType(code) {
-  return Math.floor(code/100)*100;
-}
-
-function isBroadcastMessage(code) {
-  let type = netdResponseType(code);
-  return (type == NETD_COMMAND_UNSOLICITED);
-}
-
-function isError(code) {
-  let type = netdResponseType(code);
-  return (type != NETD_COMMAND_PROCEEDING && type != NETD_COMMAND_OKAY);
-}
-
-function isComplete(code) {
-  let type = netdResponseType(code);
-  return (type != NETD_COMMAND_PROCEEDING);
-}
-
-function isProceeding(code) {
-  let type = netdResponseType(code);
-  return (type === NETD_COMMAND_PROCEEDING);
-}
-
-function sendBroadcastMessage(code, reason) {
-  let topic = null;
-  switch (code) {
-    case NETD_COMMAND_INTERFACE_CHANGE:
-      topic = "netd-interface-change";
-      break;
-    case NETD_COMMAND_BANDWIDTH_CONTROLLER:
-      topic = "netd-bandwidth-control";
-      break;
-  }
-
-  if (topic) {
-    postMessage({id: 'broadcast', topic: topic, reason: reason});
-  }
-}
-
-let gWifiFailChain = [stopSoftAP,
-                      setIpForwardingEnabled,
-                      stopTethering];
-
-function wifiTetheringFail(params) {
-  // Notify the main thread.
-  postMessage(params);
-
-  // If one of the stages fails, we try roll back to ensure
-  // we don't leave the network systems in limbo.
-
-  // This parameter is used to disable ipforwarding.
-  params.enable = false;
-  chain(params, gWifiFailChain, null);
-}
-
-function wifiTetheringSuccess(params) {
-  // Notify the main thread.
-  postMessage(params);
-  return true;
-}
-
-let gUSBFailChain = [stopSoftAP,
-                     setIpForwardingEnabled,
-                     stopTethering];
-
-function usbTetheringFail(params) {
-  // Notify the main thread.
-  postMessage(params);
-  // Try to roll back to ensure
-  // we don't leave the network systems in limbo.
-  // This parameter is used to disable ipforwarding.
-  params.enable = false;
-  chain(params, gUSBFailChain, null);
-
-  // Disable usb rndis function.
-  enableUsbRndis({enable: false, report: false});
-}
-
-function usbTetheringSuccess(params) {
-  // Notify the main thread.
-  postMessage(params);
-  return true;
-}
-
-function networkInterfaceAlarmFail(params) {
-  // Notify the main thread.
-  postMessage(params);
-  return true;
-}
-
-function networkInterfaceAlarmSuccess(params) {
-  // Notify the main thread.
-  params.error = parseFloat(params.resultReason);
-  postMessage(params);
-  return true;
-}
-
-function updateUpStreamSuccess(params) {
-  // Notify the main thread.
-  postMessage(params);
-  return true;
-}
-
-function updateUpStreamFail(params) {
-  // Notify the main thread.
-  postMessage(params);
-  return true;
-}
-
-function wifiOperationModeFail(params) {
-  // Notify the main thread.
-  postMessage(params);
-  return true;
-}
-
-function wifiOperationModeSuccess(params) {
-  // Notify the main thread.
-  postMessage(params);
-  return true;
-}
-
-/**
- * Get network interface properties from the system property table.
- *
- * @param ifname
- *        Name of the network interface.
- */
-function getIFProperties(ifname) {
-  return {
-    ifname:      ifname,
-    gateway_str: libcutils.property_get("net." + ifname + ".gw"),
-    dns1_str:    libcutils.property_get("net." + ifname + ".dns1"),
-    dns2_str:    libcutils.property_get("net." + ifname + ".dns2"),
-  };
-}
-
-/**
- * Routines accessible to the main thread.
- */
-
-/**
- * Dispatch a message from the main thread to a function.
- */
-self.onmessage = function onmessage(event) {
-  let message = event.data;
-  if (DEBUG) debug("received message: " + JSON.stringify(message));
-  // We have to keep the id in message. It will be used when post the result
-  // to NetworkManager later.
-  let ret = self[message.cmd](message);
-  if (!message.isAsync) {
-    postMessage({id: message.id, ret: ret});
-  }
-};
-
-/**
- * Start/Stop DHCP server.
- */
-function setDhcpServer(config) {
-  function onSuccess() {
-    postMessage({ id: config.id, success: true });
-    return true;
-  }
-
-  function onError() {
-    postMessage({ id: config.id, success: false });
-  }
-
-  let startDhcpServerChain = [setInterfaceUp,
-                              startTethering,
-                              onSuccess];
-
-  let stopDhcpServerChain = [stopTethering,
-                             onSuccess];
-
-  if (config.enabled) {
-    let params = { wifiStartIp: config.startIp,
-                   wifiEndIp: config.endIp,
-                   ip: config.serverIp,
-                   prefix: config.maskLength,
-                   ifname: config.ifname,
-                   link: "up" };
-
-    chain(params, startDhcpServerChain, onError);
-  } else {
-    chain({}, stopDhcpServerChain, onError);
-  }
-}
-
-/**
- * Set DNS servers for given network interface.
- */
-function setDNS(options) {
-  let ifprops = getIFProperties(options.ifname);
-  let dns1_str = options.dns1_str || ifprops.dns1_str;
-  let dns2_str = options.dns2_str || ifprops.dns2_str;
-  libcutils.property_set("net.dns1", dns1_str);
-  libcutils.property_set("net.dns2", dns2_str);
-  // Bump the DNS change property.
-  let dnschange = libcutils.property_get("net.dnschange", "0");
-  libcutils.property_set("net.dnschange", (parseInt(dnschange, 10) + 1).toString());
-}
-
-/**
- * Set default route and DNS servers for given network interface.
- */
-function setDefaultRouteAndDNS(options) {
-  if (options.oldIfname) {
-    libnetutils.ifc_remove_default_route(options.oldIfname);
-  }
-
-  let ifprops = getIFProperties(options.ifname);
-  let gateway_str = options.gateway_str || ifprops.gateway_str;
-  let dns1_str = options.dns1_str || ifprops.dns1_str;
-  let dns2_str = options.dns2_str || ifprops.dns2_str;
-  let gateway = netHelpers.stringToIP(gateway_str);
-
-  libnetutils.ifc_set_default_route(options.ifname, gateway);
-  libcutils.property_set("net.dns1", dns1_str);
-  libcutils.property_set("net.dns2", dns2_str);
-
-  // Bump the DNS change property.
-  let dnschange = libcutils.property_get("net.dnschange", "0");
-  libcutils.property_set("net.dnschange", (parseInt(dnschange, 10) + 1).toString());
-}
-
-/**
- * Remove default route for given network interface.
- */
-function removeDefaultRoute(options) {
-  libnetutils.ifc_remove_default_route(options.ifname);
-}
-
-/**
- * Add host route for given network interface.
- */
-function addHostRoute(options) {
-  for (let i = 0; i < options.hostnames.length; i++) {
-    libnetutils.ifc_add_route(options.ifname, options.hostnames[i], 32, options.gateway);
-  }
-}
-
-/**
- * Remove host route for given network interface.
- */
-function removeHostRoute(options) {
-  for (let i = 0; i < options.hostnames.length; i++) {
-    libnetutils.ifc_remove_route(options.ifname, options.hostnames[i], 32, options.gateway);
-  }
-}
-
-/**
- * Remove the routes associated with the named interface.
- */
-function removeHostRoutes(options) {
-  libnetutils.ifc_remove_host_routes(options.ifname);
-}
-
-function removeNetworkRoute(options) {
-  let ipvalue = netHelpers.stringToIP(options.ip);
-  let netmaskvalue = netHelpers.stringToIP(options.netmask);
-  let subnet = netmaskvalue & ipvalue;
-  let dst = netHelpers.ipToString(subnet);
-  let prefixLength = netHelpers.getMaskLength(netmaskvalue);
-  let gateway = "0.0.0.0";
-
-  libnetutils.ifc_remove_default_route(options.ifname);
-  libnetutils.ifc_remove_route(options.ifname, dst, prefixLength, gateway);
-}
-
-let gCommandQueue = [];
-let gCurrentCommand = null;
-let gCurrentCallback = null;
-let gPending = false;
-let gReason = [];
-
-/**
- * This helper function acts like String.split() fucntion.
- * The function finds the first token in the javascript
- * uint8 type array object, where tokens are delimited by
- * the delimiter. The first token and the index pointer to
- * the next token are returned in this function.
- */
-function split(start, data, delimiter) {
-  // Sanity check.
-  if (start < 0 || data.length <= 0) {
-    return null;
-  }
-
-  let result = "";
-  let i = start;
-  while (i < data.length) {
-    let octet = data[i];
-    i += 1;
-    if (octet === delimiter) {
-      return {token: result, index: i};
-    }
-    result += String.fromCharCode(octet);
-  }
-  return null;
-}
-
-/**
- * Handle received data from netd.
- */
-function onNetdMessage(data) {
-  let result = split(0, data, 32);
-  if (!result) {
-    nextNetdCommand();
-    return;
-  }
-  let code = parseInt(result.token);
-
-  // Netd response contains the command sequence number
-  // in non-broadcast message for Android jb version.
-  // The format is ["code" "optional sequence number" "reason"]
-  if (!isBroadcastMessage(code) && SDK_VERSION >= 16) {
-    result = split(result.index, data, 32);
-  }
-
-  let i = result.index;
-  let reason = "";
-  for (; i < data.length; i++) {
-    let octet = data[i];
-    reason += String.fromCharCode(octet);
-  }
-
-  if (isBroadcastMessage(code)) {
-    debug("Receiving broadcast message from netd.");
-    debug("          ==> Code: " + code + "  Reason: " + reason);
-    sendBroadcastMessage(code, reason);
-    nextNetdCommand();
-    return;
-  }
-
-  // Set pending to false before we handle next command.
-  debug("Receiving '" + gCurrentCommand + "' command response from netd.");
-  debug("          ==> Code: " + code + "  Reason: " + reason);
-
-  gReason.push(reason);
-
-  // 1xx response code regards as command is proceeding, we need to wait for
-  // final response code such as 2xx, 4xx and 5xx before sending next command.
-  if (isProceeding(code)) {
-    return;
-  }
-
-  if (isComplete(code)) {
-    gPending = false;
-  }
-
-  if (gCurrentCallback) {
-    gCurrentCallback(isError(code),
-                     {code: code, reason: gReason.join(INTERFACE_DELIMIT)});
-    gReason = [];
-  }
-
-  // Handling pending commands if any.
-  if (isComplete(code)) {
-    nextNetdCommand();
-  }
-}
-
-/**
- * Send command to netd.
- */
-function doCommand(command, callback) {
-  debug("Preparing to send '" + command + "' command...");
-  gCommandQueue.push([command, callback]);
-  return nextNetdCommand();
-}
-
-function nextNetdCommand() {
-  if (!gCommandQueue.length || gPending) {
-    return true;
-  }
-  [gCurrentCommand, gCurrentCallback] = gCommandQueue.shift();
-  debug("Sending '" + gCurrentCommand + "' command to netd.");
-  gPending = true;
-
-  // Android JB version adds sequence number to netd command.
-  let command = (SDK_VERSION >= 16) ? "0 " + gCurrentCommand : gCurrentCommand;
-  return postNetdCommand(command);
-}
-
-function setInterfaceUp(params, callback) {
-  let command = "interface setcfg " + params.ifname + " " + params.ip + " " +
-                params.prefix + " ";
-  if (SDK_VERSION >= 16) {
-    command += params.link;
-  } else {
-    command += "[" + params.link + "]";
-  }
-  return doCommand(command, callback);
-}
-
-function setInterfaceDown(params, callback) {
-  let command = "interface setcfg " + params.ifname + " " + params.ip + " " +
-                params.prefix + " ";
-  if (SDK_VERSION >= 16) {
-    command += params.link;
-  } else {
-    command += "[" + params.link + "]";
-  }
-  return doCommand(command, callback);
-}
-
-function setIpForwardingEnabled(params, callback) {
-  let command;
-
-  if (params.enable) {
-    command = "ipfwd enable";
-  } else {
-    // Don't disable ip forwarding because others interface still need it.
-    // Send the dummy command to continue the function chain.
-    if ("interfaceList" in params && params.interfaceList.length > 1) {
-      command = DUMMY_COMMAND;
-    } else {
-      command = "ipfwd disable";
-    }
-  }
-  return doCommand(command, callback);
-}
-
-function startTethering(params, callback) {
-  let command;
-  // We don't need to start tethering again.
-  // Send the dummy command to continue the function chain.
-  if (params.resultReason.indexOf("started") !== -1) {
-    command = DUMMY_COMMAND;
-  } else {
-    command = "tether start " + params.wifiStartIp + " " + params.wifiEndIp;
-
-    // If usbStartIp/usbEndIp is not valid, don't append them since
-    // the trailing white spaces will be parsed to extra empty args
-    // See: http://androidxref.com/4.3_r2.1/xref/system/core/libsysutils/src/FrameworkListener.cpp#78
-    if (params.usbStartIp && params.usbEndIp) {
-      command += " " + params.usbStartIp + " " + params.usbEndIp;
-    }
-  }
-  return doCommand(command, callback);
-}
-
-function tetheringStatus(params, callback) {
-  let command = "tether status";
-  return doCommand(command, callback);
-}
-
-function stopTethering(params, callback) {
-  let command;
-
-  // Don't stop tethering because others interface still need it.
-  // Send the dummy to continue the function chain.
-  if ("interfaceList" in params && params.interfaceList.length > 1) {
-    command = DUMMY_COMMAND;
-  } else {
-    command = "tether stop";
-  }
-  return doCommand(command, callback);
-}
-
-function tetherInterface(params, callback) {
-  let command = "tether interface add " + params.ifname;
-  return doCommand(command, callback);
-}
-
-function preTetherInterfaceList(params, callback) {
-  let command = (SDK_VERSION >= 16) ? "tether interface list"
-                                    : "tether interface list 0";
-  return doCommand(command, callback);
-}
-
-function postTetherInterfaceList(params, callback) {
-  params.interfaceList = params.resultReason.split(INTERFACE_DELIMIT);
-
-  // Send the dummy command to continue the function chain.
-  let command = DUMMY_COMMAND;
-  return doCommand(command, callback);
-}
-
-function untetherInterface(params, callback) {
-  let command = "tether interface remove " + params.ifname;
-  return doCommand(command, callback);
-}
-
-function setDnsForwarders(params, callback) {
-  let command = "tether dns set " + params.dns1 + " " + params.dns2;
-  return doCommand(command, callback);
-}
-
-function enableNat(params, callback) {
-  let command = "nat enable " + params.internalIfname + " " +
-                params.externalIfname + " " + "0";
-  return doCommand(command, callback);
-}
-
-function disableNat(params, callback) {
-  let command = "nat disable " + params.internalIfname + " " +
-                 params.externalIfname + " " + "0";
-  return doCommand(command, callback);
-}
-
-function wifiFirmwareReload(params, callback) {
-  let command = "softap fwreload " + params.ifname + " " + params.mode;
-  return doCommand(command, callback);
-}
-
-function startAccessPointDriver(params, callback) {
-  // Skip the command for sdk version >= 16.
-  if (SDK_VERSION >= 16) {
-    callback(false, {code: "", reason: ""});
-    return true;
-  }
-  let command = "softap start " + params.ifname;
-  return doCommand(command, callback);
-}
-
-function stopAccessPointDriver(params, callback) {
-  // Skip the command for sdk version >= 16.
-  if (SDK_VERSION >= 16) {
-    callback(false, {code: "", reason: ""});
-    return true;
-  }
-  let command = "softap stop " + params.ifname;
-  return doCommand(command, callback);
-}
-
-function startSoftAP(params, callback) {
-  let command = "softap startap";
-  return doCommand(command, callback);
-}
-
-function stopSoftAP(params, callback) {
-  let command = "softap stopap";
-  return doCommand(command, callback);
-}
-
-function enableAlarm(params, callback) {
-  let command = "bandwidth enable";
-  return doCommand(command, callback);
-}
-
-function disableAlarm(params, callback) {
-  let command = "bandwidth disable";
-  return doCommand(command, callback);
-}
-
-function setQuota(params, callback) {
-  let command = "bandwidth setiquota " + params.ifname + " " + parseInt('0xffffffffffffffff');
-  return doCommand(command, callback);
-}
-
-function removeQuota(params, callback) {
-  let command = "bandwidth removeiquota " + params.ifname;
-  return doCommand(command, callback);
-}
-
-function setAlarm(params, callback) {
-  let command = "bandwidth setinterfacealert " + params.ifname + " " + params.threshold;
-  return doCommand(command, callback);
-}
-
-function escapeQuote(str) {
-  str = str.replace(/\\/g, "\\\\");
-  return str.replace(/"/g, "\\\"");
-}
-
-/**
- * Command format for sdk version < 16
- *   Arguments:
- *     argv[2] - wlan interface
- *     argv[3] - SSID
- *     argv[4] - Security
- *     argv[5] - Key
- *     argv[6] - Channel
- *     argv[7] - Preamble
- *     argv[8] - Max SCB
- *
- * Command format for sdk version >= 16
- *   Arguments:
- *     argv[2] - wlan interface
- *     argv[3] - SSID
- *     argv[4] - Security
- *     argv[5] - Key
- */
-function setAccessPoint(params, callback) {
-  let command;
-  if (SDK_VERSION >= 16) {
-    command = "softap set " + params.ifname +
-              " \"" + escapeQuote(params.ssid) + "\"" +
-              " " + params.security +
-              " \"" + escapeQuote(params.key) + "\"";
-  } else {
-    command = "softap set " + params.ifname +
-              " " + params.wifictrlinterfacename +
-              " \"" + escapeQuote(params.ssid) + "\"" +
-              " " + params.security +
-              " \"" + escapeQuote(params.key) + "\"" +
-              " " + "6 0 8";
-  }
-  return doCommand(command, callback);
-}
-
-function cleanUpStream(params, callback) {
-  let command = "nat disable " + params.previous.internalIfname + " " +
-                params.previous.externalIfname + " " + "0";
-  return doCommand(command, callback);
-}
-
-function createUpStream(params, callback) {
-  let command = "nat enable " + params.current.internalIfname + " " +
-                params.current.externalIfname + " " + "0";
-  return doCommand(command, callback);
-}
-
-/**
- * Modify usb function's property to turn on USB RNDIS function
- */
-function enableUsbRndis(params) {
-  let report = params.report;
-  let retry = 0;
-
-  // 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.
-  //
-  // On the otoro/unagi, persist.sys.usb.config should be one of:
-  //
-  //    diag,modem,nmea,mass_storage
-  //    diag,modem,nmea,mass_storage,adb
-  //
-  // When rndis is enabled, sys.usb.config should be one of:
-  //
-  //    rdnis
-  //    rndis,adb
-  //
-  // and when rndis is disabled, it should revert to persist.sys.usb.config
-
-  let currentConfig = libcutils.property_get(SYS_USB_CONFIG_PROPERTY);
-  let configFuncs = currentConfig.split(",");
-  let persistConfig = libcutils.property_get(PERSIST_SYS_USB_CONFIG_PROPERTY);
-  let persistFuncs = persistConfig.split(",");
-
-  if (params.enable) {
-    configFuncs = [USB_FUNCTION_RNDIS];
-    if (persistFuncs.indexOf(USB_FUNCTION_ADB) >= 0) {
-      configFuncs.push(USB_FUNCTION_ADB);
-    }
-  } else {
-    // We're turning rndis off, revert back to the persist setting.
-    // adb will already be correct there, so we don't need to do any
-    // further adjustments.
-    configFuncs = persistFuncs;
-  }
-  let newConfig = configFuncs.join(",");
-  if (newConfig != currentConfig) {
-    libcutils.property_set(SYS_USB_CONFIG_PROPERTY, newConfig);
-  }
-
-  // Trigger the timer to check usb state and report the result to NetworkManager.
-  if (report) {
-    setTimeout(checkUsbRndisState, USB_FUNCTION_RETRY_INTERVAL, params);
-  }
-
-  function checkUsbRndisState(params) {
-    let currentState = libcutils.property_get(SYS_USB_STATE_PROPERTY);
-    let stateFuncs = currentState.split(",");
-    let rndisPresent = (stateFuncs.indexOf(USB_FUNCTION_RNDIS) >= 0);
-    if (params.enable == rndisPresent) {
-      params.result = true;
-      postMessage(params);
-      retry = 0;
-      return;
-    }
-    if (retry < USB_FUNCTION_RETRY_TIMES) {
-      retry++;
-      setTimeout(checkUsbRndisState, USB_FUNCTION_RETRY_INTERVAL, params);
-      return;
-    }
-    params.result = false;
-    postMessage(params);
-  };
-
-  return true;
-}
-
-function dumpParams(params, type) {
-  if (!DEBUG) {
-    return;
-  }
-
-  debug("Dump params:");
-  debug("     ifname: " + params.ifname);
-  debug("     ip: " + params.ip);
-  debug("     link: " + params.link);
-  debug("     prefix: " + params.prefix);
-  debug("     wifiStartIp: " + params.wifiStartIp);
-  debug("     wifiEndIp: " + params.wifiEndIp);
-  debug("     usbStartIp: " + params.usbStartIp);
-  debug("     usbEndIp: " + params.usbEndIp);
-  debug("     dnsserver1: " + params.dns1);
-  debug("     dnsserver2: " + params.dns2);
-  debug("     internalIfname: " + params.internalIfname);
-  debug("     externalIfname: " + params.externalIfname);
-  if (type == "WIFI") {
-    debug("     wifictrlinterfacename: " + params.wifictrlinterfacename);
-    debug("     ssid: " + params.ssid);
-    debug("     security: " + params.security);
-    debug("     key: " + params.key);
-  }
-}
-
-function chain(params, funcs, onError) {
-  let i = -1;
-  let f = funcs[i];
-  function next(error, result) {
-    params.resultCode = result.code;
-    params.resultReason = result.reason;
-    if (error) {
-      if (onError) {
-        params.error = error;
-        params.state = f.name;
-        onError(params);
-      }
-      return;
-    }
-    i += 1;
-    f = funcs[i];
-    if (f) {
-      let ret = f(params, next);
-      if (!ret && onError) {
-        params.error = true;
-        params.state = f.name;
-        onError(params);
-      }
-    }
-  };
-  next(null, {code: NETD_COMMAND_ERROR, reason: ""});
-}
-
-let gWifiEnableChain = [wifiFirmwareReload,
-                        startAccessPointDriver,
-                        setAccessPoint,
-                        startSoftAP,
-                        setInterfaceUp,
-                        tetherInterface,
-                        setIpForwardingEnabled,
-                        tetheringStatus,
-                        startTethering,
-                        setDnsForwarders,
-                        enableNat,
-                        wifiTetheringSuccess];
-
-let gWifiDisableChain = [stopSoftAP,
-                         stopAccessPointDriver,
-                         wifiFirmwareReload,
-                         untetherInterface,
-                         preTetherInterfaceList,
-                         postTetherInterfaceList,
-                         disableNat,
-                         setIpForwardingEnabled,
-                         stopTethering,
-                         wifiTetheringSuccess];
-
-/**
- * handling main thread's enable/disable WiFi Tethering request
- */
-function setWifiTethering(params) {
-  let enable = params.enable;
-  let interfaceProperties = getIFProperties(params.externalIfname);
-
-  if (interfaceProperties.dns1_str) {
-    params.dns1 = interfaceProperties.dns1_str;
-  }
-  if (interfaceProperties.dns2_str) {
-    params.dns2 = interfaceProperties.dns2_str;
-  }
-  dumpParams(params, "WIFI");
-
-  if (enable) {
-    // Enable Wifi tethering.
-    debug("Starting Wifi Tethering on " +
-           params.internalIfname + "<->" + params.externalIfname);
-    chain(params, gWifiEnableChain, wifiTetheringFail);
-  } else {
-    // Disable Wifi tethering.
-    debug("Stopping Wifi Tethering on " +
-           params.internalIfname + "<->" + params.externalIfname);
-    chain(params, gWifiDisableChain, wifiTetheringFail);
-  }
-  return true;
-}
-
-let gUpdateUpStreamChain = [cleanUpStream,
-                            createUpStream,
-                            updateUpStreamSuccess];
-/**
- * handling upstream interface change event.
- */
-function updateUpStream(params) {
-  chain(params, gUpdateUpStreamChain, updateUpStreamFail);
-}
-
-let gUSBEnableChain = [setInterfaceUp,
-                       enableNat,
-                       setIpForwardingEnabled,
-                       tetherInterface,
-                       tetheringStatus,
-                       startTethering,
-                       setDnsForwarders,
-                       usbTetheringSuccess];
-
-let gUSBDisableChain = [untetherInterface,
-                        preTetherInterfaceList,
-                        postTetherInterfaceList,
-                        disableNat,
-                        setIpForwardingEnabled,
-                        stopTethering,
-                        usbTetheringSuccess];
-
-/**
- * handling main thread's enable/disable USB Tethering request
- */
-function setUSBTethering(params) {
-  let enable = params.enable;
-  let interfaceProperties = getIFProperties(params.externalIfname);
-
-  if (interfaceProperties.dns1_str) {
-    params.dns1 = interfaceProperties.dns1_str;
-  }
-  if (interfaceProperties.dns2_str) {
-    params.dns2 = interfaceProperties.dns2_str;
-  }
-
-  dumpParams(params, "USB");
-
-  if (enable) {
-    // Enable USB tethering.
-    debug("Starting USB Tethering on " +
-           params.internalIfname + "<->" + params.externalIfname);
-    chain(params, gUSBEnableChain, usbTetheringFail);
-  } else {
-    // Disable USB tetehring.
-    debug("Stopping USB Tethering on " +
-           params.internalIfname + "<->" + params.externalIfname);
-    chain(params, gUSBDisableChain, usbTetheringFail);
-  }
-  return true;
-}
-
-let gNetworkInterfaceEnableAlarmChain = [enableAlarm,
-                                         setQuota,
-                                         setAlarm,
-                                         networkInterfaceAlarmSuccess];
-
-function enableNetworkInterfaceAlarm(params) {
-  debug("enableNetworkInterfaceAlarms: " + params.ifname);
-
-  chain(params, gNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail);
-  return true;
-}
-
-let gNetworkInterfaceDisableAlarmChain = [removeQuota,
-                                          disableAlarm,
-                                          networkInterfaceAlarmSuccess];
-
-function disableNetworkInterfaceAlarm(params) {
-  debug("disableNetworkInterfaceAlarms: " + params.ifname);
-
-  chain(params, gNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail);
-  return true;
-}
-
-let gNetworkInterfaceSetAlarmChain = [setAlarm,
-                                      networkInterfaceAlarmSuccess];
-
-function setNetworkInterfaceAlarm(params) {
-  debug("setNetworkInterfaceAlarms: " + params.ifname);
-
-  chain(params, gNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail);
-  return true;
-}
-
-let gWifiOperationModeChain = [wifiFirmwareReload,
-                               wifiOperationModeSuccess];
-
-/**
- * handling main thread's reload Wifi firmware request
- */
-function setWifiOperationMode(params) {
-  debug("setWifiOperationMode: " + params.ifname + " " + params.mode);
-  chain(params, gWifiOperationModeChain, wifiOperationModeFail);
-  return true;
-}
-
-let debug;
-if (DEBUG) {
-  debug = function(s) {
-    dump("Network Worker: " + s + "\n");
-  };
-} else {
-  debug = function(s) {};
-}
-
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/nsINetworkWorker.idl
@@ -0,0 +1,18 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(98e31d3b-6cad-4cab-b4b3-4afff566ea65)]
+interface nsINetworkEventListener : nsISupports {
+  void onEvent(in jsval result);
+};
+
+[scriptable, uuid(f9d9c694-0aac-4f9a-98ac-7788f954239a)]
+interface nsINetworkWorker : nsISupports {
+  void start(in nsINetworkEventListener listener);
+  void shutdown();
+  [implicit_jscontext]
+  void postMessage(in jsval options);
+};
--- a/dom/webidl/Contacts.webidl
+++ b/dom/webidl/Contacts.webidl
@@ -113,14 +113,14 @@ dictionary ContactFindOptions : ContactF
 
 [NoInterfaceObject, NavigatorProperty="mozContacts",
  JSImplementation="@mozilla.org/contactManager;1"]
 interface ContactManager : EventTarget {
   DOMRequest find(optional ContactFindOptions options);
   DOMCursor  getAll(optional ContactFindSortOptions options);
   DOMRequest clear();
   DOMRequest save(mozContact contact);
-  DOMRequest remove(mozContact contact);
+  DOMRequest remove((mozContact or DOMString) contactOrId);
   DOMRequest getRevision();
   DOMRequest getCount();
 
   attribute  EventHandler oncontactchange;
 };
--- a/dom/webidl/DummyBinding.webidl
+++ b/dom/webidl/DummyBinding.webidl
@@ -26,13 +26,15 @@ interface DummyInterface : EventTarget {
   void AsyncScrollEventDetail(optional AsyncScrollEventDetail arg);
   void OpenWindowEventDetail(optional OpenWindowEventDetail arg);
   void DOMWindowResizeEventDetail(optional DOMWindowResizeEventDetail arg);
   void WifiOptions(optional WifiCommandOptions arg1,
                    optional WifiResultOptions arg2);
   void AppNotificationServiceOptions(optional AppNotificationServiceOptions arg);
   void AppInfo(optional AppInfo arg1);
   void DOMFileMetadataParameters(optional DOMFileMetadataParameters arg);
+  void NetworkOptions(optional NetworkCommandOptions arg1,
+                      optional NetworkResultOptions arg2);
 };
 
 interface DummyInterfaceWorkers {
   BlobPropertyBag blobBag();
 };
--- a/dom/webidl/MozIcc.webidl
+++ b/dom/webidl/MozIcc.webidl
@@ -360,9 +360,31 @@ interface MozIcc : EventTarget
    *
    * @param aid
    *        The application identifier of the applet, to be closed.
    *
    * @return a DOMRequest.
    */
   [Throws]
   nsISupports iccCloseChannel(long channel);
+
+  // Integrated Circuit Card Helpers.
+
+  /**
+   * Verify whether the passed data (matchData) matches with some ICC's field
+   * according to the mvno type (mvnoType).
+   *
+   * @param mvnoType
+   *        Mvno type to use to compare the match data.
+   *        Currently, we only support 'imsi'.
+   * @param matchData
+   *        Data to be compared with ICC's field.
+   *
+   * @return a DOMRequest.
+   *         The request's result will be a boolean indicating the matching
+   *         result.
+   *
+   * TODO: change param mvnoType to WebIDL enum after Bug 864489 -
+   *       B2G RIL: use ipdl as IPC in MozIccManager
+   */
+  [Throws]
+  nsISupports matchMvno(DOMString mvnoType, DOMString matchData);
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/NetworkOptions.webidl
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this file,
+* You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+* This dictionnary holds the parameters sent to the network worker.
+*/
+dictionary NetworkCommandOptions
+{
+  long id = 0;                        // opaque id.
+  DOMString cmd = "";                 // the command name.
+  DOMString ifname;                   // for "removeNetworkRoute", "setDNS",
+                                      //     "setDefaultRouteAndDNS", "removeDefaultRoute"
+                                      //     "addHostRoute", "removeHostRoute"
+                                      //     "removeHostRoutes".
+  DOMString ip;                       // for "removeNetworkRoute", "setWifiTethering".
+  DOMString netmask;                  // for "removeNetworkRoute".
+  DOMString dns1_str;                 // for "setDNS", "setDefaultRouteAndDNS".
+  DOMString dns2_str;                 // for "setDNS", "setDefaultRouteAndDNS".
+  DOMString oldIfname;                // for "setDefaultRouteAndDNS".
+  DOMString gateway_str;              // for "setDefaultRouteAndDNS".
+  DOMString gateway;                  // for "addHostRoute", "removeHostRoute".
+  sequence<DOMString> hostnames;      // for "addHostRoute", "removeHostRoute".
+  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".
+  DOMString prefix;                   // for "setWifiTethering", "setDhcpServer".
+  DOMString link;                     // for "setWifiTethering", "setDhcpServer".
+  sequence<DOMString> interfaceList;  // for "setWifiTethering".
+  DOMString wifiStartIp;              // for "setWifiTethering".
+  DOMString wifiEndIp;                // for "setWifiTethering".
+  DOMString usbStartIp;               // for "setWifiTethering".
+  DOMString usbEndIp;                 // for "setWifiTethering".
+  DOMString dns1;                     // for "setWifiTethering".
+  DOMString dns2;                     // for "setWifiTethering".
+  float rxBytes;                      // for "getNetworkInterfaceStats".
+  float txBytes;                      // for "getNetworkInterfaceStats".
+  DOMString date;                     // for "getNetworkInterfaceStats".
+  long threshold;                     // for "setNetworkInterfaceAlarm",
+                                      //     "enableNetworkInterfaceAlarm".
+  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".
+};
+
+/**
+* This dictionary holds the parameters sent back to NetworkService.js.
+*/
+dictionary NetworkResultOptions
+{
+  long id = 0;                        // opaque id.
+  boolean ret = false;                // for sync command.
+  boolean broadcast = false;          // for netd broadcast message.
+  DOMString topic = "";               // for netd broadcast message.
+  DOMString reason = "";              // for netd broadcast message.
+
+  long resultCode = 0;                // for all commands.
+  DOMString resultReason = "";        // for all commands.
+  boolean error = false;              // for all commands.
+
+  float rxBytes = -1;                 // for "getNetworkInterfaceStats".
+  float txBytes = -1;                 // for "getNetworkInterfaceStats".
+  DOMString date = "";                // for "getNetworkInterfaceStats".
+  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".
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -234,16 +234,17 @@ WEBIDL_FILES = [
     'MozMmsMessage.webidl',
     'MozNamedAttrMap.webidl',
     'MozPowerManager.webidl',
     'MozTimeManager.webidl',
     'MozWakeLock.webidl',
     'MutationEvent.webidl',
     'MutationObserver.webidl',
     'NetDashboard.webidl',
+    'NetworkOptions.webidl',
     'Node.webidl',
     'NodeFilter.webidl',
     'NodeIterator.webidl',
     'NodeList.webidl',
     'Notification.webidl',
     'NotifyAudioAvailableEvent.webidl',
     'NotifyPaintEvent.webidl',
     'OfflineAudioCompletionEvent.webidl',
deleted file mode 100644
--- a/dom/wifi/NetUtils.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "NetUtils.h"
-#include <dlfcn.h>
-#include <errno.h>
-#include <cutils/properties.h>
-#include "prinit.h"
-#include "mozilla/Assertions.h"
-#include "nsDebug.h"
-
-static void* sNetUtilsLib;
-static PRCallOnceType sInitNetUtilsLib;
-
-static PRStatus
-InitNetUtilsLib()
-{
-  sNetUtilsLib = dlopen("/system/lib/libnetutils.so", RTLD_LAZY);
-  // We might fail to open the hardware lib. That's OK.
-  return PR_SUCCESS;
-}
-
-static void*
-GetNetUtilsLibHandle()
-{
-  PR_CallOnce(&sInitNetUtilsLib, InitNetUtilsLib);
-  return sNetUtilsLib;
-}
-
-// static
-void*
-NetUtils::GetSharedLibrary()
-{
-  void* netLib = GetNetUtilsLibHandle();
-  if (!netLib) {
-    NS_WARNING("No /system/lib/libnetutils.so");
-  }
-  return netLib;
-}
-
-// static
-int32_t
-NetUtils::SdkVersion()
-{
-  char propVersion[PROPERTY_VALUE_MAX];
-  property_get("ro.build.version.sdk", propVersion, "0");
-  int32_t version = strtol(propVersion, nullptr, 10);
-  return version;
-}
-
-DEFINE_DLFUNC(ifc_enable, int32_t, const char*)
-DEFINE_DLFUNC(ifc_disable, int32_t, const char*)
-DEFINE_DLFUNC(ifc_configure, int32_t, const char*, in_addr_t, uint32_t,
-              in_addr_t, in_addr_t, in_addr_t)
-DEFINE_DLFUNC(ifc_reset_connections, int32_t, const char*, const int32_t)
-DEFINE_DLFUNC(dhcp_stop, int32_t, const char*)
-
-int32_t NetUtils::do_ifc_enable(const char *ifname)
-{
-  USE_DLFUNC(ifc_enable)
-  return ifc_enable(ifname);
-}
-
-int32_t NetUtils::do_ifc_disable(const char *ifname)
-{
-  USE_DLFUNC(ifc_disable)
-  return ifc_disable(ifname);
-}
-
-int32_t NetUtils::do_ifc_configure(const char *ifname,
-                                       in_addr_t address,
-                                       uint32_t prefixLength,
-                                       in_addr_t gateway,
-                                       in_addr_t dns1,
-                                       in_addr_t dns2)
-{
-  USE_DLFUNC(ifc_configure)
-  int32_t ret = ifc_configure(ifname, address, prefixLength, gateway, dns1, dns2);
-  return ret;
-}
-
-int32_t NetUtils::do_ifc_reset_connections(const char *ifname,
-                                               const int32_t resetMask)
-{
-  USE_DLFUNC(ifc_reset_connections)
-  return ifc_reset_connections(ifname, resetMask);
-}
-
-int32_t NetUtils::do_dhcp_stop(const char *ifname)
-{
-  USE_DLFUNC(dhcp_stop)
-  return dhcp_stop(ifname);
-}
-
-int32_t NetUtils::do_dhcp_do_request(const char *ifname,
-                                         char *ipaddr,
-                                         char *gateway,
-                                         uint32_t *prefixLength,
-                                         char *dns1,
-                                         char *dns2,
-                                         char *server,
-                                         uint32_t  *lease,
-                                         char* vendorinfo)
-{
-  int32_t ret = -1;
-  uint32_t sdkVersion = SdkVersion();
-
-  if (sdkVersion == 15) {
-    // ICS
-    // http://androidxref.com/4.0.4/xref/system/core/libnetutils/dhcp_utils.c#149
-    DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*,  uint32_t*, char*, char*, char*, uint32_t*)
-    USE_DLFUNC(dhcp_do_request)
-    vendorinfo[0] = '\0';
-
-    ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns1, dns2,
-                          server, lease);
-  } else if (sdkVersion == 16 || sdkVersion == 17) {
-    // JB 4.1 and 4.2
-    // http://androidxref.com/4.1.2/xref/system/core/libnetutils/dhcp_utils.c#175
-    // http://androidxref.com/4.2.2_r1/xref/system/core/include/netutils/dhcp.h#26
-    DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*,  uint32_t*, char*, char*, char*, uint32_t*, char*)
-    USE_DLFUNC(dhcp_do_request)
-    ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns1, dns2,
-                          server, lease, vendorinfo);
-  } else if (sdkVersion == 18) {
-    // JB 4.3
-    // http://androidxref.com/4.3_r2.1/xref/system/core/libnetutils/dhcp_utils.c#181
-    DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*,  uint32_t*, char**, char*, uint32_t*, char*, char*)
-    USE_DLFUNC(dhcp_do_request)
-    char *dns[3] = {dns1, dns2, nullptr};
-    char domains[PROPERTY_VALUE_MAX];
-    ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns,
-                          server, lease, vendorinfo, domains);
-  } else if (sdkVersion == 19) {
-    // JB 4.4
-    // http://androidxref.com/4.4_r1/xref/system/core/libnetutils/dhcp_utils.c#18
-    DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*,  uint32_t*, char**, char*, uint32_t*, char*, char*, char*)
-    USE_DLFUNC(dhcp_do_request)
-    char *dns[3] = {dns1, dns2, nullptr};
-    char domains[PROPERTY_VALUE_MAX];
-    char mtu[PROPERTY_VALUE_MAX];
-    ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns,
-                          server, lease, vendorinfo, domains, mtu);
-  } else {
-    NS_WARNING("Unable to perform do_dhcp_request: unsupported sdk version!");
-  }
-  return ret;
-}
deleted file mode 100644
--- a/dom/wifi/NetUtils.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Abstraction on top of the network support from libnetutils that we
- * use to set up network connections.
- */
-
-#ifndef NetUtils_h
-#define NetUtils_h
-
-#include "arpa/inet.h"
-
-// Copied from ifc.h
-#define RESET_IPV4_ADDRESSES 0x01
-#define RESET_IPV6_ADDRESSES 0x02
-#define RESET_ALL_ADDRESSES  (RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES)
-
-// Implements netutils functions. No need for an abstract class here since we
-// only have a one sdk specific method (dhcp_do_request)
-class NetUtils
-{
-public:
-  static void* GetSharedLibrary();
-
-  int32_t do_ifc_enable(const char *ifname);
-  int32_t do_ifc_disable(const char *ifname);
-  int32_t do_ifc_configure(const char *ifname,
-                           in_addr_t address,
-                           uint32_t prefixLength,
-                           in_addr_t gateway,
-                           in_addr_t dns1,
-                           in_addr_t dns2);
-  int32_t do_ifc_reset_connections(const char *ifname, const int32_t resetMask);
-  int32_t do_dhcp_stop(const char *ifname);
-  int32_t do_dhcp_do_request(const char *ifname,
-                             char *ipaddr,
-                             char *gateway,
-                             uint32_t *prefixLength,
-                             char *dns1,
-                             char *dns2,
-                             char *server,
-                             uint32_t  *lease,
-                             char* vendorinfo);
-
-  static int32_t SdkVersion();
-};
-
-// Defines a function type with the right arguments and return type.
-#define DEFINE_DLFUNC(name, ret, args...) typedef ret (*FUNC##name)(args);
-
-// Set up a dlsymed function ready to use.
-#define USE_DLFUNC(name)                                                      \
-  FUNC##name name = (FUNC##name) dlsym(GetSharedLibrary(), #name);            \
-  if (!name) {                                                                \
-    MOZ_ASSUME_UNREACHABLE("Symbol not found in shared library : " #name);         \
-  }
-
-#endif // NetUtils_h
--- a/dom/wifi/WifiUtils.cpp
+++ b/dom/wifi/WifiUtils.cpp
@@ -3,17 +3,17 @@
  * 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 "NetUtils.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
--- a/dom/wifi/WifiUtils.h
+++ b/dom/wifi/WifiUtils.h
@@ -8,17 +8,17 @@
  */
 
 #ifndef WifiUtils_h
 #define WifiUtils_h
 
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "mozilla/dom/WifiOptionsBinding.h"
-#include "NetUtils.h"
+#include "mozilla/dom/network/NetUtils.h"
 #include "nsCxPusher.h"
 
 // Needed to add a copy constructor to WifiCommandOptions.
 struct CommandOptions
 {
 public:
   CommandOptions(const CommandOptions& aOther) {
     mId = aOther.mId;
--- a/dom/wifi/moz.build
+++ b/dom/wifi/moz.build
@@ -28,14 +28,13 @@ EXTRA_JS_MODULES += [
     'WifiCommand.jsm',
     'WifiNetUtil.jsm',
     'WifiP2pManager.jsm',
     'WifiP2pWorkerObserver.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     SOURCES = [
-        'NetUtils.cpp',
         'WifiProxyService.cpp',
         'WifiUtils.cpp',
     ]
 
 FINAL_LIBRARY = 'xul'
--- a/toolkit/library/nsStaticXULComponents.cpp
+++ b/toolkit/library/nsStaticXULComponents.cpp
@@ -244,24 +244,26 @@
 
 #define MODULE(_name) \
   NSMODULE_DECL(_name);
 
 XUL_MODULES
 
 #ifdef MOZ_WIDGET_GONK
 MODULE(WifiProxyServiceModule)
+MODULE(NetworkWorkerModule)
 #endif
 
 #undef MODULE
 
 #define MODULE(_name) \
     &NSMODULE_NAME(_name),
 
 extern const mozilla::Module *const *const kPStaticModules[] = {
   XUL_MODULES
 #ifdef MOZ_WIDGET_GONK
 MODULE(WifiProxyServiceModule)
+MODULE(NetworkWorkerModule)
 #endif
   nullptr
 };
 
 #undef MODULE