Accept incoming negotiation request when autoconnection is ON.
[platform/core/connectivity/wifi-direct-manager.git] / src / wifi-direct-session.c
index 5bc3abe..f5211f7 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <glib.h>
 
-#include <wifi-direct-internal.h>
+#include <wifi-direct.h>
 
+#include "wifi-direct-ipc.h"
 #include "wifi-direct-manager.h"
 #include "wifi-direct-oem.h"
 #include "wifi-direct-peer.h"
 #include "wifi-direct-oem.h"
 #include "wifi-direct-util.h"
 #include "wifi-direct-session.h"
-#include "wifi-direct-client.h"
 #include "wifi-direct-state.h"
+#include "wifi-direct-error.h"
+#include "wifi-direct-log.h"
+#include "wifi-direct-dbus.h"
+#include "wifi-direct-asp.h"
 
-
+//LCOV_EXCL_START
 static gboolean _session_timeout_cb(gpointer *user_data)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = wfd_get_manager();
        wfd_session_s *session = (wfd_session_s*) manager->session;
-       wifi_direct_client_noti_s noti;
        unsigned char *peer_addr = NULL;
+       char peer_mac_address[MACSTR_LEN+1] = {0, };
 
        if (!session) {
-               WDS_LOGE("Invalid parameter");
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
                return FALSE;
        }
        session->connecting_120 = 0;
        session->timer = 0;
-       WDS_LOGD("Session timer expired");
+       WDS_LOGD("Session timer expired");//LCOV_EXCL_LINE
 
        peer_addr = wfd_session_get_peer_addr(session);
-
-       memset(&noti, 0x0, sizeof(wifi_direct_client_noti_s));
-       noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_RSP;
-       noti.error = WIFI_DIRECT_ERROR_CONNECTION_CANCELED;
-       snprintf(noti.param1, MACSTR_LEN, MACSTR, MAC2STR(peer_addr));
-       wfd_client_send_event(manager, &noti);
+       if (peer_addr != NULL)
+               g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(peer_addr));
+       else
+               g_snprintf(peer_mac_address, MACSTR_LEN, "%s", "");
+
+       wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
+                                    "Connection",
+                                    g_variant_new("(iis)", WIFI_DIRECT_ERROR_CONNECTION_TIME_OUT,
+                                                           WFD_EVENT_CONNECTION_RSP,
+                                                           peer_mac_address));
+
+       if (wfd_asp_is_asp_session(session)) {
+               if (session->state < SESSION_STATE_GO_NEG)
+                       wfd_asp_connect_status(session->session_mac,
+                                       session->session_id,
+                                       ASP_CONNECT_STATUS_REQUEST_FAILED,
+                                       NULL);
+               else
+                       wfd_asp_connect_status(session->session_mac,
+                                       session->session_id,
+                                       ASP_CONNECT_STATUS_GROUP_FORMATION_FAILED,
+                                       NULL);
+       }
 
        wfd_session_cancel(session, peer_addr);
 
        if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
+
+               wfd_group_s *group = (wfd_group_s*) manager->group;
+               if (group && wfd_util_is_remove_group_allowed()) {
+                       wfd_oem_destroy_group(manager->oem_ops, group->ifname);
+               } else {
+                       wfd_state_set(manager, WIFI_DIRECT_STATE_GROUP_OWNER);
+                       wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_GROUP_OWNER);
+               }
+       } else {
+               wfd_state_set(manager, WIFI_DIRECT_STATE_ACTIVATED);
+               wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_ACTIVATED);
+       }
+
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+       return FALSE;
+}
+//LCOV_EXCL_STOP
+
+static void _wfd_notify_session_failed(wfd_manager_s *manager, unsigned char *peer_addr)
+{
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
+       char peer_mac_address[MACSTR_LEN+1] = {0, };
+
+       snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(peer_addr));
+       wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
+                                    "Connection",
+                                    g_variant_new("(iis)", WIFI_DIRECT_ERROR_CONNECTION_FAILED,
+                                                           WFD_EVENT_CONNECTION_RSP,
+                                                           peer_mac_address));
+
+
+
+       wfd_session_s *session = manager->session;
+       if (wfd_asp_is_asp_session(session)) {
+               wfd_asp_connect_status(session->session_mac,
+                                                       session->session_id,
+                                                       ASP_CONNECT_STATUS_GROUP_FORMATION_STARTED,
+                                                       NULL);
+       }
+
+       if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
                wfd_state_set(manager, WIFI_DIRECT_STATE_GROUP_OWNER);
                wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_GROUP_OWNER);
        } else {
@@ -77,75 +140,79 @@ static gboolean _session_timeout_cb(gpointer *user_data)
                wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_ACTIVATED);
        }
 
-       __WDS_LOG_FUNC_EXIT__;
-       return FALSE;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
 }
 
 int wfd_session_timer(wfd_session_s *session, int start)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
 
        if (!session) {
-               WDS_LOGE("Invalid parameter");
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
        if (start) {
-               session->connecting_120 = 1;
+               if (!session->connecting_120)
+                       session->connecting_120 = 1;
+
                if (session->timer > 0) {
-                       WDS_LOGE("Session timer already started");
-                       __WDS_LOG_FUNC_EXIT__;
+                       WDS_LOGE("Session timer already started");//LCOV_EXCL_LINE
+                       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                        return -1;
                }
                session->timer = g_timeout_add(120000,
-                                                       (GSourceFunc) _session_timeout_cb,
-                                                       session);
-               WDS_LOGD("Session timer started");
+                                               (GSourceFunc) _session_timeout_cb,
+                                               NULL);
+               WDS_LOGD("Session timer started");//LCOV_EXCL_LINE
        } else {
                session->connecting_120 = 0;
                if (session->timer > 0) {
                        g_source_remove(session->timer);
                        session->timer = 0;
-                       WDS_LOGD("Session timer stoped");
+                       WDS_LOGD("Session timer stoped");//LCOV_EXCL_LINE
                }
        }
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
-// Check the session instance which has same peer address, before using this function
+/* Check the session instance which has same peer address,
+ * before using this function */
 wfd_session_s *wfd_create_session(void *data, unsigned char *peer_addr, int wps_mode, int direction)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = (wfd_manager_s*) data;
        wfd_session_s *session = NULL;
        wfd_device_s *peer = NULL;
 
        if (!data || !peer_addr) {
-               WDS_LOGE("Invalid parameter");
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return NULL;
        }
 
+       WDS_LOGD("create session for peer[" MACSTR "]", MAC2STR(peer_addr));
+
        if (manager->session) {
-               WDS_LOGE("Session already exist");
+               WDS_LOGE("Session already exist");//LCOV_EXCL_LINE
                return NULL;
        }
 
-       session = (wfd_session_s*) calloc(1, sizeof(wfd_session_s));
+       session = (wfd_session_s*) g_try_malloc0(sizeof(wfd_session_s));
        if (!session) {
-               WDS_LOGE("Failed to allocate memory for session");
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Failed to allocate memory for session");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return NULL;
        }
 
        peer = wfd_peer_find_by_dev_addr(manager, peer_addr);
        if (!peer) {
-               WDS_LOGE("Failed to find peer info[" MACSTR "]", MAC2STR(peer_addr));
-               free(session);
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Failed to find peer info[" MACSECSTR "]", MAC2SECSTR(peer_addr));
+               g_free(session);
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return NULL;
        }
        peer->state = WFD_PEER_STATE_CONNECTING;
@@ -156,6 +223,8 @@ wfd_session_s *wfd_create_session(void *data, unsigned char *peer_addr, int wps_
                session->wps_mode = WFD_WPS_MODE_KEYPAD;
        else if (wps_mode == WFD_WPS_MODE_KEYPAD)
                session->wps_mode = WFD_WPS_MODE_DISPLAY;
+       else if (wps_mode == WFD_WPS_MODE_P2PS)
+               session->wps_mode = WFD_WPS_MODE_P2PS;
        else
                session->wps_mode = wps_mode;
        session->direction = direction;
@@ -163,65 +232,100 @@ wfd_session_s *wfd_create_session(void *data, unsigned char *peer_addr, int wps_
 
        manager->session = session;
        manager->local->wps_mode = session->wps_mode;
-       if (peer->dev_role == WFD_DEV_ROLE_GO)
+
+       if (peer->dev_role == WFD_DEV_ROLE_GO &&
+                       manager->local->wps_mode == WFD_WPS_MODE_DISPLAY) {
+                       char *generated_pin = NULL;
+                       session->wps_mode = WFD_WPS_MODE_DISPLAY;
+                       session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
+
+                       if (wfd_oem_generate_pin(manager->oem_ops, &generated_pin) != 0) {
+                               WDS_LOGE("Failed to generate pin");//LCOV_EXCL_LINE
+                               g_free(session);
+                               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+                               return NULL;
+                       }
+
+#if defined(BUILD_GTESTS)
+                       generated_pin = g_strndup("12345678", PINSTR_LEN + 1);
+#endif /* BUILD_GTESTS */
+                       g_strlcpy(session->wps_pin, generated_pin, PINSTR_LEN + 1);
+                       g_free(generated_pin);
+       }
+
+       if (peer->dev_role == WFD_DEV_ROLE_GO && manager->local->dev_role != WFD_DEV_ROLE_GO)
                manager->local->dev_role = WFD_DEV_ROLE_GC;
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return session;
 }
 
 int wfd_destroy_session(void *data)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = (wfd_manager_s*) data;
        wfd_session_s *session = NULL;
        wfd_device_s *peer = NULL;
 
        if (!manager) {
-               WDS_LOGE("Invalid parameter");
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
                return -1;
        }
 
        session = (wfd_session_s*) manager->session;
        if (!session) {
-               WDS_LOGE("Session not found");
+               WDS_LOGE("Session not found");//LCOV_EXCL_LINE  /* self prevent */
                return -1;
        }
        wfd_session_timer(session, 0);
        peer = session->peer;
-       
-       if (session->state == SESSION_STATE_COMPLETED)
-               peer->state = WFD_PEER_STATE_CONNECTED;
-       else
-               peer->state = WFD_PEER_STATE_DISCOVERED;
+       WDS_LOGD("peer :%p", peer);
 
-       free(session);
+       if (peer) {
+               if (session->state == SESSION_STATE_COMPLETED)
+                       peer->state = WFD_PEER_STATE_CONNECTED;
+               else
+                       peer->state = WFD_PEER_STATE_DISCOVERED;
+       } else {
+               WDS_LOGE("Peer not found");//LCOV_EXCL_LINE
+       }
+
+       g_free(session);
        manager->session = NULL;
        manager->local->wps_mode = WFD_WPS_MODE_PBC;
        manager->autoconnection = 0;
+       memset(manager->auto_pin, 0x0, PINSTR_LEN);
        if (manager->local->dev_role == WFD_DEV_ROLE_GC)
                manager->local->dev_role = WFD_DEV_ROLE_NONE;
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 int wfd_session_start(wfd_session_s *session)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = wfd_get_manager();
        wfd_device_s *peer = NULL;
        int join = 0;
        int res = 0;
 
        if (!session) {
-               WDS_LOGE("Invalid parameter");
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
-       // Check: Invitation Received in Incomming case -> send prov_disc join
-       // Check: User select peer to connect with in Outgoing case -> send prov_disc wps_mdde
+       if (session->state > SESSION_STATE_STARTED) {
+               WDS_LOGE("Invalid session state(%d)", session->state);
+               return -1;
+       }
+
+       /* Check: Invitation Received in Incomming case ->
+        * send prov_disc join
+        *
+        * Check: User select peer to connect with in Outgoing case ->
+        * send prov_disc wps_mode */
 
        wfd_oem_stop_scan(manager->oem_ops);
 
@@ -232,43 +336,81 @@ int wfd_session_start(wfd_session_s *session)
        res = wfd_oem_prov_disc_req(manager->oem_ops, peer->dev_addr,
                                        session->req_wps_mode, join);
        if (res < 0) {
-               WDS_LOGE("Failed to send provision discovery request to peer [" MACSTR "]",
-                                                                       MAC2STR(peer->dev_addr));
+               WDS_LOGD("Failed to send provision discovery request to peer [" MACSECSTR "]",
+                                                                       MAC2SECSTR(peer->dev_addr));
+               wfd_destroy_session(manager);
+               /* TODO: send notification to App */
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+               return -1;
+       }
+
+       wfd_session_timer(session, 1);
+
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+       return 0;
+}
+
+int wfd_session_asp_session_start(wfd_session_s *session, wfd_oem_asp_prov_s *params)
+{
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
+
+       wfd_manager_s *manager = wfd_get_manager();
+       int res = 0;
+
+       if (session == NULL || params == NULL) {
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+               return -1;
+       }
+
+       if (session->state > SESSION_STATE_STARTED) {
+               WDS_LOGE("Invalid session state(%d)", session->state);
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+               return -1;
+       }
+
+       res = wfd_oem_asp_prov_disc_req(manager->oem_ops, params);
+       if (res < 0) {
+               WDS_LOGD("Failed to send ASP provision discovery request to peer");//LCOV_EXCL_LINE
                wfd_destroy_session(manager);
-               // TODO: send notification to App
-               __WDS_LOG_FUNC_EXIT__;
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
+       session->state = SESSION_STATE_STARTED;
+       session->session_id = params->session_id;
+       memcpy(session->session_mac, params->session_mac, MACADDR_LEN);
+       memcpy(session->service_mac, params->service_mac, MACADDR_LEN);
        wfd_session_timer(session, 1);
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
+#if 0
 int wfd_session_stop(wfd_session_s *session)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = wfd_get_manager();
        wfd_device_s *peer = NULL;
        int res = 0;
 
        if (!session) {
                WDS_LOGE("Invalid parameter");
-               __WDS_LOG_FUNC_EXIT__;
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
        if (session->state > SESSION_STATE_CREATED) {
                peer = session->peer;
-               if (session->direction == SESSION_DIRECTION_INCOMING) {
+               if (session->direction == SESSION_DIRECTION_INCOMING)
                        res  = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
-               } else if (session->direction == SESSION_DIRECTION_OUTGOING) {
+               else if (session->direction == SESSION_DIRECTION_OUTGOING)
                        res = wfd_oem_cancel_connection(manager->oem_ops, peer->dev_addr);
-               }
-               if (res < 0) {
+
+                       if (res < 0) {
                        WDS_LOGE("Failed to reject or cancel connection");
-                       __WDS_LOG_FUNC_EXIT__;
+                       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                        return -1;
                }
        }
@@ -276,9 +418,10 @@ int wfd_session_stop(wfd_session_s *session)
        session->state = SESSION_STATE_STOPPED;
        wfd_destroy_session(manager);
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
+#endif
 
 /* In case of incomming session, when user accept connection request, this function should be called.
  * In case of outgoing session, when prov_disc response arrived, this function should be called.
@@ -286,20 +429,20 @@ int wfd_session_stop(wfd_session_s *session)
  */
 int wfd_session_connect(wfd_session_s *session)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = wfd_get_manager();
        wfd_oem_conn_param_s param;
        wfd_device_s *peer = NULL;
        int res = 0;
 
        if (!session) {
-               WDS_LOGE("Invalid parameter");
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
        if (session->state > SESSION_STATE_GO_NEG) {
-               WDS_LOGE("Session already starts GO Negotiation");
+               WDS_LOGE("Session already finished GO Negotiation");//LCOV_EXCL_LINE
                return -1;
        }
 
@@ -311,113 +454,132 @@ int wfd_session_connect(wfd_session_s *session)
        if (peer->dev_role == WFD_DEV_ROLE_GO || session->type == SESSION_TYPE_INVITE)
                param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
        param.go_intent = session->go_intent;
+       if (peer->display.availability)
+               param.go_intent = manager->go_intent_per_type[manager->local->display.type];
        param.freq = session->freq;
-       if (session->wps_pin[0] != '\0') {
-               strncpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN);
-               param.wps_pin[OEM_PINSTR_LEN] = '\0';
-       }
-
+       if (manager->local->group_flags & WFD_GROUP_FLAG_PERSISTENT)
+               param.conn_flags |= WFD_OEM_CONN_TYPE_PERSISTENT;
+
+       if (session->wps_pin[0] != '\0')
+               g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
+
+       /* To connect with windows phone,set go_intent value to 2.
+       *  As windows phone does not connect when local device act as GO.
+       *  WIFI_DIRECT_PRIMARY_DEVICE_TYPE_COMPUTER ==>1 (Assume Peer Device is Windows PC)
+       *  WIFI_DIRECT_SECONDARY_DEVICE_TYPE_TELEPHONE_WINDOWS_MOBILE ==>1
+       *  WIFI_DIRECT_PRIMARY_DEVICE_TYPE_TELEPHONE ==> 10
+       */
+        if ((peer->pri_dev_type == 1) ||
+                                ((peer->pri_dev_type == 10) && (peer->sec_dev_type == 1))) {
+               param.go_intent = 2;
+               WDS_LOGD("go_intent set to %d, Windows device", param.go_intent);
+        }
+
+       WDS_LOGD("connection go_intent: %d", param.go_intent);
        res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
        if (res < 0) {
-               WDS_LOGE("Failed to connect peer [" MACSTR "]", MAC2STR(peer->dev_addr));
+               WDS_LOGD("Failed to connect peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
                wfd_destroy_session(manager);
-               // TODO: send notification to App
-               __WDS_LOG_FUNC_EXIT__;
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
        wfd_session_timer(session, 1);
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 int wfd_session_cancel(wfd_session_s *session, unsigned char *peer_addr)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = wfd_get_manager();
        int res = 0;
 
        if (!session || !session->peer) {
-               WDS_LOGE("Invalid parameter");
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return WIFI_DIRECT_ERROR_NOT_PERMITTED;
        }
 
        if (memcmp(peer_addr, session->peer->dev_addr, MACADDR_LEN)) {
-               WDS_LOGE("Peer is not included in this session");
+               WDS_LOGE("Peer is not included in this session");//LCOV_EXCL_LINE
                return WIFI_DIRECT_ERROR_NOT_PERMITTED;
        }
 
-       if (session->state > SESSION_STATE_GO_NEG)
+       if (manager->local->dev_role == WFD_DEV_ROLE_GO && session->state > SESSION_STATE_GO_NEG)
                res = wfd_oem_wps_cancel(manager->oem_ops);
        else
                res = wfd_oem_cancel_connection(manager->oem_ops, peer_addr);
 
        if (res < 0) {
-               WDS_LOGE("Failed to cancel connection");
+               WDS_LOGE("Failed to cancel connection");//LCOV_EXCL_LINE
                return WIFI_DIRECT_ERROR_OPERATION_FAILED;
        }
 
        wfd_destroy_session(manager);
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 int wfd_session_reject(wfd_session_s *session, unsigned char *peer_addr)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = wfd_get_manager();
        wfd_device_s *peer = NULL;
        int res = 0;
 
-       if (!session) {
-               WDS_LOGE("Invalid parameter");
-               __WDS_LOG_FUNC_EXIT__;
+       if (!session || !manager) {
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
-       if (session->state < SESSION_STATE_STARTED) {
-               WDS_LOGE("Session is not started");
-               __WDS_LOG_FUNC_EXIT__;
+       /* Invite received case state is just created */
+       if (session->state < SESSION_STATE_CREATED ||
+               session->state >= SESSION_STATE_STOPPED) {
+               WDS_LOGE("Session state is Invalid [%d]", session->state);
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
-       if (session->direction != SESSION_DIRECTION_INCOMING) {
-               WDS_LOGE("Cannot reject with outgoing connection");
-               __WDS_LOG_FUNC_EXIT__;
-               return -1;
-       }
+       /*
+        * TODO: check session status and do proper work
+        * for example, reject prov_disc, reject nego, stop wps, etc.
+        *
+        */
 
-       // TODO: check session status and do proper work
-       // for example, reject prov_disc, reject nego, stop wps, etc.
        peer = session->peer;
-       res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
+
+       if (SESSION_TYPE_INVITE == session->type || SESSION_TYPE_JOIN == session->type)
+               res = wfd_oem_wps_cancel(manager->oem_ops);
+       else
+               res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
        if (res < 0) {
-               WDS_LOGE("Failed to reject connection");
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Failed to reject connection");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
        wfd_destroy_session(manager);
-       // TODO: send notification to App
+       /* TODO: send notification to App */
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 int wfd_session_join(wfd_session_s *session)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = wfd_get_manager();
        wfd_oem_conn_param_s param;
        wfd_device_s *peer = NULL;
        int res = 0;
 
        if (!session) {
-               WDS_LOGE("Invalid parameter");
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
@@ -430,26 +592,25 @@ int wfd_session_join(wfd_session_s *session)
                param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
        param.go_intent = session->go_intent;
        param.freq = session->freq;
-       memcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN);
+       g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
 
        res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
        if (res < 0) {
-               WDS_LOGE("Failed to join with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
+               WDS_LOGD("Failed to join with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
                wfd_destroy_session(manager);
-               // TODO: send notification to App
-               __WDS_LOG_FUNC_EXIT__;
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
        wfd_session_timer(session, 1);
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 int wfd_session_invite(wfd_session_s *session)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = wfd_get_manager();
        wfd_oem_invite_param_s param;
        wfd_device_s *peer = NULL;
@@ -457,8 +618,13 @@ int wfd_session_invite(wfd_session_s *session)
        int res = 0;
 
        if (!session) {
-               WDS_LOGE("Invalid parameter");
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+               return -1;
+       }
+
+       if (session->state > SESSION_STATE_CREATED) {
+               WDS_LOGE("Invalid session state(%d)", session->state);
                return -1;
        }
 
@@ -469,38 +635,38 @@ int wfd_session_invite(wfd_session_s *session)
        param.ifname = strdup(group->ifname);
        memcpy(param.go_dev_addr, group->go_dev_addr, MACADDR_LEN);
 
-       WDS_LOGD("Invite: Peer[" MACSTR "], GO Addr[" MACSTR "]", MAC2STR(peer->dev_addr), MAC2STR(param.go_dev_addr));
+       WDS_LOGD("Invite: Peer[" MACSTR "], GO Addr[" MACSTR "]",
+                               MAC2STR(peer->dev_addr), MAC2STR(param.go_dev_addr));
 
        res = wfd_oem_invite(manager->oem_ops, peer->dev_addr, &param);
        if (res < 0) {
-               WDS_LOGE("Failed to invite with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
+               WDS_LOGE("Failed to invite with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
                wfd_destroy_session(manager);
-               // TODO: send notification to App
-               __WDS_LOG_FUNC_EXIT__;
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
        wfd_session_timer(session, 1);
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 int wfd_session_wps(wfd_session_s *session)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_manager_s *manager = wfd_get_manager();
        wfd_device_s *peer = NULL;
        int res = 0;
 
        if (!session) {
-               WDS_LOGE("Invalid parameter");
-               __WDS_LOG_FUNC_EXIT__;
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
        if (session->state > SESSION_STATE_WPS) {
-               WDS_LOGE("Session already starts WPS");
+               WDS_LOGE("Session already starts WPS");//LCOV_EXCL_LINE
                return -1;
        }
 
@@ -512,274 +678,515 @@ int wfd_session_wps(wfd_session_s *session)
                res = wfd_oem_wps_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
        } else {
                WDS_LOGD("My device is not GO, so Enrollee will be started. WPS mode[%d]", session->wps_mode);
-               res = wfd_oem_enrollee_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
+               wfd_oem_conn_param_s param;
+               memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
+               param.wps_mode = session->wps_mode;
+               param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
+               param.freq = session->freq;     /* currently not used */
+               g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
+               res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
        }
        if (res < 0) {
-               WDS_LOGE("Failed to start wps with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
+               WDS_LOGE("Failed to start wps with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
                wfd_destroy_session(manager);
-               // TODO: send notification to App
-               __WDS_LOG_FUNC_EXIT__;
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
                return -1;
        }
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+       return 0;
+}
+
+/* In case of incomming session, when user accept connection request, this function should be called.
+ * In case of outgoing session, when prov_disc response arrived, this function should be called.
+ * Even though peer is GO, we can use this function, which can decide using join itself.
+ */
+int wfd_session_asp_connect(wfd_session_s *session, int role)
+{
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
+       wfd_manager_s *manager = wfd_get_manager();
+       wfd_oem_conn_param_s param;
+       wfd_device_s *peer = NULL;
+       int res = 0;
+
+       if (!session) {
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+               return -1;
+       }
+
+       if (session->state >= SESSION_STATE_GO_NEG) {
+               WDS_LOGE("Session already starting GO Negotiation");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+               return -1;
+       }
+
+       if (role == WFD_OEM_ASP_SESSION_ROLE_GO) {
+               session->state = SESSION_STATE_WPS;
+               return 0;
+       } else {
+               session->state = SESSION_STATE_GO_NEG;
+       }
+
+       peer = session->peer;
+
+       memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
+       param.wps_mode = session->wps_mode;
+       if (role == 2)
+               param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
+       param.go_intent = session->go_intent;
+       param.freq = session->freq;
+       param.conn_flags |= WFD_OEM_CONN_TYPE_PERSISTENT;
+
+       if (session->wps_pin[0] != '\0')
+               g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
+
+       res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
+       if (res < 0) {
+               WDS_LOGD("Failed to connect peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
+               wfd_destroy_session(manager);
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+               return -1;
+       }
+
+       wfd_session_timer(session, 1);
+
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+       return 0;
+}
+
+/* In case of incomming session, when user accept connection request, this function should be called.
+ * In case of outgoing session, when prov_disc response arrived, this function should be called.
+ * Even though peer is GO, we can use this function, which can decide using join itself.
+ */
+int wfd_session_asp_persistent_connect(wfd_session_s *session, int persist_group_id)
+{
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
+       wfd_manager_s *manager = wfd_get_manager();
+       wfd_oem_group_param_s param;
+       int res = 0;
+
+       if (!session) {
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+               return -1;
+       }
+
+       if (session->state > SESSION_STATE_GO_NEG) {
+               WDS_LOGE("Session already finished GO Negotiation");//LCOV_EXCL_LINE
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+               return -1;
+       }
+
+       session->state = SESSION_STATE_WPS;
+
+       memset(&param, 0x0, sizeof(param));
+       param.persistent = 2;
+       param.persistent_group_id = persist_group_id;
+
+       res = wfd_oem_create_group(manager->oem_ops, &param);
+       if (res < 0) {
+               WDS_LOGD("Failed to create persistent group for ASP");//LCOV_EXCL_LINE
+               wfd_destroy_session(manager);
+               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+               return -1;
+       }
+
+       wfd_session_timer(session, 1);
+
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 wfd_device_s *wfd_session_get_peer(wfd_session_s *session)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_device_s *peer = NULL;
 
        if (!session) {
-               WDS_LOGE("Invalid parameter");
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
                return NULL;
        }
-       
+
        peer = session->peer;
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return peer;
 }
 
 unsigned char *wfd_session_get_peer_addr(wfd_session_s *session)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_device_s *peer = NULL;
 
        if (!session || !session->peer) {
-               WDS_LOGE("Invalid parameter");
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
                return NULL;
        }
-       
+
        peer = session->peer;
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return peer->dev_addr;
 }
 
+#if 0
 int wfd_session_get_wps_pin(wfd_session_s *session, unsigned char *pin)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 int wfd_session_set_wps_pin(wfd_session_s *session, unsigned char *pin)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 int wfd_session_set_freq(wfd_session_s *session, int freq)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 int wfd_session_get_state(wfd_session_s *session)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
 
 int wfd_session_set_state(wfd_session_s *session, int state)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
 
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }
+#endif
 
 int wfd_session_process_event(wfd_manager_s *manager, wfd_oem_event_s *event)
 {
-       __WDS_LOG_FUNC_ENTER__;
+       __WDS_LOG_FUNC_ENTER__;//LCOV_EXCL_LINE
        wfd_session_s *session = NULL;
+       int res = 0;
 
        if (!manager || !event) {
-               WDS_LOGE("Invalid parameter");
+               WDS_LOGE("Invalid parameter");//LCOV_EXCL_LINE
                return -1;
        }
 
-       wfd_dev_connection_flag_e flag = 0;
-       flag = wfd_manager_access_control(manager, event->dev_addr);
-
        WDS_LOGD("event ID [%d]", event->event_id);
        session = manager->session;
 
        switch (event->event_id) {
        case WFD_OEM_EVENT_PROV_DISC_REQ:
        {
+               int req_wps_mode = WFD_WPS_MODE_NONE;
+
+               if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
+                       req_wps_mode = WFD_WPS_MODE_KEYPAD;
+               else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
+                       req_wps_mode = WFD_WPS_MODE_DISPLAY;
+               else
+                       req_wps_mode = WFD_WPS_MODE_PBC;
+
+               /* Only peer initiated connection or invitation session can be allowed */
                if (session) {
-                       WDS_LOGE("Unexpected event. Session already exist. This request should be ignored");
-                       break;
-               }
+                       if (session->type != SESSION_TYPE_INVITE) {
+                               WDS_LOGE("Unexpected event. Session is exist [peer: " MACSECSTR "]",
+                                                               MAC2SECSTR(event->dev_addr));
+                               break;
+                       }
+                       WDS_LOGD("=====> session already exist. (invitation session)");//LCOV_EXCL_LINE
+                       if (session->state > SESSION_STATE_WPS) {
+                               WDS_LOGE("Session already starts WPS");//LCOV_EXCL_LINE
+                               break;
+                       }
 
-               /* Create new session */
-               session = wfd_create_session(manager, event->dev_addr,
-                                               event->wps_mode, SESSION_DIRECTION_INCOMING);
-               if (!session) {
-                       WDS_LOGE("Failed to create session with peer [" MACSTR "]",
-                                               MAC2STR(event->dev_addr));
-                       break;
+                       session->req_wps_mode = req_wps_mode;
+                       session->wps_mode = event->wps_mode;
+               } else {
+                       session = wfd_create_session(manager, event->dev_addr,
+                                                               req_wps_mode, SESSION_DIRECTION_INCOMING);
+                       if (!session) {
+                               WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
+                                                               MAC2SECSTR(event->dev_addr));
+                               break;
+                       }
                }
 
                /* Update session */
-               if (event->wps_mode == WFD_OEM_WPS_MODE_DISPLAY) {
-                       strncpy(session->wps_pin, event->wps_pin, PINSTR_LEN);
-                       session->wps_pin[PINSTR_LEN] = '\0';
-               }
+               if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
+                       g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
+
                session->state = SESSION_STATE_STARTED;
+               if (session->type == SESSION_TYPE_INVITE)
+                       WDS_LOGD("Invitation session");//LCOV_EXCL_LINE
+               else if (WFD_DEV_ROLE_GO == manager->local->dev_role)
+                       session->type = SESSION_TYPE_JOIN;
+               else
+                       session->type = SESSION_TYPE_NORMAL;
+
                wfd_session_timer(session, 1);
 
-               /* Update manager */
+               /* Update local device */
                manager->local->wps_mode = event->wps_mode;
+
                wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
+               wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_CONNECTING);
 
-               if(flag == WFD_DEV_ALLOWED)
-               {
-                       WDS_LOGD("device is allowed");
-                       if (manager->local->dev_role == WFD_DEV_ROLE_GO)
-                               wfd_session_wps(session);
-                       else
-                               wfd_session_connect(session);
-
-               }else {
-                       /* Send event to application */
-                       WDS_LOGD("device is not in access/deny list");
-                       wifi_direct_client_noti_s noti;
-                       memset(&noti, 0x0, sizeof(wifi_direct_client_noti_s));
-                       noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_REQ;
-                       noti.error = WIFI_DIRECT_ERROR_NONE;
-                       snprintf(noti.param1, sizeof(noti.param1), MACSTR, MAC2STR(event->dev_addr));
-                       wfd_client_send_event(manager, &noti);
+               if (session->type == SESSION_TYPE_INVITE) {
+                       WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
+                       if (session->wps_mode != WFD_WPS_MODE_PBC) {
+                               char peer_mac_address[MACSTR_LEN+1] = {0, };
+
+                               g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
+                               wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
+                                                            "Connection",
+                                                            g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
+                                                                                   WFD_EVENT_CONNECTION_WPS_REQ,
+                                                                                   peer_mac_address));
+                               if (session->wps_mode == WFD_WPS_MODE_KEYPAD) {
+                                       /* We have to wait until user type PIN using Keypad */
+                                       break;
+                               }
+                       }
+                       res = wfd_session_wps(session);
+                       if (res < 0)
+                               _wfd_notify_session_failed(manager, event->dev_addr);
+               } else {
+                       char peer_mac_address[MACSTR_LEN+1] = {0, };
+
+                       g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
+                       wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
+                                                    "Connection",
+                                                    g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
+                                                                           WFD_EVENT_CONNECTION_REQ,
+                                                                           peer_mac_address));
                }
        }
        break;
        case WFD_OEM_EVENT_PROV_DISC_RESP:
        {
-               if (!session) {
-                       WDS_LOGE("Unexpected event. Session not exist. This response should be ignored");
+               if (!session) {         /* TODO: check validity of Event */
+                       WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
+                                                                               MAC2SECSTR(event->dev_addr));
                        break;
                }
 
                if (session->state > SESSION_STATE_STARTED) {
-                       WDS_LOGE("Unexpected event. Session is already started");
+                       WDS_LOGE("Unexpected event. Session is already started");//LCOV_EXCL_LINE
+                       break;
+               }
+
+               if (session->type == SESSION_TYPE_INVITE) {
+                       WDS_LOGE("Session type is invite, ignore provision discovery response");//LCOV_EXCL_LINE
                        break;
                }
 
                /* Update session */
-               if (event->wps_mode == WFD_OEM_WPS_MODE_DISPLAY) {
+               session->wps_mode = event->wps_mode;
+               if (event->wps_mode == WFD_WPS_MODE_DISPLAY) {
                        session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
-                       strncpy(session->wps_pin, event->wps_pin, PINSTR_LEN);
-                       session->wps_pin[PINSTR_LEN] = '\0';
-               } else if (event->wps_mode == WFD_OEM_WPS_MODE_KEYPAD) {
+                       g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
+               } else if (event->wps_mode == WFD_WPS_MODE_KEYPAD) {
                        session->req_wps_mode = WFD_WPS_MODE_DISPLAY;
                } else {
                        session->req_wps_mode = WFD_WPS_MODE_PBC;
                }
-               session->wps_mode = event->wps_mode;
+
+               session->state = SESSION_STATE_STARTED;
                wfd_session_timer(session, 1);
 
-               /* Update manager */
+               /* Update local device */
                manager->local->wps_mode = event->wps_mode;
                WDS_LOGD("Local WPS mode is %d", session->wps_mode);
 
-               if (event->wps_mode != WFD_OEM_WPS_MODE_PBC) {
-                       /* Notify WPS_MODE to application so it can display PIN or KEYPAD */
-                       wifi_direct_client_noti_s noti;
-                       memset(&noti, 0x0, sizeof(wifi_direct_client_noti_s));
-                       noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_WPS_REQ;
-                       snprintf(noti.param1, sizeof(noti.param1), MACSTR, MAC2STR(event->dev_addr));
-                       wfd_client_send_event(manager, &noti);
-                       if (session->wps_mode == WFD_WPS_MODE_KEYPAD)
+               if (session->wps_mode != WFD_WPS_MODE_PBC) {
+                       char peer_mac_address[MACSTR_LEN+1] = {0, };
+
+                       g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
+                       wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
+                                                    "Connection",
+                                                    g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
+                                                                           WFD_EVENT_CONNECTION_WPS_REQ,
+                                                                           peer_mac_address));
+                       if (session->wps_mode == WFD_WPS_MODE_KEYPAD) {
+                               /* We have to wait until user type PIN using Keypad */
                                break;
+                       }
                }
 
-               /* Go to next step of connection immediately */
-               if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
-                       WDS_LOGD("Start joining corresponding to OEM event [%d]", event->event_id);
-                       wfd_session_join(session);
-               } else if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
+               if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
                        WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
-                       wfd_session_wps(session);
+                       res = wfd_session_wps(session);
+               } else if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
+                       WDS_LOGD("Start WPS(join) corresponding to OEM event [%d]", event->event_id);
+                       res = wfd_session_join(session);
                } else {
                        WDS_LOGD("Start connection corresponding to OEM event [%d]", event->event_id);
-                       wfd_session_connect(session);
+                       res = wfd_session_connect(session);
                }
+
+               if (res < 0)
+                       _wfd_notify_session_failed(manager, event->dev_addr);
        }
        break;
        case WFD_OEM_EVENT_GO_NEG_REQ:
-               if (!session) {         // TODO: check whether connection is started by negotiation not by prov_disc
-                       WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
-                       break;
+       {
+               if (!session) {
+                       session = wfd_create_session(manager, event->dev_addr,
+                                       event->wps_mode, SESSION_DIRECTION_INCOMING);
+                       if (!session) {
+                               WDS_LOGE("Failed to create session");//LCOV_EXCL_LINE
+                               __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
+                               break;
+                       }
+
+                       session->type = SESSION_TYPE_NORMAL;
+                       session->state = SESSION_STATE_GO_NEG;
+                       wfd_session_timer(session, 1);
+                       wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
+                       wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_CONNECTING);
+
+                       if (manager->autoconnection == TRUE) {
+                               /**
+                                * TODO: Add autoconnection peer matching logic.
+                                */
+                               /**
+                                * In autoconnection mode, connection request notification
+                                * should not be sent to library.
+                                */
+                               res  = wfd_session_connect(session);
+                       } else {
+                               char peer_mac_address[MACSTR_LEN+1] = {0, };
+                               g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
+                               wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
+                                                            "Connection",
+                                                            g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
+                                                                          WFD_EVENT_CONNECTION_REQ,
+                                                                          peer_mac_address));
+                       }
                } else {
                        /* Sometimes, Provision Discovery response is not received.
                         * At this time, connection should be triggered by GO Negotiation request event */
-                       if (session->direction == SESSION_DIRECTION_OUTGOING)
-                               wfd_session_connect(session);
+                       if (session->direction == SESSION_DIRECTION_OUTGOING) {
+                               if (session->wps_mode == WFD_WPS_MODE_KEYPAD && session->wps_pin[0] == '\0')
+                                       break;
+                               res = wfd_session_connect(session);
+                       } else {
+                               /**
+                                * TODO: Add autoconnection peer matching logic.
+                                */
+                               /**
+                                * In autoconnection mode, MT should not send GO Nego Req
+                                * before receiving the GO Nego Req from peer (MO).
+                                */
+                               if (manager->autoconnection == TRUE)
+                                       res  = wfd_session_connect(session);
+                       }
+                       if (res < 0)
+                               _wfd_notify_session_failed(manager, event->dev_addr);
                }
-               break;
+       }
+       break;
        case WFD_OEM_EVENT_GO_NEG_DONE:
+       {
                if (!session) {
-                       WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
+                       WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
+                                       MAC2SECSTR(event->dev_addr));
                        break;
                } else {
+                       manager->local->dev_role = event->dev_role;
                        session->state = SESSION_STATE_WPS;
                }
-               
-               break;
+       }
+       break;
        case WFD_OEM_EVENT_WPS_DONE:
+       {
                if (!session) {
-                       WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
+                       WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
+                                       MAC2SECSTR(event->dev_addr));
                        break;
                } else {
                        session->state = SESSION_STATE_KEY_NEG;
                }
-               
-               break;
-       case WFD_OEM_EVENT_CONNECTED:
+       }
+       break;
+       case WFD_OEM_EVENT_STA_CONNECTED:
        {
                if (!session) {
-                       WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
+                       WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
+                                       MAC2SECSTR(event->dev_addr));
                        break;
                } else {
-                       wfd_group_s *group = manager->group;
-                       if (!group) {
-                               group = wfd_create_pending_group(manager, event->intf_addr);
-                               if (!group) {
-                                       WDS_LOGE("Failed to create pending group");
-                                       break;
-                               }
-                               manager->group = group;
-                       } else {        // multiconnection, additional client connected
-                               WDS_LOGE("Unexpected event. Group already exist");
-                               //wfd_group_add_member(manager, event->intf_addr, peer->dev_addr);
-                               break;
-                       }
                        session->state = SESSION_STATE_COMPLETED;
                }
        }
-       break;
-       case WFD_OEM_EVENT_STA_CONNECTED:
+               break;
+       case WFD_OEM_EVENT_ASP_PROV_START:
+       {
+               int req_wps_mode = WFD_WPS_MODE_NONE;
+
+               if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
+                       req_wps_mode = WFD_WPS_MODE_KEYPAD;
+               else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
+                       req_wps_mode = WFD_WPS_MODE_DISPLAY;
+               else
+                       req_wps_mode = WFD_WPS_MODE_P2PS;
+
+               session = wfd_create_session(manager, event->dev_addr,
+                               req_wps_mode, SESSION_DIRECTION_INCOMING);
                if (!session) {
-                       WDS_LOGD("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
+                       WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
+                                                       MAC2SECSTR(event->dev_addr));
                        break;
-               } else {
-                       session->state = SESSION_STATE_COMPLETED;
                }
-               
+
+               /* Update session */
+               if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
+                       g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
+
+               session->state = SESSION_STATE_STARTED;
+               wfd_session_timer(session, 1);
+       }
+               break;
+       case WFD_OEM_EVENT_ASP_PROV_DONE:
+       {
+               int req_wps_mode = WFD_WPS_MODE_NONE;
+
+               if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
+                       req_wps_mode = WFD_WPS_MODE_KEYPAD;
+               else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
+                       req_wps_mode = WFD_WPS_MODE_DISPLAY;
+               else
+                       req_wps_mode = WFD_WPS_MODE_P2PS;
+
+               session = (wfd_session_s*) manager->session;
+               if (!session) {
+                       session = wfd_create_session(manager, event->dev_addr,
+                                       req_wps_mode, SESSION_DIRECTION_INCOMING);
+                       if (!session) {
+                               WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
+                                                               MAC2SECSTR(event->dev_addr));
+                               break;
+                       }
+                       session->state = SESSION_STATE_STARTED;
+                       wfd_session_timer(session, 1);
+               }
+       }
                break;
        default:
                break;
        }
-       __WDS_LOG_FUNC_EXIT__;
+       __WDS_LOG_FUNC_EXIT__;//LCOV_EXCL_LINE
        return 0;
 }