2 * Network Configuration Module
4 * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * This file implements wifi direct session functions.
23 * @file wifi-direct-session.c
24 * @author Gibyoung Kim (lastkgb.kim@samsung.com)
33 #include <wifi-direct-internal.h>
35 #include "wifi-direct-manager.h"
36 #include "wifi-direct-oem.h"
37 #include "wifi-direct-peer.h"
38 #include "wifi-direct-group.h"
39 #include "wifi-direct-oem.h"
40 #include "wifi-direct-util.h"
41 #include "wifi-direct-session.h"
42 #include "wifi-direct-client.h"
43 #include "wifi-direct-state.h"
46 static gboolean _session_timeout_cb(gpointer *user_data)
48 __WDS_LOG_FUNC_ENTER__;
49 wfd_manager_s *manager = wfd_get_manager();
50 wfd_session_s *session = (wfd_session_s*) manager->session;
51 wifi_direct_client_noti_s noti;
52 unsigned char *peer_addr = NULL;
55 WDS_LOGE("Invalid parameter");
58 session->connecting_120 = 0;
60 WDS_LOGD("Session timer expired");
62 peer_addr = wfd_session_get_peer_addr(session);
64 memset(¬i, 0x0, sizeof(wifi_direct_client_noti_s));
65 noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_RSP;
66 noti.error = WIFI_DIRECT_ERROR_CONNECTION_CANCELED;
67 snprintf(noti.param1, MACSTR_LEN, MACSTR, MAC2STR(peer_addr));
68 wfd_client_send_event(manager, ¬i);
70 wfd_session_cancel(session, peer_addr);
72 if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
73 wfd_state_set(manager, WIFI_DIRECT_STATE_GROUP_OWNER);
74 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_GROUP_OWNER);
76 wfd_state_set(manager, WIFI_DIRECT_STATE_ACTIVATED);
77 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_ACTIVATED);
80 __WDS_LOG_FUNC_EXIT__;
84 int wfd_session_timer(wfd_session_s *session, int start)
86 __WDS_LOG_FUNC_ENTER__;
89 WDS_LOGE("Invalid parameter");
90 __WDS_LOG_FUNC_EXIT__;
95 session->connecting_120 = 1;
96 if (session->timer > 0) {
97 WDS_LOGE("Session timer already started");
98 __WDS_LOG_FUNC_EXIT__;
101 session->timer = g_timeout_add(120000,
102 (GSourceFunc) _session_timeout_cb,
104 WDS_LOGD("Session timer started");
106 session->connecting_120 = 0;
107 if (session->timer > 0) {
108 g_source_remove(session->timer);
110 WDS_LOGD("Session timer stoped");
114 __WDS_LOG_FUNC_EXIT__;
118 // Check the session instance which has same peer address, before using this function
119 wfd_session_s *wfd_create_session(void *data, unsigned char *peer_addr, int wps_mode, int direction)
121 __WDS_LOG_FUNC_ENTER__;
122 wfd_manager_s *manager = (wfd_manager_s*) data;
123 wfd_session_s *session = NULL;
124 wfd_device_s *peer = NULL;
126 if (!data || !peer_addr) {
127 WDS_LOGE("Invalid parameter");
128 __WDS_LOG_FUNC_EXIT__;
132 if (manager->session) {
133 WDS_LOGE("Session already exist");
137 session = (wfd_session_s*) calloc(1, sizeof(wfd_session_s));
139 WDS_LOGE("Failed to allocate memory for session");
140 __WDS_LOG_FUNC_EXIT__;
144 peer = wfd_peer_find_by_dev_addr(manager, peer_addr);
146 WDS_LOGE("Failed to find peer info[" MACSTR "]", MAC2STR(peer_addr));
148 __WDS_LOG_FUNC_EXIT__;
151 peer->state = WFD_PEER_STATE_CONNECTING;
153 session->peer = peer;
154 session->req_wps_mode = wps_mode;
155 if (wps_mode == WFD_WPS_MODE_DISPLAY)
156 session->wps_mode = WFD_WPS_MODE_KEYPAD;
157 else if (wps_mode == WFD_WPS_MODE_KEYPAD)
158 session->wps_mode = WFD_WPS_MODE_DISPLAY;
160 session->wps_mode = wps_mode;
161 session->direction = direction;
162 session->state = SESSION_STATE_CREATED;
164 manager->session = session;
165 manager->local->wps_mode = session->wps_mode;
166 if (peer->dev_role == WFD_DEV_ROLE_GO)
167 manager->local->dev_role = WFD_DEV_ROLE_GC;
169 __WDS_LOG_FUNC_EXIT__;
173 int wfd_destroy_session(void *data)
175 __WDS_LOG_FUNC_ENTER__;
176 wfd_manager_s *manager = (wfd_manager_s*) data;
177 wfd_session_s *session = NULL;
178 wfd_device_s *peer = NULL;
181 WDS_LOGE("Invalid parameter");
185 session = (wfd_session_s*) manager->session;
187 WDS_LOGE("Session not found");
190 wfd_session_timer(session, 0);
191 peer = session->peer;
193 if (session->state == SESSION_STATE_COMPLETED)
194 peer->state = WFD_PEER_STATE_CONNECTED;
196 peer->state = WFD_PEER_STATE_DISCOVERED;
199 manager->session = NULL;
200 manager->local->wps_mode = WFD_WPS_MODE_PBC;
201 manager->autoconnection = 0;
202 if (manager->local->dev_role == WFD_DEV_ROLE_GC)
203 manager->local->dev_role = WFD_DEV_ROLE_NONE;
205 __WDS_LOG_FUNC_EXIT__;
209 int wfd_session_start(wfd_session_s *session)
211 __WDS_LOG_FUNC_ENTER__;
212 wfd_manager_s *manager = wfd_get_manager();
213 wfd_device_s *peer = NULL;
218 WDS_LOGE("Invalid parameter");
219 __WDS_LOG_FUNC_EXIT__;
223 // Check: Invitation Received in Incomming case -> send prov_disc join
224 // Check: User select peer to connect with in Outgoing case -> send prov_disc wps_mdde
226 wfd_oem_stop_scan(manager->oem_ops);
228 session->state = SESSION_STATE_STARTED;
229 peer = session->peer;
230 if (peer->dev_role == WFD_DEV_ROLE_GO || session->type == SESSION_TYPE_INVITE)
232 res = wfd_oem_prov_disc_req(manager->oem_ops, peer->dev_addr,
233 session->req_wps_mode, join);
235 WDS_LOGE("Failed to send provision discovery request to peer [" MACSTR "]",
236 MAC2STR(peer->dev_addr));
237 wfd_destroy_session(manager);
238 // TODO: send notification to App
239 __WDS_LOG_FUNC_EXIT__;
243 wfd_session_timer(session, 1);
245 __WDS_LOG_FUNC_EXIT__;
249 int wfd_session_stop(wfd_session_s *session)
251 __WDS_LOG_FUNC_ENTER__;
252 wfd_manager_s *manager = wfd_get_manager();
253 wfd_device_s *peer = NULL;
257 WDS_LOGE("Invalid parameter");
258 __WDS_LOG_FUNC_EXIT__;
262 if (session->state > SESSION_STATE_CREATED) {
263 peer = session->peer;
264 if (session->direction == SESSION_DIRECTION_INCOMING) {
265 res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
266 } else if (session->direction == SESSION_DIRECTION_OUTGOING) {
267 res = wfd_oem_cancel_connection(manager->oem_ops, peer->dev_addr);
270 WDS_LOGE("Failed to reject or cancel connection");
271 __WDS_LOG_FUNC_EXIT__;
276 session->state = SESSION_STATE_STOPPED;
277 wfd_destroy_session(manager);
279 __WDS_LOG_FUNC_EXIT__;
283 /* In case of incomming session, when user accept connection request, this function should be called.
284 * In case of outgoing session, when prov_disc response arrived, this function should be called.
285 * Even though peer is GO, we can use this function, which can decide using join itself.
287 int wfd_session_connect(wfd_session_s *session)
289 __WDS_LOG_FUNC_ENTER__;
290 wfd_manager_s *manager = wfd_get_manager();
291 wfd_oem_conn_param_s param;
292 wfd_device_s *peer = NULL;
296 WDS_LOGE("Invalid parameter");
297 __WDS_LOG_FUNC_EXIT__;
301 if (session->state > SESSION_STATE_GO_NEG) {
302 WDS_LOGE("Session already starts GO Negotiation");
306 session->state = SESSION_STATE_GO_NEG;
307 peer = session->peer;
309 memset(¶m, 0x00, sizeof(wfd_oem_conn_param_s));
310 param.wps_mode = session->wps_mode;
311 if (peer->dev_role == WFD_DEV_ROLE_GO || session->type == SESSION_TYPE_INVITE)
312 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
313 param.go_intent = session->go_intent;
314 param.freq = session->freq;
315 if (session->wps_pin[0] != '\0') {
316 strncpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN);
317 param.wps_pin[OEM_PINSTR_LEN] = '\0';
320 res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, ¶m);
322 WDS_LOGE("Failed to connect peer [" MACSTR "]", MAC2STR(peer->dev_addr));
323 wfd_destroy_session(manager);
324 // TODO: send notification to App
325 __WDS_LOG_FUNC_EXIT__;
329 wfd_session_timer(session, 1);
331 __WDS_LOG_FUNC_EXIT__;
335 int wfd_session_cancel(wfd_session_s *session, unsigned char *peer_addr)
337 __WDS_LOG_FUNC_ENTER__;
338 wfd_manager_s *manager = wfd_get_manager();
341 if (!session || !session->peer) {
342 WDS_LOGE("Invalid parameter");
343 __WDS_LOG_FUNC_EXIT__;
344 return WIFI_DIRECT_ERROR_NOT_PERMITTED;
347 if (memcmp(peer_addr, session->peer->dev_addr, MACADDR_LEN)) {
348 WDS_LOGE("Peer is not included in this session");
349 return WIFI_DIRECT_ERROR_NOT_PERMITTED;
352 if (session->state > SESSION_STATE_GO_NEG)
353 res = wfd_oem_wps_cancel(manager->oem_ops);
355 res = wfd_oem_cancel_connection(manager->oem_ops, peer_addr);
358 WDS_LOGE("Failed to cancel connection");
359 return WIFI_DIRECT_ERROR_OPERATION_FAILED;
362 wfd_destroy_session(manager);
364 __WDS_LOG_FUNC_EXIT__;
368 int wfd_session_reject(wfd_session_s *session, unsigned char *peer_addr)
370 __WDS_LOG_FUNC_ENTER__;
371 wfd_manager_s *manager = wfd_get_manager();
372 wfd_device_s *peer = NULL;
376 WDS_LOGE("Invalid parameter");
377 __WDS_LOG_FUNC_EXIT__;
381 if (session->state < SESSION_STATE_STARTED) {
382 WDS_LOGE("Session is not started");
383 __WDS_LOG_FUNC_EXIT__;
387 if (session->direction != SESSION_DIRECTION_INCOMING) {
388 WDS_LOGE("Cannot reject with outgoing connection");
389 __WDS_LOG_FUNC_EXIT__;
393 // TODO: check session status and do proper work
394 // for example, reject prov_disc, reject nego, stop wps, etc.
395 peer = session->peer;
396 res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
398 WDS_LOGE("Failed to reject connection");
399 __WDS_LOG_FUNC_EXIT__;
403 wfd_destroy_session(manager);
404 // TODO: send notification to App
406 __WDS_LOG_FUNC_EXIT__;
410 int wfd_session_join(wfd_session_s *session)
412 __WDS_LOG_FUNC_ENTER__;
413 wfd_manager_s *manager = wfd_get_manager();
414 wfd_oem_conn_param_s param;
415 wfd_device_s *peer = NULL;
419 WDS_LOGE("Invalid parameter");
420 __WDS_LOG_FUNC_EXIT__;
424 session->state = SESSION_STATE_WPS;
425 peer = session->peer;
427 memset(¶m, 0x00, sizeof(wfd_oem_conn_param_s));
428 param.wps_mode = session->wps_mode;
429 if (peer->dev_role == WFD_DEV_ROLE_GO)
430 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
431 param.go_intent = session->go_intent;
432 param.freq = session->freq;
433 memcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN);
435 res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, ¶m);
437 WDS_LOGE("Failed to join with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
438 wfd_destroy_session(manager);
439 // TODO: send notification to App
440 __WDS_LOG_FUNC_EXIT__;
444 wfd_session_timer(session, 1);
446 __WDS_LOG_FUNC_EXIT__;
450 int wfd_session_invite(wfd_session_s *session)
452 __WDS_LOG_FUNC_ENTER__;
453 wfd_manager_s *manager = wfd_get_manager();
454 wfd_oem_invite_param_s param;
455 wfd_device_s *peer = NULL;
456 wfd_group_s *group = NULL;
460 WDS_LOGE("Invalid parameter");
461 __WDS_LOG_FUNC_EXIT__;
465 peer = session->peer;
466 group = (wfd_group_s*) manager->group;
468 memset(¶m, 0x00, sizeof(wfd_oem_invite_param_s));
469 param.ifname = strdup(group->ifname);
470 memcpy(param.go_dev_addr, group->go_dev_addr, MACADDR_LEN);
472 WDS_LOGD("Invite: Peer[" MACSTR "], GO Addr[" MACSTR "]", MAC2STR(peer->dev_addr), MAC2STR(param.go_dev_addr));
474 res = wfd_oem_invite(manager->oem_ops, peer->dev_addr, ¶m);
476 WDS_LOGE("Failed to invite with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
477 wfd_destroy_session(manager);
478 // TODO: send notification to App
479 __WDS_LOG_FUNC_EXIT__;
483 wfd_session_timer(session, 1);
485 __WDS_LOG_FUNC_EXIT__;
489 int wfd_session_wps(wfd_session_s *session)
491 __WDS_LOG_FUNC_ENTER__;
492 wfd_manager_s *manager = wfd_get_manager();
493 wfd_device_s *peer = NULL;
497 WDS_LOGE("Invalid parameter");
498 __WDS_LOG_FUNC_EXIT__;
502 if (session->state > SESSION_STATE_WPS) {
503 WDS_LOGE("Session already starts WPS");
507 session->state = SESSION_STATE_WPS;
508 peer = session->peer;
510 if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
511 WDS_LOGD("My device is GO, so WPS will be started. WPS mode[%d]", session->wps_mode);
512 res = wfd_oem_wps_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
514 WDS_LOGD("My device is not GO, so Enrollee will be started. WPS mode[%d]", session->wps_mode);
515 res = wfd_oem_enrollee_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
518 WDS_LOGE("Failed to start wps with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
519 wfd_destroy_session(manager);
520 // TODO: send notification to App
521 __WDS_LOG_FUNC_EXIT__;
525 __WDS_LOG_FUNC_EXIT__;
529 wfd_device_s *wfd_session_get_peer(wfd_session_s *session)
531 __WDS_LOG_FUNC_ENTER__;
532 wfd_device_s *peer = NULL;
535 WDS_LOGE("Invalid parameter");
539 peer = session->peer;
541 __WDS_LOG_FUNC_EXIT__;
545 unsigned char *wfd_session_get_peer_addr(wfd_session_s *session)
547 __WDS_LOG_FUNC_ENTER__;
548 wfd_device_s *peer = NULL;
550 if (!session || !session->peer) {
551 WDS_LOGE("Invalid parameter");
555 peer = session->peer;
557 __WDS_LOG_FUNC_EXIT__;
558 return peer->dev_addr;
561 int wfd_session_get_wps_pin(wfd_session_s *session, unsigned char *pin)
563 __WDS_LOG_FUNC_ENTER__;
565 __WDS_LOG_FUNC_EXIT__;
569 int wfd_session_set_wps_pin(wfd_session_s *session, unsigned char *pin)
571 __WDS_LOG_FUNC_ENTER__;
573 __WDS_LOG_FUNC_EXIT__;
577 int wfd_session_set_freq(wfd_session_s *session, int freq)
579 __WDS_LOG_FUNC_ENTER__;
581 __WDS_LOG_FUNC_EXIT__;
585 int wfd_session_get_state(wfd_session_s *session)
587 __WDS_LOG_FUNC_ENTER__;
589 __WDS_LOG_FUNC_EXIT__;
593 int wfd_session_set_state(wfd_session_s *session, int state)
595 __WDS_LOG_FUNC_ENTER__;
597 __WDS_LOG_FUNC_EXIT__;
601 int wfd_session_process_event(wfd_manager_s *manager, wfd_oem_event_s *event)
603 __WDS_LOG_FUNC_ENTER__;
604 wfd_session_s *session = NULL;
606 if (!manager || !event) {
607 WDS_LOGE("Invalid parameter");
611 wfd_dev_connection_flag_e flag = 0;
612 flag = wfd_manager_access_control(manager, event->dev_addr);
614 WDS_LOGD("event ID [%d]", event->event_id);
615 session = manager->session;
617 switch (event->event_id) {
618 case WFD_OEM_EVENT_PROV_DISC_REQ:
621 WDS_LOGE("Unexpected event. Session already exist. This request should be ignored");
625 /* Create new session */
626 session = wfd_create_session(manager, event->dev_addr,
627 event->wps_mode, SESSION_DIRECTION_INCOMING);
629 WDS_LOGE("Failed to create session with peer [" MACSTR "]",
630 MAC2STR(event->dev_addr));
635 if (event->wps_mode == WFD_OEM_WPS_MODE_DISPLAY) {
636 strncpy(session->wps_pin, event->wps_pin, PINSTR_LEN);
637 session->wps_pin[PINSTR_LEN] = '\0';
639 session->state = SESSION_STATE_STARTED;
640 wfd_session_timer(session, 1);
643 manager->local->wps_mode = event->wps_mode;
644 wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
646 if(flag == WFD_DEV_ALLOWED)
648 WDS_LOGD("device is allowed");
649 if (manager->local->dev_role == WFD_DEV_ROLE_GO)
650 wfd_session_wps(session);
652 wfd_session_connect(session);
655 /* Send event to application */
656 WDS_LOGD("device is not in access/deny list");
657 wifi_direct_client_noti_s noti;
658 memset(¬i, 0x0, sizeof(wifi_direct_client_noti_s));
659 noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_REQ;
660 noti.error = WIFI_DIRECT_ERROR_NONE;
661 snprintf(noti.param1, sizeof(noti.param1), MACSTR, MAC2STR(event->dev_addr));
662 wfd_client_send_event(manager, ¬i);
666 case WFD_OEM_EVENT_PROV_DISC_RESP:
669 WDS_LOGE("Unexpected event. Session not exist. This response should be ignored");
673 if (session->state > SESSION_STATE_STARTED) {
674 WDS_LOGE("Unexpected event. Session is already started");
679 if (event->wps_mode == WFD_OEM_WPS_MODE_DISPLAY) {
680 session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
681 strncpy(session->wps_pin, event->wps_pin, PINSTR_LEN);
682 session->wps_pin[PINSTR_LEN] = '\0';
683 } else if (event->wps_mode == WFD_OEM_WPS_MODE_KEYPAD) {
684 session->req_wps_mode = WFD_WPS_MODE_DISPLAY;
686 session->req_wps_mode = WFD_WPS_MODE_PBC;
688 session->wps_mode = event->wps_mode;
689 wfd_session_timer(session, 1);
692 manager->local->wps_mode = event->wps_mode;
693 WDS_LOGD("Local WPS mode is %d", session->wps_mode);
695 if (event->wps_mode != WFD_OEM_WPS_MODE_PBC) {
696 /* Notify WPS_MODE to application so it can display PIN or KEYPAD */
697 wifi_direct_client_noti_s noti;
698 memset(¬i, 0x0, sizeof(wifi_direct_client_noti_s));
699 noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_WPS_REQ;
700 snprintf(noti.param1, sizeof(noti.param1), MACSTR, MAC2STR(event->dev_addr));
701 wfd_client_send_event(manager, ¬i);
702 if (session->wps_mode == WFD_WPS_MODE_KEYPAD)
706 /* Go to next step of connection immediately */
707 if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
708 WDS_LOGD("Start joining corresponding to OEM event [%d]", event->event_id);
709 wfd_session_join(session);
710 } else if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
711 WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
712 wfd_session_wps(session);
714 WDS_LOGD("Start connection corresponding to OEM event [%d]", event->event_id);
715 wfd_session_connect(session);
719 case WFD_OEM_EVENT_GO_NEG_REQ:
720 if (!session) { // TODO: check whether connection is started by negotiation not by prov_disc
721 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
724 /* Sometimes, Provision Discovery response is not received.
725 * At this time, connection should be triggered by GO Negotiation request event */
726 if (session->direction == SESSION_DIRECTION_OUTGOING)
727 wfd_session_connect(session);
730 case WFD_OEM_EVENT_GO_NEG_DONE:
732 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
735 session->state = SESSION_STATE_WPS;
739 case WFD_OEM_EVENT_WPS_DONE:
741 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
744 session->state = SESSION_STATE_KEY_NEG;
748 case WFD_OEM_EVENT_CONNECTED:
751 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
754 wfd_group_s *group = manager->group;
756 group = wfd_create_pending_group(manager, event->intf_addr);
758 WDS_LOGE("Failed to create pending group");
761 manager->group = group;
762 } else { // multiconnection, additional client connected
763 WDS_LOGE("Unexpected event. Group already exist");
764 //wfd_group_add_member(manager, event->intf_addr, peer->dev_addr);
767 session->state = SESSION_STATE_COMPLETED;
771 case WFD_OEM_EVENT_STA_CONNECTED:
773 WDS_LOGD("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
776 session->state = SESSION_STATE_COMPLETED;
783 __WDS_LOG_FUNC_EXIT__;