5b0810ad3740c50c9166771c3746b89990c3a213
[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);
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 guint64 netconfig_wifi_tx_bytes = 0;
297         static guint64 netconfig_wifi_rx_bytes = 0;
298         static int booster_tic = 0;
299         static int old_level = 0;
300         int booster_level = 0;
301         guint64 tx, rx, tx_diff, rx_diff;
302         int transfer_state;
303
304         if (netconfig_wifi_get_bytes_statistics(&tx, &rx) == TRUE) {
305                 tx_diff = tx - netconfig_wifi_tx_bytes;
306                 rx_diff = rx - netconfig_wifi_rx_bytes;
307
308                 if (tx_diff > 0) {
309                         if (rx_diff > 0)
310                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TXRX;
311                         else
312                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TX;
313                 } else {
314                         if (rx_diff > 0)
315                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_RX;
316                         else
317                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_NONE;
318                 }
319
320                 if (transfer_state != last_transfer_state) {
321                         netconfig_set_vconf_int(VCONFKEY_WIFI_TRANSFER_STATE, transfer_state);
322                         last_transfer_state = transfer_state;
323                 }
324
325                 /* NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER */
326                 if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1 ||
327                         rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1)
328                         booster_level = 1;
329                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2 ||
330                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2)
331                         booster_level = 2;
332                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3 ||
333                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3)
334                         booster_level = 3;
335
336                 if (old_level == booster_level) {
337                         if (--booster_tic <= 0) {
338                                 __netconfig_wifi_data_activity_booster(booster_level);
339
340                                 booster_tic = 2;
341                         }
342                 } else {
343                         __netconfig_wifi_data_activity_booster(booster_level);
344
345                         if (booster_level > 0)
346                                 booster_tic = 2;
347                         else
348                                 booster_tic = 0;
349                 }
350
351                 old_level = booster_level;
352
353                 netconfig_wifi_tx_bytes = tx;
354                 netconfig_wifi_rx_bytes = rx;
355         }
356 }
357
358 static gboolean __netconfig_wifi_update_statistics(gpointer data)
359 {
360         int pm_state = VCONFKEY_PM_STATE_NORMAL;
361         char *interface_name = data;
362
363         if (wifi_state_get_service_state(interface_name) != NETCONFIG_WIFI_CONNECTED) {
364                 g_free(interface_name);
365                 return FALSE;
366         }
367
368         /* In case of LCD off, we don't need to update Wi-Fi indicator */
369         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
370         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
371                 return TRUE;
372
373         __netconfig_wifi_get_statistics();
374
375         return TRUE;
376 }
377
378 void netconfig_wifi_indicator_update(const char *interface_name,
379                 const char *path, int rssi_dbm)
380 {
381         int pm_state = VCONFKEY_PM_STATE_NORMAL;
382         int snr_level = 0;
383
384         /* In case of LCD off, we don't need to update Wi-Fi indicator */
385         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
386         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
387                 return;
388
389         snr_level = __netconfig_wifi_get_rssi_level(rssi_dbm);
390         __netconfig_wifi_set_rssi_level(interface_name, path, snr_level);
391 }
392
393 void netconfig_wifi_indicator_start(const char *interface_name,
394                 const char *profile_path)
395 {
396         const char *default_ifname = NULL;
397
398         INFO("Start Wi-Fi indicator");
399
400         __create_rssi_data(interface_name);
401
402         if (profile_path)
403                 __set_rssi_data_default_path(interface_name, profile_path);
404
405         default_ifname = netconfig_get_default_ifname();
406         if (g_strcmp0(default_ifname, interface_name) == 0)
407                 netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, VCONFKEY_WIFI_STRENGTH_MAX);
408
409         wifi_emit_rssi_changed((Wifi *)get_wifi_object(),
410                 interface_name, VCONFKEY_WIFI_STRENGTH_MAX);
411
412         netconfig_start_timer_seconds(WIFI_INDICATOR_INTERVAL,
413                 __netconfig_wifi_update_statistics, g_strdup(interface_name),
414                 &netconfig_wifi_statistics_timer);
415
416         netconfig_battery_update_wifi_rssi(VCONFKEY_WIFI_STRENGTH_MAX);
417 }
418
419 void netconfig_wifi_indicator_stop(const char *interface_name)
420 {
421         INFO("Stop Wi-Fi indicator");
422
423         netconfig_stop_timer(&netconfig_wifi_statistics_timer);
424
425         __destroy_rssi_data(interface_name);
426 }