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