Add multi interfaces function
[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 1
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         int last_snr_level;
62 } rssi_data_s;
63
64 static int netconfig_wifi_rssi = VCONFKEY_WIFI_SNR_MIN;
65 static guint32 netconfig_wifi_freq = 0;
66 static guint netconfig_wifi_indicator_timer = 0;
67 static GSList *g_rssi_list = NULL;
68
69 static rssi_data_s *__create_rssi_data(const char *interface_name)
70 {
71         rssi_data_s *rssi_data = g_try_malloc0(sizeof(rssi_data_s));
72         if (!rssi_data) {
73                 ERR("Memory allocation failed");
74                 return NULL;
75         }
76
77         rssi_data->interface_name = g_strdup(interface_name);
78
79         g_rssi_list = g_slist_append(g_rssi_list, rssi_data);
80
81         return rssi_data;
82 }
83
84 static rssi_data_s *__get_rssi_data(const char *interface_name)
85 {
86         GSList *list;
87         rssi_data_s *rssi_data = NULL;
88
89         for (list = g_rssi_list; list; list = list->next) {
90                 rssi_data = list->data;
91                 if (g_strcmp0(rssi_data->interface_name, interface_name) == 0)
92                         return rssi_data;
93         }
94
95         return rssi_data;
96 }
97
98 static void __destroy_rssi_data(const char *interface_name)
99 {
100         rssi_data_s *rssi_data = __get_rssi_data(interface_name);
101
102         if (!rssi_data)
103                 return;
104
105         g_rssi_list = g_slist_remove(g_rssi_list, rssi_data);
106         g_free(rssi_data->interface_name);
107         g_free(rssi_data);
108 }
109
110 int netconfig_wifi_get_rssi(void)
111 {
112         return netconfig_wifi_rssi;
113 }
114
115 unsigned int netconfig_wifi_get_freq(void)
116 {
117         return netconfig_wifi_freq;
118 }
119
120 static int __netconfig_wifi_update_and_get_rssi(const char *interface_name)
121 {
122         char *if_path = NULL;
123         GVariant *message = NULL;
124         GVariant *value = NULL;
125         gchar *key;
126         GVariantIter *iter;
127         GVariant *variant;
128         gint32 key_value;
129         int rssi_dbm = VCONFKEY_WIFI_SNR_MIN;
130
131         if_path = netconfig_wifi_get_supplicant_interface_path(interface_name);
132         if (if_path == NULL) {
133                 ERR("Fail to get wpa_supplicant DBus path");
134                 return 0;
135         }
136
137         message = netconfig_invoke_dbus_method(SUPPLICANT_SERVICE, if_path,
138                         SUPPLICANT_INTERFACE ".Interface", "SignalPoll", NULL);
139         if (message == NULL) {
140                 ERR("Fail to get SignalPoll from wpa_supplicant");
141                 g_free(if_path);
142                 return 0;
143         }
144
145         g_variant_get(message, "(v)", &value);
146
147         g_variant_get(value, "a{sv}", &iter);
148         while (g_variant_iter_loop(iter, "{sv}", &key, &variant)) {
149
150                 if (g_strcmp0(key, "rssi") == 0) {
151                         key_value = g_variant_get_int32(variant);
152                         rssi_dbm = (int)key_value;
153                         /* DBG("Currently signal dbm value [%d]", rssi_dbm); */
154                 } else if (g_strcmp0(key, "frequency") == 0) {
155                         netconfig_wifi_freq = g_variant_get_uint32(variant);
156                         /* DBG("Currently frequency [%u]", netconfig_wifi_freq); */
157                 }
158         }
159
160         g_variant_iter_free(iter);
161
162         g_variant_unref(message);
163
164         g_free(if_path);
165
166         netconfig_wifi_rssi = rssi_dbm;
167
168         return rssi_dbm;
169 }
170
171 static int __netconfig_wifi_convert_dbm_to_level_24(int rssi_dbm)
172 {
173         int rssi_level = 0;
174
175         /* Wi-Fi Signal Strength Display (for 2.4G (dB))
176          *
177          * Excellent :     ~ -63
178          * Good      : -64 ~ -74
179          * Weak      : -75 ~ -82
180          * Very weak : -83 ~ -88
181          * No signal : -89 ~
182          */
183
184         if (rssi_dbm >= -63)
185                 rssi_level = 4;
186         else if (rssi_dbm >= -74)
187                 rssi_level = 3;
188         else if (rssi_dbm >= -82)
189                 rssi_level = 2;
190         else if (rssi_dbm >= -88)
191                 rssi_level = 1;
192         else
193                 rssi_level = 0;
194
195         return rssi_level;
196 }
197
198 static int __netconfig_wifi_convert_dbm_to_level_50(int rssi_dbm)
199 {
200         int rssi_level = 0;
201
202         /* Wi-Fi Signal Strength Display (for 5G (dB))
203          *
204          * Excellent :     ~ -67
205          * Good      : -68 ~ -76
206          * Weak      : -77 ~ -82
207          * Very weak : -83 ~ -88
208          * No signal : -89 ~
209          */
210
211         if (rssi_dbm >= -67)
212                 rssi_level = 4;
213         else if (rssi_dbm >= -76)
214                 rssi_level = 3;
215         else if (rssi_dbm >= -82)
216                 rssi_level = 2;
217         else if (rssi_dbm >= -88)
218                 rssi_level = 1;
219         else
220                 rssi_level = 0;
221
222         return rssi_level;
223 }
224
225 int netconfig_wifi_rssi_level(const int rssi_dbm)
226 {
227         int snr_level = 0;
228         int freq = 0;
229         int ret = 0;
230
231         ret = netconfig_vconf_get_int("memory/private/wifi/frequency", &freq);
232
233         if (!ret && freq > 4900)
234                 snr_level = __netconfig_wifi_convert_dbm_to_level_50(rssi_dbm);
235         else
236                 snr_level = __netconfig_wifi_convert_dbm_to_level_24(rssi_dbm);
237
238         return snr_level;
239 }
240
241 static void __netconfig_wifi_set_rssi_level(const char *interface_name,
242                 const int snr_level)
243 {
244         rssi_data_s *rssi_data = NULL;
245         const char *default_ifname = NULL;
246
247         rssi_data = __get_rssi_data(interface_name);
248         if (rssi_data == NULL)
249                 return;
250
251         if (snr_level != rssi_data->last_snr_level) {
252                 wifi_emit_rssi_changed((Wifi *)get_wifi_object(), interface_name, snr_level);
253
254                 default_ifname = netconfig_get_default_ifname();
255                 if (g_strcmp0(default_ifname, interface_name) == 0)
256                         netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, snr_level);
257
258                 netconfig_battery_update_wifi_rssi(snr_level);
259
260                 rssi_data->last_snr_level = snr_level;
261         }
262 }
263
264 static void __netconfig_wifi_data_activity_booster(int level)
265 {
266         gboolean reply = FALSE;
267         GVariant *params = NULL;
268         int level1 = 1;
269         int level2 = 2;
270         int level3 = 3;
271
272         int lock = 2000;
273         int unlock = 0;
274
275         static int old_level = 0;
276
277         if (level < 0)
278                 return;
279
280         if (level > 0) {
281                 /* enable booster */
282                 switch (level) {
283                 case 1:
284                         params = g_variant_new("(ii)", level1, lock);
285                         break;
286                 case 2:
287                         params = g_variant_new("(ii)", level2, lock);
288                         break;
289                 case 3:
290                         params = g_variant_new("(ii)", level3, lock);
291                         break;
292                 default:
293                         ERR("Invalid level");
294                         return;
295                 }
296
297                 reply = netconfig_invoke_dbus_method_nonblock(
298                                 "org.tizen.system.deviced",
299                                 "/Org/Tizen/System/DeviceD/PmQos",
300                                 "org.tizen.system.deviced.PmQos",
301                                 "WifiThroughput",
302                                 params,
303                                 NULL,
304                                 NULL);
305                 if (reply != TRUE)
306                         return;
307         }
308
309         /* disable previous booster */
310         if (old_level == 0 || old_level == level)
311                 return;
312
313         switch (old_level) {
314         case 1:
315                 params = g_variant_new("(ii)", level1, unlock);
316                 break;
317         case 2:
318                 params = g_variant_new("(ii)", level2, unlock);
319                 break;
320         case 3:
321                 params = g_variant_new("(ii)", level3, unlock);
322                 break;
323         default:
324                 ERR("Invalid level");
325                 return;
326         }
327
328         reply = netconfig_invoke_dbus_method_nonblock(
329                         "org.tizen.system.deviced",
330                         "/Org/Tizen/System/DeviceD/PmQos",
331                         "org.tizen.system.deviced.PmQos",
332                         "WifiThroughput",
333                         params,
334                         NULL,
335                         NULL);
336         if (reply != TRUE)
337                 return;
338
339         old_level = level;
340 }
341
342 static void __netconfig_wifi_update_indicator(void)
343 {
344         static int last_transfer_state = 0;
345         static guint64 netconfig_wifi_tx_bytes = 0;
346         static guint64 netconfig_wifi_rx_bytes = 0;
347         static int booster_tic = 0;
348         static int old_level = 0;
349         int booster_level = 0;
350         guint64 tx, rx, tx_diff, rx_diff;
351         int transfer_state;
352
353         if (netconfig_wifi_get_bytes_statistics(&tx, &rx) == TRUE) {
354                 tx_diff = tx - netconfig_wifi_tx_bytes;
355                 rx_diff = rx - netconfig_wifi_rx_bytes;
356
357                 if (tx_diff > 0) {
358                         if (rx_diff > 0)
359                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TXRX;
360                         else
361                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TX;
362                 } else {
363                         if (rx_diff > 0)
364                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_RX;
365                         else
366                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_NONE;
367                 }
368
369                 if (transfer_state != last_transfer_state) {
370                         netconfig_set_vconf_int(VCONFKEY_WIFI_TRANSFER_STATE, transfer_state);
371                         last_transfer_state = transfer_state;
372                 }
373
374                 /* NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER */
375                 if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1 ||
376                         rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1)
377                         booster_level = 1;
378                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2 ||
379                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2)
380                         booster_level = 2;
381                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3 ||
382                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3)
383                         booster_level = 3;
384
385                 if (old_level == booster_level) {
386                         if (--booster_tic <= 0) {
387                                 __netconfig_wifi_data_activity_booster(booster_level);
388
389                                 booster_tic = 2;
390                         }
391                 } else {
392                         __netconfig_wifi_data_activity_booster(booster_level);
393
394                         if (booster_level > 0)
395                                 booster_tic = 2;
396                         else
397                                 booster_tic = 0;
398                 }
399
400                 old_level = booster_level;
401
402                 netconfig_wifi_tx_bytes = tx;
403                 netconfig_wifi_rx_bytes = rx;
404         }
405 }
406
407 static gboolean __wifi_indicator_monitor(gpointer data)
408 {
409         int rssi_dbm = 0;
410         int snr_level = 0;
411         int pm_state = VCONFKEY_PM_STATE_NORMAL;
412         char *interface_name = data;
413
414         if (wifi_state_get_service_state(interface_name) != NETCONFIG_WIFI_CONNECTED) {
415                 g_free(interface_name);
416                 return FALSE;
417         }
418
419         /* In case of LCD off, we don't need to update Wi-Fi indicator */
420         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
421         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
422                 return TRUE;
423
424         rssi_dbm = __netconfig_wifi_update_and_get_rssi(interface_name);
425         snr_level = netconfig_wifi_rssi_level(rssi_dbm);
426         __netconfig_wifi_set_rssi_level(interface_name, snr_level);
427
428         __netconfig_wifi_update_indicator();
429
430         return TRUE;
431 }
432
433 void netconfig_wifi_indicator_start(const char *interface_name)
434 {
435         const char *default_ifname = NULL;
436
437         INFO("Start Wi-Fi indicator");
438
439         __create_rssi_data(interface_name);
440
441         wifi_emit_rssi_changed((Wifi *)get_wifi_object(),
442                         interface_name, VCONFKEY_WIFI_STRENGTH_MAX);
443
444         default_ifname = netconfig_get_default_ifname();
445         if (g_strcmp0(default_ifname, interface_name) == 0)
446                 netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, VCONFKEY_WIFI_STRENGTH_MAX);
447
448         netconfig_start_timer_seconds(WIFI_INDICATOR_INTERVAL,
449                 __wifi_indicator_monitor, g_strdup(interface_name),
450                 &netconfig_wifi_indicator_timer);
451
452         netconfig_battery_update_wifi_rssi(VCONFKEY_WIFI_STRENGTH_MAX);
453 }
454
455 void netconfig_wifi_indicator_stop(const char *interface_name)
456 {
457         INFO("Stop Wi-Fi indicator");
458
459         netconfig_stop_timer(&netconfig_wifi_indicator_timer);
460
461         netconfig_wifi_rssi = VCONFKEY_WIFI_SNR_MIN;
462         netconfig_wifi_freq = 0;
463
464         __destroy_rssi_data(interface_name);
465 }