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 utility functions.
23 * @file wifi-direct-util.c
24 * @author Gibyoung Kim (lastkgb.kim@samsung.com)
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
42 #include <app_service.h>
43 #include <wifi-direct.h>
44 #include <wifi-direct-internal.h>
46 #include "wifi-direct-manager.h"
47 #include "wifi-direct-state.h"
48 #include "wifi-direct-client.h"
49 #include "wifi-direct-util.h"
51 static int _txt_to_mac(char *txt, unsigned char *mac)
56 mac[i++] = (char) strtoul(txt, &txt, 16);
57 if (!*txt++ || i == 6)
64 WDS_LOGD("Converted MAC address [" MACSTR "]", MAC2STR(mac));
68 static int _txt_to_ip(char *txt, unsigned char *ip)
73 ip[i++] = (char) strtoul(txt, &txt, 10);
74 if (!*txt++ || i == 4)
81 WDS_LOGD("Converted IP address [" IPSTR "]", IP2STR(ip));
85 gboolean wfd_util_execute_file(const char *file_path,
86 char *const args[], char *const envs[])
91 register unsigned int index = 0;
93 while (args[index] != NULL) {
94 WDS_LOGD("[%s]", args[index]);
98 if (!(pid = fork())) {
99 WDS_LOGD("pid(%d), ppid(%d)", getpid(), getppid());
100 WDS_LOGD("Inside child, exec (%s) command", file_path);
103 if (execve(file_path, args, envs) == -1) {
104 WDS_LOGE("Fail to execute command (%s)", strerror(errno));
107 } else if (pid > 0) {
108 if (waitpid(pid, &rv, 0) == -1)
109 WDS_LOGD("wait pid (%u) rv (%d)", pid, rv);
111 WDS_LOGD("exited, rv=%d", WEXITSTATUS(rv));
112 } else if (WIFSIGNALED(rv)) {
113 WDS_LOGD("killed by signal %d", WTERMSIG(rv));
114 } else if (WIFSTOPPED(rv)) {
115 WDS_LOGD("stopped by signal %d", WSTOPSIG(rv));
116 } else if (WIFCONTINUED(rv)) {
117 WDS_LOGD("continued");
123 WDS_LOGE("failed to fork (%s)", strerror(errno));
127 int wfd_util_freq_to_channel(int freq)
129 if (freq < 2412 || freq > 5825) {
130 WDS_LOGE("Invalid parameter");
135 return 36 + (freq - 5180)/5;
136 else if (freq <= 2472)
137 return 1 + (freq - 2412)/5;
138 else if (freq == 2484)
144 int wfd_util_get_phone_name(char *phone_name)
146 __WDS_LOG_FUNC_ENTER__;
149 name = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR);
151 WDS_LOGE( "Failed to get vconf value for %s", VCONFKEY_SETAPPL_DEVICE_NAME_STR);
154 strncpy(phone_name, name, DEV_NAME_LEN);
155 phone_name[DEV_NAME_LEN] = '\0';
157 WDS_LOGD( "[%s: %s]", VCONFKEY_SETAPPL_DEVICE_NAME_STR, phone_name);
159 __WDS_LOG_FUNC_EXIT__;
163 void _wfd_util_dev_name_changed_cb(keynode_t *key, void* data)
165 __WDS_LOG_FUNC_ENTER__;
166 char dev_name[DEV_NAME_LEN+1] = {0, };
169 res = wfd_util_get_phone_name(dev_name);
171 WDS_LOGE("Failed to get phone name(vconf)");
174 WDS_LOGD("Device name changed as [%s]", dev_name);
176 res = wfd_local_set_dev_name(dev_name);
178 WDS_LOGE("Failed to set device name");
179 __WDS_LOG_FUNC_EXIT__;
183 void wfd_util_set_dev_name_notification()
185 __WDS_LOG_FUNC_ENTER__;
187 vconf_notify_key_changed(VCONFKEY_SETAPPL_DEVICE_NAME_STR, _wfd_util_dev_name_changed_cb, NULL);
189 __WDS_LOG_FUNC_EXIT__;
193 void wfd_util_unset_dev_name_notification()
195 __WDS_LOG_FUNC_ENTER__;
197 vconf_ignore_key_changed(VCONFKEY_SETAPPL_DEVICE_NAME_STR, _wfd_util_dev_name_changed_cb);
199 __WDS_LOG_FUNC_EXIT__;
203 int wfd_util_check_wifi_state()
205 __WDS_LOG_FUNC_ENTER__;
209 /* vconf key and value (vconf-keys.h)
210 #define VCONFKEY_WIFI_STATE "memory/wifi/state"
212 VCONFKEY_WIFI_OFF = 0x00,
213 VCONFKEY_WIFI_UNCONNECTED,
214 VCONFKEY_WIFI_CONNECTED,
215 VCONFKEY_WIFI_TRANSFER,
216 VCONFKEY_WIFI_STATE_MAX
220 res = vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
222 WDS_LOGE("Failed to get vconf value [%s]", VCONFKEY_WIFI_STATE);
223 __WDS_LOG_FUNC_EXIT__;
226 WDS_LOGD("[%s: %d]", VCONFKEY_WIFI_STATE, wifi_state);
228 if (wifi_state > VCONFKEY_WIFI_OFF) {
229 WDS_LOGD("Wi-Fi is on");
230 __WDS_LOG_FUNC_EXIT__;
233 WDS_LOGD( "OK. Wi-Fi is off\n");
235 __WDS_LOG_FUNC_EXIT__;
239 int wfd_util_check_mobile_ap_state()
241 __WDS_LOG_FUNC_ENTER__;
242 int mobile_ap_state = 0;
245 res = vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_MODE, &mobile_ap_state);
247 WDS_LOGE("Failed to get vconf value[%s]", VCONFKEY_MOBILE_HOTSPOT_MODE);
248 __WDS_LOG_FUNC_EXIT__;
251 WDS_LOGD("[%s: %d]", VCONFKEY_MOBILE_HOTSPOT_MODE, mobile_ap_state);
253 if (mobile_ap_state != VCONFKEY_MOBILE_HOTSPOT_MODE_NONE) {
254 WDS_LOGD("Mobile AP is on");
255 __WDS_LOG_FUNC_EXIT__;
258 WDS_LOGD( "OK. Mobile AP is off\n");
260 __WDS_LOG_FUNC_EXIT__;
264 int wfd_util_wifi_direct_activatable()
266 __WDS_LOG_FUNC_ENTER__;
269 res = wfd_util_check_wifi_state();
271 WDS_LOGE("Failed to check Wi-Fi state");
272 return WIFI_DIRECT_ERROR_OPERATION_FAILED;
273 } else if (res > 0) {
274 WDS_LOGE("Wi-Fi is On");
275 return WIFI_DIRECT_ERROR_WIFI_USED;
277 WDS_LOGE("Wi-Fi is Off");
278 return WIFI_DIRECT_ERROR_NONE;
281 res = wfd_util_check_mobile_ap_state();
283 WDS_LOGE("Failed to check Mobile AP state");
284 return WIFI_DIRECT_ERROR_OPERATION_FAILED;
285 } else if (res > 0) {
286 WDS_LOGE("Mobile AP is On");
287 return WIFI_DIRECT_ERROR_MOBILE_AP_USED;
289 WDS_LOGE("Mobile AP is Off");
290 return WIFI_DIRECT_ERROR_NONE;
294 int wfd_util_get_wifi_direct_state()
296 __WDS_LOG_FUNC_ENTER__;
300 res = vconf_get_int(VCONFKEY_WIFI_DIRECT_STATE, &state);
302 WDS_LOGE("Failed to get vconf value [%s]\n", VCONFKEY_WIFI_DIRECT_STATE);
303 __WDS_LOG_FUNC_EXIT__;
307 __WDS_LOG_FUNC_EXIT__;
311 int wfd_util_set_wifi_direct_state(int state)
313 __WDS_LOG_FUNC_ENTER__;
317 // TODO: check validity of state
319 if (state == WIFI_DIRECT_STATE_ACTIVATED)
320 vconf_state = VCONFKEY_WIFI_DIRECT_ACTIVATED;
321 else if (state == WIFI_DIRECT_STATE_DEACTIVATED)
322 vconf_state= VCONFKEY_WIFI_DIRECT_DEACTIVATED;
323 else if (state == WIFI_DIRECT_STATE_CONNECTED)
324 vconf_state = VCONFKEY_WIFI_DIRECT_CONNECTED;
325 else if (state == WIFI_DIRECT_STATE_GROUP_OWNER)
326 vconf_state = VCONFKEY_WIFI_DIRECT_GROUP_OWNER;
327 else if (state == WIFI_DIRECT_STATE_DISCOVERING)
328 vconf_state = VCONFKEY_WIFI_DIRECT_DISCOVERING;
329 WDS_LOGD("Vconf key set [%s: %d]", VCONFKEY_WIFI_DIRECT_STATE, vconf_state);
331 res = vconf_set_int(VCONFKEY_WIFI_DIRECT_STATE, vconf_state);
333 WDS_LOGE("Failed to set vconf [%s]", VCONFKEY_WIFI_DIRECT_STATE);
334 __WDS_LOG_FUNC_EXIT__;
338 __WDS_LOG_FUNC_EXIT__;
342 int wfd_util_get_local_dev_mac(unsigned char *dev_mac)
344 __WDS_LOG_FUNC_ENTER__;
346 char local_mac[MACSTR_LEN] = {0, };
351 fd = fopen(DEFAULT_MAC_FILE_PATH, "r");
353 WDS_LOGE("Failed to open MAC info file (%s)", strerror(errno));
354 __WDS_LOG_FUNC_EXIT__;
359 ptr = fgets(local_mac, MACSTR_LEN, fd);
361 WDS_LOGE("Failed to read file or no data read(%s)", strerror(errno));
363 __WDS_LOG_FUNC_EXIT__;
366 WDS_LOGD("Local MAC address [%s]", ptr);
368 res = _txt_to_mac(local_mac, dev_mac);
370 WDS_LOGE("Failed to convert text to MAC address");
372 __WDS_LOG_FUNC_EXIT__;
377 WDS_LOGD("Local Device MAC address [" MACSTR "]", MAC2STR(dev_mac));
380 __WDS_LOG_FUNC_EXIT__;
384 int wfd_util_get_access_list(GList **access_list)
386 __WDS_LOG_FUNC_ENTER__;
388 wfd_access_list_info_s * device = NULL;
389 char device_info[MACSTR_LEN + DEV_NAME_LEN + 1] = {0, };
390 char dev_mac[MACADDR_LEN] = {0, };
391 int info_str_len = 0;
397 fd = fopen(DEFAULT_DEVICE_LIST_FILE_PATH, "r");
399 WDS_LOGE("Failed to open access list file (%s)", strerror(errno));
400 __WDS_LOG_FUNC_EXIT__;
404 while ((res = fgets(device_info, MACSTR_LEN + DEV_NAME_LEN + 2, fd)) != NULL)
406 if (device_info[0] == '\0') {
407 printf("end of list\n");
412 info_str_len = strlen(device_info);
413 if(info_str_len > MACSTR_LEN)
414 device_info[info_str_len -1] = '\0';
416 res = _txt_to_mac(device_info, dev_mac);
418 WDS_LOGE("Failed to convert text to MAC address");
422 device = calloc(1, sizeof(wfd_access_list_info_s));
423 memcpy(device->mac_address, dev_mac, MACADDR_LEN);
424 strncpy(device->device_name, &device_info[MACSTR_LEN], strlen(&device_info[MACSTR_LEN]));
425 device->allowed = (device_info[MACSTR_LEN - 1] == 'O');
427 *access_list = g_list_append(*access_list, device);
430 __WDS_LOG_FUNC_EXIT__;
434 int wfd_util_rewrite_device_list_to_file(GList *access_list)
436 __WDS_LOG_FUNC_ENTER__;
439 wfd_access_list_info_s * device = NULL;
448 list_cnt = g_list_length(access_list);
450 fd = fopen(DEFAULT_DEVICE_LIST_FILE_PATH, "w");
452 WDS_LOGE("Failed to open access list file (%s)", strerror(errno));
454 __WDS_LOG_FUNC_EXIT__;
459 buf = calloc(1,(MACSTR_LEN + DEV_NAME_LEN + 1)*list_cnt +1);
461 temp = g_list_first(access_list);
463 for(i =0; i < list_cnt; i++)
465 device = (wfd_access_list_info_s *)temp->data;
466 snprintf(ptr, MACSTR_LEN + DEV_NAME_LEN + 2, MACSTR "%c%s\n",
467 MAC2STR(device->mac_address), device->allowed?'O':'X', device->device_name);
469 temp = g_list_next(temp);
471 res = fprintf(fd, "%s",buf);
477 __WDS_LOG_FUNC_EXIT__;
481 int wfd_util_add_device_to_list(wfd_device_s *peer, int allowed)
483 __WDS_LOG_FUNC_ENTER__;
485 char buf[MACSTR_LEN + DEV_NAME_LEN + 2] = {0, };
490 WDS_LOGD("There is nothing to add to list");
494 snprintf(buf, MACSTR_LEN + DEV_NAME_LEN + 2, MACSTR "%c%s\n",
495 MAC2STR(peer->dev_addr), allowed?'O':'X', peer->dev_name);
497 fd = fopen(DEFAULT_DEVICE_LIST_FILE_PATH, "a");
499 WDS_LOGE("Failed to open access list file (%s)", strerror(errno));
500 __WDS_LOG_FUNC_EXIT__;
503 res = fprintf(fd,"%s", buf);
506 WDS_LOGE("Failed to write to access list file (%s)", strerror(errno));
509 __WDS_LOG_FUNC_EXIT__;
513 int wfd_util_reset_access_list_file()
515 __WDS_LOG_FUNC_ENTER__;
519 fd = fopen(DEFAULT_DEVICE_LIST_FILE_PATH, "w");
522 WDS_LOGE("Failed to open reset access list file (%s)", strerror(errno));
527 __WDS_LOG_FUNC_EXIT__;
532 int wfd_util_start_wifi_direct_popup()
534 __WDS_LOG_FUNC_ENTER__;
537 service_create(&service);
538 service_set_operation(service, SERVICE_OPERATION_DEFAULT);
539 service_set_package(service, "org.tizen.wifi-direct-popup");
540 service_send_launch_request(service, NULL, NULL);
541 service_destroy(service);
542 WDS_LOGD("Succeeded to launch wifi-direct-popup");
543 __WDS_LOG_FUNC_EXIT__;
548 static void _dhcps_ip_leased_cb(keynode_t *key, void* data)
550 __WDS_LOG_FUNC_ENTER__;
551 wfd_manager_s *manager = wfd_get_manager();
552 wfd_device_s *peer = (wfd_device_s*) data;
553 wifi_direct_client_noti_s noti;
555 char buf[MAX_DHCP_DUMP_SIZE];
556 char ip_str[IPSTR_LEN];
557 char intf_str[MACSTR_LEN];
558 unsigned char intf_addr[MACADDR_LEN];
562 WDS_LOGD("Invalid parameter");
565 WDS_LOGD("DHCP server: IP leased");
566 memset(¬i, 0, sizeof(wifi_direct_client_noti_s));
569 fp = fopen(DHCP_DUMP_FILE, "r");
571 WDS_LOGE("Could not read the file(%s). [%s]", DHCP_DUMP_FILE, strerror(errno));
575 while(fgets(buf, MAX_DHCP_DUMP_SIZE, fp) != NULL) {
576 WDS_LOGD("Read line [%s]", buf);
577 n = sscanf(buf,"%s %s", intf_str, ip_str);
578 WDS_LOGD("ip=[%s], mac=[%s]",ip_str, intf_str);
582 _txt_to_mac(intf_str, intf_addr);
583 if (!memcmp(peer->intf_addr, intf_addr, MACADDR_LEN)) {
584 WDS_LOGD("Peer intf mac found");
585 _txt_to_ip(ip_str, peer->ip_addr);
586 noti.event = WIFI_DIRECT_CLI_EVENT_IP_LEASED_IND;
587 snprintf(noti.param1, MACSTR_LEN, MACSTR, MAC2STR(peer->dev_addr));
588 snprintf(noti.param2, IPSTR_LEN, IPSTR, IP2STR(peer->ip_addr));
589 wfd_client_send_event(manager, ¬i);
592 WDS_LOGE("Different interface address peer[" MACSTR "] vs dhcp[" MACSTR "]", MAC2STR(peer->intf_addr), MAC2STR(intf_addr));
597 __WDS_LOG_FUNC_EXIT__;
601 static gboolean _polling_ip(gpointer user_data)
603 __WDS_LOG_FUNC_ENTER__;
604 wfd_manager_s *manager = wfd_get_manager();
605 wfd_device_s *local = (wfd_device_s*) manager->local;
606 wfd_device_s *peer = (wfd_device_s*) user_data;
608 static int count = 0;
612 WDS_LOGE("Failed to get IP");
614 __WDS_LOG_FUNC_EXIT__;
617 res = wfd_manager_get_goup_ifname(&ifname);
618 if (res < 0 || !ifname) {
619 WDS_LOGE("Failed to get group interface name");
623 res = wfd_util_dhcpc_get_ip(ifname, local->ip_addr, 0);
625 WDS_LOGE("Failed to get local IP for interface %s(count=%d)", ifname, count++);
626 __WDS_LOG_FUNC_EXIT__;
629 WDS_LOGD("Succeeded to get local(client) IP [" IPSTR "] for iface[%s]",
630 IP2STR(local->ip_addr), ifname);
632 res = wfd_util_dhcpc_get_server_ip(peer->ip_addr);
634 WDS_LOGE("Failed to get peer(server) IP(count=%d)", count++);
635 __WDS_LOG_FUNC_EXIT__;
638 WDS_LOGD("Succeeded to get server IP [" IPSTR "]", IP2STR(peer->ip_addr));
641 wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTED);
642 wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_CONNECTED);
643 wifi_direct_client_noti_s noti;
644 memset(¬i, 0x0, sizeof(wifi_direct_client_noti_s));
645 noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_RSP;
646 noti.error = WIFI_DIRECT_ERROR_NONE;
647 snprintf(noti.param1, MACSTR_LEN, MACSTR, MAC2STR(peer->dev_addr));
648 wfd_client_send_event(manager, ¬i);
650 __WDS_LOG_FUNC_EXIT__;
654 int wfd_util_dhcps_start()
656 __WDS_LOG_FUNC_ENTER__;
658 const char *path = "/usr/bin/wifi-direct-dhcp.sh";
659 char *const args[] = { "/usr/bin/wifi-direct-dhcp.sh", "server", NULL };
660 char *const envs[] = { NULL };
662 vconf_set_int(VCONFKEY_DHCPS_IP_LEASE, 0);
664 rv = wfd_util_execute_file(path, args, envs);
667 WDS_LOGE("Failed to start wifi-direct-dhcp.sh server");
670 WDS_LOGD("Successfully started wifi-direct-dhcp.sh server");
672 __WDS_LOG_FUNC_EXIT__;
676 int wfd_util_dhcps_wait_ip_leased(wfd_device_s *peer)
678 __WDS_LOG_FUNC_ENTER__;
681 WDS_LOGE("Invalid parameter");
685 vconf_set_int(VCONFKEY_DHCPS_IP_LEASE, 0);
686 vconf_notify_key_changed(VCONFKEY_DHCPS_IP_LEASE, _dhcps_ip_leased_cb, peer);
688 __WDS_LOG_FUNC_EXIT__;
692 int wfd_util_dhcps_stop()
694 __WDS_LOG_FUNC_ENTER__;
696 const char *path = "/usr/bin/wifi-direct-dhcp.sh";
697 char *const args[] = { "/usr/bin/wifi-direct-dhcp.sh", "stop", NULL };
698 char *const envs[] = { NULL };
700 vconf_ignore_key_changed(VCONFKEY_DHCPS_IP_LEASE, _dhcps_ip_leased_cb);
701 vconf_set_int(VCONFKEY_DHCPS_IP_LEASE, 0);
703 rv = wfd_util_execute_file(path, args, envs);
706 WDS_LOGE("Failed to stop wifi-direct-dhcp.sh");
709 WDS_LOGD("Successfully stopped wifi-direct-dhcp.sh");
711 __WDS_LOG_FUNC_EXIT__;
715 int wfd_util_dhcpc_start(wfd_device_s *peer)
717 __WDS_LOG_FUNC_ENTER__;
719 const char *path = "/usr/bin/wifi-direct-dhcp.sh";
720 char *const args[] = { "/usr/bin/wifi-direct-dhcp.sh", "client", NULL };
721 char *const envs[] = { NULL };
724 WDS_LOGE("Invalid parameter");
728 rv = wfd_util_execute_file(path, args, envs);
731 WDS_LOGE("Failed to start wifi-direct-dhcp.sh client");
734 WDS_LOGD("Successfully started wifi-direct-dhcp.sh client");
736 g_timeout_add(250, (GSourceFunc) _polling_ip, peer);
738 __WDS_LOG_FUNC_EXIT__;
742 int wfd_util_dhcpc_stop()
744 __WDS_LOG_FUNC_ENTER__;
746 const char *path = "/usr/bin/wifi-direct-dhcp.sh";
747 char *const args[] = { "/usr/bin/wifi-direct-dhcp.sh", "stop", NULL };
748 char *const envs[] = { NULL };
750 rv = wfd_util_execute_file(path, args, envs);
753 WDS_LOGE("Failed to stop wifi-direct-dhcp.sh");
756 WDS_LOGD("Successfully stopped wifi-direct-dhcp.sh");
758 __WDS_LOG_FUNC_EXIT__;
762 int wfd_util_dhcpc_get_ip(char *ifname, unsigned char *ip_addr, int is_IPv6)
764 __WDS_LOG_FUNC_ENTER__;
766 struct sockaddr_in *sin = NULL;
771 if (!ifname || !ip_addr) {
772 WDS_LOGE("Invalid parameter");
773 __WDS_LOG_FUNC_EXIT__;
778 sock = socket(AF_INET, SOCK_DGRAM, 0);
779 if (sock < SOCK_FD_MIN) {
780 WDS_LOGE("Failed to create socket. [%s]", strerror(errno));
783 __WDS_LOG_FUNC_EXIT__;
787 ifr.ifr_addr.sa_family = AF_INET;
788 memset(ifr.ifr_name, 0x00, 16);
789 strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);
792 res = ioctl(sock, SIOCGIFADDR, &ifr);
794 WDS_LOGE("Failed to get IP from socket. [%s]", strerror(errno));
796 __WDS_LOG_FUNC_EXIT__;
801 sin = (struct sockaddr_in*) &ifr.ifr_broadaddr;
802 ip_str = inet_ntoa(sin->sin_addr);
803 _txt_to_ip(ip_str, ip_addr);
805 __WDS_LOG_FUNC_EXIT__;
809 int wfd_util_dhcpc_get_server_ip(unsigned char* ip_addr)
811 __WDS_LOG_FUNC_ENTER__;
812 char* get_str = NULL;
816 WDS_LOGE("Invalid parameter");
817 __WDS_LOG_FUNC_EXIT__;
822 get_str = vconf_get_str(VCONFKEY_DHCPC_SERVER_IP);
824 WDS_LOGE("Failed to get vconf value[%s]", VCONFKEY_DHCPC_SERVER_IP);
825 __WDS_LOG_FUNC_EXIT__;
828 WDS_LOGD("VCONFKEY_DHCPC_SERVER_IP(%s) : %s\n", VCONFKEY_DHCPC_SERVER_IP, get_str);
829 _txt_to_ip(get_str, ip_addr);
835 __WDS_LOG_FUNC_EXIT__;