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