Merge "Add dbus method for getting wifi passphrase" into tizen
[platform/core/connectivity/net-config.git] / src / wifi-indicator.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2000 - 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 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sys/ioctl.h>
25 #include <netinet/in.h>
26 #include <netinet/ip.h>
27 #include <linux/wireless.h>
28 #include <vconf.h>
29 #include <vconf-keys.h>
30
31 #include "log.h"
32 #include "util.h"
33 #include "netdbus.h"
34 #include "wifi-state.h"
35 #include "network-state.h"
36 #include "network-statistics.h"
37 #include "netsupplicant.h"
38 #include "wifi-indicator.h"
39
40 #define VCONFKEY_WIFI_SNR_MIN   -89
41
42 #if !defined TIZEN_WEARABLE
43 #define WIFI_INDICATOR_INTERVAL 2
44 #else
45 #define WIFI_INDICATOR_INTERVAL 10
46 #endif
47
48 #if defined TIZEN_WEARABLE
49 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1     (19200 * 1024)
50 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2     (2560 * 1024)
51 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3     (1536 * 1024)
52 #else
53 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1     (19200 * 1024)
54 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2     (7680 * 1024)
55 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3     (3840 * 1024)
56 #endif
57 #define NETCONFIG_PROCWIRELESS                                  "/proc/net/wireless"
58
59 typedef struct {
60         char *interface_name;
61         char *default_path;
62         int last_snr_level;
63 } rssi_data_s;
64
65 static GSList *g_rssi_list = NULL;
66 static guint netconfig_wifi_statistics_timer = 0;
67
68 static rssi_data_s *__create_rssi_data(const char *interface_name)
69 {
70         rssi_data_s *rssi_data = g_try_malloc0(sizeof(rssi_data_s));
71         if (!rssi_data) {
72                 ERR("Memory allocation failed");
73                 return NULL;
74         }
75
76         rssi_data->interface_name = g_strdup(interface_name);
77
78         g_rssi_list = g_slist_append(g_rssi_list, rssi_data);
79
80         return rssi_data;
81 }
82
83 static rssi_data_s *__get_rssi_data(const char *interface_name)
84 {
85         GSList *list;
86         rssi_data_s *rssi_data = NULL;
87
88         for (list = g_rssi_list; list; list = list->next) {
89                 rssi_data = list->data;
90                 if (g_strcmp0(rssi_data->interface_name, interface_name) == 0)
91                         return rssi_data;
92         }
93
94         return rssi_data;
95 }
96
97 static void __set_rssi_data_default_path(const char *interface_name,
98                 const char *path)
99 {
100         rssi_data_s *rssi_data = __get_rssi_data(interface_name);
101         if (rssi_data == NULL)
102                 return;
103
104         rssi_data->default_path = g_strdup(path);
105 }
106
107 static void __destroy_rssi_data(const char *interface_name)
108 {
109         rssi_data_s *rssi_data = __get_rssi_data(interface_name);
110
111         if (!rssi_data)
112                 return;
113
114         g_rssi_list = g_slist_remove(g_rssi_list, rssi_data);
115         g_free(rssi_data->interface_name);
116         g_free(rssi_data->default_path);
117         g_free(rssi_data);
118 }
119
120 static int __netconfig_wifi_convert_dbm_to_level_24(int rssi_dbm)
121 {
122         int rssi_level = 0;
123
124         /* Wi-Fi Signal Strength Display (for 2.4G (dB))
125          *
126          * Excellent :     ~ -63
127          * Good      : -64 ~ -74
128          * Weak      : -75 ~ -82
129          * Very weak : -83 ~ -88
130          * No signal : -89 ~
131          */
132
133         if (rssi_dbm >= -63)
134                 rssi_level = 4;
135         else if (rssi_dbm >= -74)
136                 rssi_level = 3;
137         else if (rssi_dbm >= -82)
138                 rssi_level = 2;
139         else if (rssi_dbm >= -88)
140                 rssi_level = 1;
141         else
142                 rssi_level = 0;
143
144         return rssi_level;
145 }
146
147 static int __netconfig_wifi_convert_dbm_to_level_50(int rssi_dbm)
148 {
149         int rssi_level = 0;
150
151         /* Wi-Fi Signal Strength Display (for 5G (dB))
152          *
153          * Excellent :     ~ -67
154          * Good      : -68 ~ -76
155          * Weak      : -77 ~ -82
156          * Very weak : -83 ~ -88
157          * No signal : -89 ~
158          */
159
160         if (rssi_dbm >= -67)
161                 rssi_level = 4;
162         else if (rssi_dbm >= -76)
163                 rssi_level = 3;
164         else if (rssi_dbm >= -82)
165                 rssi_level = 2;
166         else if (rssi_dbm >= -88)
167                 rssi_level = 1;
168         else
169                 rssi_level = 0;
170
171         return rssi_level;
172 }
173
174 static int __netconfig_wifi_convert_dbm_to_level_60(int rssi_dbm)
175 {
176         int rssi_level = 0;
177
178         /* Wi-Fi Signal Strength Display (for 6G (dB))
179          *
180          * Excellent :     ~ -72
181          * Good      : -73 ~ -77
182          * Weak      : -78 ~ -82
183          * Very weak : -83 ~ -88
184          * No signal : -89 ~
185          */
186
187         if (rssi_dbm >= -72)
188                 rssi_level = 4;
189         else if (rssi_dbm >= -77)
190                 rssi_level = 3;
191         else if (rssi_dbm >= -82)
192                 rssi_level = 2;
193         else if (rssi_dbm >= -88)
194                 rssi_level = 1;
195         else
196                 rssi_level = 0;
197
198         return rssi_level;
199 }
200
201 static int __netconfig_wifi_get_rssi_level(const int rssi_dbm)
202 {
203         int snr_level = 0;
204         int freq = 0;
205         int ret = 0;
206
207         ret = netconfig_vconf_get_int("memory/private/wifi/frequency", &freq);
208
209         if (!ret && freq > 5925)
210                 snr_level = __netconfig_wifi_convert_dbm_to_level_60(rssi_dbm);
211         else if (!ret && freq > 4900)
212                 snr_level = __netconfig_wifi_convert_dbm_to_level_50(rssi_dbm);
213         else
214                 snr_level = __netconfig_wifi_convert_dbm_to_level_24(rssi_dbm);
215
216         return snr_level;
217 }
218
219 static void __netconfig_wifi_set_rssi_level(const char *interface_name,
220                 const char *path, const int snr_level)
221 {
222         rssi_data_s *rssi_data = NULL;
223         const char *default_ifname = NULL;
224
225         rssi_data = __get_rssi_data(interface_name);
226         if (rssi_data == NULL)
227                 return;
228
229         if (snr_level != rssi_data->last_snr_level) {
230                 default_ifname = netconfig_get_default_ifname();
231                 if (g_strcmp0(default_ifname, interface_name) == 0)
232                         netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, snr_level, FALSE);
233
234                 if (g_strcmp0(rssi_data->default_path, path) == 0) {
235                         wifi_emit_rssi_changed((Wifi *)get_wifi_object(), interface_name, snr_level);
236
237                         netconfig_battery_update_wifi_rssi(snr_level);
238
239                         rssi_data->last_snr_level = snr_level;
240                 }
241         }
242 }
243
244 static void __netconfig_wifi_data_activity_booster(int level)
245 {
246         gboolean reply = FALSE;
247         GVariant *params = NULL;
248         int level1 = 1;
249         int level2 = 2;
250         int level3 = 3;
251
252         int lock = 2000;
253         int unlock = 0;
254
255         static int old_level = 0;
256
257         if (level < 0)
258                 return;
259
260         if (level > 0) {
261                 /* enable booster */
262                 switch (level) {
263                 case 1:
264                         params = g_variant_new("(ii)", level1, lock);
265                         break;
266                 case 2:
267                         params = g_variant_new("(ii)", level2, lock);
268                         break;
269                 case 3:
270                         params = g_variant_new("(ii)", level3, lock);
271                         break;
272                 default:
273                         ERR("Invalid level");
274                         return;
275                 }
276
277                 reply = netconfig_invoke_dbus_method_nonblock(
278                                 "org.tizen.system.deviced",
279                                 "/Org/Tizen/System/DeviceD/PmQos",
280                                 "org.tizen.system.deviced.PmQos",
281                                 "WifiThroughput",
282                                 params,
283                                 NULL,
284                                 NULL);
285                 if (reply != TRUE)
286                         return;
287         }
288
289         /* disable previous booster */
290         if (old_level == 0 || old_level == level)
291                 return;
292
293         switch (old_level) {
294         case 1:
295                 params = g_variant_new("(ii)", level1, unlock);
296                 break;
297         case 2:
298                 params = g_variant_new("(ii)", level2, unlock);
299                 break;
300         case 3:
301                 params = g_variant_new("(ii)", level3, unlock);
302                 break;
303         default:
304                 ERR("Invalid level");
305                 return;
306         }
307
308         reply = netconfig_invoke_dbus_method_nonblock(
309                         "org.tizen.system.deviced",
310                         "/Org/Tizen/System/DeviceD/PmQos",
311                         "org.tizen.system.deviced.PmQos",
312                         "WifiThroughput",
313                         params,
314                         NULL,
315                         NULL);
316         if (reply != TRUE)
317                 return;
318
319         old_level = level;
320 }
321
322 static void __netconfig_wifi_get_statistics(void)
323 {
324         static int last_transfer_state = 0;
325         static int booster_tic = 0;
326         static int old_level = 0;
327         int booster_level = 0;
328         guint64 tx, rx;
329         int transfer_state;
330
331         if (netconfig_wifi_get_bytes_statistics(&tx, &rx, TRUE))
332                 netconfig_wifi_set_bytes_pkt_vconf(tx, rx, FALSE);
333
334         netconfig_wifi_get_bytes_default_iface(&tx, &rx);
335
336         if (tx > 0) {
337                 if (rx > 0)
338                         transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TXRX;
339                 else
340                         transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TX;
341         } else {
342                 if (rx > 0)
343                         transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_RX;
344                 else
345                         transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_NONE;
346         }
347
348         if (transfer_state != last_transfer_state) {
349                 netconfig_set_vconf_int(VCONFKEY_WIFI_TRANSFER_STATE, transfer_state, FALSE);
350                 last_transfer_state = transfer_state;
351         }
352
353         /* NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER */
354         if (tx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1 ||
355                 rx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1)
356                 booster_level = 1;
357         else if (tx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2 ||
358                         rx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2)
359                 booster_level = 2;
360         else if (tx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3 ||
361                         rx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3)
362                 booster_level = 3;
363
364         if (old_level == booster_level) {
365                 if (--booster_tic <= 0) {
366                         __netconfig_wifi_data_activity_booster(booster_level);
367
368                         booster_tic = 2;
369                 }
370         } else {
371                 __netconfig_wifi_data_activity_booster(booster_level);
372
373                 if (booster_level > 0)
374                         booster_tic = 2;
375                 else
376                         booster_tic = 0;
377         }
378
379         old_level = booster_level;
380 }
381
382 static gboolean __netconfig_wifi_update_statistics(gpointer data)
383 {
384         int pm_state = VCONFKEY_PM_STATE_NORMAL;
385         char *interface_name = data;
386
387         if (wifi_state_get_service_state(interface_name) != NETCONFIG_WIFI_CONNECTED) {
388                 g_free(interface_name);
389                 return FALSE;
390         }
391
392         /* In case of LCD off, we don't need to update Wi-Fi indicator */
393         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
394         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
395                 return TRUE;
396
397         __netconfig_wifi_get_statistics();
398
399         return TRUE;
400 }
401
402 void netconfig_wifi_indicator_update(const char *interface_name,
403                 const char *path, int rssi_dbm)
404 {
405         int pm_state = VCONFKEY_PM_STATE_NORMAL;
406         int snr_level = 0;
407
408         /* In case of LCD off, we don't need to update Wi-Fi indicator */
409         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
410         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
411                 return;
412
413         snr_level = __netconfig_wifi_get_rssi_level(rssi_dbm);
414         __netconfig_wifi_set_rssi_level(interface_name, path, snr_level);
415 }
416
417 void netconfig_wifi_indicator_start(const char *interface_name,
418                 const char *profile_path)
419 {
420         const char *default_ifname = NULL;
421
422         INFO("Start Wi-Fi indicator");
423
424         __create_rssi_data(interface_name);
425
426         if (profile_path)
427                 __set_rssi_data_default_path(interface_name, profile_path);
428
429         default_ifname = netconfig_get_default_ifname();
430         if (g_strcmp0(default_ifname, interface_name) == 0)
431                 netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, VCONFKEY_WIFI_STRENGTH_MAX, FALSE);
432
433         wifi_emit_rssi_changed((Wifi *)get_wifi_object(),
434                 interface_name, VCONFKEY_WIFI_STRENGTH_MAX);
435
436         if (netconfig_wifi_statistics_timer == 0) {
437                 netconfig_wifi_reset_last_bytes();
438                 netconfig_start_timer_seconds(WIFI_INDICATOR_INTERVAL,
439                         __netconfig_wifi_update_statistics, g_strdup(interface_name),
440                         &netconfig_wifi_statistics_timer);
441         }
442
443         netconfig_battery_update_wifi_rssi(VCONFKEY_WIFI_STRENGTH_MAX);
444 }
445
446 void netconfig_wifi_indicator_stop(const char *interface_name)
447 {
448         int wifi_state = 0;
449         guint64 tx, rx;
450
451         INFO("Stop Wi-Fi indicator");
452
453         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
454
455         if (wifi_state != VCONFKEY_WIFI_CONNECTED) {
456                 if (netconfig_wifi_get_bytes_statistics(&tx, &rx, TRUE))
457                         netconfig_wifi_set_bytes_pkt_vconf(tx, rx, FALSE);
458
459                 netconfig_stop_timer(&netconfig_wifi_statistics_timer);
460         }
461
462         __destroy_rssi_data(interface_name);
463 }