Check already powered during Wi-Fi enable/disable
[framework/connectivity/net-config.git] / src / wifi-indicator.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2012-2013 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 <string.h>
21 #include <unistd.h>
22 #include <sys/ioctl.h>
23 #include <netinet/in.h>
24 #include <netinet/ip.h>
25 #include <linux/wireless.h>
26 #include <vconf.h>
27 #include <vconf-keys.h>
28
29 #include "log.h"
30 #include "util.h"
31 #include "netdbus.h"
32 #include "network-statistics.h"
33 #include "netsupplicant.h"
34 #include "wifi-indicator.h"
35
36 #define VCONFKEY_WIFI_SNR_MIN   -89
37
38 #define NETCONFIG_WIFI_INDICATOR_INTERVAL       1
39
40 static guint64 netconfig_wifi_tx_bytes = 0;
41 static guint64 netconfig_wifi_rx_bytes = 0;
42
43 static guint netconfig_wifi_indicator_timer = 0;
44
45 #if defined NL80211
46 static int __netconfig_wifi_get_signal(const char *object_path)
47 {
48         DBusConnection *connection = NULL;
49         DBusMessage *message = NULL;
50         DBusMessageIter iter;
51         int rssi_dbm = 0;
52         int MessageType = 0;
53
54         if (object_path == NULL) {
55                 ERR("Error!!! path is NULL");
56                 goto error;
57         }
58
59         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
60         if (connection == NULL) {
61                 ERR("Error!!! Failed to get system DBus");
62                 goto error;
63         }
64
65         message = netconfig_supplicant_invoke_dbus_method(
66                         SUPPLICANT_SERVICE, connection, object_path,
67                         SUPPLICANT_INTERFACE ".Interface", "GetLinkSignal",
68                         NULL);
69
70         if (message == NULL) {
71                 ERR("Error!!! Failed to get service properties");
72                 goto error;
73         }
74
75         MessageType = dbus_message_get_type(message);
76
77         if (MessageType == DBUS_MESSAGE_TYPE_ERROR) {
78                 const char *err_msg = dbus_message_get_error_name(message);
79                 ERR("Error!!! Error message received [%s]", err_msg);
80                 goto error;
81         }
82
83         dbus_message_iter_init(message, &iter);
84
85         if ((MessageType = dbus_message_iter_get_arg_type(&iter)) == DBUS_TYPE_INT32)
86                 dbus_message_iter_get_basic(&iter, &rssi_dbm);
87         else
88                 goto error;
89
90         dbus_message_unref(message);
91         dbus_connection_unref(connection);
92
93         return rssi_dbm;
94
95 error:
96         if (message != NULL)
97                 dbus_message_unref(message);
98
99         if (connection != NULL)
100                 dbus_connection_unref(connection);
101
102         return VCONFKEY_WIFI_SNR_MIN;
103 }
104
105 static int __netconfig_wifi_get_rssi_from_supplicant(void)
106 {
107         int rssi_dbm =0;
108
109         char object_path[DBUS_PATH_MAX_BUFLEN] = { 0, };
110         char *path_ptr = &object_path[0];
111
112         if (netconfig_wifi_get_supplicant_interface(&path_ptr) != TRUE) {
113                 DBG("Fail to get wpa_supplicant DBus path");
114                 return VCONFKEY_WIFI_SNR_MIN;
115         }
116
117         rssi_dbm = __netconfig_wifi_get_signal((const char *)path_ptr);
118
119         return rssi_dbm;
120 }
121 #endif /* #if defined NL80211 */
122
123 #if !defined NL80211
124 static int __netconfig_wifi_get_rssi_from_system(void)
125 {
126         int rssi_dbm = 0;
127         char ifname[16] = { 0, };
128         char *ifname_ptr = &ifname[0];
129
130         int fd = -1;
131         struct iwreq wifi_req;
132         struct iw_statistics stats;
133         unsigned int iw_stats_len = sizeof(struct iw_statistics);
134
135         if (netconfig_wifi_get_ifname(&ifname_ptr) != TRUE) {
136                 DBG("Fail to get Wi-Fi ifname from wpa_supplicant: %s", ifname_ptr);
137                 return VCONFKEY_WIFI_SNR_MIN;
138         }
139
140         /* Set device name */
141         memset(wifi_req.ifr_name, 0, sizeof(wifi_req.ifr_name));
142         strncpy(wifi_req.ifr_name, ifname, sizeof(wifi_req.ifr_name) - 1);
143         wifi_req.ifr_name[sizeof(wifi_req.ifr_name) - 1] = '\0';
144
145         wifi_req.u.data.pointer = (caddr_t) &stats;
146         wifi_req.u.data.length = iw_stats_len;
147         wifi_req.u.data.flags = 1;      /* Clear updated flag */
148
149         if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
150                 DBG("Fail to open socket to get rssi");
151                 return VCONFKEY_WIFI_SNR_MIN;
152         }
153
154         memset(&stats, 0, iw_stats_len);
155
156         if (ioctl(fd, SIOCGIWSTATS, &wifi_req) < 0) {
157                 DBG("Fail to execute ioctl for SIOCGIWSTATS");
158                 close(fd);
159
160                 return VCONFKEY_WIFI_SNR_MIN;
161         }
162         close(fd);
163
164         rssi_dbm = stats.qual.level - 255; /** signed integer, so 255 */
165
166         return rssi_dbm;
167 }
168 #endif /* #if !defined NL80211 */
169
170 int netconfig_wifi_get_rssi(void)
171 {
172         int rssi_dbm = 0;
173
174         /* There are two ways to get Wi-Fi RSSI:
175          *  - WEXT interface, get DBus path of wpa_supplicant,
176          *  and get Wi-Fi interface name e.g. wlan0 from wpa_supplicant.
177          *  IOCTL with ifname will return RSSI dB.
178          *  - NL80211 interface, get DBus path of wpa_supplicant,
179          *  and get RSSI from wpa_supplicant directly.
180          *  However, in this case wpa_supplicant needs some modification
181          *  to get RSSI from DBus interface. */
182
183 #if defined NL80211
184         rssi_dbm = __netconfig_wifi_get_rssi_from_supplicant();
185 #else
186         rssi_dbm = __netconfig_wifi_get_rssi_from_system();
187 #endif
188
189         return rssi_dbm;
190 }
191
192 static void __netconfig_wifi_set_rssi_level(int rssi_dbm)
193 {
194         int snr_level = 0;
195         static int last_snr_level = 0;
196
197         /* Wi-Fi Signal Strength Display
198          *
199          * Excellent :  -63 ~
200          * Good:                -74 ~ -64
201          * Weak:                -82 ~ -75
202          * Very weak:           ~ -83
203          */
204         if (rssi_dbm >= -63)
205                 snr_level = 4;
206         else if (rssi_dbm >= -74)
207                 snr_level = 3;
208         else if (rssi_dbm >= -82)
209                 snr_level = 2;
210         else
211                 snr_level = 1;
212
213         if (snr_level != last_snr_level) {
214                 INFO("Wi-Fi RSSI: %d dB, %d level", rssi_dbm, snr_level);
215
216                 vconf_set_int(VCONFKEY_WIFI_STRENGTH, snr_level);
217
218                 last_snr_level = snr_level;
219         }
220 }
221
222 static gboolean __netconfig_wifi_indicator_monitor(gpointer data)
223 {
224         int rssi_dbm = 0;
225         int pm_state = VCONFKEY_PM_STATE_NORMAL;
226         guint64 tx = 0, rx = 0;
227
228         /* In case of LCD off, we don't need to update Wi-Fi indicator */
229         vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
230         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
231                 return TRUE;
232
233         rssi_dbm = netconfig_wifi_get_rssi();
234
235         if (netconfig_wifi_get_bytes_statistics(&tx, &rx) == TRUE) {
236                 if (netconfig_wifi_tx_bytes < tx) {
237                         if (netconfig_wifi_rx_bytes < rx)
238                                 vconf_set_int(VCONFKEY_WIFI_TRANSFER_STATE, VCONFKEY_WIFI_TRANSFER_STATE_TXRX);
239                         else
240                                 vconf_set_int(VCONFKEY_WIFI_TRANSFER_STATE, VCONFKEY_WIFI_TRANSFER_STATE_TX);
241                 } else {
242                         if (netconfig_wifi_rx_bytes < rx)
243                                 vconf_set_int(VCONFKEY_WIFI_TRANSFER_STATE, VCONFKEY_WIFI_TRANSFER_STATE_RX);
244                         else
245                                 vconf_set_int(VCONFKEY_WIFI_TRANSFER_STATE, VCONFKEY_WIFI_TRANSFER_STATE_NONE);
246                 }
247
248                 netconfig_wifi_tx_bytes = tx;
249                 netconfig_wifi_rx_bytes = rx;
250         }
251
252         __netconfig_wifi_set_rssi_level(rssi_dbm);
253
254         return TRUE;
255 }
256
257 void netconfig_wifi_indicator_start(void)
258 {
259         guint64 tx = 0, rx = 0;
260
261         INFO("Start Wi-Fi indicator");
262
263         vconf_set_int(VCONFKEY_WIFI_STRENGTH, VCONFKEY_WIFI_STRENGTH_MAX);
264
265         if (netconfig_wifi_get_bytes_statistics(&tx, &rx) == TRUE) {
266                 netconfig_wifi_tx_bytes = tx;
267                 netconfig_wifi_rx_bytes = rx;
268         } else {
269                 netconfig_wifi_tx_bytes = 0;
270                 netconfig_wifi_rx_bytes = 0;
271         }
272
273         netconfig_start_timer_seconds(
274                         NETCONFIG_WIFI_INDICATOR_INTERVAL,
275                         __netconfig_wifi_indicator_monitor,
276                         NULL,
277                         &netconfig_wifi_indicator_timer);
278 }
279
280 void netconfig_wifi_indicator_stop(void)
281 {
282         INFO("Stop Wi-Fi indicator");
283
284         vconf_set_int(VCONFKEY_WIFI_STRENGTH, VCONFKEY_WIFI_STRENGTH_MAX);
285
286         netconfig_stop_timer(&netconfig_wifi_indicator_timer);
287 }