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