[Fix] NULL_AFTER_DEREF
[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 static int netconfig_wifi_rssi = VCONFKEY_WIFI_SNR_MIN;
60 static guint netconfig_wifi_indicator_timer = 0;
61
62 int netconfig_wifi_get_rssi(void)
63 {
64         return netconfig_wifi_rssi;
65 }
66
67 static int __netconfig_wifi_update_and_get_rssi(void)
68 {
69         const char *if_path = NULL;
70         GVariant *message = NULL;
71         GVariant *value = NULL;
72         gchar *key;
73         GVariantIter *iter;
74         GVariant *variant;
75         gint32 key_value;
76         int rssi_dbm = VCONFKEY_WIFI_SNR_MIN;
77
78         if_path = netconfig_wifi_get_supplicant_interface();
79         if (if_path == NULL) {
80                 ERR("Fail to get wpa_supplicant DBus path");
81                 return 0;
82         }
83
84         message = netconfig_invoke_dbus_method(SUPPLICANT_SERVICE, if_path,
85                                 SUPPLICANT_INTERFACE ".Interface", "SignalPoll", NULL);
86         if (message == NULL) {
87                 ERR("Fail to get SignalPoll from wpa_supplicant");
88                 return 0;
89         }
90
91         g_variant_get(message, "(v)", &value);
92
93         g_variant_get(value, "a{sv}", &iter);
94         if (iter == NULL) {
95                 ERR("Fail to get list from SignalPoll");
96                 return 0;
97         }
98
99         while (g_variant_iter_loop(iter, "{sv}", &key, &variant)) {
100                 key_value = g_variant_get_int32(variant);
101
102                 if (g_strcmp0(key, "rssi") == 0) {
103                         rssi_dbm = (int)key_value;
104                         DBG("Currently signal dbm value [%d]", rssi_dbm);
105                         g_variant_unref(variant);
106                         g_free(key);
107                         break;
108                 }
109         }
110
111         g_variant_iter_free(iter);
112
113         if (value)
114                 g_variant_unref(value);
115
116         netconfig_wifi_rssi = rssi_dbm;
117
118         return rssi_dbm;
119 }
120
121 int netconfig_wifi_rssi_level(const int rssi_dbm)
122 {
123         int snr_level = 0;
124
125         /* Wi-Fi Signal Strength Display
126          *
127          * Excellent :  -63 ~
128          * Good:                -74 ~ -64
129          * Weak:                -82 ~ -75
130          * Very weak:           ~ -83
131          */
132         if (rssi_dbm >= -63)
133                 snr_level = 4;
134         else if (rssi_dbm >= -74)
135                 snr_level = 3;
136         else if (rssi_dbm >= -82)
137                 snr_level = 2;
138         else
139                 snr_level = 1;
140
141         return snr_level;
142 }
143
144 static void __netconfig_wifi_set_rssi_level(const int snr_level)
145 {
146         static int last_snr_level = 0;
147
148         if (snr_level != last_snr_level) {
149                 netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, snr_level);
150                 last_snr_level = snr_level;
151         }
152 }
153
154 static void __netconfig_wifi_data_activity_booster(int level)
155 {
156         gboolean reply = FALSE;
157         GVariant *params = NULL;
158         int level1 = 1;
159         int level2 = 2;
160         int level3 = 3;
161
162         int lock = 2000;
163         int unlock = 0;
164
165         static int old_level = 0;
166
167         if (level < 0)
168                 return;
169
170         if (level > 0) {
171                 /* enable booster */
172                 switch (level) {
173                 case 1:
174                         params = g_variant_new("(ii)", level1, lock);
175                         break;
176                 case 2:
177                         params = g_variant_new("(ii)", level2, lock);
178                         break;
179                 case 3:
180                         params = g_variant_new("(ii)", level3, lock);
181                         break;
182                 default:
183                         ERR("Invalid level");
184                         return;
185                 }
186
187                 reply = netconfig_invoke_dbus_method_nonblock(
188                                 "org.tizen.system.deviced",
189                                 "/Org/Tizen/System/DeviceD/PmQos",
190                                 "org.tizen.system.deviced.PmQos",
191                                 "WifiThroughput",
192                                 params,
193                                 NULL);
194                 if (reply != TRUE)
195                         return;
196         }
197
198         /* disable previous booster */
199         if (old_level == 0 || old_level == level)
200                 return;
201
202         switch (old_level) {
203         case 1:
204                 params = g_variant_new("(ii)", level1, unlock);
205                 break;
206         case 2:
207                 params = g_variant_new("(ii)", level2, unlock);
208                 break;
209         case 3:
210                 params = g_variant_new("(ii)", level3, unlock);
211                 break;
212         default:
213                 ERR("Invalid level");
214                 return;
215         }
216
217         reply = netconfig_invoke_dbus_method_nonblock(
218                         "org.tizen.system.deviced",
219                         "/Org/Tizen/System/DeviceD/PmQos",
220                         "org.tizen.system.deviced.PmQos",
221                         "WifiThroughput",
222                         params,
223                         NULL);
224         if (reply != TRUE)
225                 return;
226
227         old_level = level;
228 }
229
230 static void __netconfig_wifi_update_indicator(void)
231 {
232         static int last_transfer_state = 0;
233         static guint64 netconfig_wifi_tx_bytes = 0;
234         static guint64 netconfig_wifi_rx_bytes = 0;
235         static int booster_tic = 0;
236         static int old_level = 0;
237         int booster_level = 0;
238         guint64 tx, rx, tx_diff, rx_diff;
239         int transfer_state;
240
241         if (netconfig_wifi_get_bytes_statistics(&tx, &rx) == TRUE) {
242                 tx_diff = tx - netconfig_wifi_tx_bytes;
243                 rx_diff = rx - netconfig_wifi_rx_bytes;
244
245                 if (tx_diff > 0) {
246                         if (rx_diff > 0)
247                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TXRX;
248                         else
249                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TX;
250                 } else {
251                         if (rx_diff > 0)
252                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_RX;
253                         else
254                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_NONE;
255                 }
256
257                 if (transfer_state != last_transfer_state) {
258                         netconfig_set_vconf_int(VCONFKEY_WIFI_TRANSFER_STATE, transfer_state);
259                         last_transfer_state = transfer_state;
260                 }
261
262                 /* NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER */
263                 if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1 ||
264                         rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1)
265                         booster_level = 1;
266                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2 ||
267                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2)
268                         booster_level = 2;
269                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3 ||
270                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3)
271                         booster_level = 3;
272
273                 if (old_level == booster_level) {
274                         if (--booster_tic <= 0) {
275                                 __netconfig_wifi_data_activity_booster(booster_level);
276
277                                 booster_tic = 2;
278                         }
279                 } else {
280                         __netconfig_wifi_data_activity_booster(booster_level);
281
282                         if (booster_level > 0)
283                                 booster_tic = 2;
284                         else
285                                 booster_tic = 0;
286                 }
287
288                 old_level = booster_level;
289
290                 netconfig_wifi_tx_bytes = tx;
291                 netconfig_wifi_rx_bytes = rx;
292         }
293 }
294
295 static gboolean __wifi_indicator_monitor(gpointer data)
296 {
297         int rssi_dbm = 0;
298         int snr_level = 0;
299         int pm_state = VCONFKEY_PM_STATE_NORMAL;
300
301         if (wifi_state_get_service_state() != NETCONFIG_WIFI_CONNECTED)
302                 return FALSE;
303
304         /* In case of LCD off, we don't need to update Wi-Fi indicator */
305         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
306         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
307                 return TRUE;
308
309         rssi_dbm = __netconfig_wifi_update_and_get_rssi();
310         /* INFO("%d dbm", rssi_dbm); */
311         snr_level = netconfig_wifi_rssi_level(rssi_dbm);
312         __netconfig_wifi_set_rssi_level(snr_level);
313
314         __netconfig_wifi_update_indicator();
315
316         return TRUE;
317 }
318
319 void netconfig_wifi_indicator_start(void)
320 {
321         INFO("Start Wi-Fi indicator");
322
323         netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, VCONFKEY_WIFI_STRENGTH_MAX);
324         netconfig_start_timer_seconds(WIFI_INDICATOR_INTERVAL, __wifi_indicator_monitor, NULL, &netconfig_wifi_indicator_timer);
325 }
326
327 void netconfig_wifi_indicator_stop(void)
328 {
329         INFO("Stop Wi-Fi indicator");
330
331         netconfig_stop_timer(&netconfig_wifi_indicator_timer);
332
333         netconfig_wifi_rssi = VCONFKEY_WIFI_SNR_MIN;
334 }