[wfd-manager]: Fix the P2P Connection Issue with Windows OS based devices
[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
48
49 static gboolean _session_timeout_cb(gpointer *user_data)
50 {
51         __WDS_LOG_FUNC_ENTER__;
52         wfd_manager_s *manager = wfd_get_manager();
53         wfd_session_s *session = (wfd_session_s*) manager->session;
54         unsigned char *peer_addr = NULL;
55         char peer_mac_address[MACSTR_LEN+1] = {0, };
56
57         if (!session) {
58                 WDS_LOGE("Invalid parameter");
59                 return FALSE;
60         }
61         session->connecting_120 = 0;
62         session->timer = 0;
63         WDS_LOGD("Session timer expired");
64
65         peer_addr = wfd_session_get_peer_addr(session);
66         if(peer_addr != NULL)
67                 g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(peer_addr));
68         else
69                 g_snprintf(peer_mac_address, MACSTR_LEN, "%s", "");
70
71         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
72                                      "Connection",
73                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_CONNECTION_TIME_OUT,
74                                                             WFD_EVENT_CONNECTION_RSP,
75                                                             peer_mac_address));
76
77         wfd_session_cancel(session, peer_addr);
78
79         if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
80                 wfd_state_set(manager, WIFI_DIRECT_STATE_GROUP_OWNER);
81                 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_GROUP_OWNER);
82         } else {
83                 wfd_state_set(manager, WIFI_DIRECT_STATE_ACTIVATED);
84                 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_ACTIVATED);
85         }
86
87         __WDS_LOG_FUNC_EXIT__;
88         return FALSE;
89 }
90
91 static void _wfd_notify_session_failed(wfd_manager_s *manager, unsigned char *peer_addr)
92 {
93         __WDS_LOG_FUNC_ENTER__;
94         char peer_mac_address[MACSTR_LEN+1] = {0, };
95
96         snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(peer_addr));
97         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
98                                      "Connection",
99                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_CONNECTION_FAILED,
100                                                             WFD_EVENT_CONNECTION_RSP,
101                                                             peer_mac_address));
102
103         if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
104                 wfd_state_set(manager, WIFI_DIRECT_STATE_GROUP_OWNER);
105                 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_GROUP_OWNER);
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 }
113
114 int wfd_session_timer(wfd_session_s *session, int start)
115 {
116         __WDS_LOG_FUNC_ENTER__;
117
118         if (!session) {
119                 WDS_LOGE("Invalid parameter");
120                 __WDS_LOG_FUNC_EXIT__;
121                 return -1;
122         }
123
124         if (start) {
125                 if (!session->connecting_120)
126                         session->connecting_120 = 1;
127
128                 if (session->timer > 0) {
129                         WDS_LOGE("Session timer already started");
130                         __WDS_LOG_FUNC_EXIT__;
131                         return -1;
132                 }
133                 session->timer = g_timeout_add(120000,
134                                                 (GSourceFunc) _session_timeout_cb,
135                                                 NULL);
136                 WDS_LOGD("Session timer started");
137         } else {
138                 session->connecting_120 = 0;
139                 if (session->timer > 0) {
140                         g_source_remove(session->timer);
141                         session->timer = 0;
142                         WDS_LOGD("Session timer stoped");
143                 }
144         }
145
146         __WDS_LOG_FUNC_EXIT__;
147         return 0;
148 }
149
150 // Check the session instance which has same peer address, before using this function
151 wfd_session_s *wfd_create_session(void *data, unsigned char *peer_addr, int wps_mode, int direction)
152 {
153         __WDS_LOG_FUNC_ENTER__;
154         wfd_manager_s *manager = (wfd_manager_s*) data;
155         wfd_session_s *session = NULL;
156         wfd_device_s *peer = NULL;
157
158         if (!data || !peer_addr) {
159                 WDS_LOGE("Invalid parameter");
160                 __WDS_LOG_FUNC_EXIT__;
161                 return NULL;
162         }
163
164         WDS_LOGD("create session for peer[" MACSTR "]", MAC2STR(peer_addr));
165
166         if (manager->session) {
167                 WDS_LOGE("Session already exist");
168                 return NULL;
169         }
170
171         session = (wfd_session_s*) g_try_malloc0(sizeof(wfd_session_s));
172         if (!session) {
173                 WDS_LOGE("Failed to allocate memory for session");
174                 __WDS_LOG_FUNC_EXIT__;
175                 return NULL;
176         }
177
178         peer = wfd_peer_find_by_dev_addr(manager, peer_addr);
179         if (!peer) {
180                 WDS_LOGE("Failed to find peer info[" MACSECSTR "]", MAC2SECSTR(peer_addr));
181                 g_free(session);
182                 __WDS_LOG_FUNC_EXIT__;
183                 return NULL;
184         }
185         peer->state = WFD_PEER_STATE_CONNECTING;
186
187         session->peer = peer;
188         session->req_wps_mode = wps_mode;
189         if (wps_mode == WFD_WPS_MODE_DISPLAY)
190                 session->wps_mode = WFD_WPS_MODE_KEYPAD;
191         else if (wps_mode == WFD_WPS_MODE_KEYPAD)
192                 session->wps_mode = WFD_WPS_MODE_DISPLAY;
193         else
194                 session->wps_mode = wps_mode;
195         session->direction = direction;
196         session->state = SESSION_STATE_CREATED;
197
198         manager->session = session;
199         manager->local->wps_mode = session->wps_mode;
200
201         if (peer->dev_role == WFD_DEV_ROLE_GO &&
202                         manager->local->wps_mode == WFD_WPS_MODE_DISPLAY) {
203                         char *generated_pin = NULL;
204                         session->wps_mode = WFD_WPS_MODE_DISPLAY;
205                         session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
206
207                         if (wfd_oem_generate_pin(manager->oem_ops, &generated_pin) != 0) {
208                                 WDS_LOGE("Failed to generate pin");
209                                 g_free(session);
210                                 __WDS_LOG_FUNC_EXIT__;
211                                 return NULL;
212                         }
213
214                         g_strlcpy(session->wps_pin, generated_pin, PINSTR_LEN + 1);
215                         g_free(generated_pin);
216         }
217
218         if (peer->dev_role == WFD_DEV_ROLE_GO && manager->local->dev_role != WFD_DEV_ROLE_GO)
219                 manager->local->dev_role = WFD_DEV_ROLE_GC;
220
221         __WDS_LOG_FUNC_EXIT__;
222         return session;
223 }
224
225 int wfd_destroy_session(void *data)
226 {
227         __WDS_LOG_FUNC_ENTER__;
228         wfd_manager_s *manager = (wfd_manager_s*) data;
229         wfd_session_s *session = NULL;
230         wfd_device_s *peer = NULL;
231
232         if (!manager) {
233                 WDS_LOGE("Invalid parameter");
234                 return -1;
235         }
236
237         session = (wfd_session_s*) manager->session;
238         if (!session) {
239                 WDS_LOGE("Session not found");  // self prevent 13029
240                 return -1;
241         }
242         wfd_session_timer(session, 0);
243         peer = session->peer;
244
245         if(peer) {
246                 if (session->state == SESSION_STATE_COMPLETED)
247                         peer->state = WFD_PEER_STATE_CONNECTED;
248                 else
249                         peer->state = WFD_PEER_STATE_DISCOVERED;
250         } else {
251                 WDS_LOGE("Peer not found");
252         }
253
254         g_free(session);
255         manager->session = NULL;
256         manager->local->wps_mode = WFD_WPS_MODE_PBC;
257         manager->autoconnection = 0;
258         memset(manager->auto_pin, 0x0, PINSTR_LEN);
259         if (manager->local->dev_role == WFD_DEV_ROLE_GC)
260                 manager->local->dev_role = WFD_DEV_ROLE_NONE;
261
262         __WDS_LOG_FUNC_EXIT__;
263         return 0;
264 }
265
266 int wfd_session_start(wfd_session_s *session)
267 {
268         __WDS_LOG_FUNC_ENTER__;
269         wfd_manager_s *manager = wfd_get_manager();
270         wfd_device_s *peer = NULL;
271         int join = 0;
272         int res = 0;
273
274         if (!session) {
275                 WDS_LOGE("Invalid parameter");
276                 __WDS_LOG_FUNC_EXIT__;
277                 return -1;
278         }
279
280         if (session->state > SESSION_STATE_STARTED) {
281                 WDS_LOGE("Invalid session state(%d)", session->state);
282                 return -1;
283         }
284
285         // Check: Invitation Received in Incomming case -> send prov_disc join
286         // Check: User select peer to connect with in Outgoing case -> send prov_disc wps_mdde
287
288         wfd_oem_stop_scan(manager->oem_ops);
289
290         session->state = SESSION_STATE_STARTED;
291         peer = session->peer;
292         if (peer->dev_role == WFD_DEV_ROLE_GO || session->type == SESSION_TYPE_INVITE)
293                 join = 1;
294         res = wfd_oem_prov_disc_req(manager->oem_ops, peer->dev_addr,
295                                         session->req_wps_mode, join);
296         if (res < 0) {
297                 WDS_LOGD("Failed to send provision discovery request to peer [" MACSECSTR "]",
298                                                                         MAC2SECSTR(peer->dev_addr));
299                 wfd_destroy_session(manager);
300                 // TODO: send notification to App
301                 __WDS_LOG_FUNC_EXIT__;
302                 return -1;
303         }
304
305         wfd_session_timer(session, 1);
306
307         __WDS_LOG_FUNC_EXIT__;
308         return 0;
309 }
310
311 #if 0
312 int wfd_session_stop(wfd_session_s *session)
313 {
314         __WDS_LOG_FUNC_ENTER__;
315         wfd_manager_s *manager = wfd_get_manager();
316         wfd_device_s *peer = NULL;
317         int res = 0;
318
319         if (!session) {
320                 WDS_LOGE("Invalid parameter");
321                 __WDS_LOG_FUNC_EXIT__;
322                 return -1;
323         }
324
325         if (session->state > SESSION_STATE_CREATED) {
326                 peer = session->peer;
327                 if (session->direction == SESSION_DIRECTION_INCOMING) {
328                         res  = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
329                 } else if (session->direction == SESSION_DIRECTION_OUTGOING) {
330                         res = wfd_oem_cancel_connection(manager->oem_ops, peer->dev_addr);
331                 }
332                 if (res < 0) {
333                         WDS_LOGE("Failed to reject or cancel connection");
334                         __WDS_LOG_FUNC_EXIT__;
335                         return -1;
336                 }
337         }
338
339         session->state = SESSION_STATE_STOPPED;
340         wfd_destroy_session(manager);
341
342         __WDS_LOG_FUNC_EXIT__;
343         return 0;
344 }
345 #endif
346
347 /* In case of incomming session, when user accept connection request, this function should be called.
348  * In case of outgoing session, when prov_disc response arrived, this function should be called.
349  * Even though peer is GO, we can use this function, which can decide using join itself.
350  */
351 int wfd_session_connect(wfd_session_s *session)
352 {
353         __WDS_LOG_FUNC_ENTER__;
354         wfd_manager_s *manager = wfd_get_manager();
355         wfd_oem_conn_param_s param;
356         wfd_device_s *peer = NULL;
357         int res = 0;
358
359         if (!session) {
360                 WDS_LOGE("Invalid parameter");
361                 __WDS_LOG_FUNC_EXIT__;
362                 return -1;
363         }
364
365         if (session->state > SESSION_STATE_GO_NEG) {
366                 WDS_LOGE("Session already finished GO Negotiation");
367                 return -1;
368         }
369
370         wfd_oem_stop_scan(manager->oem_ops);
371
372         session->state = SESSION_STATE_GO_NEG;
373         peer = session->peer;
374
375         memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
376         param.wps_mode = session->wps_mode;
377         if (peer->dev_role == WFD_DEV_ROLE_GO || session->type == SESSION_TYPE_INVITE)
378                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
379         param.go_intent = session->go_intent;
380         param.freq = session->freq;
381         if(manager->local->group_flags & WFD_GROUP_FLAG_PERSISTENT)
382                 param.conn_flags |= WFD_OEM_CONN_TYPE_PERSISTENT;
383
384         if (session->wps_pin[0] != '\0') {
385                 g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
386         }
387
388         /* To connect with windows phone,set go_intent value to 2.
389         *  As windows phone does not connect when local device act as GO.
390         *  WIFI_DIRECT_PRIMARY_DEVICE_TYPE_COMPUTER ==>1 (Assume Peer Device is Windows PC)
391         *  WIFI_DIRECT_SECONDARY_DEVICE_TYPE_TELEPHONE_WINDOWS_MOBILE ==>1
392         *  WIFI_DIRECT_PRIMARY_DEVICE_TYPE_TELEPHONE ==> 10
393         */
394          if ((peer->pri_dev_type == 1) ||
395                                  ((peer->pri_dev_type == 10) && (peer->sec_dev_type == 1))) {
396                 param.go_intent = 2;
397                 WDS_LOGD("go_intent set to %d, Windows device",param.go_intent);
398          }
399
400         WDS_LOGD("connection go_intent: %d", param.go_intent);
401         res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
402         if (res < 0) {
403                 WDS_LOGD("Failed to connect peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
404                 wfd_destroy_session(manager);
405                 __WDS_LOG_FUNC_EXIT__;
406                 return -1;
407         }
408
409         wfd_session_timer(session, 1);
410
411         __WDS_LOG_FUNC_EXIT__;
412         return 0;
413 }
414
415 int wfd_session_cancel(wfd_session_s *session, unsigned char *peer_addr)
416 {
417         __WDS_LOG_FUNC_ENTER__;
418         wfd_manager_s *manager = wfd_get_manager();
419         int res = 0;
420
421         if (!session || !session->peer) {
422                 WDS_LOGE("Invalid parameter");
423                 __WDS_LOG_FUNC_EXIT__;
424                 return WIFI_DIRECT_ERROR_NOT_PERMITTED;
425         }
426
427         if (memcmp(peer_addr, session->peer->dev_addr, MACADDR_LEN)) {
428                 WDS_LOGE("Peer is not included in this session");
429                 return WIFI_DIRECT_ERROR_NOT_PERMITTED;
430         }
431
432         if (manager->local->dev_role == WFD_DEV_ROLE_GO && session->state > SESSION_STATE_GO_NEG)
433                 res = wfd_oem_wps_cancel(manager->oem_ops);
434         else
435                 res = wfd_oem_cancel_connection(manager->oem_ops, peer_addr);
436
437         if (res < 0) {
438                 WDS_LOGE("Failed to cancel connection");
439                 return WIFI_DIRECT_ERROR_OPERATION_FAILED;
440         }
441
442         wfd_destroy_session(manager);
443
444         __WDS_LOG_FUNC_EXIT__;
445         return 0;
446 }
447
448 int wfd_session_reject(wfd_session_s *session, unsigned char *peer_addr)
449 {
450         __WDS_LOG_FUNC_ENTER__;
451         wfd_manager_s *manager = wfd_get_manager();
452         wfd_device_s *peer = NULL;
453         int res = 0;
454
455         if (!session || !manager) {
456                 WDS_LOGE("Invalid parameter");
457                 __WDS_LOG_FUNC_EXIT__;
458                 return -1;
459         }
460
461         /* Invite received case state is just created */
462         if (session->state < SESSION_STATE_CREATED ||
463                 session->state >= SESSION_STATE_STOPPED) {
464                 WDS_LOGE("Session state is Invalid [%d]", session->state);
465                 __WDS_LOG_FUNC_EXIT__;
466                 return -1;
467         }
468
469         /*
470          * TODO: check session status and do proper work
471          * for example, reject prov_disc, reject nego, stop wps, etc.
472          *
473          */
474
475         peer = session->peer;
476
477         if (SESSION_TYPE_INVITE == session->type || SESSION_TYPE_JOIN == session->type)
478                 res = wfd_oem_wps_cancel(manager->oem_ops);
479         else
480                 res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
481         if (res < 0) {
482                 WDS_LOGE("Failed to reject connection");
483                 __WDS_LOG_FUNC_EXIT__;
484                 return -1;
485         }
486
487         wfd_destroy_session(manager);
488         // TODO: send notification to App
489
490         __WDS_LOG_FUNC_EXIT__;
491         return 0;
492 }
493
494 int wfd_session_join(wfd_session_s *session)
495 {
496         __WDS_LOG_FUNC_ENTER__;
497         wfd_manager_s *manager = wfd_get_manager();
498         wfd_oem_conn_param_s param;
499         wfd_device_s *peer = NULL;
500         int res = 0;
501
502         if (!session) {
503                 WDS_LOGE("Invalid parameter");
504                 __WDS_LOG_FUNC_EXIT__;
505                 return -1;
506         }
507
508         session->state = SESSION_STATE_WPS;
509         peer = session->peer;
510
511         memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
512         param.wps_mode = session->wps_mode;
513         if (peer->dev_role == WFD_DEV_ROLE_GO)
514                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
515         param.go_intent = session->go_intent;
516         param.freq = session->freq;
517         g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
518
519         res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
520         if (res < 0) {
521                 WDS_LOGD("Failed to join with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
522                 wfd_destroy_session(manager);
523                 __WDS_LOG_FUNC_EXIT__;
524                 return -1;
525         }
526
527         wfd_session_timer(session, 1);
528
529         __WDS_LOG_FUNC_EXIT__;
530         return 0;
531 }
532
533 int wfd_session_invite(wfd_session_s *session)
534 {
535         __WDS_LOG_FUNC_ENTER__;
536         wfd_manager_s *manager = wfd_get_manager();
537         wfd_oem_invite_param_s param;
538         wfd_device_s *peer = NULL;
539         wfd_group_s *group = NULL;
540         int res = 0;
541
542         if (!session) {
543                 WDS_LOGE("Invalid parameter");
544                 __WDS_LOG_FUNC_EXIT__;
545                 return -1;
546         }
547
548         if (session->state > SESSION_STATE_CREATED) {
549                 WDS_LOGE("Invalid session state(%d)", session->state);
550                 return -1;
551         }
552
553         peer = session->peer;
554         group = (wfd_group_s*) manager->group;
555
556         memset(&param, 0x00, sizeof(wfd_oem_invite_param_s));
557         param.ifname = strdup(group->ifname);
558         memcpy(param.go_dev_addr, group->go_dev_addr, MACADDR_LEN);
559
560         WDS_LOGD("Invite: Peer[" MACSTR "], GO Addr[" MACSTR "]",
561                                 MAC2STR(peer->dev_addr), MAC2STR(param.go_dev_addr));
562
563         res = wfd_oem_invite(manager->oem_ops, peer->dev_addr, &param);
564         if (res < 0) {
565                 WDS_LOGE("Failed to invite with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
566                 wfd_destroy_session(manager);
567                 __WDS_LOG_FUNC_EXIT__;
568                 return -1;
569         }
570
571         wfd_session_timer(session, 1);
572
573         __WDS_LOG_FUNC_EXIT__;
574         return 0;
575 }
576
577 int wfd_session_wps(wfd_session_s *session)
578 {
579         __WDS_LOG_FUNC_ENTER__;
580         wfd_manager_s *manager = wfd_get_manager();
581         wfd_device_s *peer = NULL;
582         int res = 0;
583
584         if (!session) {
585                 WDS_LOGE("Invalid parameter");
586                 __WDS_LOG_FUNC_EXIT__;
587                 return -1;
588         }
589
590         if (session->state > SESSION_STATE_WPS) {
591                 WDS_LOGE("Session already starts WPS");
592                 return -1;
593         }
594
595         session->state = SESSION_STATE_WPS;
596         peer = session->peer;
597
598         if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
599                 WDS_LOGD("My device is GO, so WPS will be started. WPS mode[%d]", session->wps_mode);
600                 res = wfd_oem_wps_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
601         } else {
602                 WDS_LOGD("My device is not GO, so Enrollee will be started. WPS mode[%d]", session->wps_mode);
603                 wfd_oem_conn_param_s param;
604                 memset(&param, 0x00, sizeof(wfd_oem_conn_param_s));
605                 param.wps_mode = session->wps_mode;
606                 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
607                 param.freq = session->freq;     // currently not used
608                 g_strlcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN + 1);
609                 res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, &param);
610         }
611         if (res < 0) {
612                 WDS_LOGE("Failed to start wps with peer [" MACSECSTR "]", MAC2SECSTR(peer->dev_addr));
613                 wfd_destroy_session(manager);
614                 __WDS_LOG_FUNC_EXIT__;
615                 return -1;
616         }
617
618         __WDS_LOG_FUNC_EXIT__;
619         return 0;
620 }
621
622 wfd_device_s *wfd_session_get_peer(wfd_session_s *session)
623 {
624         __WDS_LOG_FUNC_ENTER__;
625         wfd_device_s *peer = NULL;
626
627         if (!session) {
628                 WDS_LOGE("Invalid parameter");
629                 return NULL;
630         }
631
632         peer = session->peer;
633
634         __WDS_LOG_FUNC_EXIT__;
635         return peer;
636 }
637
638 unsigned char *wfd_session_get_peer_addr(wfd_session_s *session)
639 {
640         __WDS_LOG_FUNC_ENTER__;
641         wfd_device_s *peer = NULL;
642
643         if (!session || !session->peer) {
644                 WDS_LOGE("Invalid parameter");
645                 return NULL;
646         }
647
648         peer = session->peer;
649
650         __WDS_LOG_FUNC_EXIT__;
651         return peer->dev_addr;
652 }
653
654 #if 0
655 int wfd_session_get_wps_pin(wfd_session_s *session, unsigned char *pin)
656 {
657         __WDS_LOG_FUNC_ENTER__;
658
659         __WDS_LOG_FUNC_EXIT__;
660         return 0;
661 }
662
663 int wfd_session_set_wps_pin(wfd_session_s *session, unsigned char *pin)
664 {
665         __WDS_LOG_FUNC_ENTER__;
666
667         __WDS_LOG_FUNC_EXIT__;
668         return 0;
669 }
670
671 int wfd_session_set_freq(wfd_session_s *session, int freq)
672 {
673         __WDS_LOG_FUNC_ENTER__;
674
675         __WDS_LOG_FUNC_EXIT__;
676         return 0;
677 }
678
679 int wfd_session_get_state(wfd_session_s *session)
680 {
681         __WDS_LOG_FUNC_ENTER__;
682
683         __WDS_LOG_FUNC_EXIT__;
684         return 0;
685 }
686
687 int wfd_session_set_state(wfd_session_s *session, int state)
688 {
689         __WDS_LOG_FUNC_ENTER__;
690
691         __WDS_LOG_FUNC_EXIT__;
692         return 0;
693 }
694 #endif
695
696 int wfd_session_process_event(wfd_manager_s *manager, wfd_oem_event_s *event)
697 {
698         __WDS_LOG_FUNC_ENTER__;
699         wfd_session_s *session = NULL;
700         int res = 0;
701
702         if (!manager || !event) {
703                 WDS_LOGE("Invalid parameter");
704                 return -1;
705         }
706
707         WDS_LOGD("event ID [%d]", event->event_id);
708         session = manager->session;
709
710         switch (event->event_id) {
711         case WFD_OEM_EVENT_PROV_DISC_REQ:
712         {
713                 int req_wps_mode = WFD_WPS_MODE_NONE;
714
715                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY) {
716                         req_wps_mode = WFD_WPS_MODE_KEYPAD;
717                 } else if (event->wps_mode == WFD_WPS_MODE_KEYPAD) {
718                         req_wps_mode = WFD_WPS_MODE_DISPLAY;
719                 } else {
720                         req_wps_mode = WFD_WPS_MODE_PBC;
721                 }
722
723                 /* Only peer initiated connection or invitation session can be allowed */
724                 if (session) {
725                         if (session->type != SESSION_TYPE_INVITE) {
726                                 WDS_LOGE("Unexpected event. Session is exist [peer: " MACSECSTR "]",
727                                                                 MAC2SECSTR(event->dev_addr));
728                                 break;
729                         }
730                         WDS_LOGD("=====> session already exist. (invitation session)");
731                         session->req_wps_mode = req_wps_mode;
732                         session->wps_mode = event->wps_mode;
733                 } else {
734                         session = wfd_create_session(manager, event->dev_addr,
735                                                                 req_wps_mode, SESSION_DIRECTION_INCOMING);
736                         if (!session) {
737                                 WDS_LOGE("Failed to create session with peer [" MACSECSTR "]",
738                                                                 MAC2SECSTR(event->dev_addr));
739                                 break;
740                         }
741                 }
742
743                 /* Update session */
744                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY) {
745                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
746                 }
747                 session->state = SESSION_STATE_STARTED;
748                 if (session->type == SESSION_TYPE_INVITE) {
749                         WDS_LOGD("Invitation session");
750                 } else if (WFD_DEV_ROLE_GO == manager->local->dev_role) {
751                         session->type = SESSION_TYPE_JOIN;
752                 } else {
753                         session->type = SESSION_TYPE_NORMAL;
754                 }
755                 wfd_session_timer(session, 1);
756
757                 /* Update local device */
758                 manager->local->wps_mode = event->wps_mode;
759
760                 wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
761
762                 if (session->type == SESSION_TYPE_INVITE) {
763                         WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
764                         if (session->wps_mode != WFD_WPS_MODE_PBC) {
765                                 char peer_mac_address[MACSTR_LEN+1] = {0, };
766
767                                 g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
768                                 wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
769                                                              "Connection",
770                                                              g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
771                                                                                     WFD_EVENT_CONNECTION_WPS_REQ,
772                                                                                     peer_mac_address));
773                                 if (session->wps_mode == WFD_WPS_MODE_KEYPAD) {
774                                         /* We have to wait until user type PIN using Keypad */
775                                         break;
776                                 }
777                         }
778                         res = wfd_session_wps(session);
779                         if (res < 0)
780                                 _wfd_notify_session_failed(manager, event->dev_addr);
781                 } else {
782                         char peer_mac_address[MACSTR_LEN+1] = {0, };
783
784                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
785                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
786                                                      "Connection",
787                                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
788                                                                             WFD_EVENT_CONNECTION_REQ,
789                                                                             peer_mac_address));
790                 }
791         }
792         break;
793         case WFD_OEM_EVENT_PROV_DISC_RESP:
794         {
795                 if (!session) {         // TODO: check validity of Event
796                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
797                                                                                 MAC2SECSTR(event->dev_addr));
798                         break;
799                 }
800
801                 if (session->state > SESSION_STATE_STARTED) {
802                         WDS_LOGE("Unexpected event. Session is already started");
803                         break;
804                 }
805
806                 if (session->type == SESSION_TYPE_INVITE) {
807                         WDS_LOGE("Session type is invite, ignore provision discovery response");
808                         break;
809                 }
810
811                 /* Update session */
812                 session->wps_mode = event->wps_mode;
813                 if (event->wps_mode == WFD_WPS_MODE_DISPLAY) {
814                         session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
815                         g_strlcpy(session->wps_pin, event->wps_pin, PINSTR_LEN + 1);
816                 } else if (event->wps_mode == WFD_WPS_MODE_KEYPAD) {
817                         session->req_wps_mode = WFD_WPS_MODE_DISPLAY;
818                 } else {
819                         session->req_wps_mode = WFD_WPS_MODE_PBC;
820                 }
821                 session->state = SESSION_STATE_STARTED;
822                 wfd_session_timer(session, 1);
823
824                 /* Update local device */
825                 manager->local->wps_mode = event->wps_mode;
826                 WDS_LOGD("Local WPS mode is %d", session->wps_mode);
827
828                 if (session->wps_mode != WFD_WPS_MODE_PBC) {
829                         char peer_mac_address[MACSTR_LEN+1] = {0, };
830
831                         g_snprintf(peer_mac_address, MACSTR_LEN, MACSTR, MAC2STR(event->dev_addr));
832                         wfd_manager_dbus_emit_signal(WFD_MANAGER_MANAGE_INTERFACE,
833                                                      "Connection",
834                                                      g_variant_new("(iis)", WIFI_DIRECT_ERROR_NONE,
835                                                                             WFD_EVENT_CONNECTION_WPS_REQ,
836                                                                             peer_mac_address));
837                         if (session->wps_mode == WFD_WPS_MODE_KEYPAD) {
838                                 /* We have to wait until user type PIN using Keypad */
839                                 break;
840                         }
841                 }
842
843                 if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
844                         WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
845                         res = wfd_session_wps(session);
846                 } else if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
847                         WDS_LOGD("Start WPS(join) corresponding to OEM event [%d]", event->event_id);
848                         res = wfd_session_join(session);
849                 } else {
850                         WDS_LOGD("Start connection corresponding to OEM event [%d]", event->event_id);
851                         res = wfd_session_connect(session);
852                 }
853         }
854         if (res < 0)
855                 _wfd_notify_session_failed(manager, event->dev_addr);
856         break;
857         case WFD_OEM_EVENT_GO_NEG_REQ:
858                 if (!session) {
859                         // TODO: check whether connection is started by negotiation not by prov_disc
860                         WDS_LOGE("Unexpected event. Session not exist [peer: " MACSECSTR "]",
861                                                 MAC2SECSTR(event->dev_addr));
862                         break;
863                 } else {
864                         /* Sometimes, Provision Discovery response is not received.
865                          * At this time, connection should be triggered by GO Negotiation request event */
866                         if (session->direction == SESSION_DIRECTION_OUTGOING) {
867                                 res = wfd_session_connect(session);
868                         } else {
869                                 /* In autoconnection mode, MT should not send GO Nego Req
870                                    before receiving the GO Nego Req from peer (MO). */
871                                 if (manager->autoconnection == TRUE)
872                                         res  = wfd_session_connect(session);
873                         }
874                         if (res < 0)
875                                 _wfd_notify_session_failed(manager, event->dev_addr);
876                 }
877                 break;
878         case WFD_OEM_EVENT_GO_NEG_DONE:
879                 if (!session) {
880                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
881                                                 MAC2SECSTR(event->dev_addr));
882                         break;
883                 } else {
884                         session->state = SESSION_STATE_WPS;
885                 }
886
887                 break;
888         case WFD_OEM_EVENT_WPS_DONE:
889                 if (!session) {
890                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
891                                                 MAC2SECSTR(event->dev_addr));
892                         break;
893                 } else {
894                         session->state = SESSION_STATE_KEY_NEG;
895                 }
896
897                 break;
898         case WFD_OEM_EVENT_STA_CONNECTED:
899                 if (!session) {
900                         WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSECSTR "]",
901                                                 MAC2SECSTR(event->dev_addr));
902                         break;
903                 } else {
904                         session->state = SESSION_STATE_COMPLETED;
905                 }
906
907                 break;
908         default:
909                 break;
910         }
911         __WDS_LOG_FUNC_EXIT__;
912         return 0;
913 }