Add support for ASP session request/response
[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 finished GO Negotiation");
720                 __WDS_LOG_FUNC_EXIT__;
721                 return -1;
722         }
723
724         session->state = SESSION_STATE_GO_NEG;
725         peer = session->peer;
726
727         memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
728         param.wps_mode = session->wps_mode;
729         if (role == 2)
730                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
731         param.go_intent = session->go_intent;
732         param.freq = session->freq;
733         param.conn_flags |= WFD_OEM_CONN_TYPE_PERSISTENT;
734
735         if (session->wps_pin[0] != '\0')
736                 g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
737
738         res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
739         if (res < 0) {
740                 WDS_LOGD("Failed to connect peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
741                 wfd_destroy_session(manager);
742                 __WDS_LOG_FUNC_EXIT__;
743                 return -1;
744         }
745
746         wfd_session_timer(session, 1);
747
748         __WDS_LOG_FUNC_EXIT__;
749         return 0;
750 }
751
752 /* In case of incomming session, when user accept connection request, this function should be called.
753  * In case of outgoing session, when prov_disc response arrived, this function should be called.
754  * Even though peer is GO, we can use this function, which can decide using join itself.
755  */
756 int wfd_session_asp_persistent_connect(wfd_session_s *session, int persist_group_id)
757 {
758         __WDS_LOG_FUNC_ENTER__;
759         wfd_manager_s *manager = wfd_get_manager();
760         wfd_device_s *peer = NULL;
761         wfd_oem_group_param_s param;
762         int res = 0;
763
764         if (!session) {
765                 WDS_LOGE("Invalid parameter");
766                 __WDS_LOG_FUNC_EXIT__;
767                 return -1;
768         }
769
770         if (session->state > SESSION_STATE_GO_NEG) {
771                 WDS_LOGE("Session already finished GO Negotiation");
772                 __WDS_LOG_FUNC_EXIT__;
773                 return -1;
774         }
775
776         session->state = SESSION_STATE_WPS;
777
778         memset(&param, 0x0, sizeof(param));
779         param.persistent = 2;
780         param.persistent_group_id = persist_group_id;
781
782         res = wfd_oem_create_group(manager->oem_ops, &param);
783         if (res < 0) {
784                 WDS_LOGD("Failed to connect peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
785                 wfd_destroy_session(manager);
786                 __WDS_LOG_FUNC_EXIT__;
787                 return -1;
788         }
789
790         wfd_session_timer(session, 1);
791
792         __WDS_LOG_FUNC_EXIT__;
793         return 0;
794 }
795 #endif /* TIZEN_FEATURE_ASP */
796
797 wfd_device_s *wfd_session_get_peer(wfd_session_s *session)
798 {
799         __WDS_LOG_FUNC_ENTER__;
800         wfd_device_s *peer = NULL;
801
802         if (!session) {
803                 WDS_LOGE("Invalid parameter");
804                 return NULL;
805         }
806
807         peer = session->peer;
808
809         __WDS_LOG_FUNC_EXIT__;
810         return peer;
811 }
812
813 unsigned char *wfd_session_get_peer_addr(wfd_session_s *session)
814 {
815         __WDS_LOG_FUNC_ENTER__;
816         wfd_device_s *peer = NULL;
817
818         if (!session || !session->peer) {
819                 WDS_LOGE("Invalid parameter");
820                 return NULL;
821         }
822
823         peer = session->peer;
824
825         __WDS_LOG_FUNC_EXIT__;
826         return peer->dev_addr;
827 }
828
829 #if 0
830 int wfd_session_get_wps_pin(wfd_session_s *session, unsigned char *pin)
831 {
832         __WDS_LOG_FUNC_ENTER__;
833
834         __WDS_LOG_FUNC_EXIT__;
835         return 0;
836 }
837
838 int wfd_session_set_wps_pin(wfd_session_s *session, unsigned char *pin)
839 {
840         __WDS_LOG_FUNC_ENTER__;
841
842         __WDS_LOG_FUNC_EXIT__;
843         return 0;
844 }
845
846 int wfd_session_set_freq(wfd_session_s *session, int freq)
847 {
848         __WDS_LOG_FUNC_ENTER__;
849
850         __WDS_LOG_FUNC_EXIT__;
851         return 0;
852 }
853
854 int wfd_session_get_state(wfd_session_s *session)
855 {
856         __WDS_LOG_FUNC_ENTER__;
857
858         __WDS_LOG_FUNC_EXIT__;
859         return 0;
860 }
861
862 int wfd_session_set_state(wfd_session_s *session, int state)
863 {
864         __WDS_LOG_FUNC_ENTER__;
865
866         __WDS_LOG_FUNC_EXIT__;
867         return 0;
868 }
869 #endif
870
871 int wfd_session_process_event(wfd_manager_s *manager, wfd_oem_event_s *event)
872 {
873         __WDS_LOG_FUNC_ENTER__;
874         wfd_session_s *session = NULL;
875         int res = 0;
876
877         if (!manager || !event) {
878                 WDS_LOGE("Invalid parameter");
879                 return -1;
880         }
881
882         WDS_LOGD("event ID [%d]", event->event_id);
883         session = manager->session;
884
885         switch (event->event_id) {
886         case WFD_OEM_EVENT_PROV_DISC_REQ:
887         {
888                 int req_wps_mode = WFD_WPS_MODE_NONE;
889
890                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
891                         req_wps_mode = WFD_WPS_MODE_KEYPAD;
892                 else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
893                         req_wps_mode = WFD_WPS_MODE_DISPLAY;
894                 else
895                         req_wps_mode = WFD_WPS_MODE_PBC;
896
897                 /* Only peer initiated connection or invitation session can be allowed */
898                 if (session) {
899                         if (session->type != SESSION_TYPE_INVITE) {
900                                 WDS_LOGE("Unexpected event. Session is exist [peer: " MACSECSTR "]",
901                                                                 MAC2SECSTR(event->dev_addr));
902                                 break;
903                         }
904                         WDS_LOGD("=====> session already exist. (invitation session)");
905                         session->req_wps_mode = req_wps_mode;
906                         session->wps_mode = event->wps_mode;
907                 } else {
908                         session = wfd_create_session(manager, event->dev_addr,
909                                                                 req_wps_mode, SESSION_DIRECTION_INCOMING);
910                         if (!session) {
911                                 WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
912                                                                 MAC2SECSTR(event->dev_addr));
913                                 break;
914                         }
915                 }
916
917                 /* Update session */
918                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
919                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
920
921                 session->state = SESSION_STATE_STARTED;
922                 if (session->type == SESSION_TYPE_INVITE)
923                         WDS_LOGD("Invitation session");
924                 else if (WFD_DEV_ROLE_GO == manager->local->dev_role)
925                         session->type = SESSION_TYPE_JOIN;
926                 else
927                         session->type = SESSION_TYPE_NORMAL;
928
929                 wfd_session_timer(session, 1);
930
931                 /* Update local device */
932                 manager->local->wps_mode = event->wps_mode;
933
934                 wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
935
936                 if (session->type == SESSION_TYPE_INVITE) {
937                         WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
938                         if (session->wps_mode != WFD_WPS_MODE_PBC) {
939                                 char peer_mac_address[MACSTR_LEN+1] = {0, };
940
941                                 g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
942                                 wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
943                                                              "Connection",
944                                                              g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
945                                                                                     WFD_EVENT_CONNECTION_WPS_REQ,
946                                                                                     peer_mac_address));
947                                 if (session->wps_mode == WFD_WPS_MODE_KEYPAD) {
948                                         /* We have to wait until user type PIN using Keypad */
949                                         break;
950                                 }
951                         }
952                         res = wfd_session_wps(session);
953                         if (res < 0)
954                                 _wfd_notify_session_failed(manager, event->dev_addr);
955                 } else {
956                         char peer_mac_address[MACSTR_LEN+1] = {0, };
957
958                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
959                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
960                                                      "Connection",
961                                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
962                                                                             WFD_EVENT_CONNECTION_REQ,
963                                                                             peer_mac_address));
964                 }
965         }
966         break;
967         case WFD_OEM_EVENT_PROV_DISC_RESP:
968         {
969                 if (!session) {         /* TODO: check validity of Event */
970                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
971                                                                                 MAC2SECSTR(event->dev_addr));
972                         break;
973                 }
974
975                 if (session->state > SESSION_STATE_STARTED) {
976                         WDS_LOGE("Unexpected event. Session is already started");
977                         break;
978                 }
979
980                 if (session->type == SESSION_TYPE_INVITE) {
981                         WDS_LOGE("Session type is invite, ignore provision discovery response");
982                         break;
983                 }
984
985                 /* Update session */
986                 session->wps_mode = event->wps_mode;
987                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY) {
988                         session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
989                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
990                 } else if (event->wps_mode == WFD_WPS_MODE_KEYPAD) {
991                         session->req_wps_mode = WFD_WPS_MODE_DISPLAY;
992                 } else {
993                         session->req_wps_mode = WFD_WPS_MODE_PBC;
994                 }
995
996                 session->state = SESSION_STATE_STARTED;
997                 wfd_session_timer(session, 1);
998
999                 /* Update local device */
1000                 manager->local->wps_mode = event->wps_mode;
1001                 WDS_LOGD("Local WPS mode is %d", session->wps_mode);
1002
1003                 if (session->wps_mode != WFD_WPS_MODE_PBC) {
1004                         char peer_mac_address[MACSTR_LEN+1] = {0, };
1005
1006                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
1007                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
1008                                                      "Connection",
1009                                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
1010                                                                             WFD_EVENT_CONNECTION_WPS_REQ,
1011                                                                             peer_mac_address));
1012                         if (session->wps_mode == WFD_WPS_MODE_KEYPAD) {
1013                                 /* We have to wait until user type PIN using Keypad */
1014                                 break;
1015                         }
1016                 }
1017
1018                 if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
1019                         WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
1020                         res = wfd_session_wps(session);
1021                 } else if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
1022                         WDS_LOGD("Start WPS(join) corresponding to OEM event [%d]", event->event_id);
1023                         res = wfd_session_join(session);
1024                 } else {
1025                         WDS_LOGD("Start connection corresponding to OEM event [%d]", event->event_id);
1026                         res = wfd_session_connect(session);
1027                 }
1028
1029                 if (res < 0)
1030                         _wfd_notify_session_failed(manager, event->dev_addr);
1031         }
1032         break;
1033         case WFD_OEM_EVENT_GO_NEG_REQ:
1034         {
1035                 if (!session) {
1036                         session = wfd_create_session(manager, event->dev_addr,
1037                                         event->wps_mode, SESSION_DIRECTION_INCOMING);
1038                         if (!session) {
1039                                 WDS_LOGE("Failed to create session");
1040                                 __WDS_LOG_FUNC_EXIT__;
1041                                 break;
1042                         }
1043
1044                         session->type = SESSION_TYPE_NORMAL;
1045                         session->state = SESSION_STATE_GO_NEG;
1046                         wfd_session_timer(session, 1);
1047                         wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
1048
1049                         char peer_mac_address[MACSTR_LEN+1] = {0, };
1050                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
1051                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
1052                                         "Connection",
1053                                         g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
1054                                                 WFD_EVENT_CONNECTION_REQ,
1055                                                 peer_mac_address));
1056                 } else {
1057                         /* Sometimes, Provision Discovery response is not received.
1058                          * At this time, connection should be triggered by GO Negotiation request event */
1059                         if (session->direction == SESSION_DIRECTION_OUTGOING) {
1060                                 res = wfd_session_connect(session);
1061                         } else {
1062                                 /* In autoconnection mode, MT should not send GO Nego Req
1063                                    before receiving the GO Nego Req from peer (MO). */
1064                                 if (manager->autoconnection == TRUE)
1065                                         res  = wfd_session_connect(session);
1066                         }
1067                         if (res < 0)
1068                                 _wfd_notify_session_failed(manager, event->dev_addr);
1069                 }
1070         }
1071         break;
1072         case WFD_OEM_EVENT_GO_NEG_DONE:
1073         {
1074                 if (!session) {
1075                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
1076                                         MAC2SECSTR(event->dev_addr));
1077                         break;
1078                 } else {
1079                         manager->local->dev_role = event->dev_role;
1080                         session->state = SESSION_STATE_WPS;
1081                 }
1082         }
1083         break;
1084         case WFD_OEM_EVENT_WPS_DONE:
1085         {
1086                 if (!session) {
1087                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
1088                                         MAC2SECSTR(event->dev_addr));
1089                         break;
1090                 } else {
1091                         session->state = SESSION_STATE_KEY_NEG;
1092                 }
1093         }
1094         break;
1095         case WFD_OEM_EVENT_STA_CONNECTED:
1096         {
1097                 if (!session) {
1098                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
1099                                         MAC2SECSTR(event->dev_addr));
1100                         break;
1101                 } else {
1102                         session->state = SESSION_STATE_COMPLETED;
1103                 }
1104         }
1105                 break;
1106 #if defined(TIZEN_FEATURE_ASP)
1107         case WFD_OEM_EVENT_ASP_PROV_START:
1108         {
1109                 int req_wps_mode = WFD_WPS_MODE_NONE;
1110
1111                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
1112                         req_wps_mode = WFD_WPS_MODE_KEYPAD;
1113                 else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
1114                         req_wps_mode = WFD_WPS_MODE_DISPLAY;
1115                 else
1116                         req_wps_mode = WFD_WPS_MODE_P2PS;
1117
1118                 session = wfd_create_session(manager, event->dev_addr,
1119                                 req_wps_mode, SESSION_DIRECTION_INCOMING);
1120                 if (!session) {
1121                         WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
1122                                                         MAC2SECSTR(event->dev_addr));
1123                         break;
1124                 }
1125
1126                 /* Update session */
1127                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
1128                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
1129
1130                 session->state = SESSION_STATE_STARTED;
1131                 wfd_session_timer(session, 1);
1132         }
1133                 break;
1134         case WFD_OEM_EVENT_ASP_PROV_DONE:
1135         {
1136                 int req_wps_mode = WFD_WPS_MODE_NONE;
1137
1138                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY)
1139                         req_wps_mode = WFD_WPS_MODE_KEYPAD;
1140                 else if (event->wps_mode == WFD_WPS_MODE_KEYPAD)
1141                         req_wps_mode = WFD_WPS_MODE_DISPLAY;
1142                 else
1143                         req_wps_mode = WFD_WPS_MODE_P2PS;
1144
1145                 session = (wfd_session_s*) manager->session;
1146                 if (!session) {
1147                         session = wfd_create_session(manager, event->dev_addr,
1148                                         req_wps_mode, SESSION_DIRECTION_INCOMING);
1149                         if (!session) {
1150                                 WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
1151                                                                 MAC2SECSTR(event->dev_addr));
1152                                 break;
1153                         }
1154                         session->state = SESSION_STATE_STARTED;
1155                         wfd_session_timer(session, 1);
1156                 }
1157         }
1158                 break;
1159 #endif /* TIZEN_FEATURE_ASP */
1160         if (res < 0)
1161                 _wfd_notify_session_failed(manager, event->dev_addr);
1162         break;
1163         default:
1164                 break;
1165         }
1166         __WDS_LOG_FUNC_EXIT__;
1167         return 0;
1168 }