Add feature check code for softap
[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                         && !netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_WIFI_SOFTAP))
136                 return -ENODEV;
137
138         int rv = 0;
139         const char *path = WLAN_DRIVER_SCRIPT;
140         char *const args[] = { "/usr/bin/wlan.sh", "softap", NULL };
141         char *const envs[] = { NULL };
142
143         rv = netconfig_execute_file(path, args, envs);
144         if (rv < 0)
145                 return -EIO;
146
147         if (netconfig_interface_up(WLAN_IFACE_NAME) == FALSE)
148                 return -EIO;
149
150         DBG("Successfully loaded softap device driver");
151         return 0;
152 }
153
154 static int __netconfig_softap_firmware_stop(void)
155 {
156         if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_TETHERING)
157                         && !netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_WIFI_SOFTAP))
158                 return -ENODEV;
159
160         int rv = 0;
161         const char *path = WLAN_DRIVER_SCRIPT;
162         char *const args[] = { "/usr/bin/wlan.sh", "stop", NULL };
163         char *const envs[] = { NULL };
164
165         rv = netconfig_interface_down(WLAN_IFACE_NAME);
166         if (rv != TRUE)
167                 return -EIO;
168
169         rv = netconfig_execute_file(path, args, envs);
170         if (rv < 0)
171                 return -EIO;
172
173         DBG("Successfully removed softap device driver");
174         return 0;
175 }
176
177 static int __netconfig_wifi_firmware_start(enum netconfig_wifi_firmware type)
178 {
179         if (emulator_is_emulated() == TRUE)
180                 return -EIO;
181
182         switch (type) {
183         case NETCONFIG_WIFI_STA:
184                 return __netconfig_sta_firmware_start();
185         case NETCONFIG_WIFI_P2P:
186                 return __netconfig_p2p_firmware_start();
187         case NETCONFIG_WIFI_SOFTAP:
188                 return __netconfig_softap_firmware_start();
189         default:
190                 break;
191         }
192
193         return -ENXIO;
194 }
195
196 static int __netconfig_wifi_firmware_stop(enum netconfig_wifi_firmware type)
197 {
198         if (emulator_is_emulated() == TRUE)
199                 return -EIO;
200
201         switch (type) {
202         case NETCONFIG_WIFI_STA:
203                 return __netconfig_sta_firmware_stop();
204         case NETCONFIG_WIFI_P2P:
205                 return __netconfig_p2p_firmware_stop();
206         case NETCONFIG_WIFI_SOFTAP:
207                 return __netconfig_softap_firmware_stop();
208         default:
209                 break;
210         }
211
212         return -ENXIO;
213 }
214
215 static int __netconfig_set_rps_cpus(void)
216 {
217         int fd, curr;
218         ssize_t count;
219         char t_buf[TEMP_BUFFER_LEN];
220         char r_buf[TEMP_BUFFER_LEN];
221
222         if (access(WIFI_MAC_ADD_PATH, F_OK) != 0) {
223                 DBG("WiFi driver is not loaded... ");
224                 return -1;
225         } else {
226                 DBG("WiFi driver loaded... ");
227         }
228
229         snprintf(t_buf, TEMP_BUFFER_LEN, "/sys/class/net/wlan0/queues/rx-0/rps_cpus");
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 = %d", 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, "/sys/class/net/wlan0/queues/rx-%d/rps_cpus", curr);
249                         DBG("Command : [%s]", t_buf);
250                         continue;
251                 } else {
252                         DBG("writing e");
253                 }
254
255                 if (lseek(fd, 0, SEEK_SET) < 0) {
256                         DBG("lseek failed");
257                         close(fd);
258                         return -1;
259                 }
260
261                 count = write(fd, "e", 1);
262
263                 if (count < 0) {
264                         DBG("write failed");
265                         close(fd);
266                         return -1;
267                 } else {
268                         DBG("write size = %d", count);
269                 }
270
271                 close(fd);
272                 snprintf(t_buf, TEMP_BUFFER_LEN, "/sys/class/net/wlan0/queues/rx-%d/rps_cpus", curr);
273                 DBG("Command : [%s]", t_buf);
274         }
275
276         return 0;
277 }
278
279 int netconfig_wifi_firmware(enum netconfig_wifi_firmware type, gboolean enable)
280 {
281         int err;
282         static enum netconfig_wifi_firmware current_driver = NETCONFIG_WIFI_OFF;
283         enum netconfig_wifi_firmware alias = type;
284
285         DBG("Wi-Fi current firmware %d (type: %d %s)", current_driver, type,
286                                                         enable == TRUE ? "enable" : "disable");
287
288         if (enable == FALSE) {
289                 if (current_driver == NETCONFIG_WIFI_OFF) {
290                         return -EALREADY;
291                 } else if (current_driver == alias) {
292
293                         err = __netconfig_wifi_firmware_stop(type);
294                         if (err < 0 && err != -EALREADY)
295                                 return err;
296
297                         current_driver = NETCONFIG_WIFI_OFF;
298
299                         return err;
300                 }
301
302                 return -EIO;
303         }
304
305         if (current_driver > NETCONFIG_WIFI_OFF) {
306                 if (current_driver == alias)
307                         return -EALREADY;
308
309                 return -EIO;
310         }
311
312         err = __netconfig_wifi_firmware_start(type);
313         if (err < 0)
314                 DBG("Failed to execute script file");
315         else
316                 current_driver = alias;
317
318         if (__netconfig_set_rps_cpus() < 0)
319                 DBG("Failed to set rps_cpus");
320
321         return err;
322 }
323
324 gboolean handle_start(WifiFirmware *firmware, GDBusMethodInvocation *context, const gchar *device)
325 {
326         int err;
327
328         g_return_val_if_fail(firmware != NULL, TRUE);
329
330         DBG("Wi-Fi firmware start %s", device != NULL ? device : "null");
331
332         if (g_strcmp0("p2p", device) == 0)
333                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_P2P, TRUE);
334         else if (g_strcmp0("softap", device) == 0)
335                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_SOFTAP, TRUE);
336         else
337                 err = -EINVAL;
338
339         if (err < 0) {
340                 if (err == -EALREADY)
341                         netconfig_error_already_exists(context);
342                 else if (g_strcmp0("softap", device) == 0 && err == -EIO && netconfig_is_wifi_direct_on() == FALSE) {
343                         if (netconfig_wifi_firmware(NETCONFIG_WIFI_P2P, FALSE) == 0 && netconfig_wifi_firmware(NETCONFIG_WIFI_SOFTAP, TRUE) == 0) {
344                                 wifi_firmware_complete_start(firmware, context);
345                                 return TRUE;
346                         } else
347                                 netconfig_error_wifi_driver_failed(context);
348                 } else
349                         netconfig_error_wifi_driver_failed(context);
350
351                 return TRUE;
352         }
353
354         wifi_firmware_complete_start(firmware, context);
355         return TRUE;
356 }
357
358 gboolean handle_stop(WifiFirmware *firmware, GDBusMethodInvocation *context, const gchar *device)
359 {
360         int err;
361
362         g_return_val_if_fail(firmware != NULL, TRUE);
363
364         DBG("Wi-Fi firmware stop %s", device != NULL ? device : "null");
365
366         if (g_strcmp0("p2p", device) == 0)
367                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_P2P, FALSE);
368         else if (g_strcmp0("softap", device) == 0)
369                 err = netconfig_wifi_firmware(NETCONFIG_WIFI_SOFTAP, FALSE);
370         else
371                 err = -EINVAL;
372
373         if (err < 0) {
374                 if (err == -EALREADY)
375                         netconfig_error_already_exists(context);
376                 else
377                         netconfig_error_wifi_driver_failed(context);
378
379                 return TRUE;
380         }
381
382         wifi_firmware_complete_stop(firmware, context);
383         return TRUE;
384 }