merge b2g-inbound to mozilla-central
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 02 Dec 2013 12:46:24 +0100
changeset 173885 2581b84e0ca168be129a1fadab08fbbd17c23ab4
parent 173829 8a5221ecaa6779cb15b9aa5719e3bcd7dc2632ef (current diff)
parent 173884 d884dfe02381890e96e13fc9343253d5c02818d1 (diff)
child 173886 cc2ea69b6acd6e6d0f4e87660031c445fbd0b0f5
child 173909 691b5f265c9a1cc3f398686173fca43295ee1386
child 173946 2be8f1640e213b315ea99d833e74b1f71bb1d702
child 173988 8601e55efa523d9b7e2b394121e186ea6555d5d7
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [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: