c3747a8dd0f9d92a58a8cf7b28461de9363e4242
[platform/core/connectivity/wifi-direct-manager.git] / src / wifi-direct-util.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 utility functions.
22  *
23  * @file                wifi-direct-util.c
24  * @author      Gibyoung Kim (lastkgb.kim@samsung.com)
25  * @version     0.7
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
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>
35 #include <net/if.h>
36 #include <errno.h>
37
38 #include <glib.h>
39
40 #include <vconf.h>
41 #include <app_service.h>
42 #include <wifi-direct.h>
43 #include <wifi-direct-internal.h>
44
45 #include "wifi-direct-manager.h"
46 #include "wifi-direct-state.h"
47 #include "wifi-direct-client.h"
48 #include "wifi-direct-util.h"
49
50 static int _txt_to_mac(char *txt, unsigned char *mac)
51 {
52         int i = 0;
53
54         for (;;) {
55                 mac[i++] = (char) strtoul(txt, &txt, 16);
56                 if (!*txt++ || i == 6)
57                         break;
58         }
59
60         if (i != MACADDR_LEN)
61                 return -1;
62
63         WDS_LOGD("Converted MAC address [" MACSTR "]", MAC2STR(mac));
64         return 0;
65 }
66
67 static int _txt_to_ip(char *txt, unsigned char *ip)
68 {
69         int i = 0;
70
71         for (;;) {
72                 ip[i++] = (char) strtoul(txt, &txt, 10);
73                 if (!*txt++ || i == 4)
74                         break;
75         }
76
77         if (i != 4)
78                 return -1;
79
80         WDS_LOGD("Converted IP address [" IPSTR "]", IP2STR(ip));
81         return 0;
82 }
83
84 int wfd_util_freq_to_channel(int freq)
85 {
86         if (freq < 2412 || freq > 5825) {
87                 WDS_LOGE("Invalid parameter");
88                 return -1;
89         }
90
91         if (freq >= 5180)
92                 return 36 + (freq - 5180)/5;
93         else if (freq <= 2472)
94                 return 1 + (freq - 2412)/5;
95         else if (freq == 2484)
96                 return 14;
97         else
98                 return -1;
99 }
100
101 int wfd_util_get_phone_name(char *phone_name)
102 {
103         __WDS_LOG_FUNC_ENTER__;
104         char *name = NULL;
105
106         name = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR);
107         if (!name) {
108                 WDS_LOGE( "Failed to get vconf value for %s", VCONFKEY_SETAPPL_DEVICE_NAME_STR);
109                 return -1;
110         }
111         strncpy(phone_name, name, DEV_NAME_LEN);
112         phone_name[DEV_NAME_LEN] = '\0';
113
114         WDS_LOGD( "[%s: %s]", VCONFKEY_SETAPPL_DEVICE_NAME_STR, phone_name);
115         free(name);
116         __WDS_LOG_FUNC_EXIT__;
117         return 0;
118 }
119
120 void _wfd_util_dev_name_changed_cb(keynode_t *key, void* data)
121 {
122         __WDS_LOG_FUNC_ENTER__;
123         char dev_name[DEV_NAME_LEN+1] = {0, };
124         int res = 0;
125
126         res = wfd_util_get_phone_name(dev_name);
127         if (res < 0) {
128                 WDS_LOGE("Failed to get phone name(vconf)");
129                 return;
130         }
131         WDS_LOGD("Device name changed as [%s]", dev_name);
132
133         res = wfd_local_set_dev_name(dev_name);
134         if (res < 0)
135                 WDS_LOGE("Failed to set device name");
136         __WDS_LOG_FUNC_EXIT__;
137         return;
138 }
139
140 void wfd_util_set_dev_name_notification()
141 {
142         __WDS_LOG_FUNC_ENTER__;
143
144         vconf_notify_key_changed(VCONFKEY_SETAPPL_DEVICE_NAME_STR, _wfd_util_dev_name_changed_cb, NULL);
145
146         __WDS_LOG_FUNC_EXIT__;
147         return;
148 }
149
150 void wfd_util_unset_dev_name_notification()
151 {
152         __WDS_LOG_FUNC_ENTER__;
153
154         vconf_ignore_key_changed(VCONFKEY_SETAPPL_DEVICE_NAME_STR, _wfd_util_dev_name_changed_cb);
155
156         __WDS_LOG_FUNC_EXIT__;
157         return;
158 }
159
160 int wfd_util_check_wifi_state()
161 {
162         __WDS_LOG_FUNC_ENTER__;
163         int wifi_state = 0;
164         int res = 0;
165
166         /* vconf key and value (vconf-keys.h)
167 #define VCONFKEY_WIFI_STATE "memory/wifi/state"
168 enum {
169         VCONFKEY_WIFI_OFF = 0x00,
170         VCONFKEY_WIFI_UNCONNECTED,
171         VCONFKEY_WIFI_CONNECTED,
172         VCONFKEY_WIFI_TRANSFER,
173         VCONFKEY_WIFI_STATE_MAX
174 };
175          */
176
177         res = vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
178         if (res < 0) {
179                 WDS_LOGE("Failed to get vconf value [%s]", VCONFKEY_WIFI_STATE);
180                 __WDS_LOG_FUNC_EXIT__;
181                 return -1;
182         }
183         WDS_LOGD("[%s: %d]", VCONFKEY_WIFI_STATE, wifi_state);
184
185         if (wifi_state > VCONFKEY_WIFI_OFF) {
186                 WDS_LOGD("Wi-Fi is on");
187                 __WDS_LOG_FUNC_EXIT__;
188                 return 1;
189         }
190         WDS_LOGD( "OK. Wi-Fi is off\n");
191
192         __WDS_LOG_FUNC_EXIT__;
193         return 0;
194 }
195
196 int wfd_util_check_mobile_ap_state()
197 {
198         __WDS_LOG_FUNC_ENTER__;
199         int mobile_ap_state = 0;
200         int res = 0;
201
202         res = vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_MODE, &mobile_ap_state);
203         if (res < 0) {
204                 WDS_LOGE("Failed to get vconf value[%s]", VCONFKEY_MOBILE_HOTSPOT_MODE);
205                 __WDS_LOG_FUNC_EXIT__;
206                 return -1;
207         }
208         WDS_LOGD("[%s: %d]", VCONFKEY_MOBILE_HOTSPOT_MODE, mobile_ap_state);
209
210         if (mobile_ap_state != VCONFKEY_MOBILE_HOTSPOT_MODE_NONE) {
211                 WDS_LOGD("Mobile AP is on");
212                 __WDS_LOG_FUNC_EXIT__;
213                 return 1;
214         }
215         WDS_LOGD( "OK. Mobile AP is off\n");
216
217         __WDS_LOG_FUNC_EXIT__;
218         return 0;
219 }
220
221 int wfd_util_wifi_direct_activatable()
222 {
223         __WDS_LOG_FUNC_ENTER__;
224         int res = 0;
225
226         res = wfd_util_check_wifi_state();
227         if (res < 0) {
228                 WDS_LOGE("Failed to check Wi-Fi state");
229                 return WIFI_DIRECT_ERROR_OPERATION_FAILED;
230         } else if (res > 0) {
231                 WDS_LOGE("Wi-Fi is On");
232                 return WIFI_DIRECT_ERROR_WIFI_USED;
233         } else {
234                 WDS_LOGE("Wi-Fi is Off");
235                 return WIFI_DIRECT_ERROR_NONE;
236         }
237
238         res = wfd_util_check_mobile_ap_state();
239         if (res < 0) {
240                 WDS_LOGE("Failed to check Mobile AP state");
241                 return WIFI_DIRECT_ERROR_OPERATION_FAILED;
242         } else if (res > 0) {
243                 WDS_LOGE("Mobile AP is On");
244                 return WIFI_DIRECT_ERROR_MOBILE_AP_USED;
245         } else {
246                 WDS_LOGE("Mobile AP is Off");
247                 return WIFI_DIRECT_ERROR_NONE;
248         }
249 }
250
251 int wfd_util_get_wifi_direct_state()
252 {
253         __WDS_LOG_FUNC_ENTER__;
254         int state = 0;
255         int res = 0;
256
257         res = vconf_get_int(VCONFKEY_WIFI_DIRECT_STATE, &state);
258         if (res < 0) {
259                 WDS_LOGE("Failed to get vconf value [%s]\n", VCONFKEY_WIFI_DIRECT_STATE);
260                 __WDS_LOG_FUNC_EXIT__;
261                 return -1;
262         }
263
264         __WDS_LOG_FUNC_EXIT__;
265         return state;
266 }
267
268 int wfd_util_set_wifi_direct_state(int state)
269 {
270         __WDS_LOG_FUNC_ENTER__;
271         int vconf_state = 0;
272         int res = 0;
273
274         // TODO: check validity of state
275
276         if (state == WIFI_DIRECT_STATE_ACTIVATED)
277                 vconf_state = VCONFKEY_WIFI_DIRECT_ACTIVATED;
278         else if (state == WIFI_DIRECT_STATE_DEACTIVATED)
279                 vconf_state= VCONFKEY_WIFI_DIRECT_DEACTIVATED;
280         else if (state == WIFI_DIRECT_STATE_CONNECTED)
281                 vconf_state = VCONFKEY_WIFI_DIRECT_CONNECTED;
282         else if (state == WIFI_DIRECT_STATE_GROUP_OWNER)
283                 vconf_state = VCONFKEY_WIFI_DIRECT_GROUP_OWNER;
284         else if (state == WIFI_DIRECT_STATE_DISCOVERING)
285                 vconf_state = VCONFKEY_WIFI_DIRECT_DISCOVERING;
286         WDS_LOGD("Vconf key set [%s: %d]", VCONFKEY_WIFI_DIRECT_STATE, vconf_state);
287
288         res = vconf_set_int(VCONFKEY_WIFI_DIRECT_STATE, vconf_state);
289         if (res < 0) {
290                 WDS_LOGE("Failed to set vconf [%s]", VCONFKEY_WIFI_DIRECT_STATE);
291                 __WDS_LOG_FUNC_EXIT__;
292                 return -1;
293         }
294
295         __WDS_LOG_FUNC_EXIT__;
296         return 0;
297 }
298
299 int wfd_util_get_local_dev_mac(unsigned char *dev_mac)
300 {
301         __WDS_LOG_FUNC_ENTER__;
302         FILE *fd = NULL;
303         char local_mac[MACSTR_LEN] = {0, };
304         char *ptr = NULL;
305         int res = 0;
306
307         errno = 0;
308         fd = fopen(DEFAULT_MAC_FILE_PATH, "r");
309         if (!fd) {
310                 WDS_LOGE("Failed to open MAC info file (%s)", strerror(errno));
311                 __WDS_LOG_FUNC_EXIT__;
312                 return -1;
313         }
314
315         errno = 0;
316         ptr = fgets(local_mac, MACSTR_LEN, fd);
317         if (!ptr) {
318                 WDS_LOGE("Failed to read file or no data read(%s)", strerror(errno));
319                 fclose(fd);
320                 __WDS_LOG_FUNC_EXIT__;
321                 return -1;
322         }
323         WDS_LOGD("Local MAC address [%s]", ptr);
324
325         res = _txt_to_mac(local_mac, dev_mac);
326         if (res < 0) {
327                 WDS_LOGE("Failed to convert text to MAC address");
328                 fclose(fd);
329                 __WDS_LOG_FUNC_EXIT__;
330                 return -1;
331         }
332
333         dev_mac[0] |= 0x2;
334         WDS_LOGD("Local Device MAC address [" MACSTR "]", MAC2STR(dev_mac));
335
336         fclose(fd);
337         __WDS_LOG_FUNC_EXIT__;
338         return 0;
339 }
340
341 int wfd_util_start_wifi_direct_popup()
342 {
343         __WDS_LOG_FUNC_ENTER__;
344
345         service_h service;
346         service_create(&service);
347         service_set_operation(service, SERVICE_OPERATION_DEFAULT);
348         service_set_package(service, "org.tizen.wifi-direct-popup");
349         service_send_launch_request(service, NULL, NULL);
350         service_destroy(service);
351         WDS_LOGD("Succeeded to launch wifi-direct-popup");
352         __WDS_LOG_FUNC_EXIT__;
353         return 0;
354 }
355
356
357 static void _dhcps_ip_leased_cb(keynode_t *key, void* data)
358 {
359         __WDS_LOG_FUNC_ENTER__;
360         wfd_manager_s *manager = wfd_get_manager();
361         wfd_device_s *peer = (wfd_device_s*) data;
362         wifi_direct_client_noti_s noti;
363         FILE *fp = NULL;
364         char buf[MAX_DHCP_DUMP_SIZE];
365         char ip_str[IPSTR_LEN];
366         char intf_str[MACSTR_LEN];
367         unsigned char intf_addr[MACADDR_LEN];
368         int n = 0;
369
370         if (!peer) {
371                 WDS_LOGD("Invalid parameter");
372                 return;
373         }
374         WDS_LOGD("DHCP server: IP leased");
375         memset(&noti, 0, sizeof(wifi_direct_client_noti_s));
376
377         errno = 0;
378         fp = fopen(DHCP_DUMP_FILE, "r");
379         if (NULL == fp) {
380                 WDS_LOGE("Could not read the file(%s). [%s]", DHCP_DUMP_FILE, strerror(errno));
381                 return;
382         }
383
384         while(fgets(buf, MAX_DHCP_DUMP_SIZE, fp) != NULL) {
385                 WDS_LOGD("Read line [%s]", buf);
386                 n = sscanf(buf,"%s %s", intf_str, ip_str);
387                 WDS_LOGD("ip=[%s], mac=[%s]",ip_str, intf_str);
388                 if (n != 2) {
389                         continue;
390                 }
391                 _txt_to_mac(intf_str, intf_addr);
392                 if (!memcmp(peer->intf_addr, intf_addr, MACADDR_LEN)) {
393                         WDS_LOGD("Peer intf mac found");
394                         _txt_to_ip(ip_str, peer->ip_addr);
395                         noti.event = WIFI_DIRECT_CLI_EVENT_IP_LEASED_IND;
396                         snprintf(noti.param1, MACSTR_LEN, MACSTR, MAC2STR(peer->dev_addr));
397                         snprintf(noti.param2, IPSTR_LEN, IPSTR, IP2STR(peer->ip_addr));
398                         wfd_client_send_event(manager, &noti);
399                         break;
400                 } else {
401                         WDS_LOGE("Different interface address peer[" MACSTR "] vs dhcp[" MACSTR "]", MAC2STR(peer->intf_addr), MAC2STR(intf_addr));
402                 }
403         }
404         fclose(fp);
405
406         __WDS_LOG_FUNC_EXIT__;
407         return;
408 }
409
410 static gboolean _polling_ip(gpointer user_data)
411 {
412         __WDS_LOG_FUNC_ENTER__;
413         wfd_manager_s *manager = wfd_get_manager();
414         wfd_device_s *local = (wfd_device_s*) manager->local;
415         wfd_device_s *peer = (wfd_device_s*) user_data;
416         char *ifname = NULL;
417         static int count = 0;
418         int res = 0;
419
420         if (count > 28) {
421                 WDS_LOGE("Failed to get IP");
422                 count = 0;
423                 __WDS_LOG_FUNC_EXIT__;
424                 return FALSE;
425         }
426         res = wfd_manager_get_goup_ifname(&ifname);
427         if (res < 0 || !ifname) {
428                 WDS_LOGE("Failed to get group interface name");
429                 return FALSE;
430         }
431
432         res = wfd_util_dhcpc_get_ip(ifname, local->ip_addr, 0);
433         if (res < 0) {
434                 WDS_LOGE("Failed to get local IP for interface %s(count=%d)", ifname, count++);
435                 __WDS_LOG_FUNC_EXIT__;
436                 return TRUE;
437         }
438         WDS_LOGD("Succeeded to get local(client) IP [" IPSTR "] for iface[%s]",
439                                     IP2STR(local->ip_addr), ifname);
440
441         res = wfd_util_dhcpc_get_server_ip(peer->ip_addr);
442         if (res < 0) {
443                 WDS_LOGE("Failed to get peer(server) IP(count=%d)", count++);
444                 __WDS_LOG_FUNC_EXIT__;
445                 return TRUE;
446         }
447         WDS_LOGD("Succeeded to get server IP [" IPSTR "]", IP2STR(peer->ip_addr));
448         count = 0;
449
450         wfd_state_set(manager, WIFI_DIRECT_STATE_CONNECTED);
451         wfd_util_set_wifi_direct_state(WIFI_DIRECT_STATE_CONNECTED);
452         wifi_direct_client_noti_s noti;
453         memset(&noti, 0x0, sizeof(wifi_direct_client_noti_s));
454         noti.event = WIFI_DIRECT_CLI_EVENT_CONNECTION_RSP;
455         noti.error = WIFI_DIRECT_ERROR_NONE;
456         snprintf(noti.param1, MACSTR_LEN, MACSTR, MAC2STR(peer->dev_addr));
457         wfd_client_send_event(manager, &noti);
458
459         __WDS_LOG_FUNC_EXIT__;
460         return FALSE;
461 }
462
463 int wfd_util_dhcps_start()
464 {
465         __WDS_LOG_FUNC_ENTER__;
466         int res = 0;
467
468         vconf_set_int(VCONFKEY_DHCPS_IP_LEASE, 0);
469         res = system("/usr/bin/wifi-direct-dhcp.sh server");
470         WDS_LOGD("[/usr/bin/wifi-direct-dhcp.sh server] returns %d", res);
471
472         __WDS_LOG_FUNC_EXIT__;
473         return 0;
474 }
475
476 int wfd_util_dhcps_wait_ip_leased(wfd_device_s *peer)
477 {
478         __WDS_LOG_FUNC_ENTER__;
479
480         if (!peer) {
481                 WDS_LOGE("Invalid parameter");
482                 return -1;
483         }
484
485         vconf_set_int(VCONFKEY_DHCPS_IP_LEASE, 0);
486         vconf_notify_key_changed(VCONFKEY_DHCPS_IP_LEASE, _dhcps_ip_leased_cb, peer);
487
488         __WDS_LOG_FUNC_EXIT__;
489         return 0;
490 }
491
492 int wfd_util_dhcps_stop()
493 {
494         __WDS_LOG_FUNC_ENTER__;
495         int res = 0;
496
497         vconf_ignore_key_changed(VCONFKEY_DHCPS_IP_LEASE, _dhcps_ip_leased_cb);
498         vconf_set_int(VCONFKEY_DHCPS_IP_LEASE, 0);
499
500         res = system("/usr/bin/wifi-direct-dhcp.sh stop");
501         WDS_LOGD("[/usr/bin/wifi-direct-dhcp.sh stop] returns %d", res);
502
503         __WDS_LOG_FUNC_EXIT__;
504         return 0;
505 }
506
507 int wfd_util_dhcpc_start(wfd_device_s *peer)
508 {
509         __WDS_LOG_FUNC_ENTER__;
510         int res = 0;
511
512         if (!peer) {
513                 WDS_LOGE("Invalid parameter");
514                 return -1;
515         }
516
517         res = system("/usr/bin/wifi-direct-dhcp.sh client");
518         WDS_LOGD("[/usr/bin/wifi-direct-dhcp.sh client] returns %d", res);
519         g_timeout_add(250, (GSourceFunc) _polling_ip, peer);
520
521         __WDS_LOG_FUNC_EXIT__;
522         return 0;
523 }
524
525 int wfd_util_dhcpc_stop()
526 {
527         __WDS_LOG_FUNC_ENTER__;
528         int res = 0;
529
530         res = system("/usr/bin/wifi-direct-dhcp.sh stop");
531         WDS_LOGD("[/usr/bin/wifi-direct-dhcp.sh stop] returns %d", res);
532
533         __WDS_LOG_FUNC_EXIT__;
534         return 0;
535 }
536
537 int wfd_util_dhcpc_get_ip(char *ifname, unsigned char *ip_addr, int is_IPv6)
538 {
539         __WDS_LOG_FUNC_ENTER__;
540         struct ifreq ifr;
541         struct sockaddr_in *sin = NULL;
542         char *ip_str = NULL;
543         int sock = -1;
544         int res = -1;
545
546         if (!ifname || !ip_addr) {
547                 WDS_LOGE("Invalid parameter");
548                 __WDS_LOG_FUNC_EXIT__;
549                 return -1;
550         }
551
552         errno = 0;
553         sock = socket(AF_INET, SOCK_DGRAM, 0);
554         if (sock < SOCK_FD_MIN) {
555                 WDS_LOGE("Failed to create socket. [%s]", strerror(errno));
556                 if (sock >= 0)
557                         close(sock);
558                 __WDS_LOG_FUNC_EXIT__;
559                 return -1;
560         }
561
562         ifr.ifr_addr.sa_family = AF_INET;
563         memset(ifr.ifr_name, 0x00, 16);
564         strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);
565
566         errno = 0;
567         res = ioctl(sock, SIOCGIFADDR, &ifr);
568         if (res < 0) {
569                 WDS_LOGE("Failed to get IP from socket. [%s]", strerror(errno));
570                 close(sock);
571                 __WDS_LOG_FUNC_EXIT__;
572                 return -1;
573         }
574         close(sock);
575
576         sin = (struct sockaddr_in*) &ifr.ifr_broadaddr;
577         ip_str = inet_ntoa(sin->sin_addr);
578         _txt_to_ip(ip_str, ip_addr);
579
580         __WDS_LOG_FUNC_EXIT__;
581         return 0;
582 }
583
584 int wfd_util_dhcpc_get_server_ip(unsigned char* ip_addr)
585 {
586         __WDS_LOG_FUNC_ENTER__;
587         char* get_str = NULL;
588         int count = 0;
589
590         if (!ip_addr) {
591                 WDS_LOGE("Invalid parameter");
592                 __WDS_LOG_FUNC_EXIT__;
593                 return -1;
594         }
595
596         while(count < 10) {
597                 get_str = vconf_get_str(VCONFKEY_DHCPC_SERVER_IP);
598                 if (!get_str) {
599                         WDS_LOGE("Failed to get vconf value[%s]", VCONFKEY_DHCPC_SERVER_IP);
600                         __WDS_LOG_FUNC_EXIT__;
601                         return -1;
602                 }
603                 WDS_LOGD("VCONFKEY_DHCPC_SERVER_IP(%s) : %s\n", VCONFKEY_DHCPC_SERVER_IP, get_str);
604                 _txt_to_ip(get_str, ip_addr);
605                 if (*ip_addr)
606                         break;
607                 count++;
608         }
609
610         __WDS_LOG_FUNC_EXIT__;
611         return 0;
612 }
613