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-event.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;
53 WDS_LOGE("Invalid parameter");
57 session->connecting_120 = 0;
59 wfd_destroy_session(manager);
61 __WDS_LOG_FUNC_EXIT__;
65 static int _session_timer(wfd_session_s *session, int start)
67 __WDS_LOG_FUNC_ENTER__;
70 WDS_LOGE("Invalid parameter");
71 __WDS_LOG_FUNC_EXIT__;
76 session->connecting_120 = 1;
77 if (session->timer > 0) {
78 WDS_LOGE("Session timer already started");
79 __WDS_LOG_FUNC_EXIT__;
82 session->timer = g_timeout_add(120000,
83 (GSourceFunc) _session_timeout_cb,
85 WDS_LOGD("Session timer started");
87 session->connecting_120 = 0;
88 if (session->timer > 0) {
89 g_source_remove(session->timer);
91 WDS_LOGD("Session timer stoped");
95 __WDS_LOG_FUNC_EXIT__;
99 // Check the session instance which has same peer address, before using this function
100 wfd_session_s *wfd_create_session(void *data, unsigned char *peer_addr, int wps_mode, int direction)
102 __WDS_LOG_FUNC_ENTER__;
103 wfd_manager_s *manager = (wfd_manager_s*) data;
104 wfd_session_s *session = NULL;
105 wfd_device_s *peer = NULL;
107 if (!data || !peer_addr) {
108 WDS_LOGE("Invalid parameter");
109 __WDS_LOG_FUNC_EXIT__;
113 if (manager->session) {
114 WDS_LOGE("Session already exist");
118 session = (wfd_session_s*) calloc(1, sizeof(wfd_session_s));
120 WDS_LOGE("Failed to allocate memory for session");
121 __WDS_LOG_FUNC_EXIT__;
125 peer = wfd_peer_find_by_dev_addr(manager, peer_addr);
127 WDS_LOGE("Failed to find peer info[" MACSTR "]", MAC2STR(peer_addr));
129 __WDS_LOG_FUNC_EXIT__;
132 peer->state = WFD_PEER_STATE_CONNECTING;
134 session->peer = peer;
135 session->req_wps_mode = wps_mode;
136 if (wps_mode == WFD_WPS_MODE_DISPLAY)
137 session->wps_mode = WFD_WPS_MODE_KEYPAD;
138 else if (wps_mode == WFD_WPS_MODE_KEYPAD)
139 session->wps_mode = WFD_WPS_MODE_DISPLAY;
141 session->wps_mode = wps_mode;
142 session->direction = direction;
143 session->state = SESSION_STATE_CREATED;
145 manager->session = session;
146 manager->local->wps_mode = session->wps_mode;
147 if (peer->dev_role == WFD_DEV_ROLE_GO)
148 manager->local->dev_role = WFD_DEV_ROLE_GC;
150 __WDS_LOG_FUNC_EXIT__;
154 int wfd_destroy_session(void *data)
156 __WDS_LOG_FUNC_ENTER__;
157 wfd_manager_s *manager = (wfd_manager_s*) data;
158 wfd_session_s *session = NULL;
159 wfd_device_s *peer = NULL;
162 WDS_LOGE("Invalid parameter");
166 session = (wfd_session_s*) manager->session;
168 WDS_LOGE("Session not found");
171 _session_timer(session, 0);
172 peer = session->peer;
174 if (session->state == SESSION_STATE_COMPLETED)
175 peer->state = WFD_PEER_STATE_CONNECTED;
177 peer->state = WFD_PEER_STATE_DISCOVERED;
180 manager->session = NULL;
181 manager->local->wps_mode = WFD_WPS_MODE_PBC;
182 manager->autoconnection = 0;
183 if (manager->local->dev_role == WFD_DEV_ROLE_GC)
184 manager->local->dev_role = WFD_DEV_ROLE_NONE;
186 __WDS_LOG_FUNC_EXIT__;
190 int wfd_session_start(wfd_session_s *session)
192 __WDS_LOG_FUNC_ENTER__;
193 wfd_manager_s *manager = wfd_get_manager();
194 wfd_device_s *peer = NULL;
199 WDS_LOGE("Invalid parameter");
200 __WDS_LOG_FUNC_EXIT__;
204 // Check: Invitation Received in Incomming case -> send prov_disc join
205 // Check: User select peer to connect with in Outgoing case -> send prov_disc wps_mdde
207 wfd_oem_stop_scan(manager->oem_ops);
209 session->state = SESSION_STATE_STARTED;
210 peer = session->peer;
211 if (peer->dev_role == WFD_DEV_ROLE_GO || session->invitation)
213 res = wfd_oem_prov_disc_req(manager->oem_ops, peer->dev_addr,
214 session->req_wps_mode, join);
216 WDS_LOGE("Failed to send provision discovery request to peer [" MACSTR "]",
217 MAC2STR(peer->dev_addr));
218 wfd_destroy_session(manager);
219 // TODO: send notification to App
220 __WDS_LOG_FUNC_EXIT__;
224 _session_timer(session, 1);
226 __WDS_LOG_FUNC_EXIT__;
230 int wfd_session_stop(wfd_session_s *session)
232 __WDS_LOG_FUNC_ENTER__;
233 wfd_manager_s *manager = wfd_get_manager();
234 wfd_device_s *peer = NULL;
238 WDS_LOGE("Invalid parameter");
239 __WDS_LOG_FUNC_EXIT__;
243 if (session->state > SESSION_STATE_CREATED) {
244 peer = session->peer;
245 if (session->direction == SESSION_DIRECTION_INCOMING) {
246 res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
247 } else if (session->direction == SESSION_DIRECTION_OUTGOING) {
248 res = wfd_oem_cancel_connection(manager->oem_ops, peer->dev_addr);
251 WDS_LOGE("Failed to reject or cancel connection");
252 __WDS_LOG_FUNC_EXIT__;
257 session->state = SESSION_STATE_STOPPED;
258 wfd_destroy_session(manager);
260 __WDS_LOG_FUNC_EXIT__;
264 /* In case of incomming session, when user accept connection request, this function should be called.
265 * In case of outgoing session, when prov_disc response arrived, this function should be called.
266 * Even though peer is GO, we can use this function, which can decide using join itself.
268 int wfd_session_connect(wfd_session_s *session)
270 __WDS_LOG_FUNC_ENTER__;
271 wfd_manager_s *manager = wfd_get_manager();
272 wfd_oem_conn_param_s param;
273 wfd_device_s *peer = NULL;
277 WDS_LOGE("Invalid parameter");
278 __WDS_LOG_FUNC_EXIT__;
282 if (session->state > SESSION_STATE_GO_NEG) {
283 WDS_LOGE("Session already starts GO Negotiation");
287 session->state = SESSION_STATE_GO_NEG;
288 peer = session->peer;
290 memset(¶m, 0x00, sizeof(wfd_oem_conn_param_s));
291 param.wps_mode = session->wps_mode;
292 if (peer->dev_role == WFD_DEV_ROLE_GO)
293 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
294 param.go_intent = session->go_intent;
295 param.freq = session->freq;
296 if (session->wps_pin[0] != '\0') {
297 strncpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN);
298 param.wps_pin[OEM_PINSTR_LEN] = '\0';
301 res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, ¶m);
303 WDS_LOGE("Failed to connect peer [" MACSTR "]", MAC2STR(peer->dev_addr));
304 wfd_destroy_session(manager);
305 // TODO: send notification to App
306 __WDS_LOG_FUNC_EXIT__;
310 _session_timer(session, 1);
312 __WDS_LOG_FUNC_EXIT__;
316 int wfd_session_reject(wfd_session_s *session)
318 __WDS_LOG_FUNC_ENTER__;
319 wfd_manager_s *manager = wfd_get_manager();
320 wfd_device_s *peer = NULL;
324 WDS_LOGE("Invalid parameter");
325 __WDS_LOG_FUNC_EXIT__;
329 if (session->state < SESSION_STATE_STARTED) {
330 WDS_LOGE("Session is not started");
331 __WDS_LOG_FUNC_EXIT__;
335 if (session->direction != SESSION_DIRECTION_INCOMING) {
336 WDS_LOGE("Cannot reject with outgoing connection");
337 __WDS_LOG_FUNC_EXIT__;
341 // TODO: check session status and do proper work
342 // for example, reject prov_disc, reject nego, stop wps, etc.
343 peer = session->peer;
344 res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
346 WDS_LOGE("Failed to reject connection");
347 __WDS_LOG_FUNC_EXIT__;
351 wfd_destroy_session(manager);
352 // TODO: send notification to App
354 __WDS_LOG_FUNC_EXIT__;
358 int wfd_session_join(wfd_session_s *session)
360 __WDS_LOG_FUNC_ENTER__;
361 wfd_manager_s *manager = wfd_get_manager();
362 wfd_oem_conn_param_s param;
363 wfd_device_s *peer = NULL;
367 WDS_LOGE("Invalid parameter");
368 __WDS_LOG_FUNC_EXIT__;
372 session->state = SESSION_STATE_WPS;
373 peer = session->peer;
375 memset(¶m, 0x00, sizeof(wfd_oem_conn_param_s));
376 param.wps_mode = session->wps_mode;
377 if (peer->dev_role == WFD_DEV_ROLE_GO)
378 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
379 param.go_intent = session->go_intent;
380 param.freq = session->freq;
381 memcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN);
383 res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, ¶m);
385 WDS_LOGE("Failed to join with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
386 wfd_destroy_session(manager);
387 // TODO: send notification to App
388 __WDS_LOG_FUNC_EXIT__;
392 _session_timer(session, 1);
394 __WDS_LOG_FUNC_EXIT__;
398 int wfd_session_invite(wfd_session_s *session)
400 __WDS_LOG_FUNC_ENTER__;
401 wfd_manager_s *manager = wfd_get_manager();
402 wfd_oem_invite_param_s param;
403 wfd_device_s *peer = NULL;
404 wfd_group_s *group = NULL;
408 WDS_LOGE("Invalid parameter");
409 __WDS_LOG_FUNC_EXIT__;
413 peer = session->peer;
414 group = (wfd_group_s*) manager->group;
416 memset(¶m, 0x00, sizeof(wfd_oem_invite_param_s));
417 param.ifname = strdup(group->ifname);
418 memcpy(param.go_dev_addr, group->go_dev_addr, MACADDR_LEN);
420 WDS_LOGD("Invite: Peer[" MACSTR "], GO Addr[" MACSTR "]", MAC2STR(peer->dev_addr), MAC2STR(param.go_dev_addr));
422 res = wfd_oem_invite(manager->oem_ops, peer->dev_addr, ¶m);
424 WDS_LOGE("Failed to invite with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
425 wfd_destroy_session(manager);
426 // TODO: send notification to App
427 __WDS_LOG_FUNC_EXIT__;
431 _session_timer(session, 1);
433 __WDS_LOG_FUNC_EXIT__;
437 int wfd_session_wps(wfd_session_s *session)
439 __WDS_LOG_FUNC_ENTER__;
440 wfd_manager_s *manager = wfd_get_manager();
441 wfd_device_s *peer = NULL;
445 WDS_LOGE("Invalid parameter");
446 __WDS_LOG_FUNC_EXIT__;
450 if (session->state > SESSION_STATE_WPS) {
451 WDS_LOGE("Session already starts WPS");
455 session->state = SESSION_STATE_WPS;
456 peer = session->peer;
458 if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
459 WDS_LOGD("My device is GO, so WPS will be started. WPS mode[%d]", session->wps_mode);
460 res = wfd_oem_wps_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
462 WDS_LOGD("My device is not GO, so Enrollee will be started. WPS mode[%d]", session->wps_mode);
463 res = wfd_oem_enrollee_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
466 WDS_LOGE("Failed to start wps with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
467 wfd_destroy_session(manager);
468 // TODO: send notification to App
469 __WDS_LOG_FUNC_EXIT__;
473 __WDS_LOG_FUNC_EXIT__;
477 wfd_device_s *wfd_session_get_peer(wfd_session_s *session)
479 __WDS_LOG_FUNC_ENTER__;
480 wfd_device_s *peer = NULL;
483 WDS_LOGE("Invalid parameter");
487 peer = session->peer;
489 __WDS_LOG_FUNC_EXIT__;
493 unsigned char *wfd_session_get_peer_addr(wfd_session_s *session)
495 __WDS_LOG_FUNC_ENTER__;
496 wfd_device_s *peer = NULL;
498 if (!session || !session->peer) {
499 WDS_LOGE("Invalid parameter");
503 peer = session->peer;
505 __WDS_LOG_FUNC_EXIT__;
506 return peer->dev_addr;
509 int wfd_session_get_wps_pin(wfd_session_s *session, unsigned char *pin)
511 __WDS_LOG_FUNC_ENTER__;
513 __WDS_LOG_FUNC_EXIT__;
517 int wfd_session_set_wps_pin(wfd_session_s *session, unsigned char *pin)
519 __WDS_LOG_FUNC_ENTER__;
521 __WDS_LOG_FUNC_EXIT__;
525 int wfd_session_set_freq(wfd_session_s *session, int freq)
527 __WDS_LOG_FUNC_ENTER__;
529 __WDS_LOG_FUNC_EXIT__;
533 int wfd_session_get_state(wfd_session_s *session)
535 __WDS_LOG_FUNC_ENTER__;
537 __WDS_LOG_FUNC_EXIT__;
541 int wfd_session_set_state(wfd_session_s *session, int state)
543 __WDS_LOG_FUNC_ENTER__;
545 __WDS_LOG_FUNC_EXIT__;
549 int wfd_session_process_event(wfd_manager_s *manager, wfd_oem_event_s *event)
551 __WDS_LOG_FUNC_ENTER__;
552 wfd_session_s *session = NULL;
554 if (!manager || !event) {
555 WDS_LOGE("Invalid parameter");
559 WDS_LOGD("event ID [%d]", event->event_id);
560 session = manager->session;
562 switch (event->event_id) {
563 case WFD_OEM_EVENT_PROV_DISC_REQ:
564 case WFD_OEM_EVENT_PROV_DISC_DISPLAY:
565 case WFD_OEM_EVENT_PROV_DISC_KEYPAD:
568 int req_wps_mode = WFD_WPS_MODE_NONE;
569 int wps_mode = event->wps_mode;
571 if (wps_mode == WFD_WPS_MODE_DISPLAY) {
572 req_wps_mode = WFD_WPS_MODE_KEYPAD;
573 } else if (wps_mode == WFD_WPS_MODE_KEYPAD) {
574 req_wps_mode = WFD_WPS_MODE_DISPLAY;
576 req_wps_mode = WFD_WPS_MODE_PBC;
579 session = wfd_create_session(manager, event->dev_addr,
580 req_wps_mode, SESSION_DIRECTION_INCOMING);
582 WDS_LOGE("Failed to create session with peer [" MACSTR "]", MAC2STR(event->dev_addr));
587 if (wps_mode == WFD_WPS_MODE_DISPLAY) {
588 strncpy(session->wps_pin, event->wps_pin, PINSTR_LEN);
589 session->wps_pin[PINSTR_LEN] = '\0';
591 session->state = SESSION_STATE_STARTED;
592 _session_timer(session, 1);
594 manager->local->wps_mode = event->wps_mode;
596 wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
598 wifi_direct_client_noti_s noti;
599 memset(¬i, 0x0, sizeof(wifi_direct_client_noti_s));
600 noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_REQ;
601 noti.error = WIFI_DIRECT_ERROR_NONE;
602 snprintf(noti.param1, sizeof(noti.param1), MACSTR, MAC2STR(event->dev_addr));
603 wfd_event_notify_clients(manager, ¬i);
605 if (session->state > SESSION_STATE_STARTED ||
606 session->direction == SESSION_DIRECTION_INCOMING) {
607 WDS_LOGE("Unexpected event. Session is already started");
611 session->wps_mode = event->wps_mode;
612 if (event->wps_mode == WFD_WPS_MODE_DISPLAY) {
613 session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
614 strncpy(session->wps_pin, event->wps_pin, PINSTR_LEN);
615 session->wps_pin[PINSTR_LEN] = '\0';
616 } else if (event->wps_mode == WFD_WPS_MODE_KEYPAD) {
617 session->req_wps_mode = WFD_WPS_MODE_DISPLAY;
619 session->req_wps_mode = WFD_WPS_MODE_PBC;
621 session->state = SESSION_STATE_STARTED;
622 _session_timer(session, 1);
624 manager->local->wps_mode = event->wps_mode;
625 WDS_LOGD("Local WPS mode is %d", session->wps_mode);
627 if (session->wps_mode != WFD_WPS_MODE_PBC) {
628 wifi_direct_client_noti_s noti;
629 memset(¬i, 0x0, sizeof(wifi_direct_client_noti_s));
630 noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_WPS_REQ;
631 snprintf(noti.param1, sizeof(noti.param1), MACSTR, MAC2STR(event->dev_addr));
632 wfd_event_notify_clients(manager, ¬i);
633 if (session->wps_mode == WFD_WPS_MODE_KEYPAD)
637 if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
638 WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
639 wfd_session_wps(session);
640 } else if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
641 WDS_LOGD("Start WPS(join) corresponding to OEM event [%d]", event->event_id);
642 wfd_session_join(session);
644 WDS_LOGD("Start connection corresponding to OEM event [%d]", event->event_id);
645 wfd_session_connect(session);
650 case WFD_OEM_EVENT_PROV_DISC_RESP:
652 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
656 if (session->state > SESSION_STATE_STARTED) {
657 WDS_LOGE("Unexpected event. Session is already started");
660 session->state = SESSION_STATE_STARTED;
662 if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
663 WDS_LOGD("Start joining corresponding to OEM event [%d]", event->event_id);
664 wfd_session_join(session);
665 } else if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
666 WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
667 wfd_session_wps(session);
669 WDS_LOGD("Start connection corresponding to OEM event [%d]", event->event_id);
670 wfd_session_connect(session);
673 case WFD_OEM_EVENT_GO_NEG_REQ:
674 if (!session) { // TODO: check whether connection is started by negotiation not by prov_disc
675 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
678 /* Sometimes, Provision Discovery response is not received.
679 * At this time, connection should be triggered by GO Negotiation request event */
680 if (session->direction == SESSION_DIRECTION_OUTGOING)
681 wfd_session_connect(session);
684 case WFD_OEM_EVENT_GO_NEG_DONE:
686 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
689 session->state = SESSION_STATE_WPS;
693 case WFD_OEM_EVENT_WPS_DONE:
695 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
698 session->state = SESSION_STATE_KEY_NEG;
702 case WFD_OEM_EVENT_CONNECTED:
705 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
708 wfd_group_s *group = manager->group;
710 group = wfd_create_pending_group(manager, event->intf_addr);
712 WDS_LOGE("Failed to create pending group");
715 manager->group = group;
716 } else { // multiconnection, additional client connected
717 WDS_LOGE("Unexpected event. Group already exist");
718 //wfd_group_add_member(manager, event->intf_addr, peer->dev_addr);
721 session->state = SESSION_STATE_COMPLETED;
725 case WFD_OEM_EVENT_STA_CONNECTED:
727 WDS_LOGD("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
730 session->state = SESSION_STATE_COMPLETED;
737 __WDS_LOG_FUNC_EXIT__;