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