Fix some svaces
[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 typedef struct {
42         char *interface_name;
43         enum netconfig_wifi_firmware type;
44 } wifi_driver_s;
45
46 static GSList *wifi_driver_list;
47
48 static void __netconfig_wifi_driver_free(gpointer data)
49 {
50         wifi_driver_s *driver = (wifi_driver_s *) data;
51
52         DBG("Remove wifi driver [%d:%s]", driver->type, driver->interface_name);
53
54         g_free(driver->interface_name);
55         g_free(driver);
56 }
57
58 static gint __netconfig_cmp_wifi_driver(gconstpointer a, gconstpointer b)
59 {
60         wifi_driver_s *drv_a = (wifi_driver_s *)a;
61         wifi_driver_s *drv_b = (wifi_driver_s *)b;
62
63         if (g_strcmp0(drv_a->interface_name, drv_b->interface_name))
64                 return -1;
65
66         return 0;
67 }
68
69 static GSList * __netconfig_is_wifi_driver_in_list(
70                 enum netconfig_wifi_firmware type, const char *interface_name)
71 {
72         wifi_driver_s driver = { .type = type, .interface_name = (char *)interface_name };
73         GSList *found = g_slist_find_custom(wifi_driver_list, &driver,
74                         __netconfig_cmp_wifi_driver);
75
76         return found;
77 }
78
79 static gboolean __netconfig_add_wifi_driver_to_list(
80                 enum netconfig_wifi_firmware type, const char *interface_name)
81 {
82         GSList *found;
83         wifi_driver_s *driver;
84
85         found = __netconfig_is_wifi_driver_in_list(type, interface_name);
86         if (found)
87                 return FALSE;
88
89         driver = g_try_new0(wifi_driver_s, 1);
90         if (!driver) {
91                 ERR("g_try_new0 failed!!!");
92                 return FALSE;
93         }
94
95         driver->interface_name = g_strdup(interface_name);
96         if (!driver->interface_name) {
97                 ERR("g_strdup failed!!!");
98                 g_free(driver);
99                 return FALSE;
100         }
101
102         driver->type = type;
103
104         wifi_driver_list = g_slist_prepend(wifi_driver_list, driver);
105         return TRUE;
106 }
107
108 static gboolean __netconfig_remove_wifi_driver_from_list(
109                 enum netconfig_wifi_firmware type, const char *interface_name)
110 {
111         GSList *found;
112
113         found = __netconfig_is_wifi_driver_in_list(type, interface_name);
114         if (!found)
115                 return FALSE;
116
117         __netconfig_wifi_driver_free(found->data);
118         wifi_driver_list = g_slist_delete_link(wifi_driver_list, found);
119
120         return TRUE;
121 }
122
123 static int __netconfig_sta_firmware_start(const char *interface_name)
124 {
125         int rv = 0;
126         const char *path = WLAN_DRIVER_SCRIPT;
127         char *const args[] = { "/usr/bin/wlan.sh", "start", (char *)interface_name, NULL };
128         char *const envs[] = { NULL };
129
130         rv = netconfig_execute_file(path, args, envs);
131         if (rv < 0)
132                 return -EIO;
133
134         rv = netconfig_interface_up(interface_name);
135         if (rv != TRUE)
136                 return -EIO;
137
138         DBG("Successfully loaded wireless device driver");
139         return 0;
140 }
141
142 static int __netconfig_sta_firmware_stop(const char *interface_name)
143 {
144         int rv = 0;
145         const char *path = WLAN_DRIVER_SCRIPT;
146         char *const args[] = { "/usr/bin/wlan.sh", "stop", (char *)interface_name, NULL };
147         char *const envs[] = { NULL };
148
149         rv = netconfig_interface_down(interface_name);
150         if (rv != TRUE)
151                 return -EIO;
152
153         rv = netconfig_execute_file(path, args, envs);
154         if (rv < 0)
155                 return -EIO;
156
157         DBG("Successfully removed wireless device driver");
158         return 0;
159 }
160
161 static int __netconfig_p2p_firmware_start(const char *interface_name)
162 {
163         if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_WIFI_DIRECT))
164                 return -ENODEV;
165
166         int rv = 0;
167         const char *path = WLAN_DRIVER_SCRIPT;
168         char *const args[] = { "/usr/bin/wlan.sh", "p2p", (char *)interface_name, NULL };
169         char *const envs[] = { NULL };
170
171         rv = netconfig_execute_file(path, args, envs);
172         if (rv < 0)
173                 return -EIO;
174
175 #if defined TIZEN_WLAN_USE_P2P_INTERFACE
176         rv = netconfig_interface_up(interface_name);
177         if (rv != TRUE)
178                 return -EIO;
179 #endif
180
181         DBG("Successfully loaded p2p device driver");
182         return 0;
183 }
184
185 static int __netconfig_p2p_firmware_stop(const char *interface_name)
186 {
187         if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_WIFI_DIRECT))
188                 return -ENODEV;
189
190         int rv = 0;
191         const char *path = WLAN_DRIVER_SCRIPT;
192         char *const args[] = { "/usr/bin/wlan.sh", "stop", (char *)interface_name, NULL };
193         char *const envs[] = { NULL };
194
195         rv = netconfig_interface_down(interface_name);
196         if (rv != TRUE)
197                 return -EIO;
198
199         rv = netconfig_execute_file(path, args, envs);
200         if (rv < 0)
201                 return -EIO;
202
203         DBG("Successfully removed p2p device driver");
204         return 0;
205 }
206
207 static int __netconfig_softap_firmware_start(const char *interface_name)
208 {
209         if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_TETHERING)
210                         && !netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_WIFI_SOFTAP))
211                 return -ENODEV;
212
213         int rv = 0;
214         const char *path = WLAN_DRIVER_SCRIPT;
215         char *const args[] = { "/usr/bin/wlan.sh", "softap", (char *)interface_name, NULL };
216         char *const envs[] = { NULL };
217
218         rv = netconfig_execute_file(path, args, envs);
219         if (rv < 0)
220                 return -EIO;
221
222         if (netconfig_interface_up(interface_name) == FALSE)
223                 return -EIO;
224
225         DBG("Successfully loaded softap device driver");
226         return 0;
227 }
228
229 static int __netconfig_softap_firmware_stop(const char *interface_name)
230 {
231         if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_TETHERING)
232                         && !netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_WIFI_SOFTAP))
233                 return -ENODEV;
234
235         int rv = 0;
236         const char *path = WLAN_DRIVER_SCRIPT;
237         char *const args[] = { "/usr/bin/wlan.sh", "stop", (char *)interface_name, NULL };
238         char *const envs[] = { NULL };
239
240         rv = netconfig_interface_down(interface_name);
241         if (rv != TRUE)
242                 return -EIO;
243
244         rv = netconfig_execute_file(path, args, envs);
245         if (rv < 0)
246                 return -EIO;
247
248         DBG("Successfully removed softap device driver");
249         return 0;
250 }
251
252 static int __netconfig_wifi_firmware_start(enum netconfig_wifi_firmware type,
253                 const char *interface_name)
254 {
255         if (emulator_is_emulated() == TRUE)
256                 return -EIO;
257
258         switch (type) {
259         case NETCONFIG_WIFI_STA:
260                 return __netconfig_sta_firmware_start(interface_name);
261         case NETCONFIG_WIFI_P2P:
262                 return __netconfig_p2p_firmware_start(interface_name);
263         case NETCONFIG_WIFI_SOFTAP:
264                 return __netconfig_softap_firmware_start(interface_name);
265         default:
266                 break;
267         }
268
269         return -ENXIO;
270 }
271
272 static int __netconfig_wifi_firmware_stop(enum netconfig_wifi_firmware type,
273                 const char *interface_name)
274 {
275         if (emulator_is_emulated() == TRUE)
276                 return -EIO;
277
278         switch (type) {
279         case NETCONFIG_WIFI_STA:
280                 return __netconfig_sta_firmware_stop(interface_name);
281         case NETCONFIG_WIFI_P2P:
282                 return __netconfig_p2p_firmware_stop(interface_name);
283         case NETCONFIG_WIFI_SOFTAP:
284                 return __netconfig_softap_firmware_stop(interface_name);
285         default:
286                 break;
287         }
288
289         return -ENXIO;
290 }
291
292 static int __netconfig_set_rps_cpus(const char *interface_name)
293 {
294         int fd, curr;
295         ssize_t count;
296         char t_buf[TEMP_BUFFER_LEN];
297         char r_buf[TEMP_BUFFER_LEN];
298
299         if (access(WIFI_MAC_ADD_PATH, F_OK) != 0) {
300                 DBG("WiFi driver is not loaded... ");
301                 return -1;
302         } else {
303                 DBG("WiFi driver loaded... ");
304         }
305
306         snprintf(t_buf, TEMP_BUFFER_LEN,
307                 "/sys/class/net/%s/queues/rx-0/rps_cpus",
308                 interface_name);
309         DBG("Command : [%s]", t_buf);
310         curr = 0;
311
312         while ((fd = open(t_buf, O_RDWR | O_CLOEXEC)) >= 0) {
313                 curr++;
314                 count = read(fd, r_buf, 1);
315
316                 if (count < 0) {
317                         DBG("read failed");
318                         close(fd);
319                         return -1;
320                 } else {
321                         DBG("read size = %zd", count);
322                 }
323
324                 if (r_buf[0] == 'e') {
325                         close(fd);
326                         DBG("e is already written");
327                         snprintf(t_buf, TEMP_BUFFER_LEN,
328                                 "/sys/class/net/%s/queues/rx-%d/rps_cpus",
329                                 interface_name, curr);
330                         DBG("Command : [%s]", t_buf);
331                         continue;
332                 } else {
333                         DBG("writing e");
334                 }
335
336                 if (lseek(fd, 0, SEEK_SET) < 0) {
337                         DBG("lseek failed");
338                         close(fd);
339                         return -1;
340                 }
341
342                 count = write(fd, "e", 1);
343
344                 if (count < 0) {
345                         DBG("write failed");
346                         close(fd);
347                         return -1;
348                 } else {
349                         DBG("write size = %zd", count);
350                 }
351
352                 close(fd);
353                 snprintf(t_buf, TEMP_BUFFER_LEN,
354                         "/sys/class/net/%s/queues/rx-%d/rps_cpus",
355                         interface_name, curr);
356                 DBG("Command : [%s]", t_buf);
357         }
358
359         return 0;
360 }
361
362 int netconfig_wifi_firmware(enum netconfig_wifi_firmware type,
363                 const char *interface_name, gboolean enable)
364 {
365         int err;
366
367         DBG("Wi-Fi firmware (type: %d %s) for %s", type, enable == TRUE ? "enable" : "disable",
368                         interface_name ? interface_name : "");
369
370         GSList *found = __netconfig_is_wifi_driver_in_list(type, interface_name);
371
372         if (enable == FALSE) {
373                 wifi_driver_s *driver;
374
375                 if (!found)
376                         return -EALREADY;
377
378                 driver = (wifi_driver_s *) found->data;
379
380                 if (type != driver->type)
381                         return -EIO;
382
383                 err = __netconfig_wifi_firmware_stop(type, interface_name);
384                 if (err < 0 && err != -EALREADY)
385                         return err;
386
387                 __netconfig_remove_wifi_driver_from_list(type, interface_name);
388
389                 return err;
390         }
391
392         if (found) {
393                 wifi_driver_s *driver = (wifi_driver_s *) found->data;
394
395                 DBG("Wi-Fi interface (%s) already in use", interface_name);
396
397                 if (type == driver->type)
398                         return -EALREADY;
399
400                 return -EIO;
401         }
402
403         err = __netconfig_wifi_firmware_start(type, interface_name);
404         if (err < 0)
405                 DBG("Failed to execute script file");
406         else
407                 __netconfig_add_wifi_driver_to_list(type, interface_name);
408
409         if (__netconfig_set_rps_cpus(interface_name) < 0)
410                 DBG("Failed to set rps_cpus");
411
412         return err;
413 }
414
415 gboolean handle_start(WifiFirmware *firmware, GDBusMethodInvocation *context,
416                 const gchar *device, const gchar *ifname)
417 {
418         int err;
419
420         g_return_val_if_fail(firmware != NULL, TRUE);
421
422         DBG("Wi-Fi firmware start %s", device != NULL ? device : "null");
423
424         if (g_strcmp0("p2p", device) == 0)
425                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_P2P, ifname, TRUE);
426         else if (g_strcmp0("softap", device) == 0)
427                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_SOFTAP, ifname, TRUE);
428         else
429                 err = -EINVAL;
430
431         if (err < 0) {
432                 if (err == -EALREADY)
433                         netconfig_error_already_exists(context);
434                 else if (g_strcmp0("softap", device) == 0 &&
435                         err == -EIO && netconfig_is_wifi_direct_on() == FALSE) {
436                         if (netconfig_wifi_firmware(NETCONFIG_WIFI_P2P, ifname, FALSE) == 0 &&
437                                 netconfig_wifi_firmware(NETCONFIG_WIFI_SOFTAP, ifname, TRUE) == 0) {
438                                 wifi_firmware_complete_start(firmware, context);
439                                 return TRUE;
440                         } else
441                                 netconfig_error_wifi_driver_failed(context);
442                 } else
443                         netconfig_error_wifi_driver_failed(context);
444
445                 return TRUE;
446         }
447
448         wifi_firmware_complete_start(firmware, context);
449         return TRUE;
450 }
451
452 gboolean handle_stop(WifiFirmware *firmware, GDBusMethodInvocation *context,
453                 const gchar *device, const gchar *ifname)
454 {
455         int err;
456
457         g_return_val_if_fail(firmware != NULL, TRUE);
458
459         DBG("Wi-Fi firmware stop %s", device != NULL ? device : "null");
460
461         if (g_strcmp0("p2p", device) == 0)
462                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_P2P, ifname, FALSE);
463         else if (g_strcmp0("softap", device) == 0)
464                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_SOFTAP, ifname, FALSE);
465         else
466                 err = -EINVAL;
467
468         if (err < 0) {
469                 if (err == -EALREADY)
470                         netconfig_error_already_exists(context);
471                 else
472                         netconfig_error_wifi_driver_failed(context);
473
474                 return TRUE;
475         }
476
477         wifi_firmware_complete_stop(firmware, context);
478         return TRUE;
479 }