Revise wifi statistics routine
[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_get_rssi_level(const int rssi_dbm)
175 {
176         int snr_level = 0;
177         int freq = 0;
178         int ret = 0;
179
180         ret = netconfig_vconf_get_int("memory/private/wifi/frequency", &freq);
181
182         if (!ret && freq > 4900)
183                 snr_level = __netconfig_wifi_convert_dbm_to_level_50(rssi_dbm);
184         else
185                 snr_level = __netconfig_wifi_convert_dbm_to_level_24(rssi_dbm);
186
187         return snr_level;
188 }
189
190 static void __netconfig_wifi_set_rssi_level(const char *interface_name,
191                 const char *path, const int snr_level)
192 {
193         rssi_data_s *rssi_data = NULL;
194         const char *default_ifname = NULL;
195
196         rssi_data = __get_rssi_data(interface_name);
197         if (rssi_data == NULL)
198                 return;
199
200         if (snr_level != rssi_data->last_snr_level) {
201                 default_ifname = netconfig_get_default_ifname();
202                 if (g_strcmp0(default_ifname, interface_name) == 0)
203                         netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, snr_level, FALSE);
204
205                 if (g_strcmp0(rssi_data->default_path, path) == 0) {
206                         wifi_emit_rssi_changed((Wifi *)get_wifi_object(), interface_name, snr_level);
207
208                         netconfig_battery_update_wifi_rssi(snr_level);
209
210                         rssi_data->last_snr_level = snr_level;
211                 }
212         }
213 }
214
215 static void __netconfig_wifi_data_activity_booster(int level)
216 {
217         gboolean reply = FALSE;
218         GVariant *params = NULL;
219         int level1 = 1;
220         int level2 = 2;
221         int level3 = 3;
222
223         int lock = 2000;
224         int unlock = 0;
225
226         static int old_level = 0;
227
228         if (level < 0)
229                 return;
230
231         if (level > 0) {
232                 /* enable booster */
233                 switch (level) {
234                 case 1:
235                         params = g_variant_new("(ii)", level1, lock);
236                         break;
237                 case 2:
238                         params = g_variant_new("(ii)", level2, lock);
239                         break;
240                 case 3:
241                         params = g_variant_new("(ii)", level3, lock);
242                         break;
243                 default:
244                         ERR("Invalid level");
245                         return;
246                 }
247
248                 reply = netconfig_invoke_dbus_method_nonblock(
249                                 "org.tizen.system.deviced",
250                                 "/Org/Tizen/System/DeviceD/PmQos",
251                                 "org.tizen.system.deviced.PmQos",
252                                 "WifiThroughput",
253                                 params,
254                                 NULL,
255                                 NULL);
256                 if (reply != TRUE)
257                         return;
258         }
259
260         /* disable previous booster */
261         if (old_level == 0 || old_level == level)
262                 return;
263
264         switch (old_level) {
265         case 1:
266                 params = g_variant_new("(ii)", level1, unlock);
267                 break;
268         case 2:
269                 params = g_variant_new("(ii)", level2, unlock);
270                 break;
271         case 3:
272                 params = g_variant_new("(ii)", level3, unlock);
273                 break;
274         default:
275                 ERR("Invalid level");
276                 return;
277         }
278
279         reply = netconfig_invoke_dbus_method_nonblock(
280                         "org.tizen.system.deviced",
281                         "/Org/Tizen/System/DeviceD/PmQos",
282                         "org.tizen.system.deviced.PmQos",
283                         "WifiThroughput",
284                         params,
285                         NULL,
286                         NULL);
287         if (reply != TRUE)
288                 return;
289
290         old_level = level;
291 }
292
293 static void __netconfig_wifi_get_statistics(void)
294 {
295         static int last_transfer_state = 0;
296         static int booster_tic = 0;
297         static int old_level = 0;
298         int booster_level = 0;
299         guint64 tx, rx;
300         int transfer_state;
301
302         if (netconfig_wifi_get_bytes_statistics(&tx, &rx, TRUE))
303                 netconfig_wifi_set_bytes_pkt_vconf(tx, rx, FALSE);
304
305         netconfig_wifi_get_bytes_default_iface(&tx, &rx);
306
307         if (tx > 0) {
308                 if (rx > 0)
309                         transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TXRX;
310                 else
311                         transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TX;
312         } else {
313                 if (rx > 0)
314                         transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_RX;
315                 else
316                         transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_NONE;
317         }
318
319         if (transfer_state != last_transfer_state) {
320                 netconfig_set_vconf_int(VCONFKEY_WIFI_TRANSFER_STATE, transfer_state, FALSE);
321                 last_transfer_state = transfer_state;
322         }
323
324         /* NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER */
325         if (tx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1 ||
326                 rx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1)
327                 booster_level = 1;
328         else if (tx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2 ||
329                         rx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2)
330                 booster_level = 2;
331         else if (tx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3 ||
332                         rx >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3)
333                 booster_level = 3;
334
335         if (old_level == booster_level) {
336                 if (--booster_tic <= 0) {
337                         __netconfig_wifi_data_activity_booster(booster_level);
338
339                         booster_tic = 2;
340                 }
341         } else {
342                 __netconfig_wifi_data_activity_booster(booster_level);
343
344                 if (booster_level > 0)
345                         booster_tic = 2;
346                 else
347                         booster_tic = 0;
348         }
349
350         old_level = booster_level;
351 }
352
353 static gboolean __netconfig_wifi_update_statistics(gpointer data)
354 {
355         int pm_state = VCONFKEY_PM_STATE_NORMAL;
356         char *interface_name = data;
357
358         if (wifi_state_get_service_state(interface_name) != NETCONFIG_WIFI_CONNECTED) {
359                 g_free(interface_name);
360                 return FALSE;
361         }
362
363         /* In case of LCD off, we don't need to update Wi-Fi indicator */
364         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
365         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
366                 return TRUE;
367
368         __netconfig_wifi_get_statistics();
369
370         return TRUE;
371 }
372
373 void netconfig_wifi_indicator_update(const char *interface_name,
374                 const char *path, int rssi_dbm)
375 {
376         int pm_state = VCONFKEY_PM_STATE_NORMAL;
377         int snr_level = 0;
378
379         /* In case of LCD off, we don't need to update Wi-Fi indicator */
380         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
381         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
382                 return;
383
384         snr_level = __netconfig_wifi_get_rssi_level(rssi_dbm);
385         __netconfig_wifi_set_rssi_level(interface_name, path, snr_level);
386 }
387
388 void netconfig_wifi_indicator_start(const char *interface_name,
389                 const char *profile_path)
390 {
391         const char *default_ifname = NULL;
392
393         INFO("Start Wi-Fi indicator");
394
395         __create_rssi_data(interface_name);
396
397         if (profile_path)
398                 __set_rssi_data_default_path(interface_name, profile_path);
399
400         default_ifname = netconfig_get_default_ifname();
401         if (g_strcmp0(default_ifname, interface_name) == 0)
402                 netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, VCONFKEY_WIFI_STRENGTH_MAX, FALSE);
403
404         wifi_emit_rssi_changed((Wifi *)get_wifi_object(),
405                 interface_name, VCONFKEY_WIFI_STRENGTH_MAX);
406
407         if (netconfig_wifi_statistics_timer == 0) {
408                 netconfig_wifi_reset_last_bytes();
409                 netconfig_start_timer_seconds(WIFI_INDICATOR_INTERVAL,
410                         __netconfig_wifi_update_statistics, g_strdup(interface_name),
411                         &netconfig_wifi_statistics_timer);
412         }
413
414         netconfig_battery_update_wifi_rssi(VCONFKEY_WIFI_STRENGTH_MAX);
415 }
416
417 void netconfig_wifi_indicator_stop(const char *interface_name)
418 {
419         int wifi_state = 0;
420         guint64 tx, rx;
421
422         INFO("Stop Wi-Fi indicator");
423
424         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
425
426         if (wifi_state != VCONFKEY_WIFI_CONNECTED) {
427                 if (netconfig_wifi_get_bytes_statistics(&tx, &rx, TRUE))
428                         netconfig_wifi_set_bytes_pkt_vconf(tx, rx, FALSE);
429
430                 netconfig_stop_timer(&netconfig_wifi_statistics_timer);
431         }
432
433         __destroy_rssi_data(interface_name);
434 }