Add configuration file for Tizen Wi-Fi Direct features
[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
278         if (peer) {
279                 if (session->state == SESSION_STATE_COMPLETED)
280                         peer->state = WFD_PEER_STATE_CONNECTED;
281                 else
282                         peer->state = WFD_PEER_STATE_DISCOVERED;
283         } else {
284                 WDS_LOGE("Peer not found");
285         }
286
287         g_free(session);
288         manager->session = NULL;
289         manager->local->wps_mode = WFD_WPS_MODE_PBC;
290         manager->autoconnection = 0;
291         memset(manager->auto_pin, 0x0, PINSTR_LEN);
292         if (manager->local->dev_role == WFD_DEV_ROLE_GC)
293                 manager->local->dev_role = WFD_DEV_ROLE_NONE;
294
295         __WDS_LOG_FUNC_EXIT__;
296         return 0;
297 }
298
299 int wfd_session_start(wfd_session_s *session)
300 {
301         __WDS_LOG_FUNC_ENTER__;
302         wfd_manager_s *manager = wfd_get_manager();
303         wfd_device_s *peer = NULL;
304         int join = 0;
305         int res = 0;
306
307         if (!session) {
308                 WDS_LOGE("Invalid parameter");
309                 __WDS_LOG_FUNC_EXIT__;
310                 return -1;
311         }
312
313         if (session->state > SESSION_STATE_STARTED) {
314                 WDS_LOGE("Invalid session state(%d)", session->state);
315                 return -1;
316         }
317
318         /* Check: Invitation Received in Incomming case ->
319          * send prov_disc join
320          *
321          * Check: User select peer to connect with in Outgoing case ->
322          * send prov_disc wps_mode */
323
324         wfd_oem_stop_scan(manager->oem_ops);
325
326         session->state = SESSION_STATE_STARTED;
327         peer = session->peer;
328         if (peer->dev_role == WFD_DEV_ROLE_GO || session->type == SESSION_TYPE_INVITE)
329                 join = 1;
330         res = wfd_oem_prov_disc_req(manager->oem_ops, peer->dev_addr,
331                                         session->req_wps_mode, join);
332         if (res < 0) {
333                 WDS_LOGD("Failed to send provision discovery request to peer [" MACSECSTR "]",
334                                                                         MAC2SECSTR(peer->dev_addr));
335                 wfd_destroy_session(manager);
336                 /* TODO: send notification to App */
337                 __WDS_LOG_FUNC_EXIT__;
338                 return -1;
339         }
340
341         wfd_session_timer(session, 1);
342
343         __WDS_LOG_FUNC_EXIT__;
344         return 0;
345 }
346
347 int wfd_session_asp_session_start(wfd_session_s *session, wfd_oem_asp_prov_s *params)
348 {
349         __WDS_LOG_FUNC_ENTER__;
350
351         wfd_manager_s *manager = wfd_get_manager();
352         int res = 0;
353
354         if (session == NULL || params == NULL) {
355                 WDS_LOGE("Invalid parameter");
356                 __WDS_LOG_FUNC_EXIT__;
357                 return -1;
358         }
359
360         if (session->state > SESSION_STATE_STARTED) {
361                 WDS_LOGE("Invalid session state(%d)", session->state);
362                 __WDS_LOG_FUNC_EXIT__;
363                 return -1;
364         }
365
366         res = wfd_oem_asp_prov_disc_req(manager->oem_ops, params);
367         if (res < 0) {
368                 WDS_LOGD("Failed to send ASP provision discovery request to peer");
369                 wfd_destroy_session(manager);
370                 __WDS_LOG_FUNC_EXIT__;
371                 return -1;
372         }
373
374         session->state = SESSION_STATE_STARTED;
375         session->session_id = params->session_id;
376         memcpy(session->session_mac, params->session_mac, MACADDR_LEN);
377         memcpy(session->service_mac, params->service_mac, MACADDR_LEN);
378         wfd_session_timer(session, 1);
379
380         __WDS_LOG_FUNC_EXIT__;
381         return 0;
382 }
383
384 #if 0
385 int wfd_session_stop(wfd_session_s *session)
386 {
387         __WDS_LOG_FUNC_ENTER__;
388         wfd_manager_s *manager = wfd_get_manager();
389         wfd_device_s *peer = NULL;
390         int res = 0;
391
392         if (!session) {
393                 WDS_LOGE("Invalid parameter");
394                 __WDS_LOG_FUNC_EXIT__;
395                 return -1;
396         }
397
398         if (session->state > SESSION_STATE_CREATED) {
399                 peer = session->peer;
400                 if (session->direction == SESSION_DIRECTION_INCOMING)
401                         res  = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
402                 else if (session->direction == SESSION_DIRECTION_OUTGOING)
403                         res = wfd_oem_cancel_connection(manager->oem_ops, peer->dev_addr);
404
405                         if (res < 0) {
406                         WDS_LOGE("Failed to reject or cancel connection");
407                         __WDS_LOG_FUNC_EXIT__;
408                         return -1;
409                 }
410         }
411
412         session->state = SESSION_STATE_STOPPED;
413         wfd_destroy_session(manager);
414
415         __WDS_LOG_FUNC_EXIT__;
416         return 0;
417 }
418 #endif
419
420 /* In case of incomming session, when user accept connection request, this function should be called.
421  * In case of outgoing session, when prov_disc response arrived, this function should be called.
422  * Even though peer is GO, we can use this function, which can decide using join itself.
423  */
424 int wfd_session_connect(wfd_session_s *session)
425 {
426         __WDS_LOG_FUNC_ENTER__;
427         wfd_manager_s *manager = wfd_get_manager();
428         wfd_oem_conn_param_s param;
429         wfd_device_s *peer = NULL;
430         int res = 0;
431
432         if (!session) {
433                 WDS_LOGE("Invalid parameter");
434                 __WDS_LOG_FUNC_EXIT__;
435                 return -1;
436         }
437
438         if (session->state > SESSION_STATE_GO_NEG) {
439                 WDS_LOGE("Session already finished GO Negotiation");
440                 return -1;
441         }
442
443         session->state = SESSION_STATE_GO_NEG;
444         peer = session->peer;
445
446         memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
447         param.wps_mode = session->wps_mode;
448         if (peer->dev_role == WFD_DEV_ROLE_GO || session->type == SESSION_TYPE_INVITE)
449                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
450         param.go_intent = session->go_intent;
451         param.freq = session->freq;
452         if (manager->local->group_flags & WFD_GROUP_FLAG_PERSISTENT)
453                 param.conn_flags |= WFD_OEM_CONN_TYPE_PERSISTENT;
454
455         if (session->wps_pin[0] != '\0')
456                 g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
457
458         /* To connect with windows phone,set go_intent value to 2.
459         *  As windows phone does not connect when local device act as GO.
460         *  WIFI_DIRECT_PRIMARY_DEVICE_TYPE_COMPUTER ==>1 (Assume Peer Device is Windows PC)
461         *  WIFI_DIRECT_SECONDARY_DEVICE_TYPE_TELEPHONE_WINDOWS_MOBILE ==>1
462         *  WIFI_DIRECT_PRIMARY_DEVICE_TYPE_TELEPHONE ==> 10
463         */
464          if ((peer->pri_dev_type == 1) ||
465                                  ((peer->pri_dev_type == 10) && (peer->sec_dev_type == 1))) {
466                 param.go_intent = 2;
467                 WDS_LOGD("go_intent set to %d, Windows device", param.go_intent);
468          }
469
470         WDS_LOGD("connection go_intent: %d", param.go_intent);
471         res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
472         if (res < 0) {
473                 WDS_LOGD("Failed to connect peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
474                 wfd_destroy_session(manager);
475                 __WDS_LOG_FUNC_EXIT__;
476                 return -1;
477         }
478
479         wfd_session_timer(session, 1);
480
481         __WDS_LOG_FUNC_EXIT__;
482         return 0;
483 }
484
485 int wfd_session_cancel(wfd_session_s *session, unsigned char *peer_addr)
486 {
487         __WDS_LOG_FUNC_ENTER__;
488         wfd_manager_s *manager = wfd_get_manager();
489         int res = 0;
490
491         if (!session || !session->peer) {
492                 WDS_LOGE("Invalid parameter");
493                 __WDS_LOG_FUNC_EXIT__;
494                 return WIFI_DIRECT_ERROR_NOT_PERMITTED;
495         }
496
497         if (memcmp(peer_addr, session->peer->dev_addr, MACADDR_LEN)) {
498                 WDS_LOGE("Peer is not included in this session");
499                 return WIFI_DIRECT_ERROR_NOT_PERMITTED;
500         }
501
502         if (manager->local->dev_role == WFD_DEV_ROLE_GO && session->state > SESSION_STATE_GO_NEG)
503                 res = wfd_oem_wps_cancel(manager->oem_ops);
504         else
505                 res = wfd_oem_cancel_connection(manager->oem_ops, peer_addr);
506
507         if (res < 0) {
508                 WDS_LOGE("Failed to cancel connection");
509                 return WIFI_DIRECT_ERROR_OPERATION_FAILED;
510         }
511
512         wfd_destroy_session(manager);
513
514         __WDS_LOG_FUNC_EXIT__;
515         return 0;
516 }
517
518 int wfd_session_reject(wfd_session_s *session, unsigned char *peer_addr)
519 {
520         __WDS_LOG_FUNC_ENTER__;
521         wfd_manager_s *manager = wfd_get_manager();
522         wfd_device_s *peer = NULL;
523         int res = 0;
524
525         if (!session || !manager) {
526                 WDS_LOGE("Invalid parameter");
527                 __WDS_LOG_FUNC_EXIT__;
528                 return -1;
529         }
530
531         /* Invite received case state is just created */
532         if (session->state < SESSION_STATE_CREATED ||
533                 session->state >= SESSION_STATE_STOPPED) {
534                 WDS_LOGE("Session state is Invalid [%d]", session->state);
535                 __WDS_LOG_FUNC_EXIT__;
536                 return -1;
537         }
538
539         /*
540          * TODO: check session status and do proper work
541          * for example, reject prov_disc, reject nego, stop wps, etc.
542          *
543          */
544
545         peer = session->peer;
546
547         if (SESSION_TYPE_INVITE == session->type || SESSION_TYPE_JOIN == session->type)
548                 res = wfd_oem_wps_cancel(manager->oem_ops);
549         else
550                 res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
551         if (res < 0) {
552                 WDS_LOGE("Failed to reject connection");
553                 __WDS_LOG_FUNC_EXIT__;
554                 return -1;
555         }
556
557         wfd_destroy_session(manager);
558         /* TODO: send notification to App */
559
560         __WDS_LOG_FUNC_EXIT__;
561         return 0;
562 }
563
564 int wfd_session_join(wfd_session_s *session)
565 {
566         __WDS_LOG_FUNC_ENTER__;
567         wfd_manager_s *manager = wfd_get_manager();
568         wfd_oem_conn_param_s param;
569         wfd_device_s *peer = NULL;
570         int res = 0;
571
572         if (!session) {
573                 WDS_LOGE("Invalid parameter");
574                 __WDS_LOG_FUNC_EXIT__;
575                 return -1;
576         }
577
578         session->state = SESSION_STATE_WPS;
579         peer = session->peer;
580
581         memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
582         param.wps_mode = session->wps_mode;
583         if (peer->dev_role == WFD_DEV_ROLE_GO)
584                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
585         param.go_intent = session->go_intent;
586         param.freq = session->freq;
587         g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
588
589         res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
590         if (res < 0) {
591                 WDS_LOGD("Failed to join with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
592                 wfd_destroy_session(manager);
593                 __WDS_LOG_FUNC_EXIT__;
594                 return -1;
595         }
596
597         wfd_session_timer(session, 1);
598
599         __WDS_LOG_FUNC_EXIT__;
600         return 0;
601 }
602
603 int wfd_session_invite(wfd_session_s *session)
604 {
605         __WDS_LOG_FUNC_ENTER__;
606         wfd_manager_s *manager = wfd_get_manager();
607         wfd_oem_invite_param_s param;
608         wfd_device_s *peer = NULL;
609         wfd_group_s *group = NULL;
610         int res = 0;
611
612         if (!session) {
613                 WDS_LOGE("Invalid parameter");
614                 __WDS_LOG_FUNC_EXIT__;
615                 return -1;
616         }
617
618         if (session->state > SESSION_STATE_CREATED) {
619                 WDS_LOGE("Invalid session state(%d)", session->state);
620                 return -1;
621         }
622
623         peer = session->peer;
624         group = (wfd_group_s*) manager->group;
625
626         memset(&param, 0x00, sizeof(wfd_oem_invite_param_s));
627         param.ifname = strdup(group->ifname);
628         memcpy(param.go_dev_addr, group->go_dev_addr, MACADDR_LEN);
629
630         WDS_LOGD("Invite: Peer[" MACSTR "], GO Addr[" MACSTR "]",
631                                 MAC2STR(peer->dev_addr), MAC2STR(param.go_dev_addr));
632
633         res = wfd_oem_invite(manager->oem_ops, peer->dev_addr, &param);
634         if (res < 0) {
635                 WDS_LOGE("Failed to invite with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
636                 wfd_destroy_session(manager);
637                 __WDS_LOG_FUNC_EXIT__;
638                 return -1;
639         }
640
641         wfd_session_timer(session, 1);
642
643         __WDS_LOG_FUNC_EXIT__;
644         return 0;
645 }
646
647 int wfd_session_wps(wfd_session_s *session)
648 {
649         __WDS_LOG_FUNC_ENTER__;
650         wfd_manager_s *manager = wfd_get_manager();
651         wfd_device_s *peer = NULL;
652         int res = 0;
653
654         if (!session) {
655                 WDS_LOGE("Invalid parameter");
656                 __WDS_LOG_FUNC_EXIT__;
657                 return -1;
658         }
659
660         if (session->state > SESSION_STATE_WPS) {
661                 WDS_LOGE("Session already starts WPS");
662                 return -1;
663         }
664
665         session->state = SESSION_STATE_WPS;
666         peer = session->peer;
667
668         if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
669                 WDS_LOGD("My device is GO, so WPS will be started. WPS mode[%d]", session->wps_mode);
670                 res = wfd_oem_wps_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
671         } else {
672                 WDS_LOGD("My device is not GO, so Enrollee will be started. WPS mode[%d]", session->wps_mode);
673                 wfd_oem_conn_param_s param;
674                 memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
675                 param.wps_mode = session->wps_mode;
676                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
677                 param.freq = session->freq;     /* currently not used */
678                 g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
679                 res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
680         }
681         if (res < 0) {
682                 WDS_LOGE("Failed to start wps with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
683                 wfd_destroy_session(manager);
684                 __WDS_LOG_FUNC_EXIT__;
685                 return -1;
686         }
687
688         __WDS_LOG_FUNC_EXIT__;
689         return 0;
690 }
691
692 /* In case of incomming session, when user accept connection request, this function should be called.
693  * In case of outgoing session, when prov_disc response arrived, this function should be called.
694  * Even though peer is GO, we can use this function, which can decide using join itself.
695  */
696 int wfd_session_asp_connect(wfd_session_s *session, int role)
697 {
698         __WDS_LOG_FUNC_ENTER__;
699         wfd_manager_s *manager = wfd_get_manager();
700         wfd_oem_conn_param_s param;
701         wfd_device_s *peer = NULL;
702         int res = 0;
703
704         if (!session) {
705                 WDS_LOGE("Invalid parameter");
706                 __WDS_LOG_FUNC_EXIT__;
707                 return -1;
708         }
709
710         if (session->state >= SESSION_STATE_GO_NEG) {
711                 WDS_LOGE("Session already starting GO Negotiation");
712                 __WDS_LOG_FUNC_EXIT__;
713                 return -1;
714         }
715
716         if (role == WFD_OEM_ASP_SESSION_ROLE_GO) {
717                 session->state = SESSION_STATE_WPS;
718                 return 0;
719         } else {
720                 session->state = SESSION_STATE_GO_NEG;
721         }
722
723         peer = session->peer;
724
725         memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
726         param.wps_mode = session->wps_mode;
727         if (role == 2)
728                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
729         param.go_intent = session->go_intent;
730         param.freq = session->freq;
731         param.conn_flags |= WFD_OEM_CONN_TYPE_PERSISTENT;
732
733         if (session->wps_pin[0] != '\0')
734                 g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
735
736         res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
737         if (res < 0) {
738                 WDS_LOGD("Failed to connect peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
739                 wfd_destroy_session(manager);
740                 __WDS_LOG_FUNC_EXIT__;
741                 return -1;
742         }
743
744         wfd_session_timer(session, 1);
745
746         __WDS_LOG_FUNC_EXIT__;
747         return 0;
748 }
749
750 /* In case of incomming session, when user accept connection request, this function should be called.
751  * In case of outgoing session, when prov_disc response arrived, this function should be called.
752  * Even though peer is GO, we can use this function, which can decide using join itself.
753  */
754 int wfd_session_asp_persistent_connect(wfd_session_s *session, int persist_group_id)
755 {
756         __WDS_LOG_FUNC_ENTER__;
757         wfd_manager_s *manager = wfd_get_manager();
758         wfd_oem_group_param_s param;
759         int res = 0;
760
761         if (!session) {
762                 WDS_LOGE("Invalid parameter");
763                 __WDS_LOG_FUNC_EXIT__;
764                 return -1;
765         }
766
767         if (session->state > SESSION_STATE_GO_NEG) {
768                 WDS_LOGE("Session already finished GO Negotiation");
769                 __WDS_LOG_FUNC_EXIT__;
770                 return -1;
771         }
772
773         session->state = SESSION_STATE_WPS;
774
775         memset(&param, 0x0, sizeof(param));
776         param.persistent = 2;
777         param.persistent_group_id = persist_group_id;
778
779         res = wfd_oem_create_group(manager->oem_ops, &param);
780         if (res < 0) {
781                 WDS_LOGD("Failed to create persistent group for ASP");
782                 wfd_destroy_session(manager);
783                 __WDS_LOG_FUNC_EXIT__;
784                 return -1;
785         }
786
787         wfd_session_timer(session, 1);
788
789         __WDS_LOG_FUNC_EXIT__;
790         return 0;
791 }
792
793 wfd_device_s *wfd_session_get_peer(wfd_session_s *session)
794 {
795         __WDS_LOG_FUNC_ENTER__;
796         wfd_device_s *peer = NULL;
797
798         if (!session) {
799                 WDS_LOGE("Invalid parameter");
800                 return NULL;
801         }
802
803         peer = session->peer;
804
805         __WDS_LOG_FUNC_EXIT__;
806         return peer;
807 }
808
809 unsigned char *wfd_session_get_peer_addr(wfd_session_s *session)
810 {
811         __WDS_LOG_FUNC_ENTER__;
812         wfd_device_s *peer = NULL;
813
814         if (!session || !session->peer) {
815                 WDS_LOGE("Invalid parameter");
816                 return NULL;
817         }
818
819         peer = session->peer;
820
821         __WDS_LOG_FUNC_EXIT__;
822         return peer->dev_addr;
823 }
824
825 #if 0
826 int wfd_session_get_wps_pin(wfd_session_s *session, unsigned char *pin)
827 {
828         __WDS_LOG_FUNC_ENTER__;
829
830         __WDS_LOG_FUNC_EXIT__;
831         return 0;
832 }
833
834 int wfd_session_set_wps_pin(wfd_session_s *session, unsigned char *pin)
835 {
836         __WDS_LOG_FUNC_ENTER__;
837
838         __WDS_LOG_FUNC_EXIT__;
839         return 0;
840 }
841
842 int wfd_session_set_freq(wfd_session_s *session, int freq)
843 {
844         __WDS_LOG_FUNC_ENTER__;
845
846         __WDS_LOG_FUNC_EXIT__;
847         return 0;
848 }
849
850 int wfd_session_get_state(wfd_session_s *session)
851 {
852         __WDS_LOG_FUNC_ENTER__;
853
854         __WDS_LOG_FUNC_EXIT__;
855         return 0;
856 }
857
858 int wfd_session_set_state(wfd_session_s *session, int state)
859 {
860         __WDS_LOG_FUNC_ENTER__;
861
862         __WDS_LOG_FUNC_EXIT__;
863         return 0;
864 }
865 #endif
866
867 int wfd_session_process_event(wfd_manager_s *manager, wfd_oem_event_s *event)
868 {
869         __WDS_LOG_FUNC_ENTER__;
870         wfd_session_s *session = NULL;
871         int res = 0;
872
873         if (!manager || !event) {
874                 WDS_LOGE("Invalid parameter");
875                 return -1;
876         }
877
878         WDS_LOGD("event ID [%d]", event->event_id);
879         session = manager->session;
880
881         switch (event->event_id) {
882         case WFD_OEM_EVENT_PROV_DISC_REQ:
883         {
884                 int req_wps_mode = WFD_WPS_MODE_NONE;
885
886                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
887                         req_wps_mode = WFD_WPS_MODE_KEYPAD;
888                 else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
889                         req_wps_mode = WFD_WPS_MODE_DISPLAY;
890                 else
891                         req_wps_mode = WFD_WPS_MODE_PBC;
892
893                 /* Only peer initiated connection or invitation session can be allowed */
894                 if (session) {
895                         if (session->type != SESSION_TYPE_INVITE) {
896                                 WDS_LOGE("Unexpected event. Session is exist [peer: " MACSECSTR "]",
897                                                                 MAC2SECSTR(event->dev_addr));
898                                 break;
899                         }
900                         WDS_LOGD("=====> session already exist. (invitation session)");
901                         if (session->state > SESSION_STATE_WPS) {
902                                 WDS_LOGE("Session already starts WPS");
903                                 break;
904                         }
905
906                         session->req_wps_mode = req_wps_mode;
907                         session->wps_mode = event->wps_mode;
908                 } else {
909                         session = wfd_create_session(manager, event->dev_addr,
910                                                                 req_wps_mode, SESSION_DIRECTION_INCOMING);
911                         if (!session) {
912                                 WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
913                                                                 MAC2SECSTR(event->dev_addr));
914                                 break;
915                         }
916                 }
917
918                 /* Update session */
919                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
920                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
921
922                 session->state = SESSION_STATE_STARTED;
923                 if (session->type == SESSION_TYPE_INVITE)
924                         WDS_LOGD("Invitation session");
925                 else if (WFD_DEV_ROLE_GO == manager->local->dev_role)
926                         session->type = SESSION_TYPE_JOIN;
927                 else
928                         session->type = SESSION_TYPE_NORMAL;
929
930                 wfd_session_timer(session, 1);
931
932                 /* Update local device */
933                 manager->local->wps_mode = event->wps_mode;
934
935                 wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
936                 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_CONNECTING);
937
938                 if (session->type == SESSION_TYPE_INVITE) {
939                         WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
940                         if (session->wps_mode != WFD_WPS_MODE_PBC) {
941                                 char peer_mac_address[MACSTR_LEN+1] = {0, };
942
943                                 g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
944                                 wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
945                                                              "Connection",
946                                                              g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
947                                                                                     WFD_EVENT_CONNECTION_WPS_REQ,
948                                                                                     peer_mac_address));
949                                 if (session->wps_mode == WFD_WPS_MODE_KEYPAD) {
950                                         /* We have to wait until user type PIN using Keypad */
951                                         break;
952                                 }
953                         }
954                         res = wfd_session_wps(session);
955                         if (res < 0)
956                                 _wfd_notify_session_failed(manager, event->dev_addr);
957                 } else {
958                         char peer_mac_address[MACSTR_LEN+1] = {0, };
959
960                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
961                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
962                                                      "Connection",
963                                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
964                                                                             WFD_EVENT_CONNECTION_REQ,
965                                                                             peer_mac_address));
966                 }
967         }
968         break;
969         case WFD_OEM_EVENT_PROV_DISC_RESP:
970         {
971                 if (!session) {         /* TODO: check validity of Event */
972                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
973                                                                                 MAC2SECSTR(event->dev_addr));
974                         break;
975                 }
976
977                 if (session->state > SESSION_STATE_STARTED) {
978                         WDS_LOGE("Unexpected event. Session is already started");
979                         break;
980                 }
981
982                 if (session->type == SESSION_TYPE_INVITE) {
983                         WDS_LOGE("Session type is invite, ignore provision discovery response");
984                         break;
985                 }
986
987                 /* Update session */
988                 session->wps_mode = event->wps_mode;
989                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY) {
990                         session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
991                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
992                 } else if (event->wps_mode == WFD_WPS_MODE_KEYPAD) {
993                         session->req_wps_mode = WFD_WPS_MODE_DISPLAY;
994                 } else {
995                         session->req_wps_mode = WFD_WPS_MODE_PBC;
996                 }
997
998                 session->state = SESSION_STATE_STARTED;
999                 wfd_session_timer(session, 1);
1000
1001                 /* Update local device */
1002                 manager->local->wps_mode = event->wps_mode;
1003                 WDS_LOGD("Local WPS mode is %d", session->wps_mode);
1004
1005                 if (session->wps_mode != WFD_WPS_MODE_PBC) {
1006                         char peer_mac_address[MACSTR_LEN+1] = {0, };
1007
1008                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
1009                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
1010                                                      "Connection",
1011                                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
1012                                                                             WFD_EVENT_CONNECTION_WPS_REQ,
1013                                                                             peer_mac_address));
1014                         if (session->wps_mode == WFD_WPS_MODE_KEYPAD) {
1015                                 /* We have to wait until user type PIN using Keypad */
1016                                 break;
1017                         }
1018                 }
1019
1020                 if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
1021                         WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
1022                         res = wfd_session_wps(session);
1023                 } else if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
1024                         WDS_LOGD("Start WPS(join) corresponding to OEM event [%d]", event->event_id);
1025                         res = wfd_session_join(session);
1026                 } else {
1027                         WDS_LOGD("Start connection corresponding to OEM event [%d]", event->event_id);
1028                         res = wfd_session_connect(session);
1029                 }
1030
1031                 if (res < 0)
1032                         _wfd_notify_session_failed(manager, event->dev_addr);
1033         }
1034         break;
1035         case WFD_OEM_EVENT_GO_NEG_REQ:
1036         {
1037                 if (!session) {
1038                         session = wfd_create_session(manager, event->dev_addr,
1039                                         event->wps_mode, SESSION_DIRECTION_INCOMING);
1040                         if (!session) {
1041                                 WDS_LOGE("Failed to create session");
1042                                 __WDS_LOG_FUNC_EXIT__;
1043                                 break;
1044                         }
1045
1046                         session->type = SESSION_TYPE_NORMAL;
1047                         session->state = SESSION_STATE_GO_NEG;
1048                         wfd_session_timer(session, 1);
1049                         wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
1050                         wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_CONNECTING);
1051
1052                         char peer_mac_address[MACSTR_LEN+1] = {0, };
1053                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
1054                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
1055                                         "Connection",
1056                                         g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
1057                                                 WFD_EVENT_CONNECTION_REQ,
1058                                                 peer_mac_address));
1059                 } else {
1060                         /* Sometimes, Provision Discovery response is not received.
1061                          * At this time, connection should be triggered by GO Negotiation request event */
1062                         if (session->direction == SESSION_DIRECTION_OUTGOING) {
1063                                 if (session->wps_mode == WFD_WPS_MODE_KEYPAD && session->wps_pin[0] == '\0')
1064                                         break;
1065                                 res = wfd_session_connect(session);
1066                         } else {
1067                                 /* In autoconnection mode, MT should not send GO Nego Req
1068                                    before receiving the GO Nego Req from peer (MO). */
1069                                 if (manager->autoconnection == TRUE)
1070                                         res  = wfd_session_connect(session);
1071                         }
1072                         if (res < 0)
1073                                 _wfd_notify_session_failed(manager, event->dev_addr);
1074                 }
1075         }
1076         break;
1077         case WFD_OEM_EVENT_GO_NEG_DONE:
1078         {
1079                 if (!session) {
1080                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
1081                                         MAC2SECSTR(event->dev_addr));
1082                         break;
1083                 } else {
1084                         manager->local->dev_role = event->dev_role;
1085                         session->state = SESSION_STATE_WPS;
1086                 }
1087         }
1088         break;
1089         case WFD_OEM_EVENT_WPS_DONE:
1090         {
1091                 if (!session) {
1092                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
1093                                         MAC2SECSTR(event->dev_addr));
1094                         break;
1095                 } else {
1096                         session->state = SESSION_STATE_KEY_NEG;
1097                 }
1098         }
1099         break;
1100         case WFD_OEM_EVENT_STA_CONNECTED:
1101         {
1102                 if (!session) {
1103                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
1104                                         MAC2SECSTR(event->dev_addr));
1105                         break;
1106                 } else {
1107                         session->state = SESSION_STATE_COMPLETED;
1108                 }
1109         }
1110                 break;
1111         case WFD_OEM_EVENT_ASP_PROV_START:
1112         {
1113                 int req_wps_mode = WFD_WPS_MODE_NONE;
1114
1115                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
1116                         req_wps_mode = WFD_WPS_MODE_KEYPAD;
1117                 else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
1118                         req_wps_mode = WFD_WPS_MODE_DISPLAY;
1119                 else
1120                         req_wps_mode = WFD_WPS_MODE_P2PS;
1121
1122                 session = wfd_create_session(manager, event->dev_addr,
1123                                 req_wps_mode, SESSION_DIRECTION_INCOMING);
1124                 if (!session) {
1125                         WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
1126                                                         MAC2SECSTR(event->dev_addr));
1127                         break;
1128                 }
1129
1130                 /* Update session */
1131                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
1132                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
1133
1134                 session->state = SESSION_STATE_STARTED;
1135                 wfd_session_timer(session, 1);
1136         }
1137                 break;
1138         case WFD_OEM_EVENT_ASP_PROV_DONE:
1139         {
1140                 int req_wps_mode = WFD_WPS_MODE_NONE;
1141
1142                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
1143                         req_wps_mode = WFD_WPS_MODE_KEYPAD;
1144                 else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
1145                         req_wps_mode = WFD_WPS_MODE_DISPLAY;
1146                 else
1147                         req_wps_mode = WFD_WPS_MODE_P2PS;
1148
1149                 session = (wfd_session_s*) manager->session;
1150                 if (!session) {
1151                         session = wfd_create_session(manager, event->dev_addr,
1152                                         req_wps_mode, SESSION_DIRECTION_INCOMING);
1153                         if (!session) {
1154                                 WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
1155                                                                 MAC2SECSTR(event->dev_addr));
1156                                 break;
1157                         }
1158                         session->state = SESSION_STATE_STARTED;
1159                         wfd_session_timer(session, 1);
1160                 }
1161         }
1162                 break;
1163         default:
1164                 break;
1165         }
1166         __WDS_LOG_FUNC_EXIT__;
1167         return 0;
1168 }