Merge b2g-inbound to m-c on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 29 Jan 2014 15:37:19 -0500
changeset 182854 73eefb421e2afe6cc34a66d5bbb1896dbea13728
parent 182800 90bfbf075f3f4f2e49cfe4b7155289b00f2a05c8 (current diff)
parent 182853 27ab0949047e2fd6b28e19cdd0a0d00aaa03b348 (diff)
child 182855 67fcec5a2779eb6c553f13e30e4a978a8be04f31
child 182876 c45c9d81123bcce09b795c4337ee18afd177abf1
child 182933 9441e41f5f29712bbbc073aeb7acc38395bdda65
child 183084 3f021e06a878823693d2ede45804bca1bab92e1a
push id462
push userraliiev@mozilla.com
push dateTue, 22 Apr 2014 00:22:30 +0000
treeherdermozilla-release@ac5db8c74ac0 [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