blob: d92cdbdf05c12ed9e33c69574b0237ebbdf0217e [file] [log] [blame]
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001/*
2 * Copyright 2008, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <fcntl.h>
19#include <errno.h>
20#include <string.h>
Dmitry Shmidteea19f12011-03-25 13:37:18 -070021#include <dirent.h>
Dmitry Shmidt45bf8a62011-09-27 17:20:11 -070022#include <sys/socket.h>
Mark Salyzyn2263e472015-04-01 07:33:14 -070023#include <sys/stat.h>
Kenny Rootcf449e12012-03-15 13:10:19 -070024#include <unistd.h>
Dmitry Shmidt45bf8a62011-09-27 17:20:11 -070025#include <poll.h>
Ravi Kumar Siddojigari02bd5eb2016-06-24 21:54:26 +053026#include <sys/syscall.h>
Ricardo Cerqueiraec79cde2013-11-01 20:36:26 +000027
28#ifdef USES_TI_MAC80211
29#include <dirent.h>
30#include <net/if.h>
31#include <netlink/genl/genl.h>
32#include <netlink/genl/family.h>
33#include <netlink/genl/ctrl.h>
34#include <netlink/msg.h>
35#include <netlink/attr.h>
36#include <linux/nl80211.h>
37#endif
38
The Android Open Source Projectcc490162009-03-03 19:32:14 -080039#include "hardware_legacy/wifi.h"
Dedy Lansky8dcf57a2015-09-10 17:09:49 +030040#include "wifi_fst.h"
Dmitry Shmidt41d81d12013-11-22 15:54:27 -080041#ifdef LIBWPA_CLIENT_EXISTS
The Android Open Source Projectcc490162009-03-03 19:32:14 -080042#include "libwpa_client/wpa_ctrl.h"
Dmitry Shmidt41d81d12013-11-22 15:54:27 -080043#endif
The Android Open Source Projectcc490162009-03-03 19:32:14 -080044
45#define LOG_TAG "WifiHW"
46#include "cutils/log.h"
47#include "cutils/memory.h"
48#include "cutils/misc.h"
49#include "cutils/properties.h"
50#include "private/android_filesystem_config.h"
Elliott Hughes7a070c62015-01-12 11:38:56 -080051
The Android Open Source Projectcc490162009-03-03 19:32:14 -080052#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
53#include <sys/_system_properties.h>
The Android Open Source Projectcc490162009-03-03 19:32:14 -080054
Jean-Baptiste Queru445591d2010-06-21 13:15:01 -070055extern int do_dhcp();
56extern int ifc_init();
57extern void ifc_close();
58extern char *dhcp_lasterror();
59extern void get_dhcp_info();
The Android Open Source Projectcc490162009-03-03 19:32:14 -080060extern int init_module(void *, unsigned long, const char *);
61extern int delete_module(const char *, unsigned int);
Vinit Deshapnde0f330482013-08-08 10:39:25 -070062void wifi_close_sockets();
The Android Open Source Projectcc490162009-03-03 19:32:14 -080063
Dmitry Shmidt41d81d12013-11-22 15:54:27 -080064#ifndef LIBWPA_CLIENT_EXISTS
65#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
66struct wpa_ctrl {};
67void wpa_ctrl_cleanup(void) {}
68struct wpa_ctrl *wpa_ctrl_open(const char *ctrl_path) { return NULL; }
69void wpa_ctrl_close(struct wpa_ctrl *ctrl) {}
70int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
71 char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len))
72 { return 0; }
73int wpa_ctrl_attach(struct wpa_ctrl *ctrl) { return 0; }
74int wpa_ctrl_detach(struct wpa_ctrl *ctrl) { return 0; }
75int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
76 { return 0; }
77int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) { return 0; }
78#endif
79
80static struct wpa_ctrl *ctrl_conn;
81static struct wpa_ctrl *monitor_conn;
82
83/* socket pair used to exit from a blocking read */
84static int exit_sockets[2];
Steve Kondik56be7092012-12-20 20:39:18 -080085static int wifi_mode = 0;
Dmitry Shmidt41d81d12013-11-22 15:54:27 -080086
Irfan Sheriffda529302011-12-27 13:50:07 -080087static char primary_iface[PROPERTY_VALUE_MAX];
The Android Open Source Projectcc490162009-03-03 19:32:14 -080088// TODO: use new ANDROID_SOCKET mechanism, once support for multiple
89// sockets is in
90
Ricardo Cerqueiraec79cde2013-11-01 20:36:26 +000091#ifdef USES_TI_MAC80211
92#define P2P_INTERFACE "p2p0"
93struct nl_sock *nl_soc;
94struct nl_cache *nl_cache;
95struct genl_family *nl80211;
96#endif
97
Dmitry Shmidt243af8b2009-04-20 09:06:40 -070098#ifndef WIFI_DRIVER_MODULE_ARG
99#define WIFI_DRIVER_MODULE_ARG ""
100#endif
Steve Kondik56be7092012-12-20 20:39:18 -0800101#ifndef WIFI_DRIVER_MODULE_AP_ARG
102#define WIFI_DRIVER_MODULE_AP_ARG ""
103#endif
Dmitry Shmidt243af8b2009-04-20 09:06:40 -0700104#ifndef WIFI_FIRMWARE_LOADER
105#define WIFI_FIRMWARE_LOADER ""
106#endif
107#define WIFI_TEST_INTERFACE "sta"
108
Dmitry Shmidt4b7ffa02011-07-01 11:03:43 -0700109#ifndef WIFI_DRIVER_FW_PATH_STA
110#define WIFI_DRIVER_FW_PATH_STA NULL
111#endif
112#ifndef WIFI_DRIVER_FW_PATH_AP
113#define WIFI_DRIVER_FW_PATH_AP NULL
114#endif
115#ifndef WIFI_DRIVER_FW_PATH_P2P
116#define WIFI_DRIVER_FW_PATH_P2P NULL
117#endif
118
jerpelea94ac2712011-11-22 09:40:37 +0200119#ifdef WIFI_EXT_MODULE_NAME
120static const char EXT_MODULE_NAME[] = WIFI_EXT_MODULE_NAME;
121#ifdef WIFI_EXT_MODULE_ARG
122static const char EXT_MODULE_ARG[] = WIFI_EXT_MODULE_ARG;
123#else
124static const char EXT_MODULE_ARG[] = "";
125#endif
126#endif
127#ifdef WIFI_EXT_MODULE_PATH
128static const char EXT_MODULE_PATH[] = WIFI_EXT_MODULE_PATH;
129#endif
130
Dmitry Shmidt29a4d4d2011-07-19 15:59:13 -0700131#ifndef WIFI_DRIVER_FW_PATH_PARAM
132#define WIFI_DRIVER_FW_PATH_PARAM "/sys/module/wlan/parameters/fwpath"
133#endif
134
Dmitry Shmidted848722010-02-25 12:34:42 -0800135#define WIFI_DRIVER_LOADER_DELAY 1000000
136
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800137static const char IFACE_DIR[] = "/data/system/wpa_supplicant";
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700138#ifdef WIFI_DRIVER_MODULE_PATH
Dmitry Shmidt243af8b2009-04-20 09:06:40 -0700139static const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME;
140static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " ";
141static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH;
142static const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG;
Steve Kondik56be7092012-12-20 20:39:18 -0800143static const char DRIVER_MODULE_AP_ARG[] = WIFI_DRIVER_MODULE_AP_ARG;
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700144#endif
Dmitry Shmidt243af8b2009-04-20 09:06:40 -0700145static const char FIRMWARE_LOADER[] = WIFI_FIRMWARE_LOADER;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800146static const char DRIVER_PROP_NAME[] = "wlan.driver.status";
147static const char SUPPLICANT_NAME[] = "wpa_supplicant";
148static const char SUPP_PROP_NAME[] = "init.svc.wpa_supplicant";
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800149static const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant";
150static const char P2P_PROP_NAME[] = "init.svc.p2p_supplicant";
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800151static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf";
152static const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf";
Irfan Sheriff67ba2272011-08-26 14:39:38 -0700153static const char P2P_CONFIG_FILE[] = "/data/misc/wifi/p2p_supplicant.conf";
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800154static const char CONTROL_IFACE_PATH[] = "/data/misc/wifi/sockets";
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800155static const char MODULE_FILE[] = "/proc/modules";
156
Dmitry Shmidtec057602013-05-29 10:34:39 -0700157static const char IFNAME[] = "IFNAME=";
158#define IFNAMELEN (sizeof(IFNAME) - 1)
159static const char WPA_EVENT_IGNORE[] = "CTRL-EVENT-IGNORE ";
160
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700161static const char SUPP_ENTROPY_FILE[] = WIFI_ENTROPY_FILE;
Dmitry Shmidt07a629e2011-10-06 13:28:32 -0700162static unsigned char dummy_key[21] = { 0x02, 0x11, 0xbe, 0x33, 0x43, 0x35,
163 0x68, 0x47, 0x84, 0x99, 0xa9, 0x2b,
164 0x1c, 0xd3, 0xee, 0xff, 0xf1, 0xe2,
165 0xf3, 0xf4, 0xf5 };
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700166
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800167/* Is either SUPPLICANT_NAME or P2P_SUPPLICANT_NAME */
168static char supplicant_name[PROPERTY_VALUE_MAX];
169/* Is either SUPP_PROP_NAME or P2P_PROP_NAME */
170static char supplicant_prop_name[PROPERTY_KEY_MAX];
171
Ricardo Cerqueira0b7cb772013-11-01 20:35:09 +0000172#ifdef SAMSUNG_WIFI
173char* get_samsung_wifi_type()
174{
175 char buf[10];
176 int fd = open("/data/.cid.info", O_RDONLY);
177 if (fd < 0)
178 return NULL;
179
180 if (read(fd, buf, sizeof(buf)) < 0) {
181 close(fd);
182 return NULL;
183 }
184
185 close(fd);
186
187 if (strncmp(buf, "murata", 6) == 0)
188 return "_murata";
189
190 if (strncmp(buf, "semcove", 7) == 0)
191 return "_semcove";
192
Ethan Chen2da3d272013-07-31 16:41:56 -0700193 if (strncmp(buf, "semcosh", 7) == 0)
194 return "_semcosh";
195
Christopher N. Hessed6f4b6b2015-01-26 22:01:59 +0100196 if (strncmp(buf, "semco", 5) == 0)
197 return "_semco";
198
Ricardo Cerqueira0b7cb772013-11-01 20:35:09 +0000199 return NULL;
200}
201#endif
202
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300203int insmod(const char *filename, const char *args)
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800204{
Ravi Kumar Siddojigari02bd5eb2016-06-24 21:54:26 +0530205 /* O_NOFOLLOW is removed as wlan.ko is symlink pointing to
206 the vendor specfic file which is in readonly location */
207 int fd = open(filename, O_RDONLY | O_CLOEXEC);
208 if (fd == -1) {
209 ALOGD("insmod: open(\"%s\") failed: %s", filename, strerror(errno));
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800210 return -1;
Ravi Kumar Siddojigari02bd5eb2016-06-24 21:54:26 +0530211 }
212 int rc = syscall(__NR_finit_module, fd, args, 0);
213 if (rc == -1) {
214 ALOGD("finit_module for \"%s\" failed: %s", filename, strerror(errno));
215 }
216 close(fd);
217 return rc;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800218}
219
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300220int rmmod(const char *modname)
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800221{
222 int ret = -1;
223 int maxtry = 10;
224
225 while (maxtry-- > 0) {
226 ret = delete_module(modname, O_NONBLOCK | O_EXCL);
227 if (ret < 0 && errno == EAGAIN)
228 usleep(500000);
229 else
230 break;
231 }
232
233 if (ret != 0)
Steve Blockb381b932011-12-20 16:25:34 +0000234 ALOGD("Unable to unload driver module \"%s\": %s\n",
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800235 modname, strerror(errno));
236 return ret;
237}
238
Jean-Baptiste Queru445591d2010-06-21 13:15:01 -0700239int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
240 int *dns1, int *dns2, int *server, int *lease) {
241 /* For test driver, always report success */
Irfan Sheriffda529302011-12-27 13:50:07 -0800242 if (strcmp(primary_iface, WIFI_TEST_INTERFACE) == 0)
Jean-Baptiste Queru445591d2010-06-21 13:15:01 -0700243 return 0;
244
245 if (ifc_init() < 0)
246 return -1;
247
Irfan Sheriffda529302011-12-27 13:50:07 -0800248 if (do_dhcp(primary_iface) < 0) {
Jean-Baptiste Queru445591d2010-06-21 13:15:01 -0700249 ifc_close();
250 return -1;
251 }
252 ifc_close();
253 get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease);
254 return 0;
255}
256
257const char *get_dhcp_error_string() {
258 return dhcp_lasterror();
259}
260
Maddest Changda1c7fa2015-07-10 19:39:05 +0800261#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
262int wifi_change_driver_state(const char *state)
263{
264 int len;
265 int fd;
266 int ret = 0;
267
268 if (!state)
269 return -1;
270 fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_STATE_CTRL_PARAM, O_WRONLY));
271 if (fd < 0) {
272 ALOGE("Failed to open driver state control param (%s)", strerror(errno));
273 return -1;
274 }
275 len = strlen(state) + 1;
276 if (TEMP_FAILURE_RETRY(write(fd, state, len)) != len) {
277 ALOGE("Failed to write driver state control param (%s)", strerror(errno));
278 ret = -1;
279 }
280 close(fd);
281 return ret;
282}
283#endif
284
Irfan Sheriff2bb990b2010-07-27 12:16:08 -0700285int is_wifi_driver_loaded() {
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800286 char driver_status[PROPERTY_VALUE_MAX];
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700287#ifdef WIFI_DRIVER_MODULE_PATH
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800288 FILE *proc;
289 char line[sizeof(DRIVER_MODULE_TAG)+10];
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700290#endif
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800291
292 if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
293 || strcmp(driver_status, "ok") != 0) {
294 return 0; /* driver not loaded */
295 }
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700296#ifdef WIFI_DRIVER_MODULE_PATH
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800297 /*
298 * If the property says the driver is loaded, check to
299 * make sure that the property setting isn't just left
300 * over from a previous manual shutdown or a runtime
301 * crash.
302 */
303 if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
Steve Block64cca042012-01-05 23:27:53 +0000304 ALOGW("Could not open %s: %s", MODULE_FILE, strerror(errno));
Dmitry Shmidt243af8b2009-04-20 09:06:40 -0700305 property_set(DRIVER_PROP_NAME, "unloaded");
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800306 return 0;
307 }
308 while ((fgets(line, sizeof(line), proc)) != NULL) {
309 if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
310 fclose(proc);
Dedy Lansky79a0eb42016-08-07 11:39:11 +0300311 return 1;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800312 }
313 }
314 fclose(proc);
315 property_set(DRIVER_PROP_NAME, "unloaded");
316 return 0;
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700317#else
318 return 1;
319#endif
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800320}
321
322int wifi_load_driver()
323{
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700324#ifdef WIFI_DRIVER_MODULE_PATH
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800325 char driver_status[PROPERTY_VALUE_MAX];
326 int count = 100; /* wait at most 20 seconds for completion */
Ricardo Cerqueira0b7cb772013-11-01 20:35:09 +0000327 char module_arg2[256];
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800328
Irfan Sheriff2bb990b2010-07-27 12:16:08 -0700329 if (is_wifi_driver_loaded()) {
Dedy Lansky79a0eb42016-08-07 11:39:11 +0300330 return wifi_fst_load_driver();
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800331 }
332
Ricardo Cerqueira0b7cb772013-11-01 20:35:09 +0000333#ifdef SAMSUNG_WIFI
334 char* type = get_samsung_wifi_type();
codeworkx6e7ecf12012-12-22 13:04:14 +0100335
336 if (wifi_mode == 1) {
337 snprintf(module_arg2, sizeof(module_arg2), "%s%s", DRIVER_MODULE_AP_ARG, type == NULL ? "" : type);
338 } else {
339 snprintf(module_arg2, sizeof(module_arg2), "%s%s", DRIVER_MODULE_ARG, type == NULL ? "" : type);
340 }
Ricardo Cerqueira0b7cb772013-11-01 20:35:09 +0000341
342 if (insmod(DRIVER_MODULE_PATH, module_arg2) < 0) {
343#else
jerpelea94ac2712011-11-22 09:40:37 +0200344
Michaël Burtinece94652012-01-15 22:43:31 +0100345 property_set(DRIVER_PROP_NAME, "loading");
346
jerpelea94ac2712011-11-22 09:40:37 +0200347#ifdef WIFI_EXT_MODULE_PATH
348 if (insmod(EXT_MODULE_PATH, EXT_MODULE_ARG) < 0)
349 return -1;
350 usleep(200000);
351#endif
352
Ricardo Cerqueira0b7cb772013-11-01 20:35:09 +0000353 if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) {
354#endif
355
356#ifdef WIFI_EXT_MODULE_NAME
357 rmmod(EXT_MODULE_NAME);
358#endif
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800359 return -1;
Ricardo Cerqueira0b7cb772013-11-01 20:35:09 +0000360 }
Dmitry Shmidt243af8b2009-04-20 09:06:40 -0700361
362 if (strcmp(FIRMWARE_LOADER,"") == 0) {
Dmitry Shmidt8fb5f742010-09-14 15:11:22 -0700363 /* usleep(WIFI_DRIVER_LOADER_DELAY); */
Dmitry Shmidt243af8b2009-04-20 09:06:40 -0700364 property_set(DRIVER_PROP_NAME, "ok");
365 }
366 else {
367 property_set("ctl.start", FIRMWARE_LOADER);
368 }
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800369 sched_yield();
370 while (count-- > 0) {
371 if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
372 if (strcmp(driver_status, "ok") == 0)
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300373 return wifi_fst_load_driver();
Ajay Dudani85bff332015-05-03 17:32:49 -0700374 else if (strcmp(driver_status, "failed") == 0) {
Dmitry Shmidt7b436992009-07-28 11:03:31 -0700375 wifi_unload_driver();
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800376 return -1;
Dmitry Shmidt7b436992009-07-28 11:03:31 -0700377 }
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800378 }
379 usleep(200000);
380 }
381 property_set(DRIVER_PROP_NAME, "timeout");
Dmitry Shmidt7b436992009-07-28 11:03:31 -0700382 wifi_unload_driver();
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800383 return -1;
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700384#else
Maddest Changda1c7fa2015-07-10 19:39:05 +0800385#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
386 if (is_wifi_driver_loaded()) {
387 return 0;
388 }
389
390 if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0)
391 return -1;
392#endif
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700393 property_set(DRIVER_PROP_NAME, "ok");
394 return 0;
395#endif
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800396}
397
398int wifi_unload_driver()
399{
Dmitry Shmidt4c1a1fe2011-06-13 10:32:08 -0700400 usleep(200000); /* allow to finish interface down */
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300401
402 wifi_fst_unload_driver();
403
Dmitry Shmidt953c1142011-08-23 15:44:23 -0700404#ifdef WIFI_DRIVER_MODULE_PATH
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800405 if (rmmod(DRIVER_MODULE_NAME) == 0) {
Dmitry Shmidt953c1142011-08-23 15:44:23 -0700406 int count = 20; /* wait at most 10 seconds for completion */
Dmitry Shmidt0e9f4882011-01-04 16:35:18 -0800407 while (count-- > 0) {
408 if (!is_wifi_driver_loaded())
409 break;
410 usleep(500000);
411 }
Dmitry Shmidt953c1142011-08-23 15:44:23 -0700412 usleep(500000); /* allow card removal */
Dmitry Shmidt0e9f4882011-01-04 16:35:18 -0800413 if (count) {
jerpelea94ac2712011-11-22 09:40:37 +0200414#ifdef WIFI_EXT_MODULE_NAME
415 if (rmmod(EXT_MODULE_NAME) == 0)
416#endif
Dmitry Shmidt0e9f4882011-01-04 16:35:18 -0800417 return 0;
418 }
419 return -1;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800420 } else
421 return -1;
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700422#else
Maddest Changda1c7fa2015-07-10 19:39:05 +0800423#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
424 if (is_wifi_driver_loaded()) {
425 if (wifi_change_driver_state(WIFI_DRIVER_STATE_OFF) < 0)
426 return -1;
427 }
428#endif
Dmitry Shmidtd301cb72011-06-29 16:22:28 -0700429 property_set(DRIVER_PROP_NAME, "unloaded");
430 return 0;
431#endif
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800432}
433
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700434int ensure_entropy_file_exists()
435{
436 int ret;
437 int destfd;
438
439 ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK);
440 if ((ret == 0) || (errno == EACCES)) {
441 if ((ret != 0) &&
442 (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
Steve Block5efbd422012-01-08 10:18:02 +0000443 ALOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700444 return -1;
445 }
446 return 0;
447 }
Kenny Rootcf449e12012-03-15 13:10:19 -0700448 destfd = TEMP_FAILURE_RETRY(open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660));
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700449 if (destfd < 0) {
Steve Block5efbd422012-01-08 10:18:02 +0000450 ALOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700451 return -1;
452 }
453
Kenny Rootcf449e12012-03-15 13:10:19 -0700454 if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) {
Steve Block5efbd422012-01-08 10:18:02 +0000455 ALOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700456 close(destfd);
457 return -1;
458 }
459 close(destfd);
460
461 /* chmod is needed because open() didn't set permisions properly */
462 if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) {
Steve Block5efbd422012-01-08 10:18:02 +0000463 ALOGE("Error changing permissions of %s to 0660: %s",
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700464 SUPP_ENTROPY_FILE, strerror(errno));
465 unlink(SUPP_ENTROPY_FILE);
466 return -1;
467 }
468
469 if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) {
Steve Block5efbd422012-01-08 10:18:02 +0000470 ALOGE("Error changing group ownership of %s to %d: %s",
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700471 SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno));
472 unlink(SUPP_ENTROPY_FILE);
473 return -1;
474 }
475 return 0;
476}
477
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300478int ensure_config_file_exists(const char *config_file, const char *config_file_template)
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800479{
480 char buf[2048];
481 int srcfd, destfd;
Irfan Sheriff8a5b1972010-12-16 16:17:29 -0800482 struct stat sb;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800483 int nread;
Dmitry Shmidt89ae7032011-03-07 15:30:53 -0800484 int ret;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800485
Irfan Sheriff67ba2272011-08-26 14:39:38 -0700486 ret = access(config_file, R_OK|W_OK);
Dmitry Shmidt89ae7032011-03-07 15:30:53 -0800487 if ((ret == 0) || (errno == EACCES)) {
488 if ((ret != 0) &&
Irfan Sheriff67ba2272011-08-26 14:39:38 -0700489 (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
Steve Block5efbd422012-01-08 10:18:02 +0000490 ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno));
Dmitry Shmidt89ae7032011-03-07 15:30:53 -0800491 return -1;
492 }
Dmitry Shmidtc6bb3b52013-10-04 15:49:11 -0700493 return 0;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800494 } else if (errno != ENOENT) {
Steve Block5efbd422012-01-08 10:18:02 +0000495 ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno));
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800496 return -1;
497 }
498
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300499 srcfd = TEMP_FAILURE_RETRY(open(config_file_template, O_RDONLY));
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800500 if (srcfd < 0) {
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300501 ALOGE("Cannot open \"%s\": %s", config_file_template, strerror(errno));
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800502 return -1;
503 }
504
Kenny Rootcf449e12012-03-15 13:10:19 -0700505 destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT|O_RDWR, 0660));
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800506 if (destfd < 0) {
507 close(srcfd);
Steve Block5efbd422012-01-08 10:18:02 +0000508 ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno));
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800509 return -1;
510 }
511
Kenny Rootcf449e12012-03-15 13:10:19 -0700512 while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) {
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800513 if (nread < 0) {
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300514 ALOGE("Error reading \"%s\": %s", config_file_template, strerror(errno));
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800515 close(srcfd);
516 close(destfd);
Irfan Sheriff67ba2272011-08-26 14:39:38 -0700517 unlink(config_file);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800518 return -1;
519 }
Kenny Rootcf449e12012-03-15 13:10:19 -0700520 TEMP_FAILURE_RETRY(write(destfd, buf, nread));
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800521 }
522
523 close(destfd);
524 close(srcfd);
525
Dmitry Shmidt24bf7fc2010-08-09 11:04:49 -0700526 /* chmod is needed because open() didn't set permisions properly */
Irfan Sheriff67ba2272011-08-26 14:39:38 -0700527 if (chmod(config_file, 0660) < 0) {
Steve Block5efbd422012-01-08 10:18:02 +0000528 ALOGE("Error changing permissions of %s to 0660: %s",
Irfan Sheriff67ba2272011-08-26 14:39:38 -0700529 config_file, strerror(errno));
530 unlink(config_file);
Dmitry Shmidt24bf7fc2010-08-09 11:04:49 -0700531 return -1;
532 }
533
Irfan Sheriff67ba2272011-08-26 14:39:38 -0700534 if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) {
Steve Block5efbd422012-01-08 10:18:02 +0000535 ALOGE("Error changing group ownership of %s to %d: %s",
Irfan Sheriff67ba2272011-08-26 14:39:38 -0700536 config_file, AID_WIFI, strerror(errno));
537 unlink(config_file);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800538 return -1;
539 }
Dmitry Shmidtc6bb3b52013-10-04 15:49:11 -0700540 return 0;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800541}
542
Ricardo Cerqueiraec79cde2013-11-01 20:36:26 +0000543#ifdef USES_TI_MAC80211
544static int init_nl()
545{
546 int err;
547
548 nl_soc = nl_socket_alloc();
549 if (!nl_soc) {
550 ALOGE("Failed to allocate netlink socket.");
551 return -ENOMEM;
552 }
553
554 if (genl_connect(nl_soc)) {
555 ALOGE("Failed to connect to generic netlink.");
556 err = -ENOLINK;
557 goto out_handle_destroy;
558 }
559
560 genl_ctrl_alloc_cache(nl_soc, &nl_cache);
561 if (!nl_cache) {
562 ALOGE("Failed to allocate generic netlink cache.");
563 err = -ENOMEM;
564 goto out_handle_destroy;
565 }
566
567 nl80211 = genl_ctrl_search_by_name(nl_cache, "nl80211");
568 if (!nl80211) {
569 ALOGE("nl80211 not found.");
570 err = -ENOENT;
571 goto out_cache_free;
572 }
573
574 return 0;
575
576out_cache_free:
577 nl_cache_free(nl_cache);
578out_handle_destroy:
579 nl_socket_free(nl_soc);
580 return err;
581}
582
583static void deinit_nl()
584{
585 genl_family_put(nl80211);
586 nl_cache_free(nl_cache);
587 nl_socket_free(nl_soc);
588}
589
590// ignore the "." and ".." entries
591static int dir_filter(const struct dirent *name)
592{
593 if (0 == strcmp("..", name->d_name) ||
594 0 == strcmp(".", name->d_name))
595 return 0;
596
597 return 1;
598}
599
600// lookup the only active phy
601int phy_lookup()
602{
603 char buf[200];
604 int fd, pos;
605 struct dirent **namelist;
606 int n, i;
607
608 n = scandir("/sys/class/ieee80211", &namelist, dir_filter,
609 (int (*)(const struct dirent**, const struct dirent**))alphasort);
610 if (n != 1) {
611 ALOGE("unexpected - found %d phys in /sys/class/ieee80211", n);
612 for (i = 0; i < n; i++)
613 free(namelist[i]);
614 free(namelist);
615 return -1;
616 }
617
618 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index",
619 namelist[0]->d_name);
620 free(namelist[0]);
621 free(namelist);
622
623 fd = open(buf, O_RDONLY);
624 if (fd < 0)
625 return -1;
626 pos = read(fd, buf, sizeof(buf) - 1);
627 if (pos < 0) {
628 close(fd);
629 return -1;
630 }
631 buf[pos] = '\0';
632 close(fd);
633 return atoi(buf);
634}
635
636int nl_error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
637{
638 int *ret = (int *)arg;
639 *ret = err->error;
640 return NL_STOP;
641}
642
643int nl_finish_handler(struct nl_msg *msg, void *arg)
644{
645 int *ret = (int *)arg;
646 *ret = 0;
647 return NL_SKIP;
648}
649
650int nl_ack_handler(struct nl_msg *msg, void *arg)
651{
652 int *ret = (int *)arg;
653 *ret = 0;
654 return NL_STOP;
655}
656
657static int execute_nl_interface_cmd(const char *iface,
658 enum nl80211_iftype type,
659 uint8_t cmd)
660{
661 struct nl_cb *cb;
662 struct nl_msg *msg;
663 int devidx = 0;
664 int err;
665 int add_interface = (cmd == NL80211_CMD_NEW_INTERFACE);
666
667 if (add_interface) {
668 devidx = phy_lookup();
669 } else {
670 devidx = if_nametoindex(iface);
671 if (devidx == 0) {
672 ALOGE("failed to translate ifname to idx");
673 return -errno;
674 }
675 }
676
677 msg = nlmsg_alloc();
678 if (!msg) {
679 ALOGE("failed to allocate netlink message");
680 return 2;
681 }
682
683 cb = nl_cb_alloc(NL_CB_DEFAULT);
684 if (!cb) {
685 ALOGE("failed to allocate netlink callbacks");
686 err = 2;
687 goto out_free_msg;
688 }
689
690 genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0, 0, cmd, 0);
691
692 if (add_interface) {
693 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
694 } else {
695 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
696 }
697
698 if (add_interface) {
699 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, iface);
700 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type);
701 }
702
703 err = nl_send_auto_complete(nl_soc, msg);
704 if (err < 0)
705 goto out;
706
707 err = 1;
708
709 nl_cb_err(cb, NL_CB_CUSTOM, nl_error_handler, &err);
710 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl_finish_handler, &err);
711 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl_ack_handler, &err);
712
713 while (err > 0)
714 nl_recvmsgs(nl_soc, cb);
715out:
716 nl_cb_put(cb);
717out_free_msg:
718 nlmsg_free(msg);
719 return err;
720nla_put_failure:
721 ALOGW("building message failed");
722 return 2;
723}
724
725int add_remove_p2p_interface(int add)
726{
727 int ret;
728
729 ret = init_nl();
730 if (ret != 0)
731 return ret;
732
733 if (add) {
734 ret = execute_nl_interface_cmd(P2P_INTERFACE, NL80211_IFTYPE_STATION,
735 NL80211_CMD_NEW_INTERFACE);
736 if (ret != 0) {
737 ALOGE("could not add P2P interface: %d", ret);
738 goto cleanup;
739 }
740 } else {
741 ret = execute_nl_interface_cmd(P2P_INTERFACE, NL80211_IFTYPE_STATION,
742 NL80211_CMD_DEL_INTERFACE);
743 if (ret != 0) {
744 ALOGE("could not remove P2P interface: %d", ret);
745 goto cleanup;
746 }
747 }
748
749 ALOGD("added/removed p2p interface. add: %d", add);
750
751cleanup:
752 deinit_nl();
753 return ret;
754}
755#endif /* USES_TI_MAC80211 */
756
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800757int wifi_start_supplicant(int p2p_supported)
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800758{
759 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
760 int count = 200; /* wait at most 20 seconds for completion */
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800761 const prop_info *pi;
Irfan Sheriffda529302011-12-27 13:50:07 -0800762 unsigned serial = 0, i;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800763
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300764 if (wifi_start_fstman(0)) {
765 return -1;
766 }
767
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800768 if (p2p_supported) {
769 strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
770 strcpy(supplicant_prop_name, P2P_PROP_NAME);
771
772 /* Ensure p2p config file is created */
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300773 if (ensure_config_file_exists(P2P_CONFIG_FILE, SUPP_CONFIG_TEMPLATE) < 0) {
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800774 ALOGE("Failed to create a p2p config file");
775 return -1;
776 }
777
778 } else {
779 strcpy(supplicant_name, SUPPLICANT_NAME);
780 strcpy(supplicant_prop_name, SUPP_PROP_NAME);
781 }
782
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800783 /* Check whether already running */
Jonathan DE CESCOeed817e2012-11-20 18:59:34 +0100784 if (property_get(supplicant_prop_name, supp_status, NULL)
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800785 && strcmp(supp_status, "running") == 0) {
786 return 0;
787 }
788
789 /* Before starting the daemon, make sure its config file exists */
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300790 if (ensure_config_file_exists(SUPP_CONFIG_FILE, SUPP_CONFIG_TEMPLATE) < 0) {
Steve Block5efbd422012-01-08 10:18:02 +0000791 ALOGE("Wi-Fi will not be enabled");
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800792 return -1;
793 }
794
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700795 if (ensure_entropy_file_exists() < 0) {
Steve Block5efbd422012-01-08 10:18:02 +0000796 ALOGE("Wi-Fi entropy file was not created");
Dmitry Shmidt3ab3e662011-07-25 10:46:00 -0700797 }
798
Ricardo Cerqueiraec79cde2013-11-01 20:36:26 +0000799#ifdef USES_TI_MAC80211
800 if (p2p_supported && add_remove_p2p_interface(1) < 0) {
801 ALOGE("Wi-Fi - could not create p2p interface");
802 return -1;
803 }
804#endif
805
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800806 /* Clear out any stale socket files that might be left over. */
Dmitry Shmidtde9abff2013-05-22 16:45:57 -0700807 wpa_ctrl_cleanup();
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800808
Irfan Sheriffda529302011-12-27 13:50:07 -0800809 /* Reset sockets used for exiting from hung state */
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700810 exit_sockets[0] = exit_sockets[1] = -1;
Irfan Sheriffda529302011-12-27 13:50:07 -0800811
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800812 /*
813 * Get a reference to the status property, so we can distinguish
814 * the case where it goes stopped => running => stopped (i.e.,
815 * it start up, but fails right away) from the case in which
816 * it starts in the stopped state and never manages to start
817 * running at all.
818 */
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800819 pi = __system_property_find(supplicant_prop_name);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800820 if (pi != NULL) {
Colin Cross14c02f22013-02-04 12:34:20 -0800821 serial = __system_property_serial(pi);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800822 }
Irfan Sheriffda529302011-12-27 13:50:07 -0800823 property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800824
825 property_set("ctl.start", supplicant_name);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800826 sched_yield();
827
828 while (count-- > 0) {
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800829 if (pi == NULL) {
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800830 pi = __system_property_find(supplicant_prop_name);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800831 }
832 if (pi != NULL) {
jiaguo4431a1c2014-03-13 18:49:14 +0800833 /*
834 * property serial updated means that init process is scheduled
835 * after we sched_yield, further property status checking is based on this */
836 if (__system_property_serial(pi) != serial) {
837 __system_property_read(pi, NULL, supp_status);
838 if (strcmp(supp_status, "running") == 0) {
839 return 0;
840 } else if (strcmp(supp_status, "stopped") == 0) {
841 return -1;
842 }
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800843 }
844 }
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800845 usleep(100000);
846 }
847 return -1;
848}
849
Irfan Sheriff745e7fd2012-11-03 23:21:39 -0700850int wifi_stop_supplicant(int p2p_supported)
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800851{
852 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
853 int count = 50; /* wait at most 5 seconds for completion */
854
Irfan Sheriff745e7fd2012-11-03 23:21:39 -0700855 if (p2p_supported) {
856 strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
857 strcpy(supplicant_prop_name, P2P_PROP_NAME);
858 } else {
859 strcpy(supplicant_name, SUPPLICANT_NAME);
860 strcpy(supplicant_prop_name, SUPP_PROP_NAME);
861 }
862
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800863 /* Check whether supplicant already stopped */
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800864 if (property_get(supplicant_prop_name, supp_status, NULL)
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800865 && strcmp(supp_status, "stopped") == 0) {
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300866 wifi_stop_fstman(0);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800867 return 0;
868 }
869
Ricardo Cerqueiraec79cde2013-11-01 20:36:26 +0000870#ifdef USES_TI_MAC80211
871 if (p2p_supported && add_remove_p2p_interface(0) < 0) {
872 ALOGE("Wi-Fi - could not remove p2p interface");
873 return -1;
874 }
875#endif
876
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800877 property_set("ctl.stop", supplicant_name);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800878 sched_yield();
879
880 while (count-- > 0) {
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800881 if (property_get(supplicant_prop_name, supp_status, NULL)) {
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300882 if (strcmp(supp_status, "stopped") == 0) {
883 wifi_stop_fstman(0);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800884 return 0;
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300885 }
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800886 }
887 usleep(100000);
888 }
Irfan Sheriff745e7fd2012-11-03 23:21:39 -0700889 ALOGE("Failed to stop supplicant");
Dedy Lansky8dcf57a2015-09-10 17:09:49 +0300890 wifi_stop_fstman(0);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800891 return -1;
892}
893
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700894int wifi_connect_on_socket_path(const char *path)
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800895{
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800896 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
897
898 /* Make sure supplicant is running */
Irfan Sheriff096e49c2012-01-10 16:24:51 -0800899 if (!property_get(supplicant_prop_name, supp_status, NULL)
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800900 || strcmp(supp_status, "running") != 0) {
Steve Block5efbd422012-01-08 10:18:02 +0000901 ALOGE("Supplicant not running, cannot connect");
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800902 return -1;
903 }
904
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700905 ctrl_conn = wpa_ctrl_open(path);
906 if (ctrl_conn == NULL) {
Steve Block5efbd422012-01-08 10:18:02 +0000907 ALOGE("Unable to open connection to supplicant on \"%s\": %s",
Irfan Sheriffda529302011-12-27 13:50:07 -0800908 path, strerror(errno));
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800909 return -1;
910 }
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700911 monitor_conn = wpa_ctrl_open(path);
912 if (monitor_conn == NULL) {
913 wpa_ctrl_close(ctrl_conn);
914 ctrl_conn = NULL;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800915 return -1;
916 }
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700917 if (wpa_ctrl_attach(monitor_conn) != 0) {
918 wpa_ctrl_close(monitor_conn);
919 wpa_ctrl_close(ctrl_conn);
920 ctrl_conn = monitor_conn = NULL;
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800921 return -1;
922 }
Irfan Sheriff025321a2011-09-19 15:03:45 -0700923
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700924 if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
925 wpa_ctrl_close(monitor_conn);
926 wpa_ctrl_close(ctrl_conn);
927 ctrl_conn = monitor_conn = NULL;
Irfan Sheriff025321a2011-09-19 15:03:45 -0700928 return -1;
929 }
930
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800931 return 0;
932}
933
Irfan Sheriffda529302011-12-27 13:50:07 -0800934/* Establishes the control and monitor socket connections on the interface */
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700935int wifi_connect_to_supplicant()
Irfan Sheriffda529302011-12-27 13:50:07 -0800936{
Dmitry Shmidtec057602013-05-29 10:34:39 -0700937 static char path[PATH_MAX];
Irfan Sheriffda529302011-12-27 13:50:07 -0800938
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700939 if (access(IFACE_DIR, F_OK) == 0) {
940 snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
Irfan Sheriffda529302011-12-27 13:50:07 -0800941 } else {
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700942 snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface);
Irfan Sheriffda529302011-12-27 13:50:07 -0800943 }
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700944 return wifi_connect_on_socket_path(path);
Irfan Sheriffda529302011-12-27 13:50:07 -0800945}
946
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700947int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800948{
949 int ret;
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700950 if (ctrl_conn == NULL) {
Steve Block6a705182011-10-20 11:56:19 +0100951 ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800952 return -1;
953 }
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700954 ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800955 if (ret == -2) {
Steve Blockb381b932011-12-20 16:25:34 +0000956 ALOGD("'%s' command timed out.\n", cmd);
Irfan Sheriff025321a2011-09-19 15:03:45 -0700957 /* unblocks the monitor receive socket for termination */
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700958 TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
The Android Open Source Projectcc490162009-03-03 19:32:14 -0800959 return -2;
960 } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
961 return -1;
962 }
963 if (strncmp(cmd, "PING", 4) == 0) {
964 reply[*reply_len] = '\0';
965 }
966 return 0;
967}
968
Maheshff6902d2014-05-14 18:56:15 +0530969int wifi_supplicant_connection_active()
970{
971 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
972
973 if (property_get(supplicant_prop_name, supp_status, NULL)) {
974 if (strcmp(supp_status, "stopped") == 0)
975 return -1;
976 }
977
978 return 0;
979}
980
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700981int wifi_ctrl_recv(char *reply, size_t *reply_len)
Irfan Sheriff025321a2011-09-19 15:03:45 -0700982{
983 int res;
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700984 int ctrlfd = wpa_ctrl_get_fd(monitor_conn);
Dmitry Shmidt45bf8a62011-09-27 17:20:11 -0700985 struct pollfd rfds[2];
Irfan Sheriff025321a2011-09-19 15:03:45 -0700986
Dmitry Shmidt45bf8a62011-09-27 17:20:11 -0700987 memset(rfds, 0, 2 * sizeof(struct pollfd));
988 rfds[0].fd = ctrlfd;
989 rfds[0].events |= POLLIN;
Vinit Deshapnde0f330482013-08-08 10:39:25 -0700990 rfds[1].fd = exit_sockets[1];
Dmitry Shmidt45bf8a62011-09-27 17:20:11 -0700991 rfds[1].events |= POLLIN;
Maheshff6902d2014-05-14 18:56:15 +0530992 do {
993 res = TEMP_FAILURE_RETRY(poll(rfds, 2, 30000));
994 if (res < 0) {
995 ALOGE("Error poll = %d", res);
996 return res;
997 } else if (res == 0) {
998 /* timed out, check if supplicant is active
999 * or not ..
1000 */
1001 res = wifi_supplicant_connection_active();
1002 if (res < 0)
1003 return -2;
1004 }
1005 } while (res == 0);
1006
Dmitry Shmidt45bf8a62011-09-27 17:20:11 -07001007 if (rfds[0].revents & POLLIN) {
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001008 return wpa_ctrl_recv(monitor_conn, reply, reply_len);
Irfan Sheriff025321a2011-09-19 15:03:45 -07001009 }
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001010
1011 /* it is not rfds[0], then it must be rfts[1] (i.e. the exit socket)
1012 * or we timed out. In either case, this call has failed ..
1013 */
Irfan Sheriff897f6dd2012-10-10 15:41:13 -07001014 return -2;
Irfan Sheriff025321a2011-09-19 15:03:45 -07001015}
1016
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001017int wifi_wait_on_socket(char *buf, size_t buflen)
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001018{
1019 size_t nread = buflen - 1;
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001020 int result;
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001021 char *match, *match2;
Dmitry Shmidt0e9f4882011-01-04 16:35:18 -08001022
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001023 if (monitor_conn == NULL) {
Mahesh0ef9a332014-05-13 13:59:05 +05301024 return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
1025 primary_iface, WPA_EVENT_TERMINATING);
Irfan Sheriff2631f992010-01-27 15:35:28 -08001026 }
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001027
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001028 result = wifi_ctrl_recv(buf, &nread);
Irfan Sheriff096e49c2012-01-10 16:24:51 -08001029
1030 /* Terminate reception on exit socket */
1031 if (result == -2) {
Mahesh0ef9a332014-05-13 13:59:05 +05301032 return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
1033 primary_iface, WPA_EVENT_TERMINATING);
Irfan Sheriff096e49c2012-01-10 16:24:51 -08001034 }
1035
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001036 if (result < 0) {
Steve Blockb381b932011-12-20 16:25:34 +00001037 ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno));
Mahesh0ef9a332014-05-13 13:59:05 +05301038 return snprintf(buf, buflen, "IFNAME=%s %s - recv error",
1039 primary_iface, WPA_EVENT_TERMINATING);
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001040 }
1041 buf[nread] = '\0';
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001042 /* Check for EOF on the socket */
1043 if (result == 0 && nread == 0) {
1044 /* Fabricate an event to pass up */
Steve Blockb381b932011-12-20 16:25:34 +00001045 ALOGD("Received EOF on supplicant socket\n");
Mahesh0ef9a332014-05-13 13:59:05 +05301046 return snprintf(buf, buflen, "IFNAME=%s %s - signal 0 received",
1047 primary_iface, WPA_EVENT_TERMINATING);
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001048 }
1049 /*
1050 * Events strings are in the format
1051 *
Dmitry Shmidtec057602013-05-29 10:34:39 -07001052 * IFNAME=iface <N>CTRL-EVENT-XXX
1053 * or
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001054 * <N>CTRL-EVENT-XXX
1055 *
1056 * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
1057 * etc.) and XXX is the event name. The level information is not useful
1058 * to us, so strip it off.
1059 */
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001060
Dmitry Shmidtec057602013-05-29 10:34:39 -07001061 if (strncmp(buf, IFNAME, IFNAMELEN) == 0) {
1062 match = strchr(buf, ' ');
1063 if (match != NULL) {
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001064 if (match[1] == '<') {
1065 match2 = strchr(match + 2, '>');
1066 if (match2 != NULL) {
1067 nread -= (match2 - match);
1068 memmove(match + 1, match2 + 1, nread - (match - buf) + 1);
1069 }
Dmitry Shmidtec057602013-05-29 10:34:39 -07001070 }
Dmitry Shmidtec057602013-05-29 10:34:39 -07001071 } else {
1072 return snprintf(buf, buflen, "%s", WPA_EVENT_IGNORE);
1073 }
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001074 } else if (buf[0] == '<') {
Dmitry Shmidtec057602013-05-29 10:34:39 -07001075 match = strchr(buf, '>');
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001076 if (match != NULL) {
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001077 nread -= (match + 1 - buf);
1078 memmove(buf, match + 1, nread + 1);
1079 ALOGV("supplicant generated event without interface - %s\n", buf);
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001080 }
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001081 } else {
1082 /* let the event go as is! */
1083 ALOGW("supplicant generated event without interface and without message level - %s\n", buf);
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001084 }
Irfan Sheriff096e49c2012-01-10 16:24:51 -08001085
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001086 return nread;
1087}
1088
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001089int wifi_wait_for_event(char *buf, size_t buflen)
Irfan Sheriffda529302011-12-27 13:50:07 -08001090{
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001091 return wifi_wait_on_socket(buf, buflen);
1092}
1093
1094void wifi_close_sockets()
1095{
1096 if (ctrl_conn != NULL) {
1097 wpa_ctrl_close(ctrl_conn);
1098 ctrl_conn = NULL;
1099 }
1100
1101 if (monitor_conn != NULL) {
1102 wpa_ctrl_close(monitor_conn);
1103 monitor_conn = NULL;
1104 }
1105
1106 if (exit_sockets[0] >= 0) {
1107 close(exit_sockets[0]);
1108 exit_sockets[0] = -1;
1109 }
1110
1111 if (exit_sockets[1] >= 0) {
1112 close(exit_sockets[1]);
1113 exit_sockets[1] = -1;
Irfan Sheriffda529302011-12-27 13:50:07 -08001114 }
1115}
1116
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001117void wifi_close_supplicant_connection()
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001118{
Irfan Sheriff5a8a2d22011-08-22 13:27:56 -07001119 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
1120 int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */
1121
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001122 wifi_close_sockets();
Irfan Sheriff025321a2011-09-19 15:03:45 -07001123
Irfan Sheriff5a8a2d22011-08-22 13:27:56 -07001124 while (count-- > 0) {
Irfan Sheriff096e49c2012-01-10 16:24:51 -08001125 if (property_get(supplicant_prop_name, supp_status, NULL)) {
Irfan Sheriff5a8a2d22011-08-22 13:27:56 -07001126 if (strcmp(supp_status, "stopped") == 0)
1127 return;
1128 }
1129 usleep(100000);
1130 }
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001131}
1132
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001133int wifi_command(const char *command, char *reply, size_t *reply_len)
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001134{
Vinit Deshapnde0f330482013-08-08 10:39:25 -07001135 return wifi_send_command(command, reply, reply_len);
The Android Open Source Projectcc490162009-03-03 19:32:14 -08001136}
Dmitry Shmidt4b7ffa02011-07-01 11:03:43 -07001137
1138const char *wifi_get_fw_path(int fw_type)
1139{
1140 switch (fw_type) {
1141 case WIFI_GET_FW_PATH_STA:
1142 return WIFI_DRIVER_FW_PATH_STA;
1143 case WIFI_GET_FW_PATH_AP:
1144 return WIFI_DRIVER_FW_PATH_AP;
1145 case WIFI_GET_FW_PATH_P2P:
1146 return WIFI_DRIVER_FW_PATH_P2P;
1147 }
1148 return NULL;
1149}
Dmitry Shmidt29a4d4d2011-07-19 15:59:13 -07001150
1151int wifi_change_fw_path(const char *fwpath)
1152{
1153 int len;
1154 int fd;
1155 int ret = 0;
1156
1157 if (!fwpath)
1158 return ret;
Kenny Rootcf449e12012-03-15 13:10:19 -07001159 fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY));
Dmitry Shmidt29a4d4d2011-07-19 15:59:13 -07001160 if (fd < 0) {
Steve Block5efbd422012-01-08 10:18:02 +00001161 ALOGE("Failed to open wlan fw path param (%s)", strerror(errno));
Dmitry Shmidt29a4d4d2011-07-19 15:59:13 -07001162 return -1;
1163 }
1164 len = strlen(fwpath) + 1;
Kenny Rootcf449e12012-03-15 13:10:19 -07001165 if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) {
Steve Block5efbd422012-01-08 10:18:02 +00001166 ALOGE("Failed to write wlan fw path param (%s)", strerror(errno));
Dmitry Shmidt29a4d4d2011-07-19 15:59:13 -07001167 ret = -1;
1168 }
1169 close(fd);
1170 return ret;
1171}
Steve Kondik56be7092012-12-20 20:39:18 -08001172
1173int wifi_set_mode(int mode) {
1174 wifi_mode = mode;
1175 return 0;
1176}