=== modified file 'data/org.aethercast.xml'
--- data/org.aethercast.xml	2015-12-10 17:13:50 +0000
+++ data/org.aethercast.xml	2016-02-29 12:16:11 +0000
@@ -9,6 +9,8 @@
             <arg name="path" type="o" direction="in"/>
         </method>
         <method name="Scan"/>
+        <!-- FIXME just for demo purposes. Don't use this method. -->
+        <method name="DisconnectAll"/>
         <property name="State" type="s" access="read"/>
         <property name="Capabilities" type="as" access="read"/>
         <property name="Scanning" type="b" access="read"/>

=== modified file 'debian/control'
--- debian/control	2016-01-21 11:13:32 +0000
+++ debian/control	2016-02-29 12:16:11 +0000
@@ -5,6 +5,7 @@
 XSBC-Original-Maintainer: Simon Fels <simon.fels@canonical.com>
 Build-Depends: cmake,
                debhelper (>= 9),
+               dh-apparmor,
                dbus,
                google-mock,
                libboost-dev,

=== modified file 'debian/rules'
--- debian/rules	2016-01-17 14:01:37 +0000
+++ debian/rules	2016-02-29 12:16:11 +0000
@@ -20,3 +20,7 @@
 
 override_dh_auto_test:
 	# disable
+
+override_dh_install:
+	dh_install
+	dh_apparmor -paethercast --profile-name=usr.sbin.dhcpd

=== modified file 'debian/usr.sbin.aethercast'
--- debian/usr.sbin.aethercast	2016-01-30 12:33:55 +0000
+++ debian/usr.sbin.aethercast	2016-02-29 12:16:11 +0000
@@ -1,11 +1,15 @@
 # vim:syntax=apparmor
 
-  # Allow aethercast to start dhcpd with its own configuration
-  # file it needs to provide DHCP for groups it manages through
-  # WiFi Direct. This need to stay as long as NetworkManager does
-  # not has support for WiFi Direct and aethercast is using that.
-  /etc/aethercast/dhcpd.conf r,
-  # In addition aethercast will also point dhcpd to a private
-  # lease/pid file
-  /{,var/}run/aethercast/dhcpd*.leases* lrw,
-  /{,var/}run/aethercast/dhcpd*.pid lrw,
+# Work around bug:
+# https://bugs.launchpad.net/ubuntu/+source/isc-dhcp/+bug/1186662
+capability dac_override,
+
+# Allow aethercast to start dhcpd with its own configuration
+# file it needs to provide DHCP for groups it manages through
+# WiFi Direct. This need to stay as long as NetworkManager does
+# not has support for WiFi Direct and aethercast is using that.
+/etc/aethercast/dhcpd.conf r,
+# In addition aethercast will also point dhcpd to a private
+# lease/pid file
+/{,var/}run/aethercast/dhcpd*.leases lrw,
+/{,var/}run/aethercast/dhcpd*.pid lrw,

=== modified file 'src/mcs/forwardingmiracastcontroller.cpp'
--- src/mcs/forwardingmiracastcontroller.cpp	2016-01-21 13:25:31 +0000
+++ src/mcs/forwardingmiracastcontroller.cpp	2016-02-29 12:16:11 +0000
@@ -42,8 +42,12 @@
     fwd_->Disconnect(device, callback);
 }
 
-void ForwardingMiracastController::Scan(const std::chrono::seconds &timeout) {
-    fwd_->Scan(timeout);
+void ForwardingMiracastController::DisconnectAll(ResultCallback callback) {
+    fwd_->DisconnectAll(callback);
+}
+
+mcs::Error ForwardingMiracastController::Scan(const std::chrono::seconds &timeout) {
+    return fwd_->Scan(timeout);
 }
 
 NetworkDeviceState ForwardingMiracastController::State() const {

=== modified file 'src/mcs/forwardingmiracastcontroller.h'
--- src/mcs/forwardingmiracastcontroller.h	2016-01-21 13:25:31 +0000
+++ src/mcs/forwardingmiracastcontroller.h	2016-02-29 12:16:11 +0000
@@ -32,7 +32,9 @@
     virtual void Connect(const NetworkDevice::Ptr &device, ResultCallback callback) override;
     virtual void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback) override;
 
-    virtual void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) override;
+    virtual void DisconnectAll(ResultCallback callback) override;
+
+    virtual mcs::Error Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) override;
 
     virtual NetworkDeviceState State() const override;
     virtual std::vector<NetworkManager::Capability> Capabilities() const override;

=== modified file 'src/mcs/miracastcontroller.h'
--- src/mcs/miracastcontroller.h	2016-01-21 13:25:31 +0000
+++ src/mcs/miracastcontroller.h	2016-02-29 12:16:11 +0000
@@ -52,7 +52,9 @@
     virtual void Connect(const NetworkDevice::Ptr &device, ResultCallback callback) = 0;
     virtual void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback) = 0;
 
-    virtual void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) = 0;
+    virtual void DisconnectAll(ResultCallback callback) = 0;
+
+    virtual mcs::Error Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) = 0;
 
     virtual NetworkDeviceState State() const = 0;
     virtual std::vector<NetworkManager::Capability> Capabilities() const = 0;

=== modified file 'src/mcs/miracastcontrollerskeleton.cpp'
--- src/mcs/miracastcontrollerskeleton.cpp	2016-01-21 13:25:31 +0000
+++ src/mcs/miracastcontrollerskeleton.cpp	2016-02-29 12:16:11 +0000
@@ -119,6 +119,10 @@
                      G_CALLBACK(&MiracastControllerSkeleton::OnHandleScan), new WeakKeepAlive<MiracastControllerSkeleton>(inst),
                      [](gpointer data, GClosure *) { delete static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(data); }, GConnectFlags(0));
 
+    g_signal_connect_data(inst->manager_obj_.get(), "handle-disconnect-all",
+                     G_CALLBACK(&MiracastControllerSkeleton::OnHandleDisconnectAll), new WeakKeepAlive<MiracastControllerSkeleton>(inst),
+                     [](gpointer data, GClosure *) { delete static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(data); }, GConnectFlags(0));
+
     inst->SyncProperties();
 
     g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(inst->manager_obj_.get()),
@@ -142,13 +146,43 @@
 
     INFO("Scanning for remote devices");
 
-    inst->Scan();
+    auto error = inst->Scan();
+    if (error != mcs::Error::kNone) {
+        g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "%s", mcs::ErrorToString(error).c_str());
+        return TRUE;
+    }
 
     g_dbus_method_invocation_return_value(invocation, nullptr);
 
     return TRUE;
 }
 
+gboolean MiracastControllerSkeleton::OnHandleDisconnectAll(AethercastInterfaceManager *skeleton,
+                                                           GDBusMethodInvocation *invocation, gpointer user_data) {
+    boost::ignore_unused_variable_warning(skeleton);
+    auto inst = static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(user_data)->GetInstance().lock();
+
+    if (not inst) {
+        g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
+        return TRUE;
+    }
+
+    g_object_ref(invocation);
+    auto inv = make_shared_gobject(invocation);
+
+    inst->DisconnectAll([inv](mcs::Error error) {
+        if (error != Error::kNone) {
+            g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+                                                  "%s", mcs::ErrorToString(error).c_str());
+            return;
+        }
+
+        g_dbus_method_invocation_return_value(inv.get(), nullptr);
+    });
+
+    return TRUE;
+}
+
 std::shared_ptr<MiracastControllerSkeleton> MiracastControllerSkeleton::FinalizeConstruction() {
     auto sp = shared_from_this();
 

=== modified file 'src/mcs/miracastcontrollerskeleton.h'
--- src/mcs/miracastcontrollerskeleton.h	2015-12-21 15:20:11 +0000
+++ src/mcs/miracastcontrollerskeleton.h	2016-02-29 12:16:11 +0000
@@ -58,6 +58,8 @@
 
     static gboolean OnHandleScan(AethercastInterfaceManager *skeleton, GDBusMethodInvocation *invocation,
                                  gpointer user_data);
+    static gboolean OnHandleDisconnectAll(AethercastInterfaceManager *skeleton, GDBusMethodInvocation *invocation,
+                                          gpointer user_data);
 
     MiracastControllerSkeleton(const std::shared_ptr<MiracastController> &controller);
     std::shared_ptr<MiracastControllerSkeleton> FinalizeConstruction();

=== modified file 'src/mcs/miracastservice.cpp'
--- src/mcs/miracastservice.cpp	2016-01-21 13:25:31 +0000
+++ src/mcs/miracastservice.cpp	2016-02-29 12:16:11 +0000
@@ -377,8 +377,17 @@
     callback(Error::kNone);
 }
 
-void MiracastService::Scan(const std::chrono::seconds &timeout) {
+void MiracastService::DisconnectAll(ResultCallback callback) {
+    Disconnect(current_device_, callback);
+}
+
+mcs::Error MiracastService::Scan(const std::chrono::seconds &timeout) {
+    if (current_device_)
+        return mcs::Error::kInvalidState;
+
     network_manager_->Scan(timeout);
+
+    return mcs::Error::kNone;
 }
 
 void MiracastService::Shutdown() {

=== modified file 'src/mcs/networkutils.cpp'
--- src/mcs/networkutils.cpp	2016-01-15 19:31:22 +0000
+++ src/mcs/networkutils.cpp	2016-02-29 12:16:11 +0000
@@ -15,17 +15,28 @@
  *
  */
 
+
 #include <sys/ioctl.h>
-#include <net/if.h>
 #include <asm/types.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <unistd.h>
 #include <errno.h>
 #include <memory.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+// Hacks necessary to be able to include wireless.h
+#ifndef __user
+#define __user
+#endif
+
+#include <linux/if.h>
+#include <linux/wireless.h>
 
 #include <glib.h>
 
@@ -33,6 +44,9 @@
 #include "networkutils.h"
 #include "logger.h"
 
+namespace {
+static constexpr size_t kDriverCommandReplySize{1024};
+
 #define NLMSG_TAIL(nmsg)				\
     ((struct rtattr *) (((uint8_t*) (nmsg)) +	\
     NLMSG_ALIGN((nmsg)->nlmsg_len)))
@@ -56,6 +70,7 @@
 
     return 0;
 }
+}
 
 namespace mcs {
 int NetworkUtils::ModifyInterfaceAddress(int cmd, int flags,
@@ -259,4 +274,47 @@
         available = (int64_t) nbytes;
     return available;
 }
+
+typedef struct {
+#ifdef SUPPORT_64BIT
+    u64 bufaddr;
+#else
+    char *bufaddr;
+#endif
+    int used_len;
+    int total_len;
+} android_wifi_priv_cmd;
+
+int NetworkUtils::SendDriverPrivateCommand(const std::string &ifname, const std::string &cmd) {
+    struct ifreq ifr;
+    int ret = 0, s;
+    android_wifi_priv_cmd priv_cmd;
+    char buf[kDriverCommandReplySize];
+    size_t buf_len = kDriverCommandReplySize;
+
+    ::memset(buf, 0, sizeof(buf));
+    ::memcpy(buf, cmd.c_str(), cmd.length() + 1);
+    ::memset(&ifr, 0, sizeof(ifr));
+    ::memset(&priv_cmd, 0, sizeof(priv_cmd));
+
+    ::strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
+
+#ifdef SUPPORT_64BIT
+    priv_cmd.bufaddr = (u64)(uintptr_t) buf;
+#else
+    priv_cmd.bufaddr = buf;
+#endif
+    priv_cmd.used_len = buf_len;
+    priv_cmd.total_len = buf_len;
+    ifr.ifr_data = &priv_cmd;
+
+    s = ::socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+    if (s < 0)
+        return -EIO;
+
+    ret = ::ioctl(s, SIOCDEVPRIVATE + 1, &ifr);
+    ::close(s);
+    return ret;
+}
+
 } // namespace mcs

=== modified file 'src/mcs/networkutils.h'
--- src/mcs/networkutils.h	2016-01-15 19:31:22 +0000
+++ src/mcs/networkutils.h	2016-02-29 12:16:11 +0000
@@ -18,6 +18,8 @@
 #ifndef NETWORKUTILS_H_
 #define NETWORKUTILS_H_
 
+#include <string>
+
 namespace mcs {
 class NetworkUtils
 {
@@ -29,6 +31,7 @@
                              unsigned char prefixlen, const char *broadcast);
     static int ResetInterface(int index);
     static int BytesAvailableToRead(int fd);
+    static int SendDriverPrivateCommand(const std::string &ifname, const std::string &cmd);
 };
 } // namespace mcs
 #endif

=== modified file 'src/mcs/types.h'
--- src/mcs/types.h	2015-12-09 16:07:13 +0000
+++ src/mcs/types.h	2016-02-29 12:16:11 +0000
@@ -27,6 +27,7 @@
     kFailed,
     kAlready,
     kParamInvalid,
+    kInvalidState,
     kUnknown
 };
 
@@ -40,6 +41,8 @@
         return "Operation already in progress";
     case Error::kParamInvalid:
         return "Invalid parameters";
+    case Error::kInvalidState:
+        return "Invalid state";
     case Error::kUnknown:
     default:
         break;

=== modified file 'src/w11tng/dhcpclient.cpp'
--- src/w11tng/dhcpclient.cpp	2016-01-30 12:33:19 +0000
+++ src/w11tng/dhcpclient.cpp	2016-02-29 12:16:11 +0000
@@ -80,6 +80,8 @@
         "-d",
         // Don't be verbose
         "-q",
+        // Force us to be IPv4 no matter what the default is
+        "-4",
         // Use the temporary lease file we used above to not interfere
         // with any other parts in the system which are using dhclient
         // as well. We also want a fresh lease file on every start.

=== modified file 'src/w11tng/dhcpserver.cpp'
--- src/w11tng/dhcpserver.cpp	2016-01-30 12:33:19 +0000
+++ src/w11tng/dhcpserver.cpp	2016-02-29 12:16:11 +0000
@@ -53,6 +53,9 @@
     pid_file_path_ = mcs::Utils::Sprintf("%s/dhcpd-%s.pid",
                                          mcs::kRuntimePath,
                                          interface_name_);
+
+
+    local_address_ = mcs::IpV4Address::from_string("192.168.7.1");
 }
 
 DhcpServer::~DhcpServer() {
@@ -75,24 +78,21 @@
     monitor_ = FileMonitor::Create(lease_file_path_, shared_from_this());
 
     // FIXME store those defaults somewhere else
-    const char *address = "192.168.7.1";
     const char *broadcast = "192.168.7.255";
     unsigned char prefixlen = 24;
 
-    local_address_ = mcs::IpV4Address::from_string(address);
-
     auto interface_index = mcs::NetworkUtils::RetrieveInterfaceIndex(interface_name_.c_str());
     if (interface_index < 0)
         MCS_ERROR("Failed to determine index of network interface: %s", interface_name_);
 
     if (mcs::NetworkUtils::ModifyInterfaceAddress(RTM_NEWADDR, NLM_F_REPLACE | NLM_F_ACK, interface_index,
-                                    AF_INET, address,
+                                    AF_INET, local_address_.to_string().c_str(),
                                     NULL, prefixlen, broadcast) < 0) {
         MCS_ERROR("Failed to assign network address for %s", interface_name_);
         return;
     }
 
-    MCS_DEBUG("Assigned network address %s", address);
+    MCS_DEBUG("Assigned network address %s", local_address_.to_string());
 
     std::vector<std::string> argv = {
         "-f", "-4",

=== modified file 'src/w11tng/interfacestub.cpp'
--- src/w11tng/interfacestub.cpp	2016-01-18 16:49:07 +0000
+++ src/w11tng/interfacestub.cpp	2016-02-29 12:16:11 +0000
@@ -55,7 +55,7 @@
         }
 
         if (auto sp = inst->delegate_.lock())
-            sp->OnInterfaceReady();
+            sp->OnInterfaceReady(inst->ObjectPath());
 
     }, new mcs::SharedKeepAlive<InterfaceStub>{shared_from_this()});
 

=== modified file 'src/w11tng/interfacestub.h'
--- src/w11tng/interfacestub.h	2016-01-18 16:49:07 +0000
+++ src/w11tng/interfacestub.h	2016-02-29 12:16:11 +0000
@@ -39,7 +39,7 @@
 
     class Delegate : public mcs::NonCopyable {
     public:
-        virtual void OnInterfaceReady() = 0;
+        virtual void OnInterfaceReady(const std::string &object_path) = 0;
     };
 
     static Ptr Create(const std::string &object_path);

=== modified file 'src/w11tng/networkmanager.cpp'
--- src/w11tng/networkmanager.cpp	2016-01-30 12:33:19 +0000
+++ src/w11tng/networkmanager.cpp	2016-02-29 12:16:11 +0000
@@ -18,9 +18,11 @@
 #include <boost/concept_check.hpp>
 
 #include <algorithm>
+#include <sstream>
 
 #include <mcs/logger.h>
 #include <mcs/keep_alive.h>
+#include <mcs/networkutils.h>
 
 #include "networkmanager.h"
 #include "informationelement.h"
@@ -125,6 +127,9 @@
     if (p2p_device_)
         return;
 
+    mgmt_interface_ = InterfaceStub::Create(object_path);
+    mgmt_interface_->SetDelegate(shared_from_this());
+
     p2p_device_ = P2PDeviceStub::Create(object_path, shared_from_this());
 }
 
@@ -140,6 +145,9 @@
 
     if (p2p_device_)
         p2p_device_.reset();
+
+    if (mgmt_interface_)
+        mgmt_interface_.reset();
 }
 
 void NetworkManager::SetDelegate(mcs::NetworkManager::Delegate *delegate) {
@@ -181,13 +189,13 @@
         if (not inst)
             return FALSE;
 
-        MCS_WARNING("Connect timeout happened");
+        MCS_WARNING("Reached a timeout while trying to connect with remote %s", inst->current_device_->Address());
 
         inst->connect_timeout_ = 0;
 
         // If the device is either already connected or trying to get an address
         // over DHCP we don't do anything. DHCP process will fail on its own after
-        // some time and we will react on this.
+        // some time and we will react on
         if (inst->current_device_->State() == mcs::kConnected ||
             inst->current_device_->State() == mcs::kConfiguration)
             return FALSE;
@@ -195,6 +203,7 @@
         inst->p2p_device_->Cancel();
 
         inst->AdvanceDeviceState(inst->current_device_, mcs::kFailure);
+
         inst->current_device_.reset();
 
         // We don't have an active group if we're not in connected or configuration
@@ -390,6 +399,12 @@
 void NetworkManager::AdvanceDeviceState(const NetworkDevice::Ptr &device, mcs::NetworkDeviceState state) {
     device->SetState(state);
 
+    if (state == mcs::kDisconnected) {
+        mcs::NetworkUtils::SendDriverPrivateCommand(mgmt_interface_->Ifname(),
+                                                    BuildMiracastModeCommand(MiracastMode::Off));
+        MCS_DEBUG("Disabled WiFi driver miracast mode");
+    }
+
     // When we're switching to be connected or disconnected we need to mark the
     // session as not being available to prevent anyone else to connect with us.
     if (state == mcs::kConnected || state == mcs::kDisconnected) {
@@ -416,20 +431,30 @@
     HandleConnectFailed();
 }
 
-void NetworkManager::OnGroupOwnerNegotiationFailure(const std::string &peer_path) {
+void NetworkManager::OnGroupOwnerNegotiationFailure(const std::string &peer_path, const P2PDeviceStub::GroupOwnerNegotiationResult &result) {
     if (!current_device_)
         return;
 
-    MCS_DEBUG("peer %s", peer_path);
+    MCS_DEBUG("Connecting with peer %s failed: %s", peer_path, P2PDeviceStub::StatusToString(result.status));
 
     HandleConnectFailed();
 }
 
-void NetworkManager::OnGroupOwnerNegotiationSuccess(const std::string &peer_path) {
+void NetworkManager::OnGroupOwnerNegotiationSuccess(const std::string &peer_path, const P2PDeviceStub::GroupOwnerNegotiationResult &result) {
     if (!current_device_)
         return;
 
-    MCS_DEBUG("peer %s", peer_path);
+    std::stringstream frequencies;
+    int n = 0;
+    for (auto freq : result.frequencies) {
+        frequencies << mcs::Utils::Sprintf("%d", freq);
+        if (n < result.frequencies.size() - 1)
+            frequencies << ",";
+    }
+
+    MCS_DEBUG("peer %s selected oper freq %d wps_method %s",
+              peer_path, result.oper_freq, result.wps_method);
+    MCS_DEBUG("intersect freqs [%s]", frequencies.str());
 }
 
 void NetworkManager::OnGroupStarted(const std::string &group_path, const std::string &interface_path, const std::string &role) {
@@ -576,7 +601,7 @@
     dev_info->session_management_control_port = htons(7236);
     dev_info->maximum_throughput = htons(50);
     dev_info->field1.device_type = device_type;
-    dev_info->field1.session_availability = true; //session_available_;
+    dev_info->field1.session_availability = session_available_;
     ie.add_subelement(sub_element);
 
     auto ie_data = ie.serialize();
@@ -621,13 +646,32 @@
     interface_selector_->Process(manager_->Interfaces());
 }
 
-void NetworkManager::OnInterfaceReady() {
+void NetworkManager::OnInterfaceReady(const std::string &object_path) {
+    if (current_group_iface_ && object_path == current_group_iface_->ObjectPath())
+        OnGroupInterfaceReady();
+    else if (object_path == mgmt_interface_->ObjectPath())
+        OnManagementInterfaceReady();
+}
+
+void NetworkManager::OnManagementInterfaceReady() {
+}
+
+std::string NetworkManager::BuildMiracastModeCommand(MiracastMode mode) {
+    return mcs::Utils::Sprintf("MIRACAST %d", static_cast<int>(mode));
+}
+
+void NetworkManager::OnGroupInterfaceReady() {
     if (!current_device_ || current_device_->State() != mcs::kConfiguration)
         return;
 
     auto ifname = current_group_iface_->Ifname();
 
-    MCS_DEBUG("interface %s", ifname);
+    // Android WiFi drivers have a special mode build in when they should
+    // perform well for Miracast which we enable here. If the command is
+    // not available this is a no-op.
+    if (mcs::NetworkUtils::SendDriverPrivateCommand(mgmt_interface_->Ifname(),
+                                                    BuildMiracastModeCommand(MiracastMode::Source)) < 0)
+        MCS_WARNING("Failed to activate miracast mode of WiFi driver");
 
     auto sp = shared_from_this();
 
@@ -637,6 +681,10 @@
         dhcp_client_ = w11tng::DhcpClient::Create(sp, ifname);
 }
 
+void NetworkManager::OnInterfaceDriverCommandResult(const std::string &result) {
+    boost::ignore_unused_variable_warning(result);
+}
+
 void NetworkManager::OnHostnameChanged() {
     MCS_DEBUG("");
     SyncDeviceConfiguration();

=== modified file 'src/w11tng/networkmanager.h'
--- src/w11tng/networkmanager.h	2016-01-30 12:33:19 +0000
+++ src/w11tng/networkmanager.h	2016-02-29 12:16:11 +0000
@@ -47,7 +47,9 @@
                        public w11tng::Hostname1Stub::Delegate {
 public:
     static constexpr const char *kBusName{"fi.w1.wpa_supplicant1"};
-    static constexpr unsigned int kConnectTimeout = 100;
+    // We take two minutes as timeout here which corresponds to what wpa
+    // takes for the group formation.
+    static constexpr unsigned int kConnectTimeout = 120;
 
     static mcs::NetworkManager::Ptr Create();
 
@@ -75,8 +77,8 @@
     void OnDeviceFound(const std::string &path) override;
     void OnDeviceLost(const std::string &path) override;
     void OnPeerConnectFailed() override;
-    void OnGroupOwnerNegotiationFailure(const std::string &peer_path) override;
-    void OnGroupOwnerNegotiationSuccess(const std::string &peer_path) override;
+    void OnGroupOwnerNegotiationFailure(const std::string &peer_path, const P2PDeviceStub::GroupOwnerNegotiationResult &result) override;
+    void OnGroupOwnerNegotiationSuccess(const std::string &peer_path, const P2PDeviceStub::GroupOwnerNegotiationResult &result) override;
     void OnGroupStarted(const std::string &group_path, const std::string &interface_path, const std::string &role) override;
     void OnGroupFinished(const std::string &group_path, const std::string &interface_path) override;
     void OnGroupRequest(const std::string &peer_path, int dev_passwd_id) override;
@@ -97,7 +99,8 @@
     void OnManagerInterfaceRemoved(const std::string &path) override;
     void OnManagerInterfaceCreationFailed() override;
 
-    void OnInterfaceReady() override;
+    void OnInterfaceReady(const std::string &object_path) override;
+    void OnInterfaceDriverCommandResult(const std::string &result) override;
 
     void OnHostnameChanged() override;
 
@@ -128,10 +131,22 @@
 
     void HandleConnectFailed();
 
+    void OnGroupInterfaceReady();
+    void OnManagementInterfaceReady();
+
+    enum class MiracastMode : int {
+        Off = 0,
+        Source = 1,
+        Sink = 2
+    };
+
+    std::string BuildMiracastModeCommand(MiracastMode mode);
+
 private:
     mcs::ScopedGObject<GDBusConnection> connection_;
     mcs::NetworkManager::Delegate *delegate_;
     std::shared_ptr<ManagerStub> manager_;
+    std::shared_ptr<InterfaceStub> mgmt_interface_;
     std::shared_ptr<P2PDeviceStub> p2p_device_;
     std::unordered_map<std::string,w11tng::NetworkDevice::Ptr> devices_;
     NetworkDevice::Ptr current_device_;

=== modified file 'src/w11tng/p2pdevicestub.cpp'
--- src/w11tng/p2pdevicestub.cpp	2016-01-21 13:25:31 +0000
+++ src/w11tng/p2pdevicestub.cpp	2016-02-29 12:16:11 +0000
@@ -25,6 +25,40 @@
 
 namespace w11tng {
 
+std::string P2PDeviceStub::StatusToString(Status status) {
+    switch (status) {
+    case Status::SucccesAcceptedByUser:
+    case Status::Success:
+        return "Success";
+    case Status::InformationIsCurrentlyUnavailable:
+        return "Information is currently unavailable";
+    case Status::IncompatibleParameters:
+        return "Incompatible parameters";
+    case Status::LimitReached:
+        return "Limit reached";
+    case Status::InvalidParameter:
+        return "Invalid parameter";
+    case Status::UnableToAccommodateRequest:
+        return "Unable to accommodate request";
+    case Status::ProtcolErrorOrDisruptiveBehavior:
+        return "Protocol error or disruptive behavior";
+    case Status::NoCommonChannel:
+        return "No common channels";
+    case Status::UnknownP2PGroup:
+        return "Unknown P2P group";
+    case Status::BothGOIntent15:
+        return "Both P2P devices indicated an intent of 15 in group owner negotiation";
+    case Status::IncompatibleProvisioningMethod:
+        return "Incompatible provisioning method";
+    case Status::RejectByUser:
+        return "Rejected by user";
+    default:
+        break;
+    }
+
+    return "Failed: unknown error";
+}
+
 P2PDeviceStub::Ptr P2PDeviceStub::Create(const std::string &object_path, const std::weak_ptr<P2PDeviceStub::Delegate> &delegate) {
     return std::shared_ptr<P2PDeviceStub>(new P2PDeviceStub(delegate))->FinalizeConstruction(object_path);
 }
@@ -110,17 +144,32 @@
     auto inst = static_cast<mcs::WeakKeepAlive<P2PDeviceStub>*>(user_data)->GetInstance().lock();
 
     std::string peer_path;
+    GroupOwnerNegotiationResult result;
 
     mcs::DBusHelpers::ParseDictionary(properties, [&](const std::string &name, GVariant *value) {
-        if (name == "peer_object")
+        if (name == "status")
+            result.status = static_cast<Status>(g_variant_get_int32(g_variant_get_variant(value)));
+        else if (name == "peer_object")
             peer_path = g_variant_get_string(g_variant_get_variant(value), nullptr);
+        else if (name == "frequency")
+            result.oper_freq = g_variant_get_int32(g_variant_get_variant(value));
+        else if (name == "frequency_list") {
+            auto v = g_variant_get_variant(value);
+            for (int n = 0; n < g_variant_n_children(v); n++) {
+                Frequency freq = 0;
+                g_variant_get_child(v, n, "i", &freq);
+                result.frequencies.insert(freq);
+            }
+        }
+        else if (name == "wps_method")
+            result.wps_method = g_variant_get_string(g_variant_get_variant(value), nullptr);
     });
 
     if (peer_path.length() == 0)
         return;
 
     if (auto sp = inst->delegate_.lock())
-        sp->OnGroupOwnerNegotiationSuccess(peer_path);
+        sp->OnGroupOwnerNegotiationSuccess(peer_path, result);
 }
 
 void P2PDeviceStub::OnGONegotiationFailure(WpaSupplicantInterfaceP2PDevice *device, GVariant *properties, gpointer user_data) {
@@ -129,20 +178,20 @@
     auto inst = static_cast<mcs::WeakKeepAlive<P2PDeviceStub>*>(user_data)->GetInstance().lock();
 
     std::string peer_path;
-    int status = 0;
+    GroupOwnerNegotiationResult result;
 
     mcs::DBusHelpers::ParseDictionary(properties, [&](const std::string &name, GVariant *value) {
         if (name == "peer_object")
             peer_path = g_variant_get_string(g_variant_get_variant(value), nullptr);
         else if (name == "status")
-            status = g_variant_get_int32(g_variant_get_variant(value));
+            result.status = static_cast<Status>(g_variant_get_int32(g_variant_get_variant(value)));
     });
 
     if (peer_path.length() == 0)
         return;
 
     if (auto sp = inst->delegate_.lock())
-        sp->OnGroupOwnerNegotiationFailure(peer_path);
+        sp->OnGroupOwnerNegotiationFailure(peer_path, result);
 }
 
 void P2PDeviceStub::OnGroupStarted(WpaSupplicantInterfaceP2PDevice *device, GVariant *properties, gpointer user_data) {
@@ -306,9 +355,16 @@
 
     auto builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
 
+    int32_t intent = 7;
+    if (mcs::Utils::IsEnvSet("GO_INTENT"))
+        intent = std::stoi(mcs::Utils::GetEnvValue("GO_INTENT"));
+
+    MCS_DEBUG("Using GO intent %d", intent);
+
     g_variant_builder_add(builder, "{sv}", "peer", g_variant_new_object_path(path.c_str()));
     // We support only WPS PBC for now
     g_variant_builder_add(builder, "{sv}", "wps_method", g_variant_new_string("pbc"));
+    g_variant_builder_add(builder, "{sv}", "go_intent", g_variant_new_int32(intent));
 
     auto arguments = g_variant_builder_end(builder);
 

=== modified file 'src/w11tng/p2pdevicestub.h'
--- src/w11tng/p2pdevicestub.h	2016-01-19 17:50:15 +0000
+++ src/w11tng/p2pdevicestub.h	2016-02-29 12:16:11 +0000
@@ -21,6 +21,7 @@
 #include <chrono>
 #include <memory>
 #include <unordered_map>
+#include <set>
 
 #include <mcs/non_copyable.h>
 
@@ -41,14 +42,43 @@
 public:
     static constexpr const char *kBusName{"fi.w1.wpa_supplicant1"};
 
+    typedef int Frequency;
+    typedef std::set<Frequency> FrequencyList;
+
+    enum class Status {
+        Success = 0,
+        InformationIsCurrentlyUnavailable = 1,
+        IncompatibleParameters = 2,
+        LimitReached = 3,
+        InvalidParameter = 4,
+        UnableToAccommodateRequest = 5,
+        ProtcolErrorOrDisruptiveBehavior = 6,
+        NoCommonChannel = 7,
+        UnknownP2PGroup = 8,
+        BothGOIntent15 = 9,
+        IncompatibleProvisioningMethod = 10,
+        RejectByUser = 11,
+        SucccesAcceptedByUser = 12,
+        Unknown = 0xff
+    };
+
+    static std::string StatusToString(Status status);
+
+    struct GroupOwnerNegotiationResult {
+        Status status;
+        Frequency oper_freq;
+        FrequencyList frequencies;
+        std::string wps_method;
+    };
+
     class Delegate : public mcs::NonCopyable {
     public:
         virtual void OnDeviceFound(const std::string &path) = 0;
         virtual void OnDeviceLost(const std::string &path) = 0;
 
         virtual void OnPeerConnectFailed() = 0;
-        virtual void OnGroupOwnerNegotiationSuccess(const std::string &peer_path) = 0;
-        virtual void OnGroupOwnerNegotiationFailure(const std::string &peer_path) = 0;
+        virtual void OnGroupOwnerNegotiationSuccess(const std::string &peer_path, const GroupOwnerNegotiationResult &result) = 0;
+        virtual void OnGroupOwnerNegotiationFailure(const std::string &peer_path, const GroupOwnerNegotiationResult &result) = 0;
         virtual void OnGroupStarted(const std::string &group_path, const std::string &interface_path, const std::string &role) = 0;
         virtual void OnGroupFinished(const std::string &group_path, const std::string &interface_path) = 0;
         virtual void OnGroupRequest(const std::string &peer_path, int dev_passwd_id) = 0;

=== modified file 'tests/mcs/forwardingmiracastcontroller_tests.cpp'
--- tests/mcs/forwardingmiracastcontroller_tests.cpp	2016-01-21 13:25:31 +0000
+++ tests/mcs/forwardingmiracastcontroller_tests.cpp	2016-02-29 12:16:11 +0000
@@ -26,8 +26,9 @@
 
     MOCK_METHOD2(Connect, void(const mcs::NetworkDevice::Ptr &, mcs::ResultCallback));
     MOCK_METHOD2(Disconnect, void(const mcs::NetworkDevice::Ptr &, mcs::ResultCallback));
+    MOCK_METHOD1(DisconnectAll, void(mcs::ResultCallback));
 
-    MOCK_METHOD1(Scan, void(const std::chrono::seconds &));
+    MOCK_METHOD1(Scan, mcs::Error(const std::chrono::seconds &));
 
     MOCK_CONST_METHOD0(State, mcs::NetworkDeviceState());
     MOCK_CONST_METHOD0(Capabilities, std::vector<mcs::NetworkManager::Capability>());
@@ -48,7 +49,8 @@
     EXPECT_CALL(*impl, ResetDelegate()).Times(1);
     EXPECT_CALL(*impl, Connect(_,_)).Times(1);
     EXPECT_CALL(*impl, Disconnect(_,_)).Times(1);
-    EXPECT_CALL(*impl, Scan(_)).Times(1);
+    EXPECT_CALL(*impl, DisconnectAll(_)).Times(1);
+    EXPECT_CALL(*impl, Scan(_)).Times(1).WillRepeatedly(Return(mcs::Error::kNone));
     EXPECT_CALL(*impl, State()).Times(1).WillRepeatedly(Return(mcs::NetworkDeviceState::kConnected));
     EXPECT_CALL(*impl, Capabilities()).Times(1).WillRepeatedly(Return(std::vector<mcs::NetworkManager::Capability>{mcs::NetworkManager::Capability::kSource}));
     EXPECT_CALL(*impl, Scanning()).Times(1).WillRepeatedly(Return(true));
@@ -58,6 +60,7 @@
     fmc.ResetDelegate();
     fmc.Connect(mcs::NetworkDevice::Ptr{}, mcs::ResultCallback{});
     fmc.Disconnect(mcs::NetworkDevice::Ptr{}, mcs::ResultCallback{});
+    fmc.DisconnectAll(mcs::ResultCallback{});
     fmc.Scan(std::chrono::seconds{10});
     fmc.State();
     fmc.Capabilities();

=== modified file 'tests/w11tng/interfacestub_tests.cpp'
--- tests/w11tng/interfacestub_tests.cpp	2016-01-12 08:52:28 +0000
+++ tests/w11tng/interfacestub_tests.cpp	2016-02-29 12:16:11 +0000
@@ -43,7 +43,8 @@
 
 class MockInterfaceStubDelegate : public w11tng::InterfaceStub::Delegate {
 public:
-    MOCK_METHOD0(OnInterfaceReady, void());
+    MOCK_METHOD1(OnInterfaceReady, void(const std::string&));
+    MOCK_METHOD1(OnInterfaceDriverCommandResult, void(const std::string&));
 };
 }
 
@@ -53,7 +54,7 @@
 
     auto delegate = std::make_shared<MockInterfaceStubDelegate>();
 
-    EXPECT_CALL(*delegate, OnInterfaceReady()).Times(1);
+    EXPECT_CALL(*delegate, OnInterfaceReady(::testing::_)).Times(1);
 
     auto stub = w11tng::InterfaceStub::Create("/interface_1");
     EXPECT_TRUE(!!stub);

=== modified file 'tests/w11tng/p2pdevicestub_tests.cpp'
--- tests/w11tng/p2pdevicestub_tests.cpp	2016-01-19 15:05:54 +0000
+++ tests/w11tng/p2pdevicestub_tests.cpp	2016-02-29 12:16:11 +0000
@@ -43,8 +43,8 @@
     MOCK_METHOD1(OnDeviceFound, void(const std::string&));
     MOCK_METHOD1(OnDeviceLost, void(const std::string&));
     MOCK_METHOD0(OnPeerConnectFailed, void());
-    MOCK_METHOD1(OnGroupOwnerNegotiationSuccess, void(const std::string&));
-    MOCK_METHOD1(OnGroupOwnerNegotiationFailure, void(const std::string&));
+    MOCK_METHOD2(OnGroupOwnerNegotiationSuccess, void(const std::string&, const w11tng::P2PDeviceStub::GroupOwnerNegotiationResult&));
+    MOCK_METHOD2(OnGroupOwnerNegotiationFailure, void(const std::string&, const w11tng::P2PDeviceStub::GroupOwnerNegotiationResult &));
     MOCK_METHOD3(OnGroupStarted, void(const std::string&, const std::string&, const std::string&));
     MOCK_METHOD2(OnGroupFinished, void(const std::string&, const std::string&));
     MOCK_METHOD2(OnGroupRequest, void(const std::string&, int));
@@ -132,9 +132,9 @@
 
     EXPECT_CALL(*delegate, OnP2PDeviceChanged()).Times(::testing::AtLeast(1));
     EXPECT_CALL(*delegate, OnP2PDeviceReady()).Times(1);
-    EXPECT_CALL(*delegate, OnGroupOwnerNegotiationSuccess(std::string("/peer_1")))
+    EXPECT_CALL(*delegate, OnGroupOwnerNegotiationSuccess(std::string("/peer_1"), ::testing::_))
             .Times(1);
-    EXPECT_CALL(*delegate, OnGroupOwnerNegotiationFailure(std::string("/peer_1")))
+    EXPECT_CALL(*delegate, OnGroupOwnerNegotiationFailure(std::string("/peer_1"), ::testing::_))
             .Times(1);
     EXPECT_CALL(*delegate, OnGroupStarted(std::string("/peer_1"), std::string("/interface_1"), std::string("GO")))
             .Times(1);

