Merge "Fix bug in Ip conflict set/get enabled API's" into tizen
[platform/core/connectivity/net-config.git] / src / wifi-firmware.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 <errno.h>
21 #include <vconf.h>
22 #include <vconf-keys.h>
23 #include <stdio.h>
24 #include <fcntl.h>
25
26 #include "log.h"
27 #include "util.h"
28 #include "netdbus.h"
29 #include "emulator.h"
30 #include "neterror.h"
31 #include "netsupplicant.h"
32 #include "wifi-firmware.h"
33 #include "network-statistics.h"
34
35 #define WLAN_DRIVER_SCRIPT                      "/usr/bin/wlan.sh"
36 #define WLAN_IFACE_NAME                         "wlan0"
37
38 #define WLAN_P2P_IFACE_NAME_TV                  "p2p0"
39 #define WLAN_P2P_IFACE_NAME_COMMON                      "wlan0"
40 #define WLAN_P2P_IFACE_NAME ((TIZEN_TV) ? (WLAN_P2P_IFACE_NAME_TV) : (WLAN_P2P_IFACE_NAME_COMMON))
41 #define QUAD_CPUS_COUNT                 4
42 #define TEMP_BUFFER_LEN                 100
43 #define WIFI_MAC_ADD_PATH               "/sys/class/net/wlan0/address"
44
45 static int __netconfig_sta_firmware_start(void)
46 {
47         int rv = 0;
48         const char *path = WLAN_DRIVER_SCRIPT;
49         char *const args[] = { "/usr/bin/wlan.sh", "start", NULL };
50         char *const envs[] = { NULL };
51
52         rv = netconfig_execute_file(path, args, envs);
53         if (rv < 0)
54                 return -EIO;
55
56         rv = netconfig_interface_up(WLAN_IFACE_NAME);
57         if (rv != TRUE)
58                 return -EIO;
59
60         DBG("Successfully loaded wireless device driver");
61         return 0;
62 }
63
64 static int __netconfig_sta_firmware_stop(void)
65 {
66         int rv = 0;
67         const char *path = WLAN_DRIVER_SCRIPT;
68         char *const args[] = { "/usr/bin/wlan.sh", "stop", NULL };
69         char *const envs[] = { NULL };
70
71         /* Update statistics before driver remove */
72         netconfig_wifi_statistics_update_powered_off();
73
74         rv = netconfig_interface_down(WLAN_IFACE_NAME);
75         if (rv != TRUE)
76                 return -EIO;
77
78         rv = netconfig_execute_file(path, args, envs);
79         if (rv < 0)
80                 return -EIO;
81
82         DBG("Successfully removed wireless device driver");
83         return 0;
84 }
85
86 static int __netconfig_p2p_firmware_start(void)
87 {
88         if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_WIFI_DIRECT))
89                 return -ENODEV;
90
91         int rv = 0;
92         const char *path = WLAN_DRIVER_SCRIPT;
93         char *const args[] = { "/usr/bin/wlan.sh", "p2p", NULL };
94         char *const envs[] = { NULL };
95
96         rv = netconfig_execute_file(path, args, envs);
97         if (rv < 0)
98                 return -EIO;
99
100 #if defined TIZEN_WLAN_USE_P2P_INTERFACE
101         rv = netconfig_interface_up(WLAN_P2P_IFACE_NAME);
102         if (rv != TRUE)
103                 return -EIO;
104 #endif
105
106         DBG("Successfully loaded p2p device driver");
107         return 0;
108 }
109
110 static int __netconfig_p2p_firmware_stop(void)
111 {
112         if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_WIFI_DIRECT))
113                 return -ENODEV;
114
115         int rv = 0;
116         const char *path = WLAN_DRIVER_SCRIPT;
117         char *const args[] = { "/usr/bin/wlan.sh", "stop", NULL };
118         char *const envs[] = { NULL };
119
120         rv = netconfig_interface_down(WLAN_IFACE_NAME);
121         if (rv != TRUE)
122                 return -EIO;
123
124         rv = netconfig_execute_file(path, args, envs);
125         if (rv < 0)
126                 return -EIO;
127
128         DBG("Successfully removed p2p device driver");
129         return 0;
130 }
131
132 static int __netconfig_softap_firmware_start(void)
133 {
134         if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_TETHERING))
135                 return -ENODEV;
136
137         int rv = 0;
138         const char *path = WLAN_DRIVER_SCRIPT;
139         char *const args[] = { "/usr/bin/wlan.sh", "softap", NULL };
140         char *const envs[] = { NULL };
141
142         rv = netconfig_execute_file(path, args, envs);
143         if (rv < 0)
144                 return -EIO;
145
146         if (netconfig_interface_up(WLAN_IFACE_NAME) == FALSE)
147                 return -EIO;
148
149         DBG("Successfully loaded softap device driver");
150         return 0;
151 }
152
153 static int __netconfig_softap_firmware_stop(void)
154 {
155         if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_TETHERING))
156                 return -ENODEV;
157
158         int rv = 0;
159         const char *path = WLAN_DRIVER_SCRIPT;
160         char *const args[] = { "/usr/bin/wlan.sh", "stop", NULL };
161         char *const envs[] = { NULL };
162
163         rv = netconfig_interface_down(WLAN_IFACE_NAME);
164         if (rv != TRUE)
165                 return -EIO;
166
167         rv = netconfig_execute_file(path, args, envs);
168         if (rv < 0)
169                 return -EIO;
170
171         DBG("Successfully removed softap device driver");
172         return 0;
173 }
174
175 static int __netconfig_wifi_firmware_start(enum netconfig_wifi_firmware type)
176 {
177         if (emulator_is_emulated() == TRUE)
178                 return -EIO;
179
180         switch (type) {
181         case NETCONFIG_WIFI_STA:
182                 return __netconfig_sta_firmware_start();
183         case NETCONFIG_WIFI_P2P:
184                 return __netconfig_p2p_firmware_start();
185         case NETCONFIG_WIFI_SOFTAP:
186                 return __netconfig_softap_firmware_start();
187         default:
188                 break;
189         }
190
191         return -ENXIO;
192 }
193
194 static int __netconfig_wifi_firmware_stop(enum netconfig_wifi_firmware type)
195 {
196         if (emulator_is_emulated() == TRUE)
197                 return -EIO;
198
199         switch (type) {
200         case NETCONFIG_WIFI_STA:
201                 return __netconfig_sta_firmware_stop();
202         case NETCONFIG_WIFI_P2P:
203                 return __netconfig_p2p_firmware_stop();
204         case NETCONFIG_WIFI_SOFTAP:
205                 return __netconfig_softap_firmware_stop();
206         default:
207                 break;
208         }
209
210         return -ENXIO;
211 }
212
213 static int __netconfig_set_rps_cpus(void)
214 {
215         int fd, i;
216         ssize_t count;
217         char t_buf[TEMP_BUFFER_LEN];
218         char r_buf[TEMP_BUFFER_LEN];
219
220         if (access(WIFI_MAC_ADD_PATH, F_OK) != 0) {
221                 DBG("WiFi driver is not loaded... ");
222                 return -1;
223         } else {
224                 DBG("WiFi driver loaded... ");
225         }
226
227         for (i = 0; i < QUAD_CPUS_COUNT; i++) {
228                 snprintf(t_buf, TEMP_BUFFER_LEN, "/sys/class/net/wlan0/queues/rx-%d/rps_cpus", i);
229                 DBG("Command : [%s]", t_buf);
230                 fd = open(t_buf, O_RDWR | O_CLOEXEC);
231
232                 if (fd < 0) {
233                         DBG("failed to open rps file");
234                         return -1;
235                 } else {
236                         count = read(fd, r_buf, 1);
237
238                         if (count < 0) {
239                                 DBG("read failed");
240                                 close(fd);
241                                 return -1;
242                         } else {
243                                 DBG("read size = %d", count);
244                         }
245
246                         if (r_buf[0] == 'e') {
247                                 close(fd);
248                                 continue;
249                         } else {
250                                 DBG("e is already written");
251                         }
252
253                         if (lseek(fd, 0, SEEK_SET) < 0) {
254                                 DBG("lseek failed");
255                                 close(fd);
256                                 return -1;
257                         }
258
259                         count = write(fd, "e", 1);
260
261                         if (count < 0) {
262                                 DBG("write failed");
263                                 close(fd);
264                                 return -1;
265                         } else {
266                                 DBG("write size = %d", count);
267                         }
268
269                         close(fd);
270                 }
271         }
272
273         return 0;
274 }
275
276 int netconfig_wifi_firmware(enum netconfig_wifi_firmware type, gboolean enable)
277 {
278         int err;
279         static enum netconfig_wifi_firmware current_driver = NETCONFIG_WIFI_OFF;
280         enum netconfig_wifi_firmware alias = type;
281
282         DBG("Wi-Fi current firmware %d (type: %d %s)", current_driver, type,
283                                                         enable == TRUE ? "enable" : "disable");
284
285         if (enable == FALSE) {
286                 if (current_driver == NETCONFIG_WIFI_OFF) {
287                         return -EALREADY;
288                 } else if (current_driver == alias) {
289
290                         err = __netconfig_wifi_firmware_stop(type);
291                         if (err < 0 && err != -EALREADY)
292                                 return err;
293
294                         current_driver = NETCONFIG_WIFI_OFF;
295
296                         return err;
297                 }
298
299                 return -EIO;
300         }
301
302         if (current_driver > NETCONFIG_WIFI_OFF) {
303                 if (current_driver == alias)
304                         return -EALREADY;
305
306                 return -EIO;
307         }
308
309         err = __netconfig_wifi_firmware_start(type);
310         if (err < 0)
311                 DBG("Failed to execute script file");
312         else
313                 current_driver = alias;
314
315         if (__netconfig_set_rps_cpus() < 0)
316                 DBG("Failed to set rps_cpus");
317
318         return err;
319 }
320
321 gboolean handle_start(WifiFirmware *firmware, GDBusMethodInvocation *context, const gchar *device)
322 {
323         int err;
324
325         g_return_val_if_fail(firmware != NULL, TRUE);
326
327         DBG("Wi-Fi firmware start %s", device != NULL ? device : "null");
328
329         if (g_strcmp0("p2p", device) == 0)
330                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_P2P, TRUE);
331         else if (g_strcmp0("softap", device) == 0)
332                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_SOFTAP, TRUE);
333         else
334                 err = -EINVAL;
335
336         if (err < 0) {
337                 if (err == -EALREADY)
338                         netconfig_error_already_exists(context);
339                 else if (g_strcmp0("softap", device) == 0 && err == -EIO && netconfig_is_wifi_direct_on() == FALSE) {
340                         if (netconfig_wifi_firmware(NETCONFIG_WIFI_P2P, FALSE) == 0 && netconfig_wifi_firmware(NETCONFIG_WIFI_SOFTAP, TRUE) == 0) {
341                                 wifi_firmware_complete_start(firmware, context);
342                                 return TRUE;
343                         } else
344                                 netconfig_error_wifi_driver_failed(context);
345                 } else
346                         netconfig_error_wifi_driver_failed(context);
347
348                 return TRUE;
349         }
350
351         wifi_firmware_complete_start(firmware, context);
352         return TRUE;
353 }
354
355 gboolean handle_stop(WifiFirmware *firmware, GDBusMethodInvocation *context, const gchar *device)
356 {
357         int err;
358
359         g_return_val_if_fail(firmware != NULL, TRUE);
360
361         DBG("Wi-Fi firmware stop %s", device != NULL ? device : "null");
362
363         if (g_strcmp0("p2p", device) == 0)
364                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_P2P, FALSE);
365         else if (g_strcmp0("softap", device) == 0)
366                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_SOFTAP, FALSE);
367         else
368                 err = -EINVAL;
369
370         if (err < 0) {
371                 if (err == -EALREADY)
372                         netconfig_error_already_exists(context);
373                 else
374                         netconfig_error_wifi_driver_failed(context);
375
376                 return TRUE;
377         }
378
379         wifi_firmware_complete_stop(firmware, context);
380         return TRUE;
381 }