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