merge b2g-inbound to mozilla-central
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 02 Dec 2013 12:46:24 +0100
changeset 172911 2581b84e0ca168be129a1fadab08fbbd17c23ab4
parent 172855 8a5221ecaa6779cb15b9aa5719e3bcd7dc2632ef (current diff)
parent 172910 d884dfe02381890e96e13fc9343253d5c02818d1 (diff)
child 172912 cc2ea69b6acd6e6d0f4e87660031c445fbd0b0f5
child 172935 691b5f265c9a1cc3f398686173fca43295ee1386
child 172972 2be8f1640e213b315ea99d833e74b1f71bb1d702
child 173014 8601e55efa523d9b7e2b394121e186ea6555d5d7
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
2581b84e0ca1 / 28.0a1 / 20131202092621 / files
nightly linux64
2581b84e0ca1 / 28.0a1 / 20131202092621 / files
nightly mac
2581b84e0ca1 / 28.0a1 / 20131202092621 / files
nightly win32
2581b84e0ca1 / 28.0a1 / 20131202092621 / files
nightly win64
2581b84e0ca1 / 28.0a1 / 20131202092621 / 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 mozilla-central
dom/bluetooth/BluetoothOppManager.cpp
dom/bluetooth/BluetoothOppManager.h
dom/bluetooth/BluetoothSocket.cpp
dom/bluetooth/BluetoothUnixSocketConnector.cpp
dom/bluetooth/BluetoothUnixSocketConnector.h
dom/network/tests/unit_ipc/test_udpsocket_ipc.js
dom/network/tests/unit_ipc/udpsocket_child.js
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "121f70034b7ef01836aa345f8ff37b61b96ac88e", 
+    "revision": "cf23b263b4bbf1024210350f24c7e6eb5872a4be", 
     "repo_path": "/integration/gaia-central"
 }
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -679,16 +679,17 @@ GK_ATOM(ondblclick, "ondblclick")
 GK_ATOM(ondeliverysuccess, "ondeliverysuccess")
 GK_ATOM(ondeliveryerror, "ondeliveryerror")
 GK_ATOM(ondevicefound, "ondevicefound")
 GK_ATOM(ondialing, "ondialing")
 GK_ATOM(ondisabled, "ondisabled")
 GK_ATOM(ondischargingtimechange, "ondischargingtimechange")
 GK_ATOM(ondisconnected, "ondisconnected")
 GK_ATOM(ondisconnecting, "ondisconnecting")
+GK_ATOM(ondiscoverystatechanged, "ondiscoverystatechanged")
 GK_ATOM(ondownloading, "ondownloading")
 GK_ATOM(onDOMActivate, "onDOMActivate")
 GK_ATOM(onDOMAttrModified, "onDOMAttrModified")
 GK_ATOM(onDOMCharacterDataModified, "onDOMCharacterDataModified")
 GK_ATOM(onDOMFocusIn, "onDOMFocusIn")
 GK_ATOM(onDOMFocusOut, "onDOMFocusOut")
 GK_ATOM(onDOMMouseScroll, "onDOMMouseScroll")
 GK_ATOM(onDOMNodeInserted, "onDOMNodeInserted")
--- a/content/events/test/test_all_synthetic_events.html
+++ b/content/events/test/test_all_synthetic_events.html
@@ -43,16 +43,20 @@ const kEventConstructors = {
   BlobEvent:                                 { create: function (aName, aProps) {
                                                          return new BlobEvent(aName, aProps);
                                                        },
                                              },
   BluetoothDeviceEvent:                      { create: function (aName, aProps) {
                                                           return new BluetoothDeviceEvent(aName, aProps);
                                                        },
                                              },
+  BluetoothDiscoveryStateChangedEvent:       { create: function (aName, aProps) {
+                                                          return new BluetoothDiscoveryStateChangedEvent(aName, aProps);
+                                                       },
+                                             },
   BluetoothStatusChangedEvent:               { create: function (aName, aProps) {
                                                           return new BluetoothStatusChangedEvent(aName, aProps);
                                                        },
                                              },
   CallEvent:                                 { create: function (aName, aProps) {
                                                           return new CallEvent(aName, aProps);
                                                        },
                                              },
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -4,16 +4,17 @@
  * 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 "base/basictypes.h"
 #include "GeneratedEvents.h"
 #include "nsCxPusher.h"
 #include "nsDOMClassInfo.h"
 #include "nsIDOMBluetoothDeviceEvent.h"
+#include "nsIDOMBluetoothDiscoveryStateChangedEvent.h"
 #include "nsIDOMBluetoothStatusChangedEvent.h"
 #include "nsTArrayHelpers.h"
 #include "DOMRequest.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/BluetoothAdapterBinding.h"
 #include "mozilla/dom/ContentChild.h"
@@ -315,16 +316,29 @@ BluetoothAdapter::Notify(const Bluetooth
     DispatchTrustedEvent(event);
   } else if (aData.name().EqualsLiteral("PropertyChanged")) {
     MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
     const InfallibleTArray<BluetoothNamedValue>& arr =
       v.get_ArrayOfBluetoothNamedValue();
 
     MOZ_ASSERT(arr.Length() == 1);
     SetPropertyByValue(arr[0]);
+  } else if (aData.name().EqualsLiteral(DISCOVERY_STATE_CHANGED_ID)) {
+    MOZ_ASSERT(v.type() == BluetoothValue::Tbool);
+    bool isDiscovering = v.get_bool();
+
+    nsCOMPtr<nsIDOMEvent> event;
+    NS_NewDOMBluetoothDiscoveryStateChangedEvent(
+      getter_AddRefs(event), this, nullptr, nullptr);
+
+    nsCOMPtr<nsIDOMBluetoothDiscoveryStateChangedEvent> e =
+      do_QueryInterface(event);
+    e->InitBluetoothDiscoveryStateChangedEvent(aData.name(), false, false,
+                                               isDiscovering);
+    DispatchTrustedEvent(event);
   } else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID) ||
              aData.name().EqualsLiteral(HFP_STATUS_CHANGED_ID) ||
              aData.name().EqualsLiteral(SCO_STATUS_CHANGED_ID) ||
              aData.name().EqualsLiteral(A2DP_STATUS_CHANGED_ID)) {
     MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
     const InfallibleTArray<BluetoothNamedValue>& arr =
       v.get_ArrayOfBluetoothNamedValue();
 
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -142,16 +142,17 @@ public:
   already_AddRefed<DOMRequest> ToggleCalls(ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
     SendMediaMetaData(const MediaMetaData& aMediaMetaData, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     SendMediaPlayStatus(const MediaPlayStatus& aMediaPlayStatus, ErrorResult& aRv);
 
   IMPL_EVENT_HANDLER(devicefound);
+  IMPL_EVENT_HANDLER(discoverystatechanged);
   IMPL_EVENT_HANDLER(a2dpstatuschanged);
   IMPL_EVENT_HANDLER(hfpstatuschanged);
   IMPL_EVENT_HANDLER(pairedstatuschanged);
   IMPL_EVENT_HANDLER(requestmediaplaystatus);
   IMPL_EVENT_HANDLER(scostatuschanged);
 
   nsPIDOMWindow* GetParentObject() const
   {
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -84,16 +84,21 @@ extern bool gBluetoothDebugFlag;
 #define SCO_STATUS_CHANGED_ID                "scostatuschanged"
 
 /**
  * When the pair status of a Bluetooth device is changed, we'll dispatch an
  * event.
  */
 #define PAIRED_STATUS_CHANGED_ID             "pairedstatuschanged"
 
+ /**
+ * This event would be fired when discovery procedure starts or stops.
+ */
+#define DISCOVERY_STATE_CHANGED_ID           "discoverystatechanged"
+
 /**
  * When receiving a query about current play status from remote device, we'll
  * dispatch an event.
  */
 #define REQUEST_MEDIA_PLAYSTATUS_ID          "requestmediaplaystatus"
 
 // Bluetooth address format: xx:xx:xx:xx:xx:xx (or xx_xx_xx_xx_xx_xx)
 #define BLUETOOTH_ADDRESS_LENGTH 17
--- a/dom/bluetooth/BluetoothProfileController.cpp
+++ b/dom/bluetooth/BluetoothProfileController.cpp
@@ -158,16 +158,17 @@ BluetoothProfileController::SetupProfile
 }
 
 void
 BluetoothProfileController::Start()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mDeviceAddress.IsEmpty());
   MOZ_ASSERT(mProfilesIndex == -1);
+  NS_ENSURE_TRUE_VOID(mProfiles.Length() > 0);
 
   ++mProfilesIndex;
   BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
 
   if (mConnect) {
     mProfiles[mProfilesIndex]->Connect(mDeviceAddress, this);
   } else {
     mProfiles[mProfilesIndex]->Disconnect(this);
--- a/dom/bluetooth/BluetoothProfileController.h
+++ b/dom/bluetooth/BluetoothProfileController.h
@@ -35,18 +35,18 @@ BEGIN_BLUETOOTH_NAMESPACE
 #define GET_MINOR_DEVICE_CLASS(cod)  ((cod & 0xfc) >> 2)
 
 // Bit 21: Major service class = 0x100, Audio
 #define HAS_AUDIO(cod)               (cod & 0x200000)
 
 // Bit 18: Major service class = 0x20, Rendering
 #define HAS_RENDERING(cod)           (cod & 0x40000)
 
-// Major device class = 0xA, Peripheral
-#define IS_PERIPHERAL(cod)           (GET_MAJOR_DEVICE_CLASS(cod) == 0xa)
+// Major device class = 0x5, Peripheral
+#define IS_PERIPHERAL(cod)           (GET_MAJOR_DEVICE_CLASS(cod) == 0x5)
 
 class BluetoothProfileManagerBase;
 class BluetoothReplyRunnable;
 typedef void (*BluetoothProfileControllerCallback)();
 
 class BluetoothProfileController : public RefCounted<BluetoothProfileController>
 {
 public:
--- a/dom/bluetooth/bluedroid/gonk/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/gonk/BluetoothServiceBluedroid.cpp
@@ -44,17 +44,16 @@ static bool sAdapterDiscoverable = false
 static bool sIsBtEnabled = false;
 static nsString sAdapterBdAddress;
 static nsString sAdapterBdName;
 static uint32_t sAdapterDiscoverableTimeout;
 static InfallibleTArray<nsString> sAdapterBondedAddressArray;
 static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
 static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
 static nsTArray<int> sRequestedDeviceCountArray;
 static StaticAutoPtr<Monitor> sToggleBtMonitor;
 
 /**
  *  Classes only used in this file
@@ -491,22 +490,26 @@ DeviceFoundCallback(int aNumProperties, 
   }
 }
 
 static void
 DiscoveryStateChangedCallback(bt_discovery_state_t aState)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
-  if (!sChangeDiscoveryRunnableArray.IsEmpty()) {
-    BluetoothValue values(true);
-    DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0],
-                           values, EmptyString());
+  bool isDiscovering = (aState == BT_DISCOVERY_STARTED);
 
-    sChangeDiscoveryRunnableArray.RemoveElementAt(0);
+  BluetoothSignal signal(NS_LITERAL_STRING(DISCOVERY_STATE_CHANGED_ID),
+                         NS_LITERAL_STRING(KEY_ADAPTER),
+                         isDiscovering);
+
+  nsRefPtr<DistributeBluetoothSignalTask>
+    t = new DistributeBluetoothSignalTask(signal);
+  if (NS_FAILED(NS_DispatchToMainThread(t))) {
+    BT_WARNING("Failed to dispatch to main thread!");
   }
 }
 
 static void
 PinRequestCallback(bt_bdaddr_t* aRemoteBdAddress,
                    bt_bdname_t* aRemoteBdName, uint32_t aRemoteClass)
 {
   MOZ_ASSERT(!NS_IsMainThread());
@@ -913,27 +916,27 @@ nsresult
 BluetoothServiceBluedroid::StartDiscoveryInternal(
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!IsReady()) {
     NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
     DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
-
     return NS_OK;
   }
+
   int ret = sBtInterface->start_discovery();
   if (ret != BT_STATUS_SUCCESS) {
     ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StartDiscovery"));
-
-    return NS_OK;
+    return NS_ERROR_FAILURE;
   }
 
-  sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
+  DispatchBluetoothReply(aRunnable, true, EmptyString());
+
   return NS_OK;
 }
 
 nsresult
 BluetoothServiceBluedroid::StopDiscoveryInternal(
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -942,20 +945,20 @@ BluetoothServiceBluedroid::StopDiscovery
     NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
     DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
     return NS_OK;
   }
 
   int ret = sBtInterface->cancel_discovery();
   if (ret != BT_STATUS_SUCCESS) {
     ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StopDiscovery"));
-    return NS_OK;
+    return NS_ERROR_FAILURE;
   }
 
-  sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
+  DispatchBluetoothReply(aRunnable, true, EmptyString());
 
   return NS_OK;
 }
 
 nsresult
 BluetoothServiceBluedroid::GetDevicePropertiesInternal(
   const BluetoothSignal& aSignal)
 {
--- a/dom/bluetooth/bluez/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/bluez/linux/BluetoothDBusService.cpp
@@ -1507,16 +1507,30 @@ EventFilter(DBusConnection* aConn, DBusM
     }
   } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE,
                                     "PropertyChanged")) {
     ParsePropertyChange(aMsg,
                         v,
                         errorStr,
                         sAdapterProperties,
                         ArrayLength(sAdapterProperties));
+
+    BluetoothNamedValue& property = v.get_ArrayOfBluetoothNamedValue()[0];
+    if (property.name().EqualsLiteral("Discovering")) {
+      bool isDiscovering = property.value();
+      BluetoothSignal signal(NS_LITERAL_STRING(DISCOVERY_STATE_CHANGED_ID),
+                             NS_LITERAL_STRING(KEY_ADAPTER),
+                             isDiscovering);
+
+      nsRefPtr<DistributeBluetoothSignalTask>
+        t = new DistributeBluetoothSignalTask(signal);
+      if (NS_FAILED(NS_DispatchToMainThread(t))) {
+        BT_WARNING("Failed to dispatch to main thread!");
+      }
+    }
   } else if (dbus_message_is_signal(aMsg, DBUS_DEVICE_IFACE,
                                     "PropertyChanged")) {
     ParsePropertyChange(aMsg,
                         v,
                         errorStr,
                         sDeviceProperties,
                         ArrayLength(sDeviceProperties));
 
--- a/dom/bluetooth/interfaces/moz.build
+++ b/dom/bluetooth/interfaces/moz.build
@@ -3,12 +3,13 @@
 # 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/.
 
 if CONFIG['MOZ_B2G_BT']:
     XPIDL_SOURCES += [
         'nsIDOMBluetoothDevice.idl',
         'nsIDOMBluetoothDeviceEvent.idl',
+        'nsIDOMBluetoothDiscoveryStateChangedEvent.idl',
         'nsIDOMBluetoothStatusChangedEvent.idl',
     ]
     XPIDL_MODULE = 'dom_bluetooth'
 
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/interfaces/nsIDOMBluetoothDiscoveryStateChangedEvent.idl
@@ -0,0 +1,22 @@
+/* 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 "nsIDOMEvent.idl"
+
+[scriptable, builtinclass, uuid(9de639cb-71c4-4144-8462-09763ec87c20)]
+interface nsIDOMBluetoothDiscoveryStateChangedEvent : nsIDOMEvent
+{
+  readonly attribute boolean discovering;
+
+  [noscript]
+  void initBluetoothDiscoveryStateChangedEvent(in DOMString aType,
+                                               in boolean aCanBubble,
+                                               in boolean aCancelable,
+                                               in boolean aDiscovering);
+};
+
+dictionary BluetoothDiscoveryStateChangedEventInit : EventInit
+{
+  bool discovering;
+};
--- a/dom/devicestorage/DeviceStorage.h
+++ b/dom/devicestorage/DeviceStorage.h
@@ -90,16 +90,17 @@ public:
   void collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> >& aFiles,
                             PRTime aSince, nsAString& aRootPath);
 
   void AccumDiskUsage(uint64_t* aPicturesSoFar, uint64_t* aVideosSoFar,
                       uint64_t* aMusicSoFar, uint64_t* aTotalSoFar);
 
   void GetDiskFreeSpace(int64_t* aSoFar);
   void GetStatus(nsAString& aStatus);
+  void DoFormat(nsAString& aStatus);
   static void GetRootDirectoryForType(const nsAString& aStorageType,
                                       const nsAString& aStorageName,
                                       nsIFile** aFile);
 
   nsresult CalculateSizeAndModifiedDate();
   nsresult CalculateMimeType();
 
 private:
@@ -232,16 +233,17 @@ public:
   }
   already_AddRefed<DOMCursor>
   EnumerateEditable(const nsAString& aPath,
                     const EnumerationParameters& aOptions, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest> FreeSpace(ErrorResult& aRv);
   already_AddRefed<DOMRequest> UsedSpace(ErrorResult& aRv);
   already_AddRefed<DOMRequest> Available(ErrorResult& aRv);
+  already_AddRefed<DOMRequest> Format(ErrorResult& aRv);
 
   bool Default();
 
   // Uses XPCOM GetStorageName
 
   static void
   CreateDeviceStorageFor(nsPIDOMWindow* aWin,
                          const nsAString& aType,
--- a/dom/devicestorage/DeviceStorageRequestChild.cpp
+++ b/dom/devicestorage/DeviceStorageRequestChild.cpp
@@ -98,16 +98,26 @@ DeviceStorageRequestChild::
       AvailableStorageResponse r = aValue;
       AutoJSContext cx;
       JS::Rooted<JS::Value> result(
         cx, StringToJsval(mRequest->GetOwner(), r.mountState()));
       mRequest->FireSuccess(result);
       break;
     }
 
+    case DeviceStorageResponseValue::TFormatStorageResponse:
+    {
+      FormatStorageResponse r = aValue;
+      AutoJSContext cx;
+      JS::Rooted<JS::Value> result(
+        cx, StringToJsval(mRequest->GetOwner(), r.mountState()));
+      mRequest->FireSuccess(result);
+      break;
+    }
+
     case DeviceStorageResponseValue::TEnumerationResponse:
     {
       EnumerationResponse r = aValue;
       nsDOMDeviceStorageCursor* cursor
         = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
 
       uint32_t count = r.paths().Length();
       for (uint32_t i = 0; i < count; i++) {
--- a/dom/devicestorage/DeviceStorageRequestParent.cpp
+++ b/dom/devicestorage/DeviceStorageRequestParent.cpp
@@ -126,16 +126,28 @@ DeviceStorageRequestParent::Dispatch()
       nsRefPtr<DeviceStorageFile> dsf =
         new DeviceStorageFile(p.type(), p.storageName());
       nsRefPtr<PostAvailableResultEvent> r
         = new PostAvailableResultEvent(this, dsf);
       NS_DispatchToMainThread(r);
       break;
     }
 
+    case DeviceStorageParams::TDeviceStorageFormatParams:
+    {
+      DeviceStorageFormatParams p = mParams;
+
+      nsRefPtr<DeviceStorageFile> dsf =
+        new DeviceStorageFile(p.type(), p.storageName());
+      nsRefPtr<PostFormatResultEvent> r
+        = new PostFormatResultEvent(this, dsf);
+      NS_DispatchToMainThread(r);
+      break;
+    }
+
     case DeviceStorageParams::TDeviceStorageEnumerationParams:
     {
       DeviceStorageEnumerationParams p = mParams;
       nsRefPtr<DeviceStorageFile> dsf
         = new DeviceStorageFile(p.type(), p.storageName(),
                                 p.rootdir(), NS_LITERAL_STRING(""));
       nsRefPtr<CancelableRunnable> r
         = new EnumerateFileEvent(this, dsf, p.since());
@@ -210,16 +222,24 @@ DeviceStorageRequestParent::EnsureRequir
     case DeviceStorageParams::TDeviceStorageAvailableParams:
     {
       DeviceStorageAvailableParams p = mParams;
       type = p.type();
       requestType = DEVICE_STORAGE_REQUEST_AVAILABLE;
       break;
     }
 
+    case DeviceStorageParams::TDeviceStorageFormatParams:
+    {
+      DeviceStorageFormatParams p = mParams;
+      type = p.type();
+      requestType = DEVICE_STORAGE_REQUEST_FORMAT;
+      break;
+    }
+
     case DeviceStorageParams::TDeviceStorageEnumerationParams:
     {
       DeviceStorageEnumerationParams p = mParams;
       type = p.type();
       requestType = DEVICE_STORAGE_REQUEST_READ;
       break;
     }
 
@@ -721,11 +741,39 @@ DeviceStorageRequestParent::PostAvailabl
     mFile->GetStatus(state);
   }
 
   AvailableStorageResponse response(state);
   unused << mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
+DeviceStorageRequestParent::PostFormatResultEvent::
+  PostFormatResultEvent(DeviceStorageRequestParent* aParent,
+                           DeviceStorageFile* aFile)
+  : CancelableRunnable(aParent)
+  , mFile(aFile)
+{
+}
+
+DeviceStorageRequestParent::PostFormatResultEvent::
+  ~PostFormatResultEvent()
+{
+}
+
+nsresult
+DeviceStorageRequestParent::PostFormatResultEvent::CancelableRun()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  nsString state = NS_LITERAL_STRING("unavailable");
+  if (mFile) {
+    mFile->DoFormat(state);
+  }
+
+  FormatStorageResponse response(state);
+  unused << mParent->Send__delete__(mParent, response);
+  return NS_OK;
+}
+
 } // namespace devicestorage
 } // namespace dom
 } // namespace mozilla
--- a/dom/devicestorage/DeviceStorageRequestParent.h
+++ b/dom/devicestorage/DeviceStorageRequestParent.h
@@ -222,16 +222,26 @@ private:
     public:
       PostAvailableResultEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile);
       virtual ~PostAvailableResultEvent();
       virtual nsresult CancelableRun();
     private:
       nsRefPtr<DeviceStorageFile> mFile;
  };
 
+ class PostFormatResultEvent : public CancelableRunnable
+ {
+    public:
+      PostFormatResultEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile);
+      virtual ~PostFormatResultEvent();
+      virtual nsresult CancelableRun();
+    private:
+      nsRefPtr<DeviceStorageFile> mFile;
+ };
+
 protected:
   bool AddRunnable(CancelableRunnable* aRunnable) {
     MutexAutoLock lock(mMutex);
     if (mActorDestoryed)
       return false;
 
     mRunnables.AppendElement(aRunnable);
     return true;
--- a/dom/devicestorage/PDeviceStorageRequest.ipdl
+++ b/dom/devicestorage/PDeviceStorageRequest.ipdl
@@ -48,25 +48,31 @@ struct UsedSpaceStorageResponse
   uint64_t usedBytes;
 };
 
 struct AvailableStorageResponse
 {
   nsString mountState;
 };
 
+struct FormatStorageResponse
+{
+  nsString mountState;
+};
+
 union DeviceStorageResponseValue
 {
   ErrorResponse;
   SuccessResponse;
   BlobResponse;
   EnumerationResponse;
   FreeSpaceStorageResponse;
   UsedSpaceStorageResponse;
   AvailableStorageResponse;
+  FormatStorageResponse;
 };
 
 sync protocol PDeviceStorageRequest {
     manager PContent;
 child:
     __delete__(DeviceStorageResponseValue response);
 };
 
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -385,16 +385,17 @@ DeviceStorageTypeChecker::GetAccessForRe
     case DEVICE_STORAGE_REQUEST_WATCH:
     case DEVICE_STORAGE_REQUEST_FREE_SPACE:
     case DEVICE_STORAGE_REQUEST_USED_SPACE:
     case DEVICE_STORAGE_REQUEST_AVAILABLE:
       aAccessResult.AssignLiteral("read");
       break;
     case DEVICE_STORAGE_REQUEST_WRITE:
     case DEVICE_STORAGE_REQUEST_DELETE:
+    case DEVICE_STORAGE_REQUEST_FORMAT:
       aAccessResult.AssignLiteral("write");
       break;
     case DEVICE_STORAGE_REQUEST_CREATE:
       aAccessResult.AssignLiteral("create");
       break;
     default:
       aAccessResult.AssignLiteral("undefined");
   }
@@ -1275,16 +1276,46 @@ bool
 DeviceStorageFile::IsAvailable()
 {
   nsString status;
   GetStatus(status);
   return status.EqualsLiteral("available");
 }
 
 void
+DeviceStorageFile::DoFormat(nsAString& aStatus)
+{
+  DeviceStorageTypeChecker* typeChecker
+    = DeviceStorageTypeChecker::CreateOrGet();
+  if (!typeChecker) {
+    return;
+  }
+  if (!typeChecker->IsVolumeBased(mStorageType)) {
+    aStatus.AssignLiteral("notVolume");
+    return;
+  }
+#ifdef MOZ_WIDGET_GONK
+  nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID);
+  NS_ENSURE_TRUE_VOID(vs);
+
+  nsCOMPtr<nsIVolume> vol;
+  nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol));
+  NS_ENSURE_SUCCESS_VOID(rv);
+  if (!vol) {
+    return;
+  }
+
+  vol->Format();
+
+  aStatus.AssignLiteral("formatting");
+#endif
+  return;
+}
+
+void
 DeviceStorageFile::GetStatus(nsAString& aStatus)
 {
   DeviceStorageTypeChecker* typeChecker
     = DeviceStorageTypeChecker::CreateOrGet();
   if (!typeChecker) {
     return;
   }
   if (!typeChecker->IsVolumeBased(mStorageType)) {
@@ -1311,16 +1342,23 @@ DeviceStorageFile::GetStatus(nsAString& 
   }
   bool isSharing;
   rv = vol->GetIsSharing(&isSharing);
   NS_ENSURE_SUCCESS_VOID(rv);
   if (isSharing) {
     aStatus.AssignLiteral("shared");
     return;
   }
+  bool isFormatting;
+  rv = vol->GetIsFormatting(&isFormatting);
+  NS_ENSURE_SUCCESS_VOID(rv);
+  if (isFormatting) {
+    aStatus.AssignLiteral("unavailable");
+    return;
+  }
   int32_t volState;
   rv = vol->GetState(&volState);
   NS_ENSURE_SUCCESS_VOID(rv);
   if (volState == nsIVolume::STATE_MOUNTED) {
     aStatus.AssignLiteral("available");
   }
 #endif
 }
@@ -1843,16 +1881,49 @@ public:
     return NS_OK;
   }
 
 private:
   nsRefPtr<DeviceStorageFile> mFile;
   nsRefPtr<DOMRequest> mRequest;
 };
 
+class PostFormatResultEvent : public nsRunnable
+{
+public:
+  PostFormatResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest)
+    : mFile(aFile)
+    , mRequest(aRequest)
+  {
+  }
+
+  ~PostFormatResultEvent() {}
+
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsString state = NS_LITERAL_STRING("unavailable");
+    if (mFile) {
+      mFile->DoFormat(state);
+    }
+
+    AutoJSContext cx;
+    JS::Rooted<JS::Value> result(cx,
+                                 StringToJsval(mRequest->GetOwner(), state));
+    mRequest->FireSuccess(result);
+    mRequest = nullptr;
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<DeviceStorageFile> mFile;
+  nsRefPtr<DOMRequest> mRequest;
+};
+
 class PostResultEvent : public nsRunnable
 {
 public:
   PostResultEvent(already_AddRefed<DOMRequest> aRequest,
                   DeviceStorageFile* aFile)
     : mFile(aFile)
     , mRequest(aRequest)
   {}
@@ -2418,16 +2489,33 @@ public:
         return NS_OK;
       }
 
       case DEVICE_STORAGE_REQUEST_WATCH:
       {
         mDeviceStorage->mAllowedToWatchFile = true;
         return NS_OK;
       }
+
+      case DEVICE_STORAGE_REQUEST_FORMAT:
+      {
+        if (XRE_GetProcessType() != GeckoProcessType_Default) {
+          PDeviceStorageRequestChild* child
+            = new DeviceStorageRequestChild(mRequest, mFile);
+          DeviceStorageFormatParams params(mFile->mStorageType,
+                                           mFile->mStorageName);
+          ContentChild::GetSingleton()
+            ->SendPDeviceStorageRequestConstructor(child, params);
+          return NS_OK;
+        }
+        r = new PostFormatResultEvent(mFile, mRequest);
+        NS_DispatchToMainThread(r);
+        return NS_OK;
+      }
+
     }
 
     if (r) {
       nsCOMPtr<nsIEventTarget> target
         = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       NS_ASSERTION(target, "Must have stream transport service");
       target->Dispatch(r, NS_DISPATCH_NORMAL);
     }
@@ -3078,16 +3166,36 @@ nsDOMDeviceStorage::Available(ErrorResul
                                                           mStorageName);
   nsCOMPtr<nsIRunnable> r
     = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_AVAILABLE,
                                win, mPrincipal, dsf, request);
   NS_DispatchToMainThread(r);
   return request.forget();
 }
 
+already_AddRefed<DOMRequest>
+nsDOMDeviceStorage::Format(ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
+
+  nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType,
+                                                          mStorageName);
+  nsCOMPtr<nsIRunnable> r
+    = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FORMAT,
+                               win, mPrincipal, dsf, request);
+  NS_DispatchToMainThread(r);
+  return request.forget();
+}
+
 NS_IMETHODIMP
 nsDOMDeviceStorage::GetRootDirectoryForFile(const nsAString& aName,
                                             nsIFile** aRootDirectory)
 {
   nsRefPtr<nsDOMDeviceStorage> ds;
 
   if (IsFullPath(aName)) {
     nsString storagePath;
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -46,17 +46,18 @@ class ErrorResult;
 enum DeviceStorageRequestType {
     DEVICE_STORAGE_REQUEST_READ,
     DEVICE_STORAGE_REQUEST_WRITE,
     DEVICE_STORAGE_REQUEST_CREATE,
     DEVICE_STORAGE_REQUEST_DELETE,
     DEVICE_STORAGE_REQUEST_WATCH,
     DEVICE_STORAGE_REQUEST_FREE_SPACE,
     DEVICE_STORAGE_REQUEST_USED_SPACE,
-    DEVICE_STORAGE_REQUEST_AVAILABLE
+    DEVICE_STORAGE_REQUEST_AVAILABLE,
+    DEVICE_STORAGE_REQUEST_FORMAT
 };
 
 class DeviceStorageUsedSpaceCache MOZ_FINAL
 {
 public:
   static DeviceStorageUsedSpaceCache* CreateOrGet();
 
   DeviceStorageUsedSpaceCache();
--- a/dom/icc/interfaces/SimToolKit.idl
+++ b/dom/icc/interfaces/SimToolKit.idl
@@ -111,16 +111,27 @@ dictionary MozStkMenu
    * Help information available or not.
    *
    * @see TS 11.14, clause 12.6, Command Qualifier, SET UP MENU, bit 8.
    *
    * true: help information available.
    * false: no help information available.
    */
   boolean isHelpAvailable;
+
+  /**
+   * List of Next Action Indicators.
+   * Each element should be one of nsIDOMMozIccManager.STK_CMD_*
+   *                            or nsIDOMMozIccManager.STK_NEXT_ACTION_*
+   * If it's STK_NEXT_ACTION_NULL, the terminal should ignore this action
+   * in corresponding item.
+   *
+   * @see TS 11.14, clause 12.24, Items Next Action Indicator.
+   */
+  jsval nextActionList; // unsigned short []
 };
 
 dictionary MozStkInput
 {
   /**
    * Text for the ME to display in conjunction with asking the user to respond.
    */
   DOMString text;
--- a/dom/icc/interfaces/nsIDOMIccManager.idl
+++ b/dom/icc/interfaces/nsIDOMIccManager.idl
@@ -1,17 +1,17 @@
 /* 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 "nsIDOMEventTarget.idl"
 
 interface nsIDOMMozIcc;
 
-[scriptable, builtinclass, uuid(23067d6f-e0cb-4f34-8648-77c2b25a11f5)]
+[scriptable, builtinclass, uuid(67e40e8e-35ee-40a4-a5b8-414588675133)]
 interface nsIDOMMozIccManager : nsIDOMEventTarget
 {
   /**
    * STK menu presentation types.
    */
   const unsigned short STK_MENU_TYPE_NOT_SPECIFIED      = 0x00;
   const unsigned short STK_MENU_TYPE_DATA_VALUES        = 0x01;
   const unsigned short STK_MENU_TYPE_NAVIGATION_OPTIONS = 0x03;
@@ -42,20 +42,20 @@ interface nsIDOMMozIccManager : nsIDOMEv
   const unsigned short STK_CMD_DISPLAY_TEXT          = 0x21;
   const unsigned short STK_CMD_GET_INKEY             = 0x22;
   const unsigned short STK_CMD_GET_INPUT             = 0x23;
   const unsigned short STK_CMD_SELECT_ITEM           = 0x24;
   const unsigned short STK_CMD_SET_UP_MENU           = 0x25;
   const unsigned short STK_CMD_PROVIDE_LOCAL_INFO    = 0x26;
   const unsigned short STK_CMD_TIMER_MANAGEMENT      = 0x27;
   const unsigned short STK_CMD_SET_UP_IDLE_MODE_TEXT = 0x28;
-  const unsigned short STK_CMD_OPEN_CHANNEL          = 0x30;
-  const unsigned short STK_CMD_CLOSE_CHANNEL         = 0x31;
-  const unsigned short STK_CMD_RECEIVE_DATA          = 0x32;
-  const unsigned short STK_CMD_SEND_DATA             = 0x33;
+  const unsigned short STK_CMD_OPEN_CHANNEL          = 0x40;
+  const unsigned short STK_CMD_CLOSE_CHANNEL         = 0x41;
+  const unsigned short STK_CMD_RECEIVE_DATA          = 0x42;
+  const unsigned short STK_CMD_SEND_DATA             = 0x43;
 
   /**
    * STK result code.
    *
    * @see TS 11.14, clause 12.12
    *
    * Results '0X' and '1X' indicate that the command has been performed.
    */
@@ -218,16 +218,22 @@ interface nsIDOMMozIccManager : nsIDOMEv
 
   /**
    * Browser termination cause.
    */
   const unsigned short STK_BROWSER_TERMINATION_CAUSE_USER  = 0x00;
   const unsigned short STK_BROWSER_TERMINATION_CAUSE_ERROR = 0x01;
 
   /**
+   * Next Action Indicator.
+   */
+  const unsigned short STK_NEXT_ACTION_NULL                  = 0x00;
+  const unsigned short STK_NEXT_ACTION_END_PROACTIVE_SESSION = 0x81;
+
+  /**
    * Array of iccIds that are currently detected.
    */
   readonly attribute jsval iccIds;  // DOMString[]
 
   /**
    * Get ICC object by iccId.
    *
    * @param iccId
--- a/dom/icc/tests/marionette/manifest.ini
+++ b/dom/icc/tests/marionette/manifest.ini
@@ -17,12 +17,13 @@ qemu = true
 [test_stk_send_dtmf.js]
 [test_stk_launch_browser.js]
 [test_stk_display_text.js]
 [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]
 disabled = Bug 933654
 [test_icc_detected_undetected_event.js]
 disabled = Bug 933654
new file mode 100644
--- /dev/null
+++ b/dom/icc/tests/marionette/test_stk_bip_command.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_HEAD_JS = "stk_helper.js";
+
+function testBipCommand(command, expect) {
+  log("STK CMD " + JSON.stringify(command));
+
+  is(command.typeOfCommand, expect.typeOfCommand, expect.name);
+  is(command.options.text, expect.text, expect.name);
+
+  runNextTest();
+}
+
+let tests = [
+  {command: "d04b81030140018202818205074f70656e204944350702030403041f0239020578470a065465737447700272730d08f4557365724c6f670d08f4557365725077643c0301ad9c3e052101010101",
+   func: testBipCommand,
+   expect: {name: "open_channel_1",
+            typeOfCommand: iccManager.STK_CMD_OPEN_CHANNEL,
+            text: "Open ID"}},
+  {command: "d0448103014001820281820500350702030403041f0239020578470a065465737447700272730d08f4557365724c6f670d08f4557365725077643c0301ad9c3e052101010101",
+   func: testBipCommand,
+   expect: {name: "open_channel_2",
+            typeOfCommand: iccManager.STK_CMD_OPEN_CHANNEL,
+            text: ""}},
+  {command: "d05381030140018202818205094f70656e2049442031350702030403041f0239020578470a065465737447700272730d08f4557365724c6f670d08f4557365725077643c0301ad9c3e052101010101d004000900b4",
+   func: testBipCommand,
+   expect: {name: "open_channel_3",
+            typeOfCommand: iccManager.STK_CMD_OPEN_CHANNEL,
+            text: "Open ID 1"}},
+  {command: "d01b810301410082028121850a436c6f73652049442031d004000a00b4",
+   func: testBipCommand,
+   expect: {name: "close_channel_1",
+            typeOfCommand: iccManager.STK_CMD_CLOSE_CHANNEL,
+            text: "Close ID 1"}},
+  {command: "d022810301420082028121850e5265636569766520446174612031b701c8d004000e00b4",
+   func: testBipCommand,
+   expect: {name: "receive_data_1",
+            typeOfCommand: iccManager.STK_CMD_RECEIVE_DATA,
+            text: "Receive Data 1"}},
+  {command: "d026810301430182028121850b53656e6420446174612031b6080001020304050607d004000b00b4",
+   func: testBipCommand,
+   expect: {name: "send_data_1",
+            typeOfCommand: iccManager.STK_CMD_SEND_DATA,
+            text: "Send Data 1"}},
+];
+
+runNextTest();
--- a/dom/icc/tests/marionette/test_stk_select_item.js
+++ b/dom/icc/tests/marionette/test_stk_select_item.js
@@ -7,16 +7,20 @@ function testSelectItem(command, expect)
   log("STK CMD " + JSON.stringify(command));
   is(command.typeOfCommand, iccManager.STK_CMD_SELECT_ITEM, expect.name);
   is(command.commandQualifier, expect.commandQualifier, expect.name);
   is(command.options.title, expect.title, expect.name);
   for (let index in command.options.items) {
     is(command.options.items[index].identifier, expect.items[index].identifier, expect.name);
     is(command.options.items[index].text, expect.items[index].text, expect.name);
   }
+  let length = command.options.nextActionList ? command.options.nextActionList.length : 0;
+  for (let i = 0; i < length; i++) {
+    is(command.options.nextActionList[i], expect.nextActionList[i], expect.name);
+  }
 
   runNextTest();
 }
 
 let tests = [
   {command: "d03d810301240082028182850e546f6f6c6b69742053656c6563748f07014974656d20318f07024974656d20328f07034974656d20338f07044974656d2034",
    func: testSelectItem,
    expect: {name: "select_item_cmd_1",
@@ -53,17 +57,18 @@ let tests = [
             commandQualifier: 0x00,
             title: "0LargeMenu",
             items: [{identifier: 255, text: "1 Call Forward Unconditional"}, {identifier: 254, text: "2 Call Forward On User Busy"}, {identifier: 253, text: "3 Call Forward On No Reply"}, {identifier: 252, text: "4 Call Forward On User Not Reachable"}, {identifier: 251, text: "5 Barring Of All Outgoing Calls"}, {identifier: 250, text: "6 Barring Of All Outgoing Int Calls"}, {identifier: 249, text: "7 CLI Presentation"}]}},
   {command: "d039810301240082028182850e546f6f6c6b69742053656c6563748f07014974656d20318f07024974656d20328f07034974656d20331803131026",
    func: testSelectItem,
    expect: {name: "select_item_cmd_7",
             commandQualifier: 0x00,
             title: "Toolkit Select",
-            items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}]}},
+            items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}],
+            nextActionList: [iccManager.STK_CMD_SEND_SMS, iccManager.STK_CMD_SET_UP_CALL, iccManager.STK_CMD_PROVIDE_LOCAL_INFO]}},
   {command: "d037810301240082028182850e546f6f6c6b69742053656c6563748f07014974656d20318f07024974656d20328f07034974656d2033900102",
    func: testSelectItem,
    expect: {name: "select_item_cmd_8",
             commandQualifier: 0x00,
             title: "Toolkit Select",
             items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}]}},
   {command: "d034810301248082028182850e546f6f6c6b69742053656c6563748f07014974656d20318f07024974656d20328f07034974656d2033",
    func: testSelectItem,
@@ -299,12 +304,19 @@ let tests = [
             commandQualifier: 0x00,
             title: "81ル0",
             items: [{identifier: 1, text: "81ル1"}, {identifier: 2, text: "81ル2"}, {identifier: 3, text: "81ル3"}]}},
   {command: "d0348103012400820281828508820430a03832cb308f0901820430a03832cb318f0902820430a03832cb328f0903820430a03832cb33",
    func: testSelectItem,
    expect: {name: "select_item_cmd_48",
             commandQualifier: 0x00,
             title: "82ル0",
-            items: [{identifier: 1, text: "82ル1"}, {identifier: 2, text: "82ル2"}, {identifier: 3, text: "82ル3"}]}}
+            items: [{identifier: 1, text: "82ル1"}, {identifier: 2, text: "82ル2"}, {identifier: 3, text: "82ル3"}]}},
+  {command: "d039810301240082028182850e546f6f6c6b69742053656c6563748f07014974656d20318f07024974656d20328f07034974656d20331803000081",
+   func: testSelectItem,
+   expect: {name: "select_item_cmd_49",
+            commandQualifier: 0x00,
+            title: "Toolkit Select",
+            items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}],
+            nextActionList: [iccManager.STK_NEXT_ACTION_NULL, iccManager.STK_NEXT_ACTION_NULL, iccManager.STK_NEXT_ACTION_END_PROACTIVE_SESSION]}},
 ];
 
 runNextTest();
--- a/dom/icc/tests/marionette/test_stk_setup_menu.js
+++ b/dom/icc/tests/marionette/test_stk_setup_menu.js
@@ -7,16 +7,20 @@ function testSetupMenu(command, expect) 
   log("STK CMD " + JSON.stringify(command));
   is(command.typeOfCommand, iccManager.STK_CMD_SET_UP_MENU, expect.name);
   is(command.commandQualifier, expect.commandQualifier, expect.name);
   is(command.options.title, expect.title, expect.name);
   for (let index in command.options.items) {
     is(command.options.items[index].identifier, expect.items[index].identifier, expect.name);
     is(command.options.items[index].text, expect.items[index].text, expect.name);
   }
+  let length = command.options.nextActionList ? command.options.nextActionList.length : 0;
+  for (let i = 0; i < length; i++) {
+    is(command.options.nextActionList[i], expect.nextActionList[i], expect.name);
+  }
 
   runNextTest();
 }
 
 function isFirstMenuItemNull(command) {
   return (command.options.items.length == 1 && !(command.options.items[0]));
 }
 
@@ -72,17 +76,18 @@ let tests = [
             commandQualifier: 0x80,
             title: "Toolkit Menu",
             items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}, {identifier: 4, text: "Item 4"}]}},
   {command: "d041810301250082028182850c546f6f6c6b6974204d656e758f07014974656d20318f07024974656d20328f07034974656d20338f07044974656d2034180413101526",
    func: testSetupMenu,
    expect: {name: "setup_menu_cmd_7",
             commandQualifier: 0x00,
             title: "Toolkit Menu",
-            items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}, {identifier: 4, text: "Item 4"}]}},
+            items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}, {identifier: 4, text: "Item 4"}],
+            nextActionList: [iccManager.STK_CMD_SEND_SMS, iccManager.STK_CMD_SET_UP_CALL, iccManager.STK_CMD_LAUNCH_BROWSER, iccManager.STK_CMD_PROVIDE_LOCAL_INFO]}},
   {command: "d03c810301250082028182850c546f6f6c6b6974204d656e758f07014974656d20318f07024974656d20328f07034974656d20339e0201019f0401050505",
    func: testSetupMenu,
    expect: {name: "setup_menu_cmd_8",
             commandQualifier: 0x00,
             title: "Toolkit Menu",
             items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}]}},
   {command: "d03c810301250082028182850c546f6f6c6b6974204d656e758f07014974656d20318f07024974656d20328f07034974656d20339e0200019f0400050505",
    func: testSetupMenu,
@@ -217,16 +222,23 @@ let tests = [
             title: "80ル0",
             items: [{identifier: 1, text: "80ル1"}, {identifier: 2, text: "80ル2"}, {identifier: 3, text: "80ル3"}, {identifier: 4, text: "80ル4"}]}},
   {command: "d02c8103012500820281828509800038003030eb00308f0a11800038003030eb00358f0a12800038003030eb0036",
    func: testSetupMenu,
    expect: {name: "setup_menu_cmd_31",
             commandQualifier: 0x00,
             title: "80ル0",
             items: [{identifier: 17, text: "80ル5"}, {identifier: 18, text: "80ル6"}]}},
+  {command: "d041810301250082028182850c546f6f6c6b6974204d656e758f07014974656d20318f07024974656d20328f07034974656d20338f07044974656d2034180481000000",
+   func: testSetupMenu,
+   expect: {name: "setup_menu_cmd_32",
+            commandQualifier: 0x00,
+            title: "Toolkit Menu",
+            items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}, {identifier: 4, text: "Item 4"}],
+            nextActionList: [iccManager.STK_NEXT_ACTION_END_PROACTIVE_SESSION, iccManager.STK_NEXT_ACTION_NULL, iccManager.STK_NEXT_ACTION_NULL, iccManager.STK_NEXT_ACTION_NULL]}},
   {command: "D00D81030125008202818285008F00",
    func: testRemoveSetupMenu},
   {command:"D03B810301250082028182850C546F6F6C6B6974204D656E758F07014974656D20318F07024974656D20328F07034974656D20338F07044974656D2034",
    func: testInitialSetupMenu},
 
 ];
 
 runNextTest();
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -74,16 +74,22 @@ struct DeviceStorageUsedSpaceParams
 };
 
 struct DeviceStorageAvailableParams
 {
   nsString type;
   nsString storageName;
 };
 
+struct DeviceStorageFormatParams
+{
+  nsString type;
+  nsString storageName;
+};
+
 struct DeviceStorageAddParams
 {
   nsString type;
   nsString storageName;
   nsString relpath;
   PBlob blob;
 };
 
@@ -114,16 +120,17 @@ union DeviceStorageParams
 {
   DeviceStorageAddParams;
   DeviceStorageGetParams;
   DeviceStorageDeleteParams;
   DeviceStorageEnumerationParams;
   DeviceStorageFreeSpaceParams;
   DeviceStorageUsedSpaceParams;
   DeviceStorageAvailableParams;
+  DeviceStorageFormatParams;
 };
 
 struct FMRadioRequestEnableParams
 {
   double frequency;
 };
 
 struct FMRadioRequestDisableParams
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -549,21 +549,16 @@ TabChild::HandlePossibleViewportChange()
   CSSSize viewport(viewportInfo.GetSize());
 
   // We're not being displayed in any way; don't bother doing anything because
   // that will just confuse future adjustments.
   if (!screenW || !screenH) {
     return;
   }
 
-  // Make sure the viewport height is not shorter than the window when the page
-  // is zoomed out to show its full width. Note that before we set the viewport
-  // width, the "full width" of the page isn't properly defined, so that's why
-  // we have to call SetCSSViewport twice - once to set the width, and the
-  // second time to figure out the height based on the layout at that width.
   float oldBrowserWidth = mOldViewportWidth;
   mLastMetrics.mViewport.SizeTo(viewport);
   if (!oldBrowserWidth) {
     oldBrowserWidth = kDefaultViewportSize.width;
   }
   SetCSSViewport(viewport);
 
   // If this page has not been painted yet, then this must be getting run
@@ -601,23 +596,16 @@ TabChild::HandlePossibleViewportChange()
     // For non-HTML content (e.g. SVG), just assume page size == viewport size.
     pageSize = viewport;
   }
   if (!pageSize.width) {
     // Return early rather than divide by 0.
     return;
   }
 
-  CSSToScreenScale minScale(mInnerSize.width / pageSize.width);
-  minScale = clamped(minScale, viewportInfo.GetMinZoom(), viewportInfo.GetMaxZoom());
-  NS_ENSURE_TRUE_VOID(minScale.scale); // (return early rather than divide by 0)
-
-  viewport.height = std::max(viewport.height, screenH / minScale.scale);
-  SetCSSViewport(viewport);
-
   float oldScreenWidth = mLastMetrics.mCompositionBounds.width;
   if (!oldScreenWidth) {
     oldScreenWidth = mInnerSize.width;
   }
 
   FrameMetrics metrics(mLastMetrics);
   metrics.mViewport = CSSRect(CSSPoint(), viewport);
   metrics.mScrollableRect = CSSRect(CSSPoint(), pageSize);
--- a/dom/media/bridge/MediaModule.cpp
+++ b/dom/media/bridge/MediaModule.cpp
@@ -11,32 +11,41 @@
 
 #include "PeerConnectionImpl.h"
 
 #define PEERCONNECTION_CID \
 {0xb93af7a1, 0x3411, 0x44a8, {0xbd, 0x0a, 0x8a, 0xf3, 0xdd, 0xe4, 0xd8, 0xd8}}
 
 #define PEERCONNECTION_CONTRACTID "@mozilla.org/peerconnection;1"
 
+#include "stun_udp_socket_filter.h"
+
+NS_DEFINE_NAMED_CID(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CID)
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsStunUDPSocketFilterHandler)
+
+
 namespace sipcc
 {
 // Factory defined in sipcc::, defines sipcc::PeerConnectionImplConstructor
 NS_GENERIC_FACTORY_CONSTRUCTOR(PeerConnectionImpl)
 }
 
 // Defines kPEERCONNECTION_CID
 NS_DEFINE_NAMED_CID(PEERCONNECTION_CID);
 
 static const mozilla::Module::CIDEntry kCIDs[] = {
   { &kPEERCONNECTION_CID, false, nullptr, sipcc::PeerConnectionImplConstructor },
+  { &kNS_STUN_UDP_SOCKET_FILTER_HANDLER_CID, false, nullptr, nsStunUDPSocketFilterHandlerConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kContracts[] = {
   { PEERCONNECTION_CONTRACTID, &kPEERCONNECTION_CID },
+  { NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID, &kNS_STUN_UDP_SOCKET_FILTER_HANDLER_CID },
   { nullptr }
 };
 
 static const mozilla::Module kModule = {
   mozilla::Module::kVersion,
   kCIDs,
   kContracts
 };
--- a/dom/network/interfaces/nsIUDPSocketChild.idl
+++ b/dom/network/interfaces/nsIUDPSocketChild.idl
@@ -17,16 +17,18 @@ union NetAddr;
 native NetAddr(mozilla::net::NetAddr);
 [ptr] native NetAddrPtr(mozilla::net::NetAddr);
 
 [scriptable, uuid(B47E5A0F-D384-48EF-8885-4259793D9CF0)]
 interface nsIUDPSocketChild : nsISupports
 {
   readonly attribute unsigned short localPort;
   readonly attribute AUTF8String localAddress;
+  attribute AUTF8String filterName;
+
   // Tell the chrome process to bind the UDP socket to a given local host and port
   void bind(in nsIUDPSocketInternal socket, in AUTF8String host, in unsigned short port);
 
   // Tell the chrome process to perform equivalent operations to all following methods
   void send(in AUTF8String host, in unsigned short port,
             [const, array, size_is(byteLength)] in uint8_t bytes,
             in unsigned long byteLength);
   // Send without DNS query
--- a/dom/network/src/UDPSocketChild.cpp
+++ b/dom/network/src/UDPSocketChild.cpp
@@ -62,17 +62,17 @@ UDPSocketChild::Bind(nsIUDPSocketInterna
                      const nsACString& aHost,
                      uint16_t aPort)
 {
   NS_ENSURE_ARG(aSocket);
 
   mSocket = aSocket;
   AddIPDLReference();
 
-  gNeckoChild->SendPUDPSocketConstructor(this, nsCString(aHost), aPort);
+  gNeckoChild->SendPUDPSocketConstructor(this, nsCString(aHost), aPort, mFilterName);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UDPSocketChild::Close()
 {
   SendClose();
@@ -144,16 +144,34 @@ UDPSocketChild::GetLocalPort(uint16_t *a
 
 NS_IMETHODIMP
 UDPSocketChild::GetLocalAddress(nsACString &aLocalAddress)
 {
   aLocalAddress = mLocalAddress;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+UDPSocketChild::SetFilterName(const nsACString &aFilterName)
+{
+  if (!mFilterName.IsEmpty()) {
+    // filter name can only be set once.
+    return NS_ERROR_FAILURE;
+  }
+  mFilterName = aFilterName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UDPSocketChild::GetFilterName(nsACString &aFilterName)
+{
+  aFilterName = mFilterName;
+  return NS_OK;
+}
+
 // PUDPSocketChild Methods
 bool
 UDPSocketChild::RecvCallback(const nsCString &aType,
                              const UDPCallbackData &aData,
                              const nsCString &aState)
 {
   if (NS_FAILED(mSocket->UpdateReadyState(aState)))
     NS_ERROR("Shouldn't fail!");
--- a/dom/network/src/UDPSocketChild.h
+++ b/dom/network/src/UDPSocketChild.h
@@ -41,14 +41,15 @@ public:
   virtual ~UDPSocketChild();
 
   virtual bool RecvCallback(const nsCString& aType,
                             const UDPCallbackData& aData,
                             const nsCString& aState) MOZ_OVERRIDE;
 private:
   uint16_t mLocalPort;
   nsCString mLocalAddress;
+  nsCString mFilterName;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // !defined(mozilla_dom_UDPSocketChild_h__)
--- a/dom/network/src/UDPSocketParent.cpp
+++ b/dom/network/src/UDPSocketParent.cpp
@@ -1,12 +1,15 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "nsIServiceManager.h"
 #include "UDPSocketParent.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIUDPSocket.h"
 #include "nsINetAddr.h"
 #include "mozilla/unused.h"
 #include "mozilla/net/DNS.h"
 
 namespace mozilla {
@@ -60,16 +63,17 @@ UDPSocketParent::~UDPSocketParent()
 }
 
 // PUDPSocketParent methods
 
 bool
 UDPSocketParent::Init(const nsCString &aHost, const uint16_t aPort)
 {
   nsresult rv;
+  NS_ASSERTION(mFilter, "No packet filter");
 
   nsCOMPtr<nsIUDPSocket> sock =
       do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
   if (NS_FAILED(rv)) {
     FireInternalError(this, __LINE__);
     return true;
   }
 
@@ -119,37 +123,56 @@ UDPSocketParent::Init(const nsCString &a
 }
 
 bool
 UDPSocketParent::RecvData(const InfallibleTArray<uint8_t> &aData,
                           const nsCString& aRemoteAddress,
                           const uint16_t& aPort)
 {
   NS_ENSURE_TRUE(mSocket, true);
+  NS_ASSERTION(mFilter, "No packet filter");
+  // TODO, Bug 933102, filter packets that are sent with hostname.
+  // Until then we simply throw away packets that are sent to a hostname.
+  return true;
+
+#if 0
+  // Enable this once we have filtering working with hostname delivery.
   uint32_t count;
   nsresult rv = mSocket->Send(aRemoteAddress,
                               aPort, aData.Elements(),
                               aData.Length(), &count);
   mozilla::unused <<
       PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
                                      UDPSendResult(rv),
                                      NS_LITERAL_CSTRING("connected"));
   NS_ENSURE_SUCCESS(rv, true);
   NS_ENSURE_TRUE(count > 0, true);
   return true;
+#endif
 }
 
 bool
 UDPSocketParent::RecvDataWithAddress(const InfallibleTArray<uint8_t>& aData,
                                      const mozilla::net::NetAddr& aAddr)
 {
   NS_ENSURE_TRUE(mSocket, true);
+  NS_ASSERTION(mFilter, "No packet filter");
+
   uint32_t count;
-  nsresult rv = mSocket->SendWithAddress(&aAddr, aData.Elements(),
-                                         aData.Length(), &count);
+  nsresult rv;
+  bool allowed;
+  rv = mFilter->FilterPacket(&aAddr, aData.Elements(),
+                             aData.Length(), nsIUDPSocketFilter::SF_OUTGOING,
+                             &allowed);
+  // Sending unallowed data, kill content.
+  NS_ENSURE_SUCCESS(rv, false);
+  NS_ENSURE_TRUE(allowed, false);
+
+  rv = mSocket->SendWithAddress(&aAddr, aData.Elements(),
+                                aData.Length(), &count);
   mozilla::unused <<
       PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
                                      UDPSendResult(rv),
                                      NS_LITERAL_CSTRING("connected"));
   NS_ENSURE_SUCCESS(rv, true);
   NS_ENSURE_TRUE(count > 0, true);
   return true;
 }
@@ -186,30 +209,42 @@ UDPSocketParent::ActorDestroy(ActorDestr
 
 NS_IMETHODIMP
 UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
 {
   // receiving packet from remote host, forward the message content to child process
   if (!mIPCOpen) {
     return NS_OK;
   }
+  NS_ASSERTION(mFilter, "No packet filter");
 
   uint16_t port;
   nsCString ip;
   nsCOMPtr<nsINetAddr> fromAddr;
   aMessage->GetFromAddr(getter_AddRefs(fromAddr));
   fromAddr->GetPort(&port);
   fromAddr->GetAddress(ip);
 
   nsCString data;
   aMessage->GetData(data);
 
   const char* buffer = data.get();
   uint32_t len = data.Length();
 
+  bool allowed;
+  mozilla::net::NetAddr addr;
+  fromAddr->GetNetAddr(&addr);
+  nsresult rv = mFilter->FilterPacket(&addr,
+                                      (const uint8_t*)buffer, len,
+                                      nsIUDPSocketFilter::SF_INCOMING,
+                                      &allowed);
+  // Receiving unallowed data, drop.
+  NS_ENSURE_SUCCESS(rv, NS_OK);
+  NS_ENSURE_TRUE(allowed, NS_OK);
+
   FallibleTArray<uint8_t> fallibleArray;
   if (!fallibleArray.InsertElementsAt(0, buffer, len)) {
     FireInternalError(this, __LINE__);
     return NS_ERROR_OUT_OF_MEMORY;
   }
   InfallibleTArray<uint8_t> infallibleArray;
   infallibleArray.SwapElements(fallibleArray);
 
--- a/dom/network/src/UDPSocketParent.h
+++ b/dom/network/src/UDPSocketParent.h
@@ -1,30 +1,36 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 mozilla_dom_UDPSocketParent_h__
 #define mozilla_dom_UDPSocketParent_h__
 
 #include "mozilla/net/PUDPSocketParent.h"
 #include "nsCOMPtr.h"
 #include "nsIUDPSocket.h"
+#include "nsIUDPSocketFilter.h"
 
 namespace mozilla {
 namespace dom {
 
 class UDPSocketParent : public mozilla::net::PUDPSocketParent
                       , public nsIUDPSocketListener
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIUDPSOCKETLISTENER
 
-  UDPSocketParent() : mIPCOpen(true) {}
+  UDPSocketParent(nsIUDPSocketFilter* filter) :
+    mIPCOpen(true),
+    mFilter(filter) {}
+
   virtual ~UDPSocketParent();
 
   bool Init(const nsCString& aHost, const uint16_t aPort);
 
   virtual bool RecvClose() MOZ_OVERRIDE;
   virtual bool RecvData(const InfallibleTArray<uint8_t>& aData,
                         const nsCString& aRemoteAddress,
                         const uint16_t& aPort) MOZ_OVERRIDE;
@@ -32,14 +38,15 @@ public:
                                     const mozilla::net::NetAddr& addr);
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
 
 private:
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   bool mIPCOpen;
   nsCOMPtr<nsIUDPSocket> mSocket;
+  nsCOMPtr<nsIUDPSocketFilter> mFilter;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // !defined(mozilla_dom_UDPSocketParent_h__)
deleted file mode 100644
--- a/dom/network/tests/unit_ipc/test_udpsocket_ipc.js
+++ /dev/null
@@ -1,9 +0,0 @@
-Components.utils.import("resource://gre/modules/Services.jsm");
-
-function run_test() {
-  Services.prefs.setBoolPref('media.peerconnection.ipc.enabled', true);
-  run_test_in_child("/udpsocket_child.js", function() {
-    Services.prefs.clearUserPref('media.peerconnection.ipc.enabled');
-    do_test_finished();
-  });
-}
deleted file mode 100644
--- a/dom/network/tests/unit_ipc/udpsocket_child.js
+++ /dev/null
@@ -1,164 +0,0 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-'use strict';
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-
-const SERVER_PORT = 12345;
-const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
-
-function UDPSocketInternalImpl() {
-}
-
-UDPSocketInternalImpl.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIUDPSocketInternal]),
-  callListenerError: function(type, message, filename, lineNumber, columnNumber) {
-    if (this.onerror) {
-      this.onerror();
-    } else {
-      do_throw('Received unexpected error: ' + message + ' at ' + filename +
-                ':' + lineNumber + ':' + columnNumber);
-    }
-  },
-  callListenerReceivedData: function(type, host, port, data, dataLength) {
-    do_print('*** recv data(' + dataLength + ')=' + data.join() + '\n');
-    if (this.ondata) {
-      try {
-        this.ondata(data, dataLength);
-      } catch(ex) {
-        if (ex === Cr.NS_ERROR_ABORT)
-          throw ex;
-        do_print('Caught exception: ' + ex + '\n' + ex.stack);
-        do_throw('test is broken; bad ondata handler; see above');
-      }
-    } else {
-      do_throw('Received ' + dataLength + ' bytes of unexpected data!');
-    }
-  },
-  callListenerVoid: function(type) {
-    switch (type) {
-    case 'onopen':
-      if (this.onopen) {
-        this.onopen();
-      }
-      break;
-    case 'onclose':
-      if (this.onclose) {
-        this.onclose();
-      }
-      break;
-    }
-  },
-  callListenerSent: function(type, value) {
-    if (value != Cr.NS_OK) {
-      do_throw('Previous send was failed with cause: ' + value);
-    }
-  },
-  updateReadyState: function(readyState) {
-    do_print('*** current state: ' + readyState + '\n');
-  },
-  onopen: function() {},
-  onclose: function() {},
-};
-
-function makeSuccessCase(name) {
-  return function() {
-    do_print('got expected: ' + name);
-    run_next_test();
-  };
-}
-
-function makeJointSuccess(names) {
-  let funcs = {}, successCount = 0;
-  names.forEach(function(name) {
-    funcs[name] = function() {
-      do_print('got excepted: ' + name);
-      if (++successCount === names.length)
-        run_next_test();
-    };
-  });
-  return funcs;
-}
-
-function makeExpectedData(expectedData, callback) {
-  return function(receivedData, receivedDataLength) {
-    if (receivedDataLength != expectedData.length) {
-      do_throw('Received data size mismatched, expected ' + expectedData.length +
-               ' but got ' + receivedDataLength);
-    }
-    for (let i = 0; i < receivedDataLength; i++) {
-      if (receivedData[i] != expectedData[i]) {
-        do_throw('Received mismatched data at position ' + i);
-      }
-    }
-    if (callback) {
-      callback();
-    } else {
-      run_next_test();
-    }
-  };
-}
-
-function makeFailureCase(name) {
-  return function() {
-    let argstr;
-    if (arguments.length) {
-      argstr = '(args: ' +
-        Array.map(arguments, function(x) {return x.data + ""; }).join(" ") + ')';
-    } else {
-      argstr = '(no arguments)';
-    }
-    do_throw('got unexpected: ' + name + ' ' + argstr);
-  };
-}
-
-function createSocketChild() {
-  return Cc['@mozilla.org/udp-socket-child;1']
-           .createInstance(Ci.nsIUDPSocketChild);
-}
-
-var UDPSocket = createSocketChild();
-var callback = new UDPSocketInternalImpl();
-
-function connectSock() {
-  UDPSocket.bind(callback, '127.0.0.1', SERVER_PORT);
-  callback.onopen = makeSuccessCase('open');
-}
-
-function sendData() {
-  UDPSocket.send('127.0.0.1', SERVER_PORT, DATA_ARRAY, DATA_ARRAY.length);
-  callback.ondata = makeExpectedData(DATA_ARRAY);
-}
-
-function clientClose() {
-  UDPSocket.close();
-  callback.ondata = makeFailureCase('data');
-  callback.onclose = makeSuccessCase('close');
-}
-
-function connectError() {
-  UDPSocket = createSocketChild();
-  UDPSocket.bind(callback, 'some non-IP string', SERVER_PORT);
-  callback.onerror = makeSuccessCase('error');
-  callback.onopen = makeFailureCase('open');
-}
-
-function cleanup() {
-  UDPSocket = null;
-  run_next_test();
-}
-
-add_test(connectSock);
-add_test(sendData);
-add_test(clientClose);
-add_test(connectError);
-add_test(cleanup);
-
-function run_test() {
-  run_next_test();
-}
--- a/dom/network/tests/unit_ipc/xpcshell.ini
+++ b/dom/network/tests/unit_ipc/xpcshell.ini
@@ -1,10 +1,7 @@
 [DEFAULT]
 head =
 tail =
-support-files =
-  udpsocket_child.js
 
 [test_tcpsocket_ipc.js]
 [test_tcpserversocket_ipc.js]
-[test_udpsocket_ipc.js]
 run-sequentially = Uses hardcoded port, bug 903830.
--- a/dom/system/gonk/AutoMounter.cpp
+++ b/dom/system/gonk/AutoMounter.cpp
@@ -258,16 +258,31 @@ public:
       return;
     }
     vol->SetSharingEnabled(aAllowSharing);
     DBG("Calling UpdateState due to volume %s shareing set to %d",
         vol->NameStr(), (int)aAllowSharing);
     UpdateState();
   }
 
+  void FormatVolume(const nsACString& aVolumeName)
+  {
+    RefPtr<Volume> vol = VolumeManager::FindVolumeByName(aVolumeName);
+    if (!vol) {
+      return;
+    }
+    if (vol->IsFormatRequested()) {
+      return;
+    }
+    vol->SetFormatRequested(true);
+    DBG("Calling UpdateState due to volume %s formatting set to %d",
+        vol->NameStr(), (int)vol->IsFormatRequested());
+    UpdateState();
+  }
+
 private:
 
   AutoVolumeEventObserver         mVolumeEventObserver;
   AutoVolumeManagerStateObserver  mVolumeManagerStateObserver;
   RefPtr<VolumeResponseCallback>  mResponseCallback;
   int32_t                         mMode;
 };
 
@@ -423,50 +438,54 @@ AutoMounter::UpdateState()
       LOG("UpdateState: Volume %s is %s and %s", vol->NameStr(), vol->StateStr(),
           vol->MediaPresent() ? "inserted" : "missing");
     }
     if (!vol->MediaPresent()) {
       // No media - nothing we can do
       continue;
     }
 
-    if (tryToShare && vol->IsSharingEnabled()) {
+    if ((tryToShare && vol->IsSharingEnabled()) || vol->IsFormatRequested()) {
       // We're going to try to unmount and share the volumes
       switch (volState) {
         case nsIVolume::STATE_MOUNTED: {
           if (vol->IsMountLocked()) {
             // The volume is currently locked, so leave it in the mounted
             // state.
-            LOGW("UpdateState: Mounted volume %s is locked, not sharing",
+            LOGW("UpdateState: Mounted volume %s is locked, not sharing or formatting",
                  vol->NameStr());
             break;
           }
 
           // Mark the volume as if we've started sharing. This will cause
           // apps which watch device storage notifications to see the volume
           // go into the shared state, and prompt them to close any open files
           // that they might have.
-          vol->SetIsSharing(true);
+          if (tryToShare && vol->IsSharingEnabled()) {
+            vol->SetIsSharing(true);
+          } else if (vol->IsFormatRequested()){
+            vol->SetIsFormatting(true);
+          }
 
           // Check to see if there are any open files on the volume and
           // don't initiate the unmount while there are open files.
           OpenFileFinder::Info fileInfo;
           OpenFileFinder fileFinder(vol->MountPoint());
           if (fileFinder.First(&fileInfo)) {
             LOGW("The following files are open under '%s'",
                  vol->MountPoint().get());
             do {
               LOGW("  PID: %d file: '%s' app: '%s' comm: '%s' exe: '%s'\n",
                    fileInfo.mPid,
                    fileInfo.mFileName.get(),
                    fileInfo.mAppName.get(),
                    fileInfo.mComm.get(),
                    fileInfo.mExe.get());
             } while (fileFinder.Next(&fileInfo));
-            LOGW("UpdateState: Mounted volume %s has open files, not sharing",
+            LOGW("UpdateState: Mounted volume %s has open files, not sharing or formatting",
                  vol->NameStr());
 
             // Check again in a few seconds to see if the files are closed.
             // Since we're trying to share the volume, this implies that we're
             // plugged into the PC via USB and this in turn implies that the
             // battery is charging, so we don't need to be too concerned about
             // wasting battery here.
             //
@@ -490,20 +509,33 @@ AutoMounter::UpdateState()
 
           // Volume is mounted, we need to unmount before
           // we can share.
           LOG("UpdateState: Unmounting %s", vol->NameStr());
           vol->StartUnmount(mResponseCallback);
           return; // UpdateState will be called again when the Unmount command completes
         }
         case nsIVolume::STATE_IDLE: {
-          // Volume is unmounted. We can go ahead and share.
-          LOG("UpdateState: Sharing %s", vol->NameStr());
-          vol->StartShare(mResponseCallback);
-          return; // UpdateState will be called again when the Share command completes
+          LOG("UpdateState: Volume %s is nsIVolume::STATE_IDLE", vol->NameStr());
+          if (vol->IsFormatting() && !vol->IsFormatRequested()) {
+            vol->SetFormatRequested(false);
+            LOG("UpdateState: Mounting %s", vol->NameStr());
+            vol->StartMount(mResponseCallback);
+            break;
+          }
+          if (tryToShare && vol->IsSharingEnabled()) {
+            // Volume is unmounted. We can go ahead and share.
+            LOG("UpdateState: Sharing %s", vol->NameStr());
+            vol->StartShare(mResponseCallback);
+          } else if (vol->IsFormatRequested()){
+            // Volume is unmounted. We can go ahead and format.
+            LOG("UpdateState: Formatting %s", vol->NameStr());
+            vol->StartFormat(mResponseCallback);
+          }
+          return; // UpdateState will be called again when the Share/Format command completes
         }
         default: {
           // Not in a state that we can do anything about.
           break;
         }
       }
     } else {
       // We're going to try and unshare and remount the volumes
@@ -574,16 +606,25 @@ SetAutoMounterSharingModeIOThread(const 
 {
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   MOZ_ASSERT(sAutoMounter);
 
   sAutoMounter->SetSharingMode(aVolumeName, aAllowSharing);
 }
 
 static void
+AutoMounterFormatVolumeIOThread(const nsCString& aVolumeName)
+{
+  MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
+  MOZ_ASSERT(sAutoMounter);
+
+  sAutoMounter->FormatVolume(aVolumeName);
+}
+
+static void
 UsbCableEventIOThread()
 {
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
 
   if (!sAutoMounter) {
     return;
   }
   DBG("Calling UpdateState due to USBCableEvent");
@@ -727,21 +768,30 @@ SetAutoMounterMode(int32_t aMode)
       NewRunnableFunction(SetAutoMounterModeIOThread, aMode));
 }
 
 void
 SetAutoMounterSharingMode(const nsCString& aVolumeName, bool aAllowSharing)
 {
   XRE_GetIOMessageLoop()->PostTask(
       FROM_HERE,
-      NewRunnableFunction(SetAutoMounterSharingModeIOThread, 
+      NewRunnableFunction(SetAutoMounterSharingModeIOThread,
                           aVolumeName, aAllowSharing));
 }
 
 void
+AutoMounterFormatVolume(const nsCString& aVolumeName)
+{
+  XRE_GetIOMessageLoop()->PostTask(
+      FROM_HERE,
+      NewRunnableFunction(AutoMounterFormatVolumeIOThread,
+                          aVolumeName));
+}
+
+void
 ShutdownAutoMounter()
 {
   sAutoMounterSetting = nullptr;
   sUsbCableObserver = nullptr;
 
   XRE_GetIOMessageLoop()->PostTask(
       FROM_HERE,
       NewRunnableFunction(ShutdownAutoMounterIOThread));
--- a/dom/system/gonk/AutoMounter.h
+++ b/dom/system/gonk/AutoMounter.h
@@ -55,16 +55,25 @@ GetAutoMounterStatus();
  * If a volume is enabled for sharing, and the autmounter
  * is in a state to share, then the volume will be shared
  * with the PC.
  */
 void
 SetAutoMounterSharingMode(const nsCString& aVolumeName, bool aAllowSharing);
 
 /**
+ * Formats the volume with specified volume name.
+ *
+ * If the volume is ready to format, automounter
+ * will unmount it, format it and then mount it again.
+ */
+void
+AutoMounterFormatVolume(const nsCString& aVolumeName);
+
+/**
  * Shuts down the automounter.
  *
  * This leaves the volumes in whatever state they're in.
  */
 void
 ShutdownAutoMounter();
 
 } // system
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -297,21 +297,22 @@ XPCOMUtils.defineLazyGetter(this, "gMess
         if (DEBUG) debug("Unregistered " + topic + " target: " + target);
       }
     },
 
     _enqueueTargetMessage: function _enqueueTargetMessage(topic, message, options) {
       let msg = { topic : topic,
                   message : message,
                   options : options };
-      // Remove previous queued message of same message type, only one message
-      // per message type is allowed in queue.
+      // Remove previous queued message with the same message type and client Id
+      // , only one message per (message type + client Id) is allowed in queue.
       let messageQueue = this.targetMessageQueue;
       for(let i = 0; i < messageQueue.length; i++) {
-        if (messageQueue[i].message === message) {
+        if (messageQueue[i].message === message &&
+            messageQueue[i].options.clientId === options.clientId) {
           messageQueue.splice(i, 1);
           break;
         }
       }
 
       messageQueue.push(msg);
     },
 
--- a/dom/system/gonk/Volume.cpp
+++ b/dom/system/gonk/Volume.cpp
@@ -55,17 +55,19 @@ static int32_t sMountGeneration = 0;
 Volume::Volume(const nsCSubstring& aName)
   : mMediaPresent(true),
     mState(nsIVolume::STATE_INIT),
     mName(aName),
     mMountGeneration(-1),
     mMountLocked(true),  // Needs to agree with nsVolume::nsVolume
     mSharingEnabled(false),
     mCanBeShared(true),
-    mIsSharing(false)
+    mIsSharing(false),
+    mFormatRequested(false),
+    mIsFormatting(false)
 {
   DBG("Volume %s: created", NameStr());
 }
 
 void
 Volume::SetIsSharing(bool aIsSharing)
 {
   if (aIsSharing == mIsSharing) {
@@ -75,16 +77,30 @@ Volume::SetIsSharing(bool aIsSharing)
   LOG("Volume %s: IsSharing set to %d state %s",
       NameStr(), (int)mIsSharing, StateStr(mState));
   if (mIsSharing) {
     mEventObserverList.Broadcast(this);
   }
 }
 
 void
+Volume::SetIsFormatting(bool aIsFormatting)
+{
+  if (aIsFormatting == mIsFormatting) {
+    return;
+  }
+  mIsFormatting = aIsFormatting;
+  LOG("Volume %s: IsFormatting set to %d state %s",
+      NameStr(), (int)mIsFormatting, StateStr(mState));
+  if (mIsFormatting) {
+    mEventObserverList.Broadcast(this);
+  }
+}
+
+void
 Volume::SetMediaPresent(bool aMediaPresent)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
 
   // mMediaPresent is slightly redunant to the state, however
   // when media is removed (while Idle), we get the following:
   //    631 Volume sdcard /mnt/sdcard disk removed (179:0)
@@ -122,21 +138,29 @@ Volume::SetSharingEnabled(bool aSharingE
 {
   mSharingEnabled = aSharingEnabled;
 
   LOG("SetSharingMode for volume %s to %d canBeShared = %d",
       NameStr(), (int)mSharingEnabled, (int)mCanBeShared);
 }
 
 void
+Volume::SetFormatRequested(bool aFormatRequested)
+{
+  mFormatRequested = aFormatRequested;
+
+  LOG("SetFormatRequested for volume %s to %d CanBeFormatted = %d",
+      NameStr(), (int)mFormatRequested, (int)CanBeFormatted());
+}
+
+void
 Volume::SetState(Volume::STATE aNewState)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
-
   if (aNewState == mState) {
     return;
   }
   if (aNewState == nsIVolume::STATE_MOUNTED) {
     mMountGeneration = ++sMountGeneration;
     LOG("Volume %s: changing state from %s to %s @ '%s' (%d observers) "
         "mountGeneration = %d, locked = %d",
         NameStr(), StateStr(mState),
@@ -151,17 +175,22 @@ Volume::SetState(Volume::STATE aNewState
   switch (aNewState) {
      case nsIVolume::STATE_NOMEDIA:
        // Cover the startup case where we don't get insertion/removal events
        mMediaPresent = false;
        mIsSharing = false;
        break;
 
      case nsIVolume::STATE_MOUNTED:
+       mIsFormatting = false;
+       mIsSharing = false;
+       break;
      case nsIVolume::STATE_FORMATTING:
+       mFormatRequested = false;
+       mIsFormatting = true;
        mIsSharing = false;
        break;
 
      case nsIVolume::STATE_SHARED:
      case nsIVolume::STATE_SHAREDMNT:
        // Covers startup cases. Normally, mIsSharing would be set to true
        // when we issue the command to initiate the sharing process, but
        // it's conceivable that a volume could already be in a shared state
@@ -203,16 +232,25 @@ Volume::StartUnmount(VolumeResponseCallb
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
 
   StartCommand(new VolumeActionCommand(this, "unmount", "force", aCallback));
 }
 
 void
+Volume::StartFormat(VolumeResponseCallback* aCallback)
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
+  MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
+
+  StartCommand(new VolumeActionCommand(this, "format", "", aCallback));
+}
+
+void
 Volume::StartShare(VolumeResponseCallback* aCallback)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
 
   StartCommand(new VolumeActionCommand(this, "share", "ums", aCallback));
 }
 
--- a/dom/system/gonk/Volume.h
+++ b/dom/system/gonk/Volume.h
@@ -41,20 +41,24 @@ public:
   // The mount point is the name of the directory where the volume is mounted.
   // (i.e. path that leads to the files stored on the volume).
   const nsCString& MountPoint() const { return mMountPoint; }
 
   int32_t MountGeneration() const     { return mMountGeneration; }
   bool IsMountLocked() const          { return mMountLocked; }
   bool MediaPresent() const           { return mMediaPresent; }
   bool CanBeShared() const            { return mCanBeShared; }
+  bool CanBeFormatted() const         { return CanBeShared(); }
   bool IsSharingEnabled() const       { return mCanBeShared && mSharingEnabled; }
+  bool IsFormatRequested() const      { return CanBeFormatted() && mFormatRequested; }
   bool IsSharing() const              { return mIsSharing; }
+  bool IsFormatting() const           { return mIsFormatting; }
 
   void SetSharingEnabled(bool aSharingEnabled);
+  void SetFormatRequested(bool aFormatRequested);
 
   typedef mozilla::Observer<Volume *>     EventObserver;
   typedef mozilla::ObserverList<Volume *> EventObserverList;
 
   // NOTE: that observers must live in the IOThread.
   static void RegisterObserver(EventObserver* aObserver);
   static void UnregisterObserver(EventObserver* aObserver);
 
@@ -64,20 +68,22 @@ private:
   friend class VolumeManager;       // Calls HandleVoldResponse
   friend class VolumeListCallback;  // Calls SetMountPoint, SetState
 
   // The StartXxx functions will queue up a command to the VolumeManager.
   // You can queue up as many commands as you like, and aCallback will
   // be called as each one completes.
   void StartMount(VolumeResponseCallback* aCallback);
   void StartUnmount(VolumeResponseCallback* aCallback);
+  void StartFormat(VolumeResponseCallback* aCallback);
   void StartShare(VolumeResponseCallback* aCallback);
   void StartUnshare(VolumeResponseCallback* aCallback);
 
   void SetIsSharing(bool aIsSharing);
+  void SetIsFormatting(bool aIsFormatting);
   void SetState(STATE aNewState);
   void SetMediaPresent(bool aMediaPresent);
   void SetMountPoint(const nsCSubstring& aMountPoint);
   void StartCommand(VolumeCommand* aCommand);
 
   void HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer);
 
   static void UpdateMountLock(const nsACString& aVolumeName,
@@ -86,18 +92,20 @@ private:
 
   bool              mMediaPresent;
   STATE             mState;
   const nsCString   mName;
   nsCString         mMountPoint;
   int32_t           mMountGeneration;
   bool              mMountLocked;
   bool              mSharingEnabled;
+  bool              mFormatRequested;
   bool              mCanBeShared;
   bool              mIsSharing;
+  bool              mIsFormatting;
 
   static EventObserverList mEventObserverList;
 };
 
 } // system
 } // mozilla
 
 #endif  // mozilla_system_volumemanager_h__
--- a/dom/system/gonk/VolumeServiceIOThread.h
+++ b/dom/system/gonk/VolumeServiceIOThread.h
@@ -32,13 +32,14 @@ private:
   virtual void Notify(const VolumeManager::StateChangedEvent& aEvent);
   virtual void Notify(Volume* const & aVolume);
 
   RefPtr<nsVolumeService>   mVolumeService;
 };
 
 void InitVolumeServiceIOThread(nsVolumeService* const & aVolumeService);
 void ShutdownVolumeServiceIOThread();
+void FormatVolume(const nsCString& aVolume);
 
 } // system
 } // mozilla
 
 #endif  // mozilla_system_volumeserviceiothread_h__
--- a/dom/system/gonk/nsIVolume.idl
+++ b/dom/system/gonk/nsIVolume.idl
@@ -1,16 +1,16 @@
 /* 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"
 #include "nsIVolumeStat.idl"
 
-[scriptable, uuid(e476e7ea-5cde-4d5a-b00d-d60daad76398)]
+[scriptable, uuid(8c163fe4-5577-11e3-b3d0-10bf48d707fb)]
 interface nsIVolume : nsISupports
 {
   // These MUST match the states from android's system/vold/Volume.h header
   const long STATE_INIT        = -1;
   const long STATE_NOMEDIA     = 0;
   const long STATE_IDLE        = 1;
   const long STATE_PENDING     = 2;
   const long STATE_CHECKING    = 3;
@@ -57,18 +57,27 @@ interface nsIVolume : nsISupports
   // Determines if the volume is currently being shared. This covers off
   // more than just state == STATE_SHARED. isSharing will return true from the
   // time that the volume leaves the mounted state, until it gets back to
   // mounted, nomedia, or formatting states. This attribute is to allow
   // device storage to suppress unwanted 'unavailable' status when
   // transitioning from mounted to sharing and back again.
   readonly attribute boolean isSharing;
 
+  // Determines if the volume is currently formatting. This sets true once 
+  // mFormatRequest == true and mState == STATE_MOUNTED, and sets false
+  // once the volume has been formatted and mounted again.
+  readonly attribute boolean isFormatting;
+
   nsIVolumeStat getStats();
 
+  // Formats the volume in IO thread, if the volume is ready to be formatted.
+  // Automounter will unmount it, format it and then mount it again.
+  void format();
+
   // Whether this is a fake volume.
   readonly attribute boolean isFake;
 };
 
 %{C++
 // For use with the ObserverService
 #define NS_VOLUME_STATE_CHANGED  "volume-state-changed"
 
--- a/dom/system/gonk/nsVolume.cpp
+++ b/dom/system/gonk/nsVolume.cpp
@@ -8,16 +8,18 @@
 #include "nsIPowerManagerService.h"
 #include "nsISupportsUtils.h"
 #include "nsIVolume.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsVolumeStat.h"
 #include "nsXULAppAPI.h"
 #include "Volume.h"
+#include "AutoMounter.h"
+#include "VolumeManager.h"
 
 #define VOLUME_MANAGER_LOG_TAG  "nsVolume"
 #include "VolumeManagerLog.h"
 
 namespace mozilla {
 namespace system {
 
 const char *
@@ -48,17 +50,18 @@ NS_IMPL_ISUPPORTS1(nsVolume, nsIVolume)
 nsVolume::nsVolume(const Volume* aVolume)
   : mName(NS_ConvertUTF8toUTF16(aVolume->Name())),
     mMountPoint(NS_ConvertUTF8toUTF16(aVolume->MountPoint())),
     mState(aVolume->State()),
     mMountGeneration(aVolume->MountGeneration()),
     mMountLocked(aVolume->IsMountLocked()),
     mIsFake(false),
     mIsMediaPresent(aVolume->MediaPresent()),
-    mIsSharing(aVolume->IsSharing())
+    mIsSharing(aVolume->IsSharing()),
+    mIsFormatting(aVolume->IsFormatting())
 {
 }
 
 bool nsVolume::Equals(nsIVolume* aVolume)
 {
   nsString volName;
   aVolume->GetName(volName);
   if (!mName.Equals(volName)) {
@@ -96,16 +99,22 @@ bool nsVolume::Equals(nsIVolume* aVolume
   }
 
   bool isSharing;
   aVolume->GetIsSharing(&isSharing);
   if (mIsSharing != isSharing) {
     return false;
   }
 
+  bool isFormatting;
+  aVolume->GetIsFormatting(&isFormatting);
+  if (mIsFormatting != isFormatting) {
+    return false;
+  }
+
   return true;
 }
 
 NS_IMETHODIMP nsVolume::GetIsMediaPresent(bool *aIsMediaPresent)
 {
   *aIsMediaPresent = mIsMediaPresent;
   return NS_OK;
 }
@@ -117,16 +126,22 @@ NS_IMETHODIMP nsVolume::GetIsMountLocked
 }
 
 NS_IMETHODIMP nsVolume::GetIsSharing(bool *aIsSharing)
 {
   *aIsSharing = mIsSharing;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsVolume::GetIsFormatting(bool *aIsFormatting)
+{
+  *aIsFormatting = mIsFormatting;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsVolume::GetName(nsAString& aName)
 {
   aName = mName;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsVolume::GetMountGeneration(int32_t* aMountGeneration)
 {
@@ -165,41 +180,63 @@ NS_IMETHODIMP nsVolume::GetStats(nsIVolu
 }
 
 NS_IMETHODIMP nsVolume::GetIsFake(bool *aIsFake)
 {
   *aIsFake = mIsFake;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsVolume::Format()
+{
+  XRE_GetIOMessageLoop()->PostTask(
+      FROM_HERE,
+      NewRunnableFunction(FormatVolumeIOThread, NameStr()));
+
+  return NS_OK;
+}
+
+/* static */
+void nsVolume::FormatVolumeIOThread(const nsCString& aVolume)
+{
+  MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
+  if (VolumeManager::State() != VolumeManager::VOLUMES_READY) {
+    return;
+  }
+
+  AutoMounterFormatVolume(aVolume);
+}
+
 void
 nsVolume::LogState() const
 {
   if (mState == nsIVolume::STATE_MOUNTED) {
     LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d "
-        "media %d sharing %d",
+        "media %d sharing %d formatting %d",
         NameStr().get(), StateStr(), MountPointStr().get(),
         MountGeneration(), (int)IsMountLocked(), (int)IsFake(),
-        (int)IsMediaPresent(), (int)IsSharing());
+        (int)IsMediaPresent(), (int)IsSharing(),
+        (int)IsFormatting());
     return;
   }
 
   LOG("nsVolume: %s state %s", NameStr().get(), StateStr());
 }
 
 void nsVolume::Set(nsIVolume* aVolume)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   aVolume->GetName(mName);
   aVolume->GetMountPoint(mMountPoint);
   aVolume->GetState(&mState);
   aVolume->GetIsFake(&mIsFake);
   aVolume->GetIsMediaPresent(&mIsMediaPresent);
   aVolume->GetIsSharing(&mIsSharing);
+  aVolume->GetIsFormatting(&mIsFormatting);
 
   int32_t volMountGeneration;
   aVolume->GetMountGeneration(&volMountGeneration);
 
   if (mState != nsIVolume::STATE_MOUNTED) {
     // Since we're not in the mounted state, we need to
     // forgot whatever mount generation we may have had.
     mMountGeneration = -1;
--- a/dom/system/gonk/nsVolume.h
+++ b/dom/system/gonk/nsVolume.h
@@ -32,30 +32,32 @@ public:
            const bool& aIsMediaPresent, const bool& aIsSharing)
     : mName(aName),
       mMountPoint(aMountPoint),
       mState(aState),
       mMountGeneration(aMountGeneration),
       mMountLocked(false),
       mIsFake(false),
       mIsMediaPresent(aIsMediaPresent),
-      mIsSharing(aIsSharing)
+      mIsSharing(aIsSharing),
+      mIsFormatting(false)
   {
   }
 
   // This constructor is used by nsVolumeService::FindAddVolumeByName, and
   // will be followed shortly by a Set call.
   nsVolume(const nsAString& aName)
     : mName(aName),
       mState(STATE_INIT),
       mMountGeneration(-1),
       mMountLocked(true),  // Needs to agree with Volume::Volume
       mIsFake(false),
       mIsMediaPresent(false),
-      mIsSharing(false)
+      mIsSharing(false),
+      mIsFormatting(false)
   {
   }
 
   bool Equals(nsIVolume* aVolume);
   void Set(nsIVolume* aVolume);
 
   void LogState() const;
 
@@ -69,35 +71,38 @@ public:
   nsCString MountPointStr() const     { return NS_LossyConvertUTF16toASCII(mMountPoint); }
 
   int32_t State() const               { return mState; }
   const char* StateStr() const        { return NS_VolumeStateStr(mState); }
 
   bool IsFake() const                 { return mIsFake; }
   bool IsMediaPresent() const         { return mIsMediaPresent; }
   bool IsSharing() const              { return mIsSharing; }
+  bool IsFormatting() const           { return mIsFormatting; }
 
   typedef nsTArray<nsRefPtr<nsVolume> > Array;
 
 private:
   ~nsVolume() {}
 
   friend class nsVolumeService; // Calls the following XxxMountLock functions
   void UpdateMountLock(const nsAString& aMountLockState);
   void UpdateMountLock(bool aMountLocked);
 
   void SetIsFake(bool aIsFake);
   void SetState(int32_t aState);
+  static void FormatVolumeIOThread(const nsCString& aVolume);
 
   nsString mName;
   nsString mMountPoint;
   int32_t  mState;
   int32_t  mMountGeneration;
   bool     mMountLocked;
   bool     mIsFake;
   bool     mIsMediaPresent;
   bool     mIsSharing;
+  bool     mIsFormatting;
 };
 
 } // system
 } // mozilla
 
 #endif  // mozilla_system_nsvolume_h__
--- a/dom/system/gonk/nsVolumeService.cpp
+++ b/dom/system/gonk/nsVolumeService.cpp
@@ -426,38 +426,40 @@ public:
   {
     MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
     DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d "
-        "media %d sharing %d",
+        "media %d sharing %d formatting %d",
         mVolume->NameStr().get(), mVolume->StateStr(),
         mVolume->MountGeneration(), (int)mVolume->IsMountLocked(),
-        (int)mVolume->IsMediaPresent(), mVolume->IsSharing());
+        (int)mVolume->IsMediaPresent(), mVolume->IsSharing(),
+        mVolume->IsFormatting());
 
     mVolumeService->UpdateVolume(mVolume);
     mVolumeService = nullptr;
     mVolume = nullptr;
     return NS_OK;
   }
 
 private:
   nsRefPtr<nsVolumeService> mVolumeService;
   nsRefPtr<nsVolume>        mVolume;
 };
 
 void
 nsVolumeService::UpdateVolumeIOThread(const Volume* aVolume)
 {
   DBG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s' gen %d locked %d "
-      "media %d sharing %d",
+      "media %d sharing %d formatting %d",
       aVolume->NameStr(), aVolume->StateStr(), aVolume->MountPoint().get(),
       aVolume->MountGeneration(), (int)aVolume->IsMountLocked(),
-      (int)aVolume->MediaPresent(), (int)aVolume->IsSharing());
+      (int)aVolume->MediaPresent(), (int)aVolume->IsSharing(),
+      (int)aVolume->IsFormatting());
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   NS_DispatchToMainThread(new UpdateVolumeRunnable(this, aVolume));
 }
 
 } // namespace system
 } // namespace mozilla
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -704,16 +704,17 @@ this.COMPREHENSIONTLV_TAG_ITEM = 0x0f;
 this.COMPREHENSIONTLV_TAG_ITEM_ID = 0x10;
 this.COMPREHENSIONTLV_TAG_RESPONSE_LENGTH = 0x11;
 this.COMPREHENSIONTLV_TAG_FILE_LIST = 0x12;
 this.COMPREHENSIONTLV_TAG_LOCATION_INFO = 0x13;
 this.COMPREHENSIONTLV_TAG_IMEI = 0x14;
 this.COMPREHENSIONTLV_TAG_HELP_REQUEST = 0x15;
 this.COMPREHENSIONTLV_TAG_NMR = 0x16;
 this.COMPREHENSIONTLV_TAG_DEFAULT_TEXT = 0x17;
+this.COMPREHENSIONTLV_TAG_NEXT_ACTION_IND = 0x18;
 this.COMPREHENSIONTLV_TAG_CAUSE = 0x1a;
 this.COMPREHENSIONTLV_TAG_LOCATION_STATUS = 0x1b;
 this.COMPREHENSIONTLV_TAG_TRANSACTION_ID = 0x1c;
 this.COMPREHENSIONTLV_TAG_EVENT_LIST = 0x19;
 this.COMPREHENSIONTLV_TAG_ICON_ID = 0x1e;
 this.COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f;
 this.COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER = 0x24;
 this.COMPREHENSIONTLV_TAG_TIMER_VALUE = 0x25;
@@ -754,29 +755,29 @@ this.STK_CMD_POLL_INTERVAL = 0x03;
 this.STK_CMD_POLL_OFF = 0x04;
 this.STK_CMD_SET_UP_EVENT_LIST = 0x05;
 this.STK_CMD_SET_UP_CALL = 0x10;
 this.STK_CMD_SEND_SS = 0x11;
 this.STK_CMD_SEND_USSD = 0x12;
 this.STK_CMD_SEND_SMS = 0x13;
 this.STK_CMD_SEND_DTMF = 0x14;
 this.STK_CMD_LAUNCH_BROWSER = 0x15;
-this.STK_CMD_OPEN_CHANNEL = 0x16;
-this.STK_CMD_CLOSE_CHANNEL = 0x17;
-this.STK_CMD_RECEIVE_DATA = 0x18;
-this.STK_CMD_SEND_DATA = 0x19;
 this.STK_CMD_PLAY_TONE = 0x20;
 this.STK_CMD_DISPLAY_TEXT = 0x21;
 this.STK_CMD_GET_INKEY = 0x22;
 this.STK_CMD_GET_INPUT = 0x23;
 this.STK_CMD_SELECT_ITEM = 0x24;
 this.STK_CMD_SET_UP_MENU = 0x25;
 this.STK_CMD_PROVIDE_LOCAL_INFO = 0x26;
 this.STK_CMD_TIMER_MANAGEMENT = 0x27;
 this.STK_CMD_SET_UP_IDLE_MODE_TEXT = 0x28;
+this.STK_CMD_OPEN_CHANNEL = 0x40;
+this.STK_CMD_CLOSE_CHANNEL = 0x41;
+this.STK_CMD_RECEIVE_DATA = 0x42;
+this.STK_CMD_SEND_DATA = 0x43;
 
 // STK Result code.
 // TS 11.14, clause 12.12
 
 // Results '0X' and '1X' indicate that the command has been performed.
 
 // Command performed successfully.
 this.STK_RESULT_OK = 0x00;
@@ -977,16 +978,20 @@ this.STK_LOCAL_INFO_NMR_FOR_MULTIPLE_ACC
 this.STK_TIMER_START = 0x00;
 this.STK_TIMER_DEACTIVATE = 0x01;
 this.STK_TMIER_GET_CURRENT_VALUE = 0x02;
 
 // Browser Termination Cause.
 this.STK_BROWSER_TERMINATION_CAUSE_USER = 0x00;
 this.STK_BROWSER_TERMINATION_CAUSE_ERROR = 0x01;
 
+// Next Action Indicator.
+this.STK_NEXT_ACTION_NULL = 0x00;
+this.STK_NEXT_ACTION_END_PROACTIVE_SESSION = 0x81;
+
 /**
  * Supported Terminal Facilities.
  *
  * value = 1, supported.
  *         0, not supported.
  */
 this.STK_TERMINAL_SUPPORT_PROFILE_DOWNLOAD             = 1;
 this.STK_TERMINAL_SUPPORT_SMS_PP_DOWNLOAD              = 1;
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -9724,16 +9724,21 @@ let StkCommandParamsFactory = {
     // The 1st bit and 2nd bit determines the presentation type.
     menu.presentationType = cmdDetails.commandQualifier & 0x03;
 
     // Help information available.
     if (cmdDetails.commandQualifier & 0x80) {
       menu.isHelpAvailable = true;
     }
 
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_NEXT_ACTION_IND, ctlvs);
+    if (ctlv) {
+      menu.nextActionList = ctlv.value;
+    }
+
     return menu;
   },
 
   processDisplayText: function processDisplayText(cmdDetails, ctlvs) {
     let textMsg = {};
 
     let ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_TEXT_STRING, ctlvs);
     if (!ctlv) {
@@ -10414,16 +10419,33 @@ let StkProactiveCmdHelper = {
   retrieveUrl: function retrieveUrl(length) {
     let s = "";
     for (let i = 0; i < length; i++) {
       s += String.fromCharCode(GsmPDUHelper.readHexOctet());
     }
     return {url: s};
   },
 
+  /**
+   * Next Action Indicator List.
+   *
+   * | Byte  | Description      | Length |
+   * |  1    | Next Action tag  |   1    |
+   * |  1    | Length(X)        |   1    |
+   * |  3~   | Next Action List |   X    |
+   * | 3+X-1 |                  |        |
+   */
+  retrieveNextActionList: function retrieveNextActionList(length) {
+    let nextActionList = [];
+    for (let i = 0; i < length; i++) {
+      nextActionList.push(GsmPDUHelper.readHexOctet());
+    }
+    return nextActionList;
+  },
+
   searchForTag: function searchForTag(tag, ctlvs) {
     let iter = Iterator(ctlvs);
     return this.searchForNextTag(tag, iter);
   },
 
   searchForNextTag: function searchForNextTag(tag, iter) {
     for (let [index, ctlv] in iter) {
       if ((ctlv.tag & ~COMPREHENSIONTLV_FLAG_CR) == tag) {
@@ -10479,16 +10501,19 @@ StkProactiveCmdHelper[COMPREHENSIONTLV_T
   return this.retrieveTimerValue(length);
 };
 StkProactiveCmdHelper[COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE] = function COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE(length) {
   return this.retrieveImmediaResponse(length);
 };
 StkProactiveCmdHelper[COMPREHENSIONTLV_TAG_URL] = function COMPREHENSIONTLV_TAG_URL(length) {
   return this.retrieveUrl(length);
 };
+StkProactiveCmdHelper[COMPREHENSIONTLV_TAG_NEXT_ACTION_IND] = function COMPREHENSIONTLV_TAG_NEXT_ACTION_IND(length) {
+  return this.retrieveNextActionList(length);
+};
 
 let ComprehensionTlvHelper = {
   /**
    * Decode raw data to a Comprehension-TLV.
    */
   decode: function decode() {
     let hlen = 0; // For header(tag field + length field) length.
     let temp = GsmPDUHelper.readHexOctet();
--- a/dom/system/gonk/tests/test_ril_worker_stk.js
+++ b/dom/system/gonk/tests/test_ril_worker_stk.js
@@ -653,16 +653,186 @@ add_test(function test_stk_proactive_com
   do_check_eq(tlv.value.commandNumber, 0x01);
   do_check_eq(tlv.value.typeOfCommand, STK_CMD_MORE_TIME);
   do_check_eq(tlv.value.commandQualifier, 0x00);
 
   run_next_test();
 });
 
 /**
+ * Verify Proactive Command : Select Item
+ */
+add_test(function test_stk_proactive_command_select_item() {
+  let worker = newUint8Worker();
+  let pduHelper = worker.GsmPDUHelper;
+  let berHelper = worker.BerTlvHelper;
+  let stkHelper = worker.StkProactiveCmdHelper;
+  let stkFactory = worker.StkCommandParamsFactory;
+
+  let select_item_1 = [
+    0xD0,
+    0x33,
+    0x81, 0x03, 0x01, 0x24, 0x00,
+    0x82, 0x02, 0x81, 0x82,
+    0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65,
+    0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31,
+    0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32,
+    0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33,
+    0x18, 0x03, 0x10, 0x15, 0x20,
+    0x90, 0x01, 0x01
+  ];
+
+  for(let i = 0 ; i < select_item_1.length; i++) {
+    pduHelper.writeHexOctet(select_item_1[i]);
+  }
+
+  let berTlv = berHelper.decode(select_item_1.length);
+  let ctlvs = berTlv.value;
+  let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
+  do_check_eq(tlv.value.commandNumber, 0x01);
+  do_check_eq(tlv.value.typeOfCommand, STK_CMD_SELECT_ITEM);
+  do_check_eq(tlv.value.commandQualifier, 0x00);
+
+  let menu = stkFactory.createParam(tlv.value, ctlvs);
+  do_check_eq(menu.title, "Title");
+  do_check_eq(menu.items[0].identifier, 1);
+  do_check_eq(menu.items[0].text, "item 1");
+  do_check_eq(menu.items[1].identifier, 2);
+  do_check_eq(menu.items[1].text, "item 2");
+  do_check_eq(menu.items[2].identifier, 3);
+  do_check_eq(menu.items[2].text, "item 3");
+  do_check_eq(menu.nextActionList[0], STK_CMD_SET_UP_CALL);
+  do_check_eq(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER);
+  do_check_eq(menu.nextActionList[2], STK_CMD_PLAY_TONE);
+  do_check_eq(menu.defaultItem, 0x00);
+
+  let select_item_2 = [
+    0xD0,
+    0x33,
+    0x81, 0x03, 0x01, 0x24, 0x00,
+    0x82, 0x02, 0x81, 0x82,
+    0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65,
+    0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31,
+    0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32,
+    0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33,
+    0x18, 0x03, 0x00, 0x15, 0x81,
+    0x90, 0x01, 0x03
+  ];
+
+  for(let i = 0 ; i < select_item_2.length; i++) {
+    pduHelper.writeHexOctet(select_item_2[i]);
+  }
+
+  berTlv = berHelper.decode(select_item_2.length);
+  ctlvs = berTlv.value;
+  tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
+  do_check_eq(tlv.value.commandNumber, 0x01);
+  do_check_eq(tlv.value.typeOfCommand, STK_CMD_SELECT_ITEM);
+  do_check_eq(tlv.value.commandQualifier, 0x00);
+
+  menu = stkFactory.createParam(tlv.value, ctlvs);
+  do_check_eq(menu.title, "Title");
+  do_check_eq(menu.items[0].identifier, 1);
+  do_check_eq(menu.items[0].text, "item 1");
+  do_check_eq(menu.items[1].identifier, 2);
+  do_check_eq(menu.items[1].text, "item 2");
+  do_check_eq(menu.items[2].identifier, 3);
+  do_check_eq(menu.items[2].text, "item 3");
+  do_check_eq(menu.nextActionList[0], STK_NEXT_ACTION_NULL);
+  do_check_eq(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER);
+  do_check_eq(menu.nextActionList[2], STK_NEXT_ACTION_END_PROACTIVE_SESSION);
+  do_check_eq(menu.defaultItem, 0x02);
+
+  run_next_test();
+});
+
+/**
+ * Verify Proactive Command : Set Up Menu
+ */
+add_test(function test_stk_proactive_command_set_up_menu() {
+  let worker = newUint8Worker();
+  let pduHelper = worker.GsmPDUHelper;
+  let berHelper = worker.BerTlvHelper;
+  let stkHelper = worker.StkProactiveCmdHelper;
+  let stkFactory = worker.StkCommandParamsFactory;
+
+  let set_up_menu_1 = [
+    0xD0,
+    0x30,
+    0x81, 0x03, 0x01, 0x25, 0x00,
+    0x82, 0x02, 0x81, 0x82,
+    0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65,
+    0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31,
+    0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32,
+    0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33,
+    0x18, 0x03, 0x10, 0x15, 0x20
+  ];
+
+  for(let i = 0 ; i < set_up_menu_1.length; i++) {
+    pduHelper.writeHexOctet(set_up_menu_1[i]);
+  }
+
+  let berTlv = berHelper.decode(set_up_menu_1.length);
+  let ctlvs = berTlv.value;
+  let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
+  do_check_eq(tlv.value.commandNumber, 0x01);
+  do_check_eq(tlv.value.typeOfCommand, STK_CMD_SET_UP_MENU);
+  do_check_eq(tlv.value.commandQualifier, 0x00);
+
+  let menu = stkFactory.createParam(tlv.value, ctlvs);
+  do_check_eq(menu.title, "Title");
+  do_check_eq(menu.items[0].identifier, 1);
+  do_check_eq(menu.items[0].text, "item 1");
+  do_check_eq(menu.items[1].identifier, 2);
+  do_check_eq(menu.items[1].text, "item 2");
+  do_check_eq(menu.items[2].identifier, 3);
+  do_check_eq(menu.items[2].text, "item 3");
+  do_check_eq(menu.nextActionList[0], STK_CMD_SET_UP_CALL);
+  do_check_eq(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER);
+  do_check_eq(menu.nextActionList[2], STK_CMD_PLAY_TONE);
+
+  let set_up_menu_2 = [
+    0xD0,
+    0x30,
+    0x81, 0x03, 0x01, 0x25, 0x00,
+    0x82, 0x02, 0x81, 0x82,
+    0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65,
+    0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31,
+    0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32,
+    0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33,
+    0x18, 0x03, 0x81, 0x00, 0x00
+  ];
+
+  for(let i = 0 ; i < set_up_menu_2.length; i++) {
+    pduHelper.writeHexOctet(set_up_menu_2[i]);
+  }
+
+  berTlv = berHelper.decode(set_up_menu_2.length);
+  ctlvs = berTlv.value;
+  tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
+  do_check_eq(tlv.value.commandNumber, 0x01);
+  do_check_eq(tlv.value.typeOfCommand, STK_CMD_SET_UP_MENU);
+  do_check_eq(tlv.value.commandQualifier, 0x00);
+
+  let menu = stkFactory.createParam(tlv.value, ctlvs);
+  do_check_eq(menu.title, "Title");
+  do_check_eq(menu.items[0].identifier, 1);
+  do_check_eq(menu.items[0].text, "item 1");
+  do_check_eq(menu.items[1].identifier, 2);
+  do_check_eq(menu.items[1].text, "item 2");
+  do_check_eq(menu.items[2].identifier, 3);
+  do_check_eq(menu.items[2].text, "item 3");
+  do_check_eq(menu.nextActionList[0], STK_NEXT_ACTION_END_PROACTIVE_SESSION);
+  do_check_eq(menu.nextActionList[1], STK_NEXT_ACTION_NULL);
+  do_check_eq(menu.nextActionList[2], STK_NEXT_ACTION_NULL);
+
+  run_next_test();
+});
+
+/**
  * Verify Proactive Command : Set Up Call
  */
 add_test(function test_stk_proactive_command_set_up_call() {
   let worker = newUint8Worker();
   let pduHelper = worker.GsmPDUHelper;
   let berHelper = worker.BerTlvHelper;
   let stkHelper = worker.StkProactiveCmdHelper;
   let cmdFactory = worker.StkCommandParamsFactory;
@@ -812,17 +982,17 @@ add_test(function test_stk_proactive_com
   let pduHelper = worker.GsmPDUHelper;
   let berHelper = worker.BerTlvHelper;
   let stkHelper = worker.StkProactiveCmdHelper;
 
   // Open Channel
   let open_channel = [
     0xD0,
     0x0F,
-    0x81, 0x03, 0x01, 0x16, 0x00,
+    0x81, 0x03, 0x01, 0x40, 0x00,
     0x82, 0x02, 0x81, 0x82,
     0x85, 0x04, 0x4F, 0x70, 0x65, 0x6E //alpha id: "Open"
   ];
 
   for (let i = 0; i < open_channel.length; i++) {
     pduHelper.writeHexOctet(open_channel[i]);
   }
 
@@ -835,17 +1005,17 @@ add_test(function test_stk_proactive_com
 
   tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
   do_check_eq(tlv.value.identifier, "Open");
 
   // Close Channel
   let close_channel = [
     0xD0,
     0x10,
-    0x81, 0x03, 0x01, 0x17, 0x00,
+    0x81, 0x03, 0x01, 0x41, 0x00,
     0x82, 0x02, 0x81, 0x82,
     0x85, 0x05, 0x43, 0x6C, 0x6F, 0x73, 0x65 //alpha id: "Close"
   ];
 
   for (let i = 0; i < close_channel.length; i++) {
     pduHelper.writeHexOctet(close_channel[i]);
   }
 
@@ -858,17 +1028,17 @@ add_test(function test_stk_proactive_com
 
   tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
   do_check_eq(tlv.value.identifier, "Close");
 
   // Receive Data
   let receive_data = [
     0XD0,
     0X12,
-    0x81, 0x03, 0x01, 0x18, 0x00,
+    0x81, 0x03, 0x01, 0x42, 0x00,
     0x82, 0x02, 0x81, 0x82,
     0x85, 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65 //alpha id: "Receive"
   ];
 
   for (let i = 0; i < receive_data.length; i++) {
     pduHelper.writeHexOctet(receive_data[i]);
   }
 
@@ -881,17 +1051,17 @@ add_test(function test_stk_proactive_com
 
   tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
   do_check_eq(tlv.value.identifier, "Receive");
 
   // Send Data
   let send_data = [
     0xD0,
     0x0F,
-    0x81, 0x03, 0x01, 0x19, 0x00,
+    0x81, 0x03, 0x01, 0x43, 0x00,
     0x82, 0x02, 0x81, 0x82,
     0x85, 0x04, 0x53, 0x65, 0x6E, 0x64 //alpha id: "Send"
   ];
 
   for (let i = 0; i < send_data.length; i++) {
     pduHelper.writeHexOctet(send_data[i]);
   }
 
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -129,16 +129,17 @@ var interfaceNamesInGlobalScope =
     "BatteryManager",
     "BeforeUnloadEvent",
     "BiquadFilterNode",
     "Blob",
     "BlobEvent",
     {name: "BluetoothAdapter", b2g: true},
     {name: "BluetoothDevice", b2g: true},
     {name: "BluetoothDeviceEvent", b2g: true},
+    {name: "BluetoothDiscoveryStateChangedEvent", b2g: true},
     {name: "BluetoothManager", b2g: true},
     {name: "BluetoothStatusChangedEvent", b2g: true},
     {name: "BoxObject", xbl: true},
     {name: "BrowserFeedWriter", desktop: true},
     {name: "CallEvent", b2g: true, pref: "dom.telephony.enabled"},
     {name: "CallGroupErrorEvent", b2g: true, pref: "dom.telephony.enabled"},
     "CameraCapabilities",
     "CameraControl",
--- a/dom/webidl/BluetoothAdapter.webidl
+++ b/dom/webidl/BluetoothAdapter.webidl
@@ -44,16 +44,17 @@ interface BluetoothAdapter : EventTarget
   [GetterThrows]
   readonly attribute any            devices;
 
   // array of type DOMString[]
   [GetterThrows]
   readonly attribute any            uuids;
 
            attribute EventHandler   ondevicefound;
+           attribute EventHandler   ondiscoverystatechanged;
 
   // Fired when pairing process is completed
            attribute EventHandler   onpairedstatuschanged;
 
   // Fired when a2dp connection status changed
            attribute EventHandler   ona2dpstatuschanged;
 
   // Fired when handsfree connection status changed
new file mode 100644
--- /dev/null
+++ b/dom/webidl/BluetoothDiscoveryStateChangedEvent.webidl
@@ -0,0 +1,16 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+[Constructor(DOMString type, optional BluetoothDiscoveryStateChangedEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
+interface BluetoothDiscoveryStateChangedEvent : Event
+{
+  readonly attribute boolean discovering;
+};
+
+dictionary BluetoothDiscoveryStateChangedEventInit : EventInit
+{
+  boolean discovering = false;
+};
--- a/dom/webidl/DeviceStorage.webidl
+++ b/dom/webidl/DeviceStorage.webidl
@@ -34,16 +34,18 @@ interface DeviceStorage : EventTarget {
                               optional DeviceStorageEnumerationParameters options);
 
   [Throws]
   DOMRequest freeSpace();
   [Throws]
   DOMRequest usedSpace();
   [Throws]
   DOMRequest available();
+  [Throws]
+  DOMRequest format();
 
   // Note that the storageName is just a name (like sdcard), and doesn't
   // include any path information.
   readonly attribute DOMString storageName;
 
   // Determines if this storage area is the one which will be used by default
   // for storing new files.
   readonly attribute boolean default;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -498,16 +498,17 @@ WEBIDL_FILES += [
     'StyleSheetChangeEvent.webidl',
 ]
 
 if CONFIG['MOZ_B2G_BT']:
     WEBIDL_FILES += [
         'BluetoothAdapter.webidl',
         'BluetoothDevice.webidl',
         'BluetoothDeviceEvent.webidl',
+        'BluetoothDiscoveryStateChangedEvent.webidl',
         'BluetoothManager.webidl',
         'BluetoothStatusChangedEvent.webidl',
     ]
 
 if CONFIG['MOZ_B2G_RIL']:
     WEBIDL_FILES += [
         'CFStateChangeEvent.webidl',
         'DataErrorEvent.webidl',
--- a/js/xpconnect/src/event_impl_gen.conf.in
+++ b/js/xpconnect/src/event_impl_gen.conf.in
@@ -25,16 +25,17 @@ simple_events = [
     'StyleSheetApplicableStateChangeEvent',
 #ifdef MOZ_WIDGET_GONK
     'MozWifiStatusChangeEvent',
     'MozWifiConnectionInfoEvent',
 #endif
 #ifdef MOZ_B2G_BT
     'BluetoothDeviceEvent',
     'BluetoothStatusChangedEvent',
+    'BluetoothDiscoveryStateChangedEvent',
 #endif
 #ifdef MOZ_B2G_RIL
     'CFStateChangeEvent',
     'DataErrorEvent',
     'MozEmergencyCbModeEvent',
     'MozOtaStatusEvent',
     'MozCellBroadcastEvent',
     'MozVoicemailEvent',
--- a/media/mtransport/build/moz.build
+++ b/media/mtransport/build/moz.build
@@ -10,16 +10,17 @@ EXPORTS.mtransport += [
     '../nricectx.h',
     '../nricemediastream.h',
     '../nriceresolverfake.h',
     '../rlogringbuffer.h',
     '../runnable_utils.h',
     '../runnable_utils_generated.h',
     '../sigslot.h',
     '../simpletokenbucket.h',
+    '../stun_udp_socket_filter.h',
     '../transportflow.h',
     '../transportlayer.h',
     '../transportlayerdtls.h',
     '../transportlayerice.h',
     '../transportlayerlog.h',
     '../transportlayerloopback.h',
     '../transportlayerprsock.h',
 ]
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -891,16 +891,18 @@ void NrSocketIpc::create_m(const nsACStr
 
   nsresult rv;
   socket_child_ = do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv);
   if (NS_FAILED(rv)) {
     err_ = true;
     MOZ_ASSERT(false, "Failed to create UDPSocketChild");
   }
 
+  socket_child_->SetFilterName(nsCString("stun"));
+
   if (NS_FAILED(socket_child_->Bind(this, host, port))) {
     err_ = true;
     MOZ_ASSERT(false, "Failed to create UDP socket");
   }
 }
 
 void NrSocketIpc::sendto_m(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf) {
   ASSERT_ON_THREAD(main_thread_);
--- a/media/mtransport/objs.mozbuild
+++ b/media/mtransport/objs.mozbuild
@@ -10,16 +10,17 @@ mtransport_lcppsrcs = [
     'nr_timer.cpp',
     'nricectx.cpp',
     'nricemediastream.cpp',
     'nriceresolver.cpp',
     'nriceresolverfake.cpp',
     'nrinterfaceprioritizer.cpp',
     'rlogringbuffer.cpp',
     'simpletokenbucket.cpp',
+    'stun_udp_socket_filter.cpp',
     'transportflow.cpp',
     'transportlayer.cpp',
     'transportlayerdtls.cpp',
     'transportlayerice.cpp',
     'transportlayerlog.cpp',
     'transportlayerloopback.cpp',
     'transportlayerprsock.cpp',
 ]
new file mode 100644
--- /dev/null
+++ b/media/mtransport/stun_udp_socket_filter.cpp
@@ -0,0 +1,207 @@
+/* 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 <string>
+#include <set>
+
+extern "C" {
+#include "nr_api.h"
+#include "transport_addr.h"
+#include "stun.h"
+}
+
+#include "mozilla/net/DNS.h"
+#include "stun_udp_socket_filter.h"
+#include "nr_socket_prsock.h"
+
+namespace {
+
+class NetAddressAdapter {
+ public:
+  NetAddressAdapter(const mozilla::net::NetAddr& netaddr)
+    : addr_(ntohl(netaddr.inet.ip)),
+      port_(ntohs(netaddr.inet.port)) {
+    MOZ_ASSERT(netaddr.raw.family == AF_INET);
+  }
+
+  bool operator<(const NetAddressAdapter& rhs) const {
+    return addr_ != rhs.addr_ ? (addr_ < rhs.addr_) : (port_ < rhs.port_);
+  }
+
+  bool operator!=(const NetAddressAdapter& rhs) const {
+    return (*this < rhs) || (rhs < *this);
+  }
+
+ private:
+  const uint32_t addr_;
+  const uint16_t port_;
+};
+
+class PendingSTUNRequest {
+ public:
+  PendingSTUNRequest(const NetAddressAdapter& netaddr, const UINT12 &id)
+    : id_(id),
+      net_addr_(netaddr),
+      is_id_set_(true) {}
+
+  PendingSTUNRequest(const NetAddressAdapter& netaddr)
+    : id_(),
+      net_addr_(netaddr),
+      is_id_set_(false) {}
+
+  bool operator<(const PendingSTUNRequest& rhs) const {
+    if (net_addr_ != rhs.net_addr_) {
+      return net_addr_ < rhs.net_addr_;
+    }
+
+    if (!is_id_set_ && !rhs.is_id_set_) {
+      // PendingSTUNRequest can be stored to set only when it has id,
+      // so comparing two PendingSTUNRequst without id is not going
+      // to happen.
+      MOZ_CRASH();
+    }
+
+    if (!(is_id_set_ && rhs.is_id_set_)) {
+      // one of operands doesn't have id, ignore the difference.
+      return false;
+    }
+
+    return memcmp(id_.octet, rhs.id_.octet, sizeof(id_.octet)) < 0;
+  }
+
+ private:
+  const UINT12 id_;
+  const NetAddressAdapter net_addr_;
+  const bool is_id_set_;
+};
+
+class STUNUDPSocketFilter : public nsIUDPSocketFilter {
+ public:
+  STUNUDPSocketFilter()
+    : white_list_(),
+      pending_requests_() {}
+
+  virtual ~STUNUDPSocketFilter() {}
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIUDPSOCKETFILTER
+
+ private:
+  bool filter_incoming_packet(const mozilla::net::NetAddr *remote_addr,
+                              const uint8_t *data,
+                              uint32_t len);
+
+  bool filter_outgoing_packet(const mozilla::net::NetAddr *remote_addr,
+                              const uint8_t *data,
+                              uint32_t len);
+
+  std::set<NetAddressAdapter> white_list_;
+  std::set<PendingSTUNRequest> pending_requests_;
+  std::set<PendingSTUNRequest> response_allowed_;
+};
+
+NS_IMPL_ISUPPORTS1(STUNUDPSocketFilter, nsIUDPSocketFilter)
+
+NS_IMETHODIMP
+STUNUDPSocketFilter::FilterPacket(const mozilla::net::NetAddr *remote_addr,
+                                  const uint8_t *data,
+                                  uint32_t len,
+                                  int32_t direction,
+                                  bool *result) {
+  // Allowing IPv4 address only.
+  if (remote_addr->raw.family != AF_INET) {
+    *result = false;
+    return NS_OK;
+  }
+
+  switch (direction) {
+    case nsIUDPSocketFilter::SF_INCOMING:
+      *result = filter_incoming_packet(remote_addr, data, len);
+      break;
+    case nsIUDPSocketFilter::SF_OUTGOING:
+      *result = filter_outgoing_packet(remote_addr, data, len);
+      break;
+    default:
+      MOZ_CRASH("Unknown packet direction");
+  }
+  return NS_OK;
+}
+
+bool STUNUDPSocketFilter::filter_incoming_packet(const mozilla::net::NetAddr *remote_addr,
+                                                 const uint8_t *data, uint32_t len) {
+  // Check white list
+  if (white_list_.find(*remote_addr) != white_list_.end()) {
+    return true;
+  }
+
+  // Check if we had sent any stun request to this destination. If we had sent a request
+  // to this host, we check the transaction id, and we can add this address to whitelist.
+  std::set<PendingSTUNRequest>::iterator it =
+    pending_requests_.find(PendingSTUNRequest(*remote_addr));
+  if (it != pending_requests_.end()) {
+    if (nr_is_stun_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
+      const nr_stun_message_header *msg = reinterpret_cast<const nr_stun_message_header*>(data);
+      // If it is a STUN response message and we can match its id with one of the pending
+      // requests, we can add this address into whitelist.
+      if (nr_is_stun_response_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
+        PendingSTUNRequest pending_req(*remote_addr, msg->id);
+        std::set<PendingSTUNRequest>::iterator it = pending_requests_.find(pending_req);
+        if (it != pending_requests_.end()) {
+          pending_requests_.erase(it);
+          response_allowed_.erase(pending_req);
+          white_list_.insert(*remote_addr);
+        }
+      } else {
+        // If it is a STUN message, but not a response message, we add it into response
+        // allowed list and allow outgoing filter to send a response back.
+        response_allowed_.insert(PendingSTUNRequest(*remote_addr, msg->id));
+      }
+    }
+    return true;
+  }
+
+  return false;
+}
+
+bool STUNUDPSocketFilter::filter_outgoing_packet(const mozilla::net::NetAddr *remote_addr,
+                                                 const uint8_t *data, uint32_t len) {
+  // Check white list
+  if (white_list_.find(*remote_addr) != white_list_.end()) {
+    return true;
+  }
+
+  // Check if it is a stun packet. If yes, we put it into a pending list and wait for
+  // response packet.
+  if (nr_is_stun_request_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
+    const nr_stun_message_header *msg = reinterpret_cast<const nr_stun_message_header*>(data);
+    pending_requests_.insert(PendingSTUNRequest(*remote_addr, msg->id));
+    return true;
+  }
+
+  // If it is a stun response packet, and we had received the request before, we can
+  // allow it packet to pass filter.
+  if (nr_is_stun_response_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
+    const nr_stun_message_header *msg = reinterpret_cast<const nr_stun_message_header*>(data);
+    std::set<PendingSTUNRequest>::iterator it =
+      response_allowed_.find(PendingSTUNRequest(*remote_addr, msg->id));
+    if (it != response_allowed_.end()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+} // anonymous namespace
+
+NS_IMPL_ISUPPORTS1(nsStunUDPSocketFilterHandler, nsIUDPSocketFilterHandler)
+
+NS_IMETHODIMP nsStunUDPSocketFilterHandler::NewFilter(nsIUDPSocketFilter **result)
+{
+  nsIUDPSocketFilter *ret = new STUNUDPSocketFilter();
+  if (!ret) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  NS_ADDREF(*result = ret);
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/media/mtransport/stun_udp_socket_filter.h
@@ -0,0 +1,21 @@
+/* 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 stun_udp_socket_filter_h__
+#define stun_udp_socket_filter_h__
+
+#include "nsIUDPSocketFilter.h"
+
+#define NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX "stun"
+#define NS_STUN_UDP_SOCKET_FILTER_HANDLER_CID { 0x3e43ee93, 0x829e, 0x4ea6, \
+      { 0xa3, 0x4e, 0x62, 0xd9, 0xe4, 0xc9, 0xf9, 0x93 } };
+
+class nsStunUDPSocketFilterHandler : public nsIUDPSocketFilterHandler {
+public:
+  virtual ~nsStunUDPSocketFilterHandler() {}
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIUDPSOCKETFILTERHANDLER
+};
+
+
+#endif // stun_udp_socket_filter_h__
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -32,16 +32,18 @@
 #include "nrinterfaceprioritizer.h"
 #include "mtransport_test_utils.h"
 #include "rlogringbuffer.h"
 #include "runnable_utils.h"
 #include "stunserver.h"
 // TODO(bcampen@mozilla.com): Big fat hack since the build system doesn't give
 // us a clean way to add object files to a single executable.
 #include "stunserver.cpp"
+#include "stun_udp_socket_filter.h"
+#include "mozilla/net/DNS.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 #include "gtest_utils.h"
 
 using namespace mozilla;
 MtransportTestUtils *test_utils;
 
@@ -915,16 +917,62 @@ class PrioritizerTest : public ::testing
     ASSERT_EQ(0, r);
     ASSERT_LE(pref1, pref2);
   }
 
  private:
   nr_interface_prioritizer *prioritizer_;
 };
 
+class PacketFilterTest : public ::testing::Test {
+ public:
+  PacketFilterTest(): filter_(nullptr) {}
+
+  void SetUp() {
+    nsCOMPtr<nsIUDPSocketFilterHandler> handler =
+      do_GetService(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID);
+    handler->NewFilter(getter_AddRefs(filter_));
+  }
+
+  void TestIncoming(const uint8_t* data, uint32_t len,
+                    uint8_t from_addr, int from_port,
+                    bool expected_result) {
+    mozilla::net::NetAddr addr;
+    MakeNetAddr(&addr, from_addr, from_port);
+    bool result;
+    nsresult rv = filter_->FilterPacket(&addr, data, len,
+                                        nsIUDPSocketFilter::SF_INCOMING,
+                                        &result);
+    ASSERT_EQ(NS_OK, rv);
+    ASSERT_EQ(expected_result, result);
+  }
+
+  void TestOutgoing(const uint8_t* data, uint32_t len,
+                    uint8_t to_addr, int to_port,
+                    bool expected_result) {
+    mozilla::net::NetAddr addr;
+    MakeNetAddr(&addr, to_addr, to_port);
+    bool result;
+    nsresult rv = filter_->FilterPacket(&addr, data, len,
+                                        nsIUDPSocketFilter::SF_OUTGOING,
+                                        &result);
+    ASSERT_EQ(NS_OK, rv);
+    ASSERT_EQ(expected_result, result);
+  }
+
+ private:
+  void MakeNetAddr(mozilla::net::NetAddr* net_addr,
+                   uint8_t last_digit, uint16_t port) {
+    net_addr->inet.family = AF_INET;
+    net_addr->inet.ip = 192 << 24 | 168 << 16 | 1 << 8 | last_digit;
+    net_addr->inet.port = port;
+  }
+
+  nsCOMPtr<nsIUDPSocketFilter> filter_;
+};
 }  // end namespace
 
 TEST_F(IceGatherTest, TestGatherFakeStunServerHostnameNoResolver) {
   peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort);
   Gather();
 }
 
 TEST_F(IceGatherTest, TestGatherFakeStunServerIpAddress) {
@@ -1318,16 +1366,127 @@ TEST_F(PrioritizerTest, TestPrioritizer)
   HasLowerPreference("9", "2");
   HasLowerPreference("2", "6");
   HasLowerPreference("6", "7");
   HasLowerPreference("7", "1");
   HasLowerPreference("1", "5");
   HasLowerPreference("5", "4");
 }
 
+TEST_F(PacketFilterTest, TestSendNonStunPacket) {
+  const unsigned char data[] = "12345abcde";
+  TestOutgoing(data, sizeof(data), 123, 45, false);
+}
+
+TEST_F(PacketFilterTest, TestRecvNonStunPacket) {
+  const unsigned char data[] = "12345abcde";
+  TestIncoming(data, sizeof(data), 123, 45, false);
+}
+
+TEST_F(PacketFilterTest, TestSendStunPacket) {
+  nr_stun_message *msg;
+  ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg));
+  msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestOutgoing(msg->buffer, msg->length, 123, 45, true);
+  ASSERT_EQ(0, nr_stun_message_destroy(&msg));
+}
+
+TEST_F(PacketFilterTest, TestRecvStunPacketWithoutAPendingId) {
+  nr_stun_message *msg;
+  ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg));
+
+  msg->header.id.octet[0] = 1;
+  msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestOutgoing(msg->buffer, msg->length, 123, 45, true);
+
+  msg->header.id.octet[0] = 0;
+  msg->header.type = NR_STUN_MSG_BINDING_RESPONSE;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestIncoming(msg->buffer, msg->length, 123, 45, true);
+
+  ASSERT_EQ(0, nr_stun_message_destroy(&msg));
+}
+
+TEST_F(PacketFilterTest, TestRecvStunPacketWithoutAPendingAddress) {
+  nr_stun_message *msg;
+  ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg));
+
+  msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestOutgoing(msg->buffer, msg->length, 123, 45, true);
+
+  msg->header.type = NR_STUN_MSG_BINDING_RESPONSE;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestIncoming(msg->buffer, msg->length, 123, 46, false);
+  TestIncoming(msg->buffer, msg->length, 124, 45, false);
+
+  ASSERT_EQ(0, nr_stun_message_destroy(&msg));
+}
+
+TEST_F(PacketFilterTest, TestRecvStunPacketWithPendingIdAndAddress) {
+  nr_stun_message *msg;
+  ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg));
+
+  msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestOutgoing(msg->buffer, msg->length, 123, 45, true);
+
+  msg->header.type = NR_STUN_MSG_BINDING_RESPONSE;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestIncoming(msg->buffer, msg->length, 123, 45, true);
+
+  // Test whitelist by filtering non-stun packets.
+  const unsigned char data[] = "12345abcde";
+
+  // 123:45 is white-listed.
+  TestOutgoing(data, sizeof(data), 123, 45, true);
+  TestIncoming(data, sizeof(data), 123, 45, true);
+
+  // Indications pass as well.
+  msg->header.type = NR_STUN_MSG_BINDING_INDICATION;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestOutgoing(msg->buffer, msg->length, 123, 45, true);
+  TestIncoming(msg->buffer, msg->length, 123, 45, true);
+
+  // Packets from and to other address are still disallowed.
+  TestOutgoing(data, sizeof(data), 123, 46, false);
+  TestIncoming(data, sizeof(data), 123, 46, false);
+  TestOutgoing(data, sizeof(data), 124, 45, false);
+  TestIncoming(data, sizeof(data), 124, 45, false);
+
+  ASSERT_EQ(0, nr_stun_message_destroy(&msg));
+}
+
+TEST_F(PacketFilterTest, TestSendNonRequestStunPacket) {
+  nr_stun_message *msg;
+  ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg));
+
+  msg->header.type = NR_STUN_MSG_BINDING_RESPONSE;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestOutgoing(msg->buffer, msg->length, 123, 45, false);
+
+  // Send a packet so we allow the incoming request.
+  msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestOutgoing(msg->buffer, msg->length, 123, 45, true);
+
+  // This packet makes us able to send a response.
+  msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestIncoming(msg->buffer, msg->length, 123, 45, true);
+
+  msg->header.type = NR_STUN_MSG_BINDING_RESPONSE;
+  ASSERT_EQ(0, nr_stun_encode_message(msg));
+  TestOutgoing(msg->buffer, msg->length, 123, 45, true);
+
+  ASSERT_EQ(0, nr_stun_message_destroy(&msg));
+}
+
 static std::string get_environment(const char *name) {
   char *value = getenv(name);
 
   if (!value)
     return "";
 
   return value;
 }
--- a/netwerk/base/public/moz.build
+++ b/netwerk/base/public/moz.build
@@ -102,16 +102,17 @@ XPIDL_SOURCES += [
     'nsISyncStreamListener.idl',
     'nsISystemProxySettings.idl',
     'nsIThreadRetargetableRequest.idl',
     'nsIThreadRetargetableStreamListener.idl',
     'nsITimedChannel.idl',
     'nsITraceableChannel.idl',
     'nsITransport.idl',
     'nsIUDPSocket.idl',
+    'nsIUDPSocketFilter.idl',
     'nsIUnicharStreamLoader.idl',
     'nsIUploadChannel.idl',
     'nsIUploadChannel2.idl',
     'nsIURI.idl',
     'nsIURIChecker.idl',
     'nsIURIClassifier.idl',
     'nsIURIWithPrincipal.idl',
     'nsIURL.idl',
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIUDPSocketFilter.idl
@@ -0,0 +1,45 @@
+/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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"
+#include "nsINetAddr.idl"
+
+native NetAddr(mozilla::net::NetAddr);
+[ptr] native NetAddrPtr(mozilla::net::NetAddr);
+
+
+/**
+ * Filters are created and run on the parent, and filter all UDP packets, both
+ * ingoing and outgoing. The child must specify the name of a recognized filter
+ * in order to create a UDP socket.
+ */
+[uuid(24f20de4-09e9-42ab-947a-0d6a3d103d59)]
+interface nsIUDPSocketFilter : nsISupports
+{
+  const long SF_INCOMING = 0;
+  const long SF_OUTGOING = 1;
+
+  bool filterPacket([const]in NetAddrPtr remote_addr,
+                    [const, array, size_is(len)]in uint8_t data,
+                    in unsigned long len,
+                    in long direction);
+};
+
+/**
+ * Factory of a specified filter.
+ */
+[uuid(81ee76c6-4753-4125-9c8c-290ed9ba62fb)]
+interface nsIUDPSocketFilterHandler : nsISupports
+{
+   nsIUDPSocketFilter newFilter();
+};
+
+%{C++
+/**
+ * Filter handlers are registered with XPCOM under the following CONTRACTID prefix:
+ */
+#define NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX "@mozilla.org/network/udp-filter-handler;1?name="
+%}
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -209,17 +209,18 @@ NeckoChild::DeallocPTCPServerSocketChild
 {
   TCPServerSocketChild* p = static_cast<TCPServerSocketChild*>(child);
   p->ReleaseIPDLReference();
   return true;
 }
 
 PUDPSocketChild*
 NeckoChild::AllocPUDPSocketChild(const nsCString& aHost,
-                                 const uint16_t& aPort)
+                                 const uint16_t& aPort,
+                                 const nsCString& aFilter)
 {
   NS_NOTREACHED("AllocPUDPSocket should not be called");
   return nullptr;
 }
 
 bool
 NeckoChild::DeallocPUDPSocketChild(PUDPSocketChild* child)
 {
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -43,17 +43,18 @@ protected:
   virtual bool DeallocPWebSocketChild(PWebSocketChild*);
   virtual PTCPSocketChild* AllocPTCPSocketChild();
   virtual bool DeallocPTCPSocketChild(PTCPSocketChild*);
   virtual PTCPServerSocketChild* AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
                                                        const uint16_t& aBacklog,
                                                        const nsString& aBinaryType);
   virtual bool DeallocPTCPServerSocketChild(PTCPServerSocketChild*);
   virtual PUDPSocketChild* AllocPUDPSocketChild(const nsCString& aHost,
-                                                const uint16_t& aPort);
+                                                const uint16_t& aPort,
+                                                const nsCString& aFilter);
   virtual bool DeallocPUDPSocketChild(PUDPSocketChild*);
   virtual PRemoteOpenFileChild* AllocPRemoteOpenFileChild(const URIParams&,
                                                           const OptionalURIParams&);
   virtual bool DeallocPRemoteOpenFileChild(PRemoteOpenFileChild*);
   virtual PRtspControllerChild* AllocPRtspControllerChild();
   virtual bool DeallocPRtspControllerChild(PRtspControllerChild*);
 };
 
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -23,16 +23,17 @@
 #include "mozilla/dom/network/TCPServerSocketParent.h"
 #include "mozilla/dom/network/UDPSocketParent.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/AppProcessChecker.h"
 #include "nsPrintfCString.h"
 #include "nsHTMLDNSPrefetch.h"
 #include "nsIAppsService.h"
+#include "nsIUDPSocketFilter.h"
 #include "nsEscape.h"
 #include "RemoteOpenFileParent.h"
 #include "SerializedLoadContext.h"
 
 using mozilla::dom::ContentParent;
 using mozilla::dom::TabParent;
 using mozilla::net::PTCPSocketParent;
 using mozilla::dom::TCPSocketParent;
@@ -374,33 +375,52 @@ NeckoParent::DeallocPTCPServerSocketPare
 {
   TCPServerSocketParent* p = static_cast<TCPServerSocketParent*>(actor);
    p->ReleaseIPDLReference();
   return true;
 }
 
 PUDPSocketParent*
 NeckoParent::AllocPUDPSocketParent(const nsCString& aHost,
-                                   const uint16_t& aPort)
+                                   const uint16_t& aPort,
+                                   const nsCString& aFilter)
 {
-  bool enabled = Preferences::GetBool("media.peerconnection.ipc.enabled", false);
-  if (!enabled) {
-    NS_WARNING("Not support UDP socket in content process, aborting subprocess");
-    return nullptr;
+  UDPSocketParent* p;
+
+  // Only allow socket if it specifies a valid packet filter.
+  nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
+  contractId.Append(aFilter);
+
+  if (!aFilter.IsEmpty()) {
+    nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
+      do_GetService(contractId.get());
+    if (filterHandler) {
+      nsCOMPtr<nsIUDPSocketFilter> filter;
+      nsresult rv = filterHandler->NewFilter(getter_AddRefs(filter));
+      if (NS_SUCCEEDED(rv)) {
+        p = new UDPSocketParent(filter);
+      } else {
+        printf_stderr("Cannot create filter that content specified. "
+                      "filter name: %s, error code: %d.", aFilter.get(), rv);
+      }
+    } else {
+      printf_stderr("Content doesn't have a valid filter. "
+                    "filter name: %s.", aFilter.get());
+    }
   }
-  UDPSocketParent* p = new UDPSocketParent();
-  p->AddRef();
+
+  NS_IF_ADDREF(p);
   return p;
-
 }
 
 bool
 NeckoParent::RecvPUDPSocketConstructor(PUDPSocketParent* aActor,
                                        const nsCString& aHost,
-                                       const uint16_t& aPort)
+                                       const uint16_t& aPort,
+                                       const nsCString& aFilter)
 {
   return static_cast<UDPSocketParent*>(aActor)->Init(aHost, aPort);
 }
 
 bool
 NeckoParent::DeallocPUDPSocketParent(PUDPSocketParent* actor)
 {
   UDPSocketParent* p = static_cast<UDPSocketParent*>(actor);
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -112,20 +112,22 @@ protected:
                                                         const uint16_t& aBacklog,
                                                         const nsString& aBinaryType);
   virtual bool RecvPTCPServerSocketConstructor(PTCPServerSocketParent*,
                                                const uint16_t& aLocalPort,
                                                const uint16_t& aBacklog,
                                                const nsString& aBinaryType);
   virtual bool DeallocPTCPServerSocketParent(PTCPServerSocketParent*);
   virtual PUDPSocketParent* AllocPUDPSocketParent(const nsCString& aHost,
-                                                  const uint16_t& aPort);
+                                                  const uint16_t& aPort,
+                                                  const nsCString& aFilter);
   virtual bool RecvPUDPSocketConstructor(PUDPSocketParent*,
                                          const nsCString& aHost,
-                                         const uint16_t& aPort);
+                                         const uint16_t& aPort,
+                                         const nsCString& aFilter);
   virtual bool DeallocPUDPSocketParent(PUDPSocketParent*);
   virtual bool RecvHTMLDNSPrefetch(const nsString& hostname,
                                    const uint16_t& flags);
   virtual bool RecvCancelHTMLDNSPrefetch(const nsString& hostname,
                                          const uint16_t& flags,
                                          const nsresult& reason);
 
   virtual mozilla::ipc::IProtocol*
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -52,17 +52,17 @@ parent:
                SerializedLoadContext loadContext,
                HttpChannelCreationArgs args);
   PWyciwygChannel();
   PFTPChannel(PBrowser browser, SerializedLoadContext loadContext,
               FTPChannelCreationArgs args);
 
   PWebSocket(PBrowser browser, SerializedLoadContext loadContext);
   PTCPServerSocket(uint16_t localPort, uint16_t backlog, nsString binaryType);
-  PUDPSocket(nsCString host, uint16_t port);
+  PUDPSocket(nsCString host, uint16_t port, nsCString filter);
 
   PRemoteOpenFile(URIParams fileuri, OptionalURIParams appuri);
 
   HTMLDNSPrefetch(nsString hostname, uint16_t flags);
   CancelHTMLDNSPrefetch(nsString hostname, uint16_t flags, nsresult reason);
   PRtspController();
 
 both: