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