Modify the cmake files
[platform/core/connectivity/wifi-direct-manager.git] / src / wifi-direct-session.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 /**
21  * This file implements wifi direct session functions.
22  *
23  * @file                wifi-direct-session.c
24  * @author      Gibyoung Kim (lastkgb.kim@samsung.com)
25  * @version     0.7
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <glib.h>
33
34 #include <wifi-direct.h>
35
36 #include "wifi-direct-ipc.h"
37 #include "wifi-direct-manager.h"
38 #include "wifi-direct-oem.h"
39 #include "wifi-direct-peer.h"
40 #include "wifi-direct-group.h"
41 #include "wifi-direct-oem.h"
42 #include "wifi-direct-util.h"
43 #include "wifi-direct-session.h"
44 #include "wifi-direct-state.h"
45 #include "wifi-direct-error.h"
46 #include "wifi-direct-log.h"
47 #include "wifi-direct-dbus.h"
48 #include "wifi-direct-asp.h"
49
50
51 static gboolean _session_timeout_cb(gpointer *user_data)
52 {
53         __WDS_LOG_FUNC_ENTER__;
54         wfd_manager_s *manager = wfd_get_manager();
55         wfd_session_s *session = (wfd_session_s*) manager->session;
56         unsigned char *peer_addr = NULL;
57         char peer_mac_address[MACSTR_LEN+1] = {0, };
58
59         if (!session) {
60                 WDS_LOGE("Invalid parameter");
61                 return FALSE;
62         }
63         session->connecting_120 = 0;
64         session->timer = 0;
65         WDS_LOGD("Session timer expired");
66
67         peer_addr = wfd_session_get_peer_addr(session);
68         if (peer_addr != NULL)
69                 g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(peer_addr));
70         else
71                 g_snprintf(peer_mac_address, MACSTR_LEN, "%s", "");
72
73         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
74                                      "Connection",
75                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_CONNECTION_TIME_OUT,
76                                                             WFD_EVENT_CONNECTION_RSP,
77                                                             peer_mac_address));
78
79         if (wfd_asp_is_asp_session(session)) {
80                 if (session->state < SESSION_STATE_GO_NEG)
81                         wfd_asp_connect_status(session->session_mac,
82                                         session->session_id,
83                                         ASP_CONNECT_STATUS_REQUEST_FAILED,
84                                         NULL);
85                 else
86                         wfd_asp_connect_status(session->session_mac,
87                                         session->session_id,
88                                         ASP_CONNECT_STATUS_GROUP_FORMATION_FAILED,
89                                         NULL);
90         }
91
92         wfd_session_cancel(session, peer_addr);
93
94         if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
95
96                 wfd_group_s *group = (wfd_group_s*) manager->group;
97                 if (group && wfd_util_is_remove_group_allowed()) {
98                         wfd_oem_destroy_group(manager->oem_ops, group->ifname);
99                 } else {
100                         wfd_state_set(manager, WIFI_DIRECT_STATE_GROUP_OWNER);
101                         wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_GROUP_OWNER);
102                 }
103         } else {
104                 wfd_state_set(manager, WIFI_DIRECT_STATE_ACTIVATED);
105                 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_ACTIVATED);
106         }
107
108         __WDS_LOG_FUNC_EXIT__;
109         return FALSE;
110 }
111
112 static void _wfd_notify_session_failed(wfd_manager_s *manager, unsigned char *peer_addr)
113 {
114         __WDS_LOG_FUNC_ENTER__;
115         char peer_mac_address[MACSTR_LEN+1] = {0, };
116
117         snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(peer_addr));
118         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
119                                      "Connection",
120                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_CONNECTION_FAILED,
121                                                             WFD_EVENT_CONNECTION_RSP,
122                                                             peer_mac_address));
123
124
125
126         wfd_session_s *session = manager->session;
127         if (wfd_asp_is_asp_session(session)) {
128                 wfd_asp_connect_status(session->session_mac,
129                                                         session->session_id,
130                                                         ASP_CONNECT_STATUS_GROUP_FORMATION_STARTED,
131                                                         NULL);
132         }
133
134         if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
135                 wfd_state_set(manager, WIFI_DIRECT_STATE_GROUP_OWNER);
136                 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_GROUP_OWNER);
137         } else {
138                 wfd_state_set(manager, WIFI_DIRECT_STATE_ACTIVATED);
139                 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_ACTIVATED);
140         }
141
142         __WDS_LOG_FUNC_EXIT__;
143 }
144
145 int wfd_session_timer(wfd_session_s *session, int start)
146 {
147         __WDS_LOG_FUNC_ENTER__;
148
149         if (!session) {
150                 WDS_LOGE("Invalid parameter");
151                 __WDS_LOG_FUNC_EXIT__;
152                 return -1;
153         }
154
155         if (start) {
156                 if (!session->connecting_120)
157                         session->connecting_120 = 1;
158
159                 if (session->timer > 0) {
160                         WDS_LOGE("Session timer already started");
161                         __WDS_LOG_FUNC_EXIT__;
162                         return -1;
163                 }
164                 session->timer = g_timeout_add(120000,
165                                                 (GSourceFunc) _session_timeout_cb,
166                                                 NULL);
167                 WDS_LOGD("Session timer started");
168         } else {
169                 session->connecting_120 = 0;
170                 if (session->timer > 0) {
171                         g_source_remove(session->timer);
172                         session->timer = 0;
173                         WDS_LOGD("Session timer stoped");
174                 }
175         }
176
177         __WDS_LOG_FUNC_EXIT__;
178         return 0;
179 }
180
181 /* Check the session instance which has same peer address,
182  * before using this function */
183 wfd_session_s *wfd_create_session(void *data, unsigned char *peer_addr, int wps_mode, int direction)
184 {
185         __WDS_LOG_FUNC_ENTER__;
186         wfd_manager_s *manager = (wfd_manager_s*) data;
187         wfd_session_s *session = NULL;
188         wfd_device_s *peer = NULL;
189
190         if (!data || !peer_addr) {
191                 WDS_LOGE("Invalid parameter");
192                 __WDS_LOG_FUNC_EXIT__;
193                 return NULL;
194         }
195
196         WDS_LOGD("create session for peer[" MACSTR "]", MAC2STR(peer_addr));
197
198         if (manager->session) {
199                 WDS_LOGE("Session already exist");
200                 return NULL;
201         }
202
203         session = (wfd_session_s*) g_try_malloc0(sizeof(wfd_session_s));
204         if (!session) {
205                 WDS_LOGE("Failed to allocate memory for session");
206                 __WDS_LOG_FUNC_EXIT__;
207                 return NULL;
208         }
209
210         peer = wfd_peer_find_by_dev_addr(manager, peer_addr);
211         if (!peer) {
212                 WDS_LOGE("Failed to find peer info[" MACSECSTR "]", MAC2SECSTR(peer_addr));
213                 g_free(session);
214                 __WDS_LOG_FUNC_EXIT__;
215                 return NULL;
216         }
217         peer->state = WFD_PEER_STATE_CONNECTING;
218
219         session->peer = peer;
220         session->req_wps_mode = wps_mode;
221         if (wps_mode == WFD_WPS_MODE_DISPLAY)
222                 session->wps_mode = WFD_WPS_MODE_KEYPAD;
223         else if (wps_mode == WFD_WPS_MODE_KEYPAD)
224                 session->wps_mode = WFD_WPS_MODE_DISPLAY;
225         else if (wps_mode == WFD_WPS_MODE_P2PS)
226                 session->wps_mode = WFD_WPS_MODE_P2PS;
227         else
228                 session->wps_mode = wps_mode;
229         session->direction = direction;
230         session->state = SESSION_STATE_CREATED;
231
232         manager->session = session;
233         manager->local->wps_mode = session->wps_mode;
234
235         if (peer->dev_role == WFD_DEV_ROLE_GO &&
236                         manager->local->wps_mode == WFD_WPS_MODE_DISPLAY) {
237                         char *generated_pin = NULL;
238                         session->wps_mode = WFD_WPS_MODE_DISPLAY;
239                         session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
240
241                         if (wfd_oem_generate_pin(manager->oem_ops, &generated_pin) != 0) {
242                                 WDS_LOGE("Failed to generate pin");
243                                 g_free(session);
244                                 __WDS_LOG_FUNC_EXIT__;
245                                 return NULL;
246                         }
247
248                         g_strlcpy(session->wps_pin, generated_pin, PINSTR_LEN + 1);
249                         g_free(generated_pin);
250         }
251
252         if (peer->dev_role == WFD_DEV_ROLE_GO && manager->local->dev_role != WFD_DEV_ROLE_GO)
253                 manager->local->dev_role = WFD_DEV_ROLE_GC;
254
255         __WDS_LOG_FUNC_EXIT__;
256         return session;
257 }
258
259 int wfd_destroy_session(void *data)
260 {
261         __WDS_LOG_FUNC_ENTER__;
262         wfd_manager_s *manager = (wfd_manager_s*) data;
263         wfd_session_s *session = NULL;
264         wfd_device_s *peer = NULL;
265
266         if (!manager) {
267                 WDS_LOGE("Invalid parameter");
268                 return -1;
269         }
270
271         session = (wfd_session_s*) manager->session;
272         if (!session) {
273                 WDS_LOGE("Session not found");  /* self prevent */
274                 return -1;
275         }
276         wfd_session_timer(session, 0);
277         peer = session->peer;
278         WDS_LOGD("peer :%p", peer);
279
280         if (peer) {
281                 if (session->state == SESSION_STATE_COMPLETED)
282                         peer->state = WFD_PEER_STATE_CONNECTED;
283                 else
284                         peer->state = WFD_PEER_STATE_DISCOVERED;
285         } else {
286                 WDS_LOGE("Peer not found");
287         }
288
289         g_free(session);
290         manager->session = NULL;
291         manager->local->wps_mode = WFD_WPS_MODE_PBC;
292         manager->autoconnection = 0;
293         memset(manager->auto_pin, 0x0, PINSTR_LEN);
294         if (manager->local->dev_role == WFD_DEV_ROLE_GC)
295                 manager->local->dev_role = WFD_DEV_ROLE_NONE;
296
297         __WDS_LOG_FUNC_EXIT__;
298         return 0;
299 }
300
301 int wfd_session_start(wfd_session_s *session)
302 {
303         __WDS_LOG_FUNC_ENTER__;
304         wfd_manager_s *manager = wfd_get_manager();
305         wfd_device_s *peer = NULL;
306         int join = 0;
307         int res = 0;
308
309         if (!session) {
310                 WDS_LOGE("Invalid parameter");
311                 __WDS_LOG_FUNC_EXIT__;
312                 return -1;
313         }
314
315         if (session->state > SESSION_STATE_STARTED) {
316                 WDS_LOGE("Invalid session state(%d)", session->state);
317                 return -1;
318         }
319
320         /* Check: Invitation Received in Incomming case ->
321          * send prov_disc join
322          *
323          * Check: User select peer to connect with in Outgoing case ->
324          * send prov_disc wps_mode */
325
326         wfd_oem_stop_scan(manager->oem_ops);
327
328         session->state = SESSION_STATE_STARTED;
329         peer = session->peer;
330         if (peer->dev_role == WFD_DEV_ROLE_GO || session->type == SESSION_TYPE_INVITE)
331                 join = 1;
332         res = wfd_oem_prov_disc_req(manager->oem_ops, peer->dev_addr,
333                                         session->req_wps_mode, join);
334         if (res < 0) {
335                 WDS_LOGD("Failed to send provision discovery request to peer [" MACSECSTR "]",
336                                                                         MAC2SECSTR(peer->dev_addr));
337                 wfd_destroy_session(manager);
338                 /* TODO: send notification to App */
339                 __WDS_LOG_FUNC_EXIT__;
340                 return -1;
341         }
342
343         wfd_session_timer(session, 1);
344
345         __WDS_LOG_FUNC_EXIT__;
346         return 0;
347 }
348
349 int wfd_session_asp_session_start(wfd_session_s *session, wfd_oem_asp_prov_s *params)
350 {
351         __WDS_LOG_FUNC_ENTER__;
352
353         wfd_manager_s *manager = wfd_get_manager();
354         int res = 0;
355
356         if (session == NULL || params == NULL) {
357                 WDS_LOGE("Invalid parameter");
358                 __WDS_LOG_FUNC_EXIT__;
359                 return -1;
360         }
361
362         if (session->state > SESSION_STATE_STARTED) {
363                 WDS_LOGE("Invalid session state(%d)", session->state);
364                 __WDS_LOG_FUNC_EXIT__;
365                 return -1;
366         }
367
368         res = wfd_oem_asp_prov_disc_req(manager->oem_ops, params);
369         if (res < 0) {
370                 WDS_LOGD("Failed to send ASP provision discovery request to peer");
371                 wfd_destroy_session(manager);
372                 __WDS_LOG_FUNC_EXIT__;
373                 return -1;
374         }
375
376         session->state = SESSION_STATE_STARTED;
377         session->session_id = params->session_id;
378         memcpy(session->session_mac, params->session_mac, MACADDR_LEN);
379         memcpy(session->service_mac, params->service_mac, MACADDR_LEN);
380         wfd_session_timer(session, 1);
381
382         __WDS_LOG_FUNC_EXIT__;
383         return 0;
384 }
385
386 #if 0
387 int wfd_session_stop(wfd_session_s *session)
388 {
389         __WDS_LOG_FUNC_ENTER__;
390         wfd_manager_s *manager = wfd_get_manager();
391         wfd_device_s *peer = NULL;
392         int res = 0;
393
394         if (!session) {
395                 WDS_LOGE("Invalid parameter");
396                 __WDS_LOG_FUNC_EXIT__;
397                 return -1;
398         }
399
400         if (session->state > SESSION_STATE_CREATED) {
401                 peer = session->peer;
402                 if (session->direction == SESSION_DIRECTION_INCOMING)
403                         res  = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
404                 else if (session->direction == SESSION_DIRECTION_OUTGOING)
405                         res = wfd_oem_cancel_connection(manager->oem_ops, peer->dev_addr);
406
407                         if (res < 0) {
408                         WDS_LOGE("Failed to reject or cancel connection");
409                         __WDS_LOG_FUNC_EXIT__;
410                         return -1;
411                 }
412         }
413
414         session->state = SESSION_STATE_STOPPED;
415         wfd_destroy_session(manager);
416
417         __WDS_LOG_FUNC_EXIT__;
418         return 0;
419 }
420 #endif
421
422 /* In case of incomming session, when user accept connection request, this function should be called.
423  * In case of outgoing session, when prov_disc response arrived, this function should be called.
424  * Even though peer is GO, we can use this function, which can decide using join itself.
425  */
426 int wfd_session_connect(wfd_session_s *session)
427 {
428         __WDS_LOG_FUNC_ENTER__;
429         wfd_manager_s *manager = wfd_get_manager();
430         wfd_oem_conn_param_s param;
431         wfd_device_s *peer = NULL;
432         int res = 0;
433
434         if (!session) {
435                 WDS_LOGE("Invalid parameter");
436                 __WDS_LOG_FUNC_EXIT__;
437                 return -1;
438         }
439
440         if (session->state > SESSION_STATE_GO_NEG) {
441                 WDS_LOGE("Session already finished GO Negotiation");
442                 return -1;
443         }
444
445         session->state = SESSION_STATE_GO_NEG;
446         peer = session->peer;
447
448         memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
449         param.wps_mode = session->wps_mode;
450         if (peer->dev_role == WFD_DEV_ROLE_GO || session->type == SESSION_TYPE_INVITE)
451                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
452         param.go_intent = session->go_intent;
453         param.freq = session->freq;
454         if (manager->local->group_flags & WFD_GROUP_FLAG_PERSISTENT)
455                 param.conn_flags |= WFD_OEM_CONN_TYPE_PERSISTENT;
456
457         if (session->wps_pin[0] != '\0')
458                 g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
459
460         /* To connect with windows phone,set go_intent value to 2.
461         *  As windows phone does not connect when local device act as GO.
462         *  WIFI_DIRECT_PRIMARY_DEVICE_TYPE_COMPUTER ==>1 (Assume Peer Device is Windows PC)
463         *  WIFI_DIRECT_SECONDARY_DEVICE_TYPE_TELEPHONE_WINDOWS_MOBILE ==>1
464         *  WIFI_DIRECT_PRIMARY_DEVICE_TYPE_TELEPHONE ==> 10
465         */
466          if ((peer->pri_dev_type == 1) ||
467                                  ((peer->pri_dev_type == 10) && (peer->sec_dev_type == 1))) {
468                 param.go_intent = 2;
469                 WDS_LOGD("go_intent set to %d, Windows device", param.go_intent);
470          }
471
472         WDS_LOGD("connection go_intent: %d", param.go_intent);
473         res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
474         if (res < 0) {
475                 WDS_LOGD("Failed to connect peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
476                 wfd_destroy_session(manager);
477                 __WDS_LOG_FUNC_EXIT__;
478                 return -1;
479         }
480
481         wfd_session_timer(session, 1);
482
483         __WDS_LOG_FUNC_EXIT__;
484         return 0;
485 }
486
487 int wfd_session_cancel(wfd_session_s *session, unsigned char *peer_addr)
488 {
489         __WDS_LOG_FUNC_ENTER__;
490         wfd_manager_s *manager = wfd_get_manager();
491         int res = 0;
492
493         if (!session || !session->peer) {
494                 WDS_LOGE("Invalid parameter");
495                 __WDS_LOG_FUNC_EXIT__;
496                 return WIFI_DIRECT_ERROR_NOT_PERMITTED;
497         }
498
499         if (memcmp(peer_addr, session->peer->dev_addr, MACADDR_LEN)) {
500                 WDS_LOGE("Peer is not included in this session");
501                 return WIFI_DIRECT_ERROR_NOT_PERMITTED;
502         }
503
504         if (manager->local->dev_role == WFD_DEV_ROLE_GO && session->state > SESSION_STATE_GO_NEG)
505                 res = wfd_oem_wps_cancel(manager->oem_ops);
506         else
507                 res = wfd_oem_cancel_connection(manager->oem_ops, peer_addr);
508
509         if (res < 0) {
510                 WDS_LOGE("Failed to cancel connection");
511                 return WIFI_DIRECT_ERROR_OPERATION_FAILED;
512         }
513
514         wfd_destroy_session(manager);
515
516         __WDS_LOG_FUNC_EXIT__;
517         return 0;
518 }
519
520 int wfd_session_reject(wfd_session_s *session, unsigned char *peer_addr)
521 {
522         __WDS_LOG_FUNC_ENTER__;
523         wfd_manager_s *manager = wfd_get_manager();
524         wfd_device_s *peer = NULL;
525         int res = 0;
526
527         if (!session || !manager) {
528                 WDS_LOGE("Invalid parameter");
529                 __WDS_LOG_FUNC_EXIT__;
530                 return -1;
531         }
532
533         /* Invite received case state is just created */
534         if (session->state < SESSION_STATE_CREATED ||
535                 session->state >= SESSION_STATE_STOPPED) {
536                 WDS_LOGE("Session state is Invalid [%d]", session->state);
537                 __WDS_LOG_FUNC_EXIT__;
538                 return -1;
539         }
540
541         /*
542          * TODO: check session status and do proper work
543          * for example, reject prov_disc, reject nego, stop wps, etc.
544          *
545          */
546
547         peer = session->peer;
548
549         if (SESSION_TYPE_INVITE == session->type || SESSION_TYPE_JOIN == session->type)
550                 res = wfd_oem_wps_cancel(manager->oem_ops);
551         else
552                 res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
553         if (res < 0) {
554                 WDS_LOGE("Failed to reject connection");
555                 __WDS_LOG_FUNC_EXIT__;
556                 return -1;
557         }
558
559         wfd_destroy_session(manager);
560         /* TODO: send notification to App */
561
562         __WDS_LOG_FUNC_EXIT__;
563         return 0;
564 }
565
566 int wfd_session_join(wfd_session_s *session)
567 {
568         __WDS_LOG_FUNC_ENTER__;
569         wfd_manager_s *manager = wfd_get_manager();
570         wfd_oem_conn_param_s param;
571         wfd_device_s *peer = NULL;
572         int res = 0;
573
574         if (!session) {
575                 WDS_LOGE("Invalid parameter");
576                 __WDS_LOG_FUNC_EXIT__;
577                 return -1;
578         }
579
580         session->state = SESSION_STATE_WPS;
581         peer = session->peer;
582
583         memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
584         param.wps_mode = session->wps_mode;
585         if (peer->dev_role == WFD_DEV_ROLE_GO)
586                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
587         param.go_intent = session->go_intent;
588         param.freq = session->freq;
589         g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
590
591         res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
592         if (res < 0) {
593                 WDS_LOGD("Failed to join with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
594                 wfd_destroy_session(manager);
595                 __WDS_LOG_FUNC_EXIT__;
596                 return -1;
597         }
598
599         wfd_session_timer(session, 1);
600
601         __WDS_LOG_FUNC_EXIT__;
602         return 0;
603 }
604
605 int wfd_session_invite(wfd_session_s *session)
606 {
607         __WDS_LOG_FUNC_ENTER__;
608         wfd_manager_s *manager = wfd_get_manager();
609         wfd_oem_invite_param_s param;
610         wfd_device_s *peer = NULL;
611         wfd_group_s *group = NULL;
612         int res = 0;
613
614         if (!session) {
615                 WDS_LOGE("Invalid parameter");
616                 __WDS_LOG_FUNC_EXIT__;
617                 return -1;
618         }
619
620         if (session->state > SESSION_STATE_CREATED) {
621                 WDS_LOGE("Invalid session state(%d)", session->state);
622                 return -1;
623         }
624
625         peer = session->peer;
626         group = (wfd_group_s*) manager->group;
627
628         memset(&param, 0x00, sizeof(wfd_oem_invite_param_s));
629         param.ifname = strdup(group->ifname);
630         memcpy(param.go_dev_addr, group->go_dev_addr, MACADDR_LEN);
631
632         WDS_LOGD("Invite: Peer[" MACSTR "], GO Addr[" MACSTR "]",
633                                 MAC2STR(peer->dev_addr), MAC2STR(param.go_dev_addr));
634
635         res = wfd_oem_invite(manager->oem_ops, peer->dev_addr, &param);
636         if (res < 0) {
637                 WDS_LOGE("Failed to invite with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
638                 wfd_destroy_session(manager);
639                 __WDS_LOG_FUNC_EXIT__;
640                 return -1;
641         }
642
643         wfd_session_timer(session, 1);
644
645         __WDS_LOG_FUNC_EXIT__;
646         return 0;
647 }
648
649 int wfd_session_wps(wfd_session_s *session)
650 {
651         __WDS_LOG_FUNC_ENTER__;
652         wfd_manager_s *manager = wfd_get_manager();
653         wfd_device_s *peer = NULL;
654         int res = 0;
655
656         if (!session) {
657                 WDS_LOGE("Invalid parameter");
658                 __WDS_LOG_FUNC_EXIT__;
659                 return -1;
660         }
661
662         if (session->state > SESSION_STATE_WPS) {
663                 WDS_LOGE("Session already starts WPS");
664                 return -1;
665         }
666
667         session->state = SESSION_STATE_WPS;
668         peer = session->peer;
669
670         if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
671                 WDS_LOGD("My device is GO, so WPS will be started. WPS mode[%d]", session->wps_mode);
672                 res = wfd_oem_wps_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
673         } else {
674                 WDS_LOGD("My device is not GO, so Enrollee will be started. WPS mode[%d]", session->wps_mode);
675                 wfd_oem_conn_param_s param;
676                 memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
677                 param.wps_mode = session->wps_mode;
678                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
679                 param.freq = session->freq;     /* currently not used */
680                 g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
681                 res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
682         }
683         if (res < 0) {
684                 WDS_LOGE("Failed to start wps with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
685                 wfd_destroy_session(manager);
686                 __WDS_LOG_FUNC_EXIT__;
687                 return -1;
688         }
689
690         __WDS_LOG_FUNC_EXIT__;
691         return 0;
692 }
693
694 /* In case of incomming session, when user accept connection request, this function should be called.
695  * In case of outgoing session, when prov_disc response arrived, this function should be called.
696  * Even though peer is GO, we can use this function, which can decide using join itself.
697  */
698 int wfd_session_asp_connect(wfd_session_s *session, int role)
699 {
700         __WDS_LOG_FUNC_ENTER__;
701         wfd_manager_s *manager = wfd_get_manager();
702         wfd_oem_conn_param_s param;
703         wfd_device_s *peer = NULL;
704         int res = 0;
705
706         if (!session) {
707                 WDS_LOGE("Invalid parameter");
708                 __WDS_LOG_FUNC_EXIT__;
709                 return -1;
710         }
711
712         if (session->state >= SESSION_STATE_GO_NEG) {
713                 WDS_LOGE("Session already starting GO Negotiation");
714                 __WDS_LOG_FUNC_EXIT__;
715                 return -1;
716         }
717
718         if (role == WFD_OEM_ASP_SESSION_ROLE_GO) {
719                 session->state = SESSION_STATE_WPS;
720                 return 0;
721         } else {
722                 session->state = SESSION_STATE_GO_NEG;
723         }
724
725         peer = session->peer;
726
727         memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
728         param.wps_mode = session->wps_mode;
729         if (role == 2)
730                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
731         param.go_intent = session->go_intent;
732         param.freq = session->freq;
733         param.conn_flags |= WFD_OEM_CONN_TYPE_PERSISTENT;
734
735         if (session->wps_pin[0] != '\0')
736                 g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
737
738         res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
739         if (res < 0) {
740                 WDS_LOGD("Failed to connect peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
741                 wfd_destroy_session(manager);
742                 __WDS_LOG_FUNC_EXIT__;
743                 return -1;
744         }
745
746         wfd_session_timer(session, 1);
747
748         __WDS_LOG_FUNC_EXIT__;
749         return 0;
750 }
751
752 /* In case of incomming session, when user accept connection request, this function should be called.
753  * In case of outgoing session, when prov_disc response arrived, this function should be called.
754  * Even though peer is GO, we can use this function, which can decide using join itself.
755  */
756 int wfd_session_asp_persistent_connect(wfd_session_s *session, int persist_group_id)
757 {
758         __WDS_LOG_FUNC_ENTER__;
759         wfd_manager_s *manager = wfd_get_manager();
760         wfd_oem_group_param_s param;
761         int res = 0;
762
763         if (!session) {
764                 WDS_LOGE("Invalid parameter");
765                 __WDS_LOG_FUNC_EXIT__;
766                 return -1;
767         }
768
769         if (session->state > SESSION_STATE_GO_NEG) {
770                 WDS_LOGE("Session already finished GO Negotiation");
771                 __WDS_LOG_FUNC_EXIT__;
772                 return -1;
773         }
774
775         session->state = SESSION_STATE_WPS;
776
777         memset(&param, 0x0, sizeof(param));
778         param.persistent = 2;
779         param.persistent_group_id = persist_group_id;
780
781         res = wfd_oem_create_group(manager->oem_ops, &param);
782         if (res < 0) {
783                 WDS_LOGD("Failed to create persistent group for ASP");
784                 wfd_destroy_session(manager);
785                 __WDS_LOG_FUNC_EXIT__;
786                 return -1;
787         }
788
789         wfd_session_timer(session, 1);
790
791         __WDS_LOG_FUNC_EXIT__;
792         return 0;
793 }
794
795 wfd_device_s *wfd_session_get_peer(wfd_session_s *session)
796 {
797         __WDS_LOG_FUNC_ENTER__;
798         wfd_device_s *peer = NULL;
799
800         if (!session) {
801                 WDS_LOGE("Invalid parameter");
802                 return NULL;
803         }
804
805         peer = session->peer;
806
807         __WDS_LOG_FUNC_EXIT__;
808         return peer;
809 }
810
811 unsigned char *wfd_session_get_peer_addr(wfd_session_s *session)
812 {
813         __WDS_LOG_FUNC_ENTER__;
814         wfd_device_s *peer = NULL;
815
816         if (!session || !session->peer) {
817                 WDS_LOGE("Invalid parameter");
818                 return NULL;
819         }
820
821         peer = session->peer;
822
823         __WDS_LOG_FUNC_EXIT__;
824         return peer->dev_addr;
825 }
826
827 #if 0
828 int wfd_session_get_wps_pin(wfd_session_s *session, unsigned char *pin)
829 {
830         __WDS_LOG_FUNC_ENTER__;
831
832         __WDS_LOG_FUNC_EXIT__;
833         return 0;
834 }
835
836 int wfd_session_set_wps_pin(wfd_session_s *session, unsigned char *pin)
837 {
838         __WDS_LOG_FUNC_ENTER__;
839
840         __WDS_LOG_FUNC_EXIT__;
841         return 0;
842 }
843
844 int wfd_session_set_freq(wfd_session_s *session, int freq)
845 {
846         __WDS_LOG_FUNC_ENTER__;
847
848         __WDS_LOG_FUNC_EXIT__;
849         return 0;
850 }
851
852 int wfd_session_get_state(wfd_session_s *session)
853 {
854         __WDS_LOG_FUNC_ENTER__;
855
856         __WDS_LOG_FUNC_EXIT__;
857         return 0;
858 }
859
860 int wfd_session_set_state(wfd_session_s *session, int state)
861 {
862         __WDS_LOG_FUNC_ENTER__;
863
864         __WDS_LOG_FUNC_EXIT__;
865         return 0;
866 }
867 #endif
868
869 int wfd_session_process_event(wfd_manager_s *manager, wfd_oem_event_s *event)
870 {
871         __WDS_LOG_FUNC_ENTER__;
872         wfd_session_s *session = NULL;
873         int res = 0;
874
875         if (!manager || !event) {
876                 WDS_LOGE("Invalid parameter");
877                 return -1;
878         }
879
880         WDS_LOGD("event ID [%d]", event->event_id);
881         session = manager->session;
882
883         switch (event->event_id) {
884         case WFD_OEM_EVENT_PROV_DISC_REQ:
885         {
886                 int req_wps_mode = WFD_WPS_MODE_NONE;
887
888                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
889                         req_wps_mode = WFD_WPS_MODE_KEYPAD;
890                 else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
891                         req_wps_mode = WFD_WPS_MODE_DISPLAY;
892                 else
893                         req_wps_mode = WFD_WPS_MODE_PBC;
894
895                 /* Only peer initiated connection or invitation session can be allowed */
896                 if (session) {
897                         if (session->type != SESSION_TYPE_INVITE) {
898                                 WDS_LOGE("Unexpected event. Session is exist [peer: " MACSECSTR "]",
899                                                                 MAC2SECSTR(event->dev_addr));
900                                 break;
901                         }
902                         WDS_LOGD("=====> session already exist. (invitation session)");
903                         if (session->state > SESSION_STATE_WPS) {
904                                 WDS_LOGE("Session already starts WPS");
905                                 break;
906                         }
907
908                         session->req_wps_mode = req_wps_mode;
909                         session->wps_mode = event->wps_mode;
910                 } else {
911                         session = wfd_create_session(manager, event->dev_addr,
912                                                                 req_wps_mode, SESSION_DIRECTION_INCOMING);
913                         if (!session) {
914                                 WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
915                                                                 MAC2SECSTR(event->dev_addr));
916                                 break;
917                         }
918                 }
919
920                 /* Update session */
921                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
922                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
923
924                 session->state = SESSION_STATE_STARTED;
925                 if (session->type == SESSION_TYPE_INVITE)
926                         WDS_LOGD("Invitation session");
927                 else if (WFD_DEV_ROLE_GO == manager->local->dev_role)
928                         session->type = SESSION_TYPE_JOIN;
929                 else
930                         session->type = SESSION_TYPE_NORMAL;
931
932                 wfd_session_timer(session, 1);
933
934                 /* Update local device */
935                 manager->local->wps_mode = event->wps_mode;
936
937                 wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
938                 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_CONNECTING);
939
940                 if (session->type == SESSION_TYPE_INVITE) {
941                         WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
942                         if (session->wps_mode != WFD_WPS_MODE_PBC) {
943                                 char peer_mac_address[MACSTR_LEN+1] = {0, };
944
945                                 g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
946                                 wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
947                                                              "Connection",
948                                                              g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
949                                                                                     WFD_EVENT_CONNECTION_WPS_REQ,
950                                                                                     peer_mac_address));
951                                 if (session->wps_mode == WFD_WPS_MODE_KEYPAD) {
952                                         /* We have to wait until user type PIN using Keypad */
953                                         break;
954                                 }
955                         }
956                         res = wfd_session_wps(session);
957                         if (res < 0)
958                                 _wfd_notify_session_failed(manager, event->dev_addr);
959                 } else {
960                         char peer_mac_address[MACSTR_LEN+1] = {0, };
961
962                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
963                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
964                                                      "Connection",
965                                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
966                                                                             WFD_EVENT_CONNECTION_REQ,
967                                                                             peer_mac_address));
968                 }
969         }
970         break;
971         case WFD_OEM_EVENT_PROV_DISC_RESP:
972         {
973                 if (!session) {         /* TODO: check validity of Event */
974                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
975                                                                                 MAC2SECSTR(event->dev_addr));
976                         break;
977                 }
978
979                 if (session->state > SESSION_STATE_STARTED) {
980                         WDS_LOGE("Unexpected event. Session is already started");
981                         break;
982                 }
983
984                 if (session->type == SESSION_TYPE_INVITE) {
985                         WDS_LOGE("Session type is invite, ignore provision discovery response");
986                         break;
987                 }
988
989                 /* Update session */
990                 session->wps_mode = event->wps_mode;
991                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY) {
992                         session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
993                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
994                 } else if (event->wps_mode == WFD_WPS_MODE_KEYPAD) {
995                         session->req_wps_mode = WFD_WPS_MODE_DISPLAY;
996                 } else {
997                         session->req_wps_mode = WFD_WPS_MODE_PBC;
998                 }
999
1000                 session->state = SESSION_STATE_STARTED;
1001                 wfd_session_timer(session, 1);
1002
1003                 /* Update local device */
1004                 manager->local->wps_mode = event->wps_mode;
1005                 WDS_LOGD("Local WPS mode is %d", session->wps_mode);
1006
1007                 if (session->wps_mode != WFD_WPS_MODE_PBC) {
1008                         char peer_mac_address[MACSTR_LEN+1] = {0, };
1009
1010                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
1011                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
1012                                                      "Connection",
1013                                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
1014                                                                             WFD_EVENT_CONNECTION_WPS_REQ,
1015                                                                             peer_mac_address));
1016                         if (session->wps_mode == WFD_WPS_MODE_KEYPAD) {
1017                                 /* We have to wait until user type PIN using Keypad */
1018                                 break;
1019                         }
1020                 }
1021
1022                 if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
1023                         WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
1024                         res = wfd_session_wps(session);
1025                 } else if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
1026                         WDS_LOGD("Start WPS(join) corresponding to OEM event [%d]", event->event_id);
1027                         res = wfd_session_join(session);
1028                 } else {
1029                         WDS_LOGD("Start connection corresponding to OEM event [%d]", event->event_id);
1030                         res = wfd_session_connect(session);
1031                 }
1032
1033                 if (res < 0)
1034                         _wfd_notify_session_failed(manager, event->dev_addr);
1035         }
1036         break;
1037         case WFD_OEM_EVENT_GO_NEG_REQ:
1038         {
1039                 if (!session) {
1040                         session = wfd_create_session(manager, event->dev_addr,
1041                                         event->wps_mode, SESSION_DIRECTION_INCOMING);
1042                         if (!session) {
1043                                 WDS_LOGE("Failed to create session");
1044                                 __WDS_LOG_FUNC_EXIT__;
1045                                 break;
1046                         }
1047
1048                         session->type = SESSION_TYPE_NORMAL;
1049                         session->state = SESSION_STATE_GO_NEG;
1050                         wfd_session_timer(session, 1);
1051                         wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
1052                         wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_CONNECTING);
1053
1054                         char peer_mac_address[MACSTR_LEN+1] = {0, };
1055                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
1056                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
1057                                         "Connection",
1058                                         g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
1059                                                 WFD_EVENT_CONNECTION_REQ,
1060                                                 peer_mac_address));
1061                 } else {
1062                         /* Sometimes, Provision Discovery response is not received.
1063                          * At this time, connection should be triggered by GO Negotiation request event */
1064                         if (session->direction == SESSION_DIRECTION_OUTGOING) {
1065                                 if (session->wps_mode == WFD_WPS_MODE_KEYPAD && session->wps_pin[0] == '\0')
1066                                         break;
1067                                 res = wfd_session_connect(session);
1068                         } else {
1069                                 /* In autoconnection mode, MT should not send GO Nego Req
1070                                    before receiving the GO Nego Req from peer (MO). */
1071                                 if (manager->autoconnection == TRUE)
1072                                         res  = wfd_session_connect(session);
1073                         }
1074                         if (res < 0)
1075                                 _wfd_notify_session_failed(manager, event->dev_addr);
1076                 }
1077         }
1078         break;
1079         case WFD_OEM_EVENT_GO_NEG_DONE:
1080         {
1081                 if (!session) {
1082                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
1083                                         MAC2SECSTR(event->dev_addr));
1084                         break;
1085                 } else {
1086                         manager->local->dev_role = event->dev_role;
1087                         session->state = SESSION_STATE_WPS;
1088                 }
1089         }
1090         break;
1091         case WFD_OEM_EVENT_WPS_DONE:
1092         {
1093                 if (!session) {
1094                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
1095                                         MAC2SECSTR(event->dev_addr));
1096                         break;
1097                 } else {
1098                         session->state = SESSION_STATE_KEY_NEG;
1099                 }
1100         }
1101         break;
1102         case WFD_OEM_EVENT_STA_CONNECTED:
1103         {
1104                 if (!session) {
1105                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
1106                                         MAC2SECSTR(event->dev_addr));
1107                         break;
1108                 } else {
1109                         session->state = SESSION_STATE_COMPLETED;
1110                 }
1111         }
1112                 break;
1113         case WFD_OEM_EVENT_ASP_PROV_START:
1114         {
1115                 int req_wps_mode = WFD_WPS_MODE_NONE;
1116
1117                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
1118                         req_wps_mode = WFD_WPS_MODE_KEYPAD;
1119                 else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
1120                         req_wps_mode = WFD_WPS_MODE_DISPLAY;
1121                 else
1122                         req_wps_mode = WFD_WPS_MODE_P2PS;
1123
1124                 session = wfd_create_session(manager, event->dev_addr,
1125                                 req_wps_mode, SESSION_DIRECTION_INCOMING);
1126                 if (!session) {
1127                         WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
1128                                                         MAC2SECSTR(event->dev_addr));
1129                         break;
1130                 }
1131
1132                 /* Update session */
1133                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
1134                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
1135
1136                 session->state = SESSION_STATE_STARTED;
1137                 wfd_session_timer(session, 1);
1138         }
1139                 break;
1140         case WFD_OEM_EVENT_ASP_PROV_DONE:
1141         {
1142                 int req_wps_mode = WFD_WPS_MODE_NONE;
1143
1144                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
1145                         req_wps_mode = WFD_WPS_MODE_KEYPAD;
1146                 else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
1147                         req_wps_mode = WFD_WPS_MODE_DISPLAY;
1148                 else
1149                         req_wps_mode = WFD_WPS_MODE_P2PS;
1150
1151                 session = (wfd_session_s*) manager->session;
1152                 if (!session) {
1153                         session = wfd_create_session(manager, event->dev_addr,
1154                                         req_wps_mode, SESSION_DIRECTION_INCOMING);
1155                         if (!session) {
1156                                 WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
1157                                                                 MAC2SECSTR(event->dev_addr));
1158                                 break;
1159                         }
1160                         session->state = SESSION_STATE_STARTED;
1161                         wfd_session_timer(session, 1);
1162                 }
1163         }
1164                 break;
1165         default:
1166                 break;
1167         }
1168         __WDS_LOG_FUNC_EXIT__;
1169         return 0;
1170 }