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_session_s *session = NULL;
104 wfd_device_s *peer = NULL;
105 wfd_manager_s *manager = (wfd_manager_s*) data;
107 if (!data || !peer_addr) {
108 WDS_LOGE("Invalid parameter");
109 __WDS_LOG_FUNC_EXIT__;
113 session = (wfd_session_s*) calloc(1, sizeof(wfd_session_s));
115 WDS_LOGE("Failed to allocate memory for session");
116 __WDS_LOG_FUNC_EXIT__;
120 peer = wfd_peer_find_by_dev_addr(manager, peer_addr);
122 WDS_LOGE("Failed to find peer info[" MACSTR "]", MAC2STR(peer_addr));
124 __WDS_LOG_FUNC_EXIT__;
127 session->peer = peer;
128 session->wps_mode = wps_mode;
129 if (wps_mode == WFD_WPS_MODE_DISPLAY)
130 session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
131 else if (wps_mode == WFD_WPS_MODE_KEYPAD)
132 session->req_wps_mode = WFD_WPS_MODE_DISPLAY;
134 session->req_wps_mode = wps_mode;
135 session->direction = direction;
136 session->state = SESSION_STATE_CREATED;
138 manager->session = session;
139 manager->local->wps_mode = wps_mode;
141 __WDS_LOG_FUNC_EXIT__;
145 int wfd_destroy_session(void *data)
147 __WDS_LOG_FUNC_ENTER__;
148 wfd_manager_s *manager = (wfd_manager_s*) data;
149 wfd_session_s *session = NULL;
150 wfd_device_s *peer = NULL;
153 WDS_LOGE("Invalid parameter");
157 session = (wfd_session_s*) manager->session;
159 WDS_LOGE("Session not found");
162 _session_timer(session, 0);
163 peer = session->peer;
165 if (session->state != SESSION_STATE_COMPLETED) {
166 wifi_direct_client_noti_s noti;
167 memset(¬i, 0x0, sizeof(wifi_direct_client_noti_s));
168 noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_RSP;
169 noti.error = WIFI_DIRECT_ERROR_CONNECTION_FAILED;
170 snprintf(noti.param1, MACSTR_LEN, MACSTR, MAC2STR(peer->dev_addr));
171 wfd_event_notify_clients(manager, ¬i);
175 manager->session = NULL;
176 manager->local->wps_mode = WFD_WPS_MODE_PBC;
178 __WDS_LOG_FUNC_EXIT__;
182 int wfd_session_start(wfd_session_s *session)
184 __WDS_LOG_FUNC_ENTER__;
185 wfd_manager_s *manager = wfd_get_manager();
186 wfd_device_s *peer = NULL;
191 WDS_LOGE("Invalid parameter");
192 __WDS_LOG_FUNC_EXIT__;
196 // Check: Invitation Received in Incomming case -> send prov_disc join
197 // Check: User select peer to connect with in Outgoing case -> send prov_disc wps_mdde
199 session->state = SESSION_STATE_STARTED;
200 peer = session->peer;
201 if (peer->dev_role == WFD_DEV_ROLE_GO || session->invitation)
203 res = wfd_oem_prov_disc_req(manager->oem_ops, peer->dev_addr,
204 session->req_wps_mode, join);
206 WDS_LOGE("Failed to send provision discovery request to peer [" MACSTR "]",
207 MAC2STR(peer->dev_addr));
208 wfd_destroy_session(manager);
209 // TODO: send notification to App
210 __WDS_LOG_FUNC_EXIT__;
214 _session_timer(session, 1);
216 __WDS_LOG_FUNC_EXIT__;
220 int wfd_session_stop(wfd_session_s *session)
222 __WDS_LOG_FUNC_ENTER__;
223 wfd_manager_s *manager = wfd_get_manager();
224 wfd_device_s *peer = NULL;
228 WDS_LOGE("Invalid parameter");
229 __WDS_LOG_FUNC_EXIT__;
233 if (session->state > SESSION_STATE_CREATED) {
234 peer = session->peer;
235 if (session->direction == SESSION_DIRECTION_INCOMING) {
236 res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
237 } else if (session->direction == SESSION_DIRECTION_OUTGOING) {
238 res = wfd_oem_cancel_connection(manager->oem_ops, peer->dev_addr);
241 WDS_LOGE("Failed to reject or cancel connection");
242 __WDS_LOG_FUNC_EXIT__;
247 session->state = SESSION_STATE_STOPPED;
248 wfd_destroy_session(manager);
250 __WDS_LOG_FUNC_EXIT__;
254 /* In case of incomming session, when user accept connection request, this function should be called.
255 * In case of outgoing session, when prov_disc response arrived, this function should be called.
256 * Even though peer is GO, we can use this function, which can decide using join itself.
258 int wfd_session_connect(wfd_session_s *session)
260 __WDS_LOG_FUNC_ENTER__;
261 wfd_manager_s *manager = wfd_get_manager();
262 wfd_oem_conn_param_s param;
263 wfd_device_s *peer = NULL;
267 WDS_LOGE("Invalid parameter");
268 __WDS_LOG_FUNC_EXIT__;
272 if (session->state > SESSION_STATE_GO_NEG) {
273 WDS_LOGE("Session already starts GO Negotiation");
277 session->state = SESSION_STATE_GO_NEG;
278 peer = session->peer;
280 memset(¶m, 0x00, sizeof(wfd_oem_conn_param_s));
281 param.wps_mode = session->wps_mode;
282 if (peer->dev_role == WFD_DEV_ROLE_GO)
283 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
284 param.go_intent = session->go_intent;
285 param.freq = session->freq;
286 if (session->wps_pin[0] != '\0') {
287 strncpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN);
288 param.wps_pin[OEM_PINSTR_LEN] = '\0';
291 res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, ¶m);
293 WDS_LOGE("Failed to connect peer [" MACSTR "]", MAC2STR(peer->dev_addr));
294 wfd_destroy_session(manager);
295 // TODO: send notification to App
296 __WDS_LOG_FUNC_EXIT__;
300 _session_timer(session, 1);
302 __WDS_LOG_FUNC_EXIT__;
306 int wfd_session_reject(wfd_session_s *session)
308 __WDS_LOG_FUNC_ENTER__;
309 wfd_manager_s *manager = wfd_get_manager();
310 wfd_device_s *peer = NULL;
314 WDS_LOGE("Invalid parameter");
315 __WDS_LOG_FUNC_EXIT__;
319 if (session->state < SESSION_STATE_STARTED) {
320 WDS_LOGE("Session is not started");
321 __WDS_LOG_FUNC_EXIT__;
325 if (session->direction != SESSION_DIRECTION_INCOMING) {
326 WDS_LOGE("Cannot reject with outgoing connection");
327 __WDS_LOG_FUNC_EXIT__;
331 // TODO: check session status and do proper work
332 // for example, reject prov_disc, reject nego, stop wps, etc.
333 peer = session->peer;
334 res = wfd_oem_reject_connection(manager->oem_ops, peer->dev_addr);
336 WDS_LOGE("Failed to reject connection");
337 __WDS_LOG_FUNC_EXIT__;
341 wfd_destroy_session(manager);
342 // TODO: send notification to App
344 __WDS_LOG_FUNC_EXIT__;
348 int wfd_session_join(wfd_session_s *session)
350 __WDS_LOG_FUNC_ENTER__;
351 wfd_manager_s *manager = wfd_get_manager();
352 wfd_oem_conn_param_s param;
353 wfd_device_s *peer = NULL;
357 WDS_LOGE("Invalid parameter");
358 __WDS_LOG_FUNC_EXIT__;
362 session->state = SESSION_STATE_WPS;
363 peer = session->peer;
365 memset(¶m, 0x00, sizeof(wfd_oem_conn_param_s));
366 param.wps_mode = session->wps_mode;
367 if (peer->dev_role == WFD_DEV_ROLE_GO)
368 param.conn_flags |= WFD_OEM_CONN_TYPE_JOIN;
369 param.go_intent = session->go_intent;
370 param.freq = session->freq;
371 memcpy(param.wps_pin, session->wps_pin, OEM_PINSTR_LEN);
373 res = wfd_oem_connect(manager->oem_ops, peer->dev_addr, ¶m);
375 WDS_LOGE("Failed to join with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
376 wfd_destroy_session(manager);
377 // TODO: send notification to App
378 __WDS_LOG_FUNC_EXIT__;
382 _session_timer(session, 1);
384 __WDS_LOG_FUNC_EXIT__;
388 int wfd_session_invite(wfd_session_s *session)
390 __WDS_LOG_FUNC_ENTER__;
391 wfd_manager_s *manager = wfd_get_manager();
392 wfd_oem_invite_param_s param;
393 wfd_device_s *peer = NULL;
394 wfd_group_s *group = NULL;
398 WDS_LOGE("Invalid parameter");
399 __WDS_LOG_FUNC_EXIT__;
403 peer = session->peer;
404 group = (wfd_group_s*) manager->group;
406 memset(¶m, 0x00, sizeof(wfd_oem_invite_param_s));
407 param.ifname = strdup(group->ifname);
408 memcpy(param.go_dev_addr, group->go_dev_addr, MACADDR_LEN);
410 WDS_LOGD("Invite: Peer[" MACSTR "], GO Addr[" MACSTR "]", MAC2STR(peer->dev_addr), MAC2STR(param.go_dev_addr));
412 res = wfd_oem_invite(manager->oem_ops, peer->dev_addr, ¶m);
414 WDS_LOGE("Failed to invite with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
415 wfd_destroy_session(manager);
416 // TODO: send notification to App
417 __WDS_LOG_FUNC_EXIT__;
421 _session_timer(session, 1);
423 __WDS_LOG_FUNC_EXIT__;
427 int wfd_session_wps(wfd_session_s *session)
429 __WDS_LOG_FUNC_ENTER__;
430 wfd_manager_s *manager = wfd_get_manager();
431 wfd_device_s *peer = NULL;
435 WDS_LOGE("Invalid parameter");
436 __WDS_LOG_FUNC_EXIT__;
440 if (session->state > SESSION_STATE_WPS) {
441 WDS_LOGE("Session already starts WPS");
445 session->state = SESSION_STATE_WPS;
446 peer = session->peer;
448 if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
449 WDS_LOGD("My device is GO, so WPS will be started. WPS mode[%d]", session->wps_mode);
450 res = wfd_oem_wps_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
452 WDS_LOGD("My device is not GO, so Enrollee will be started. WPS mode[%d]", session->wps_mode);
453 res = wfd_oem_enrollee_start(manager->oem_ops, peer->dev_addr, session->wps_mode, session->wps_pin);
456 WDS_LOGE("Failed to start wps with peer [" MACSTR "]", MAC2STR(peer->dev_addr));
457 wfd_destroy_session(manager);
458 // TODO: send notification to App
459 __WDS_LOG_FUNC_EXIT__;
463 __WDS_LOG_FUNC_EXIT__;
467 wfd_device_s *wfd_session_get_peer(wfd_session_s *session)
469 __WDS_LOG_FUNC_ENTER__;
470 wfd_device_s *peer = NULL;
473 WDS_LOGE("Invalid parameter");
477 peer = session->peer;
479 __WDS_LOG_FUNC_EXIT__;
483 unsigned char *wfd_session_get_peer_addr(wfd_session_s *session)
485 __WDS_LOG_FUNC_ENTER__;
486 wfd_device_s *peer = NULL;
488 if (!session || !session->peer) {
489 WDS_LOGE("Invalid parameter");
493 peer = session->peer;
495 __WDS_LOG_FUNC_EXIT__;
496 return peer->dev_addr;
499 int wfd_session_get_wps_pin(wfd_session_s *session, unsigned char *pin)
501 __WDS_LOG_FUNC_ENTER__;
503 __WDS_LOG_FUNC_EXIT__;
507 int wfd_session_set_wps_pin(wfd_session_s *session, unsigned char *pin)
509 __WDS_LOG_FUNC_ENTER__;
511 __WDS_LOG_FUNC_EXIT__;
515 int wfd_session_set_freq(wfd_session_s *session, int freq)
517 __WDS_LOG_FUNC_ENTER__;
519 __WDS_LOG_FUNC_EXIT__;
523 int wfd_session_get_state(wfd_session_s *session)
525 __WDS_LOG_FUNC_ENTER__;
527 __WDS_LOG_FUNC_EXIT__;
531 int wfd_session_set_state(wfd_session_s *session, int state)
533 __WDS_LOG_FUNC_ENTER__;
535 __WDS_LOG_FUNC_EXIT__;
539 int wfd_session_process_event(wfd_manager_s *manager, wfd_oem_event_s *event)
541 __WDS_LOG_FUNC_ENTER__;
542 wfd_session_s *session = NULL;
544 if (!manager || !event) {
545 WDS_LOGE("Invalid parameter");
549 WDS_LOGD("event ID [%d]", event->event_id);
550 session = manager->session;
552 switch (event->event_id) {
553 case WFD_OEM_EVENT_PROV_DISC_REQ:
554 case WFD_OEM_EVENT_PROV_DISC_DISPLAY:
555 case WFD_OEM_EVENT_PROV_DISC_KEYPAD:
558 session = wfd_create_session(manager, event->dev_addr,
559 event->wps_mode, SESSION_DIRECTION_INCOMING);
561 WDS_LOGE("Failed to create session with peer [" MACSTR "]", MAC2STR(event->dev_addr));
566 if (event->wps_mode == WFD_OEM_WPS_MODE_DISPLAY) {
567 strncpy(session->wps_pin, event->wps_pin, PINSTR_LEN);
568 session->wps_pin[PINSTR_LEN] = '\0';
570 session->state = SESSION_STATE_STARTED;
571 _session_timer(session, 1);
573 manager->local->wps_mode = event->wps_mode;
575 wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTING);
577 wifi_direct_client_noti_s noti;
578 memset(¬i, 0x0, sizeof(wifi_direct_client_noti_s));
579 noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_REQ;
580 noti.error = WIFI_DIRECT_ERROR_NONE;
581 snprintf(noti.param1, sizeof(noti.param1), MACSTR, MAC2STR(event->dev_addr));
582 wfd_event_notify_clients(manager, ¬i);
584 if (session->state > SESSION_STATE_STARTED) {
585 WDS_LOGE("Unexpected event. Session is already started");
589 session->wps_mode = event->wps_mode;
590 if (event->wps_mode == WFD_WPS_MODE_DISPLAY) {
591 session->req_wps_mode = WFD_WPS_MODE_KEYPAD;
592 strncpy(session->wps_pin, event->wps_pin, PINSTR_LEN);
593 session->wps_pin[PINSTR_LEN] = '\0';
594 } else if (event->wps_mode == WFD_WPS_MODE_KEYPAD) {
595 session->req_wps_mode = WFD_WPS_MODE_DISPLAY;
597 session->req_wps_mode = WFD_WPS_MODE_PBC;
599 session->state = SESSION_STATE_STARTED;
600 _session_timer(session, 1);
602 manager->local->wps_mode = event->wps_mode;
603 WDS_LOGD("Local WPS mode is %d", session->wps_mode);
605 if (session->wps_mode != WFD_WPS_MODE_PBC) {
606 wifi_direct_client_noti_s noti;
607 memset(¬i, 0x0, sizeof(wifi_direct_client_noti_s));
608 noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_WPS_REQ;
609 snprintf(noti.param1, sizeof(noti.param1), MACSTR, MAC2STR(event->dev_addr));
610 wfd_event_notify_clients(manager, ¬i);
611 if (session->wps_mode == WFD_WPS_MODE_KEYPAD)
615 if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
616 WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
617 wfd_session_wps(session);
618 } else if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
619 WDS_LOGD("Start WPS(join) corresponding to OEM event [%d]", event->event_id);
620 wfd_session_join(session);
622 WDS_LOGD("Start connection corresponding to OEM event [%d]", event->event_id);
623 wfd_session_connect(session);
628 case WFD_OEM_EVENT_PROV_DISC_RESP:
630 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
634 if (session->state > SESSION_STATE_STARTED) {
635 WDS_LOGE("Unexpected event. Session is already started");
638 session->state = SESSION_STATE_STARTED;
640 if (session->peer->dev_role == WFD_DEV_ROLE_GO) {
641 WDS_LOGD("Start joining corresponding to OEM event [%d]", event->event_id);
642 wfd_session_join(session);
643 } else if (manager->local->dev_role == WFD_DEV_ROLE_GO) {
644 WDS_LOGD("Start WPS corresponding to OEM event [%d]", event->event_id);
645 wfd_session_wps(session);
647 WDS_LOGD("Start connection corresponding to OEM event [%d]", event->event_id);
648 wfd_session_connect(session);
651 case WFD_OEM_EVENT_GO_NEG_REQ:
652 if (!session) { // TODO: check whether connection is started by negotiation not by prov_disc
653 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
656 /* Sometimes, Provision Discovery response is not received.
657 * At this time, connection should be triggered by GO Negotiation request event */
658 if (session->direction == SESSION_DIRECTION_OUTGOING)
659 wfd_session_connect(session);
663 case WFD_OEM_EVENT_GO_NEG_DONE:
665 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
668 session->state = SESSION_STATE_WPS;
672 case WFD_OEM_EVENT_WPS_DONE:
674 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
677 session->state = SESSION_STATE_KEY_NEG;
681 case WFD_OEM_EVENT_CONNECTED:
684 WDS_LOGE("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
687 wfd_group_s *group = manager->group;
689 group = wfd_create_pending_group(manager, event->intf_addr);
691 WDS_LOGE("Failed to create pending group");
694 manager->group = group;
695 } else { // multiconnection, additional client connected
696 WDS_LOGE("Unexpected event. Group already exist");
697 //wfd_group_add_member(manager, event->intf_addr, peer->dev_addr);
700 session->state = SESSION_STATE_COMPLETED;
704 case WFD_OEM_EVENT_STA_CONNECTED:
706 WDS_LOGD("Unexpected event. Session is NULL [peer: " MACSTR "]", MAC2STR(event->dev_addr));
709 session->state = SESSION_STATE_COMPLETED;
716 __WDS_LOG_FUNC_EXIT__;