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