The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1 | /* |
| 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 Shmidt | eea19f1 | 2011-03-25 13:37:18 -0700 | [diff] [blame] | 21 | #include <dirent.h> |
Dmitry Shmidt | 45bf8a6 | 2011-09-27 17:20:11 -0700 | [diff] [blame] | 22 | #include <sys/socket.h> |
Mark Salyzyn | 2263e47 | 2015-04-01 07:33:14 -0700 | [diff] [blame] | 23 | #include <sys/stat.h> |
Kenny Root | cf449e1 | 2012-03-15 13:10:19 -0700 | [diff] [blame] | 24 | #include <unistd.h> |
Dmitry Shmidt | 45bf8a6 | 2011-09-27 17:20:11 -0700 | [diff] [blame] | 25 | #include <poll.h> |
Ravi Kumar Siddojigari | 02bd5eb | 2016-06-24 21:54:26 +0530 | [diff] [blame] | 26 | #include <sys/syscall.h> |
Ricardo Cerqueira | ec79cde | 2013-11-01 20:36:26 +0000 | [diff] [blame] | 27 | |
| 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 39 | #include "hardware_legacy/wifi.h" |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 40 | #include "wifi_fst.h" |
Dmitry Shmidt | 41d81d1 | 2013-11-22 15:54:27 -0800 | [diff] [blame] | 41 | #ifdef LIBWPA_CLIENT_EXISTS |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 42 | #include "libwpa_client/wpa_ctrl.h" |
Dmitry Shmidt | 41d81d1 | 2013-11-22 15:54:27 -0800 | [diff] [blame] | 43 | #endif |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 44 | |
| 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 Hughes | 7a070c6 | 2015-01-12 11:38:56 -0800 | [diff] [blame] | 51 | |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 52 | #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ |
| 53 | #include <sys/_system_properties.h> |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 54 | |
Jean-Baptiste Queru | 445591d | 2010-06-21 13:15:01 -0700 | [diff] [blame] | 55 | extern int do_dhcp(); |
| 56 | extern int ifc_init(); |
| 57 | extern void ifc_close(); |
| 58 | extern char *dhcp_lasterror(); |
| 59 | extern void get_dhcp_info(); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 60 | extern int init_module(void *, unsigned long, const char *); |
| 61 | extern int delete_module(const char *, unsigned int); |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 62 | void wifi_close_sockets(); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 63 | |
Dmitry Shmidt | 41d81d1 | 2013-11-22 15:54:27 -0800 | [diff] [blame] | 64 | #ifndef LIBWPA_CLIENT_EXISTS |
| 65 | #define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING " |
| 66 | struct wpa_ctrl {}; |
| 67 | void wpa_ctrl_cleanup(void) {} |
| 68 | struct wpa_ctrl *wpa_ctrl_open(const char *ctrl_path) { return NULL; } |
| 69 | void wpa_ctrl_close(struct wpa_ctrl *ctrl) {} |
| 70 | int 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; } |
| 73 | int wpa_ctrl_attach(struct wpa_ctrl *ctrl) { return 0; } |
| 74 | int wpa_ctrl_detach(struct wpa_ctrl *ctrl) { return 0; } |
| 75 | int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) |
| 76 | { return 0; } |
| 77 | int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) { return 0; } |
| 78 | #endif |
| 79 | |
| 80 | static struct wpa_ctrl *ctrl_conn; |
| 81 | static struct wpa_ctrl *monitor_conn; |
| 82 | |
| 83 | /* socket pair used to exit from a blocking read */ |
| 84 | static int exit_sockets[2]; |
Steve Kondik | 56be709 | 2012-12-20 20:39:18 -0800 | [diff] [blame] | 85 | static int wifi_mode = 0; |
Dmitry Shmidt | 41d81d1 | 2013-11-22 15:54:27 -0800 | [diff] [blame] | 86 | |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 87 | static char primary_iface[PROPERTY_VALUE_MAX]; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 88 | // TODO: use new ANDROID_SOCKET mechanism, once support for multiple |
| 89 | // sockets is in |
| 90 | |
Ricardo Cerqueira | ec79cde | 2013-11-01 20:36:26 +0000 | [diff] [blame] | 91 | #ifdef USES_TI_MAC80211 |
| 92 | #define P2P_INTERFACE "p2p0" |
| 93 | struct nl_sock *nl_soc; |
| 94 | struct nl_cache *nl_cache; |
| 95 | struct genl_family *nl80211; |
| 96 | #endif |
| 97 | |
Dmitry Shmidt | 243af8b | 2009-04-20 09:06:40 -0700 | [diff] [blame] | 98 | #ifndef WIFI_DRIVER_MODULE_ARG |
| 99 | #define WIFI_DRIVER_MODULE_ARG "" |
| 100 | #endif |
Steve Kondik | 56be709 | 2012-12-20 20:39:18 -0800 | [diff] [blame] | 101 | #ifndef WIFI_DRIVER_MODULE_AP_ARG |
| 102 | #define WIFI_DRIVER_MODULE_AP_ARG "" |
| 103 | #endif |
Dmitry Shmidt | 243af8b | 2009-04-20 09:06:40 -0700 | [diff] [blame] | 104 | #ifndef WIFI_FIRMWARE_LOADER |
| 105 | #define WIFI_FIRMWARE_LOADER "" |
| 106 | #endif |
| 107 | #define WIFI_TEST_INTERFACE "sta" |
| 108 | |
Dmitry Shmidt | 4b7ffa0 | 2011-07-01 11:03:43 -0700 | [diff] [blame] | 109 | #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 | |
jerpelea | 94ac271 | 2011-11-22 09:40:37 +0200 | [diff] [blame] | 119 | #ifdef WIFI_EXT_MODULE_NAME |
| 120 | static const char EXT_MODULE_NAME[] = WIFI_EXT_MODULE_NAME; |
| 121 | #ifdef WIFI_EXT_MODULE_ARG |
| 122 | static const char EXT_MODULE_ARG[] = WIFI_EXT_MODULE_ARG; |
| 123 | #else |
| 124 | static const char EXT_MODULE_ARG[] = ""; |
| 125 | #endif |
| 126 | #endif |
| 127 | #ifdef WIFI_EXT_MODULE_PATH |
| 128 | static const char EXT_MODULE_PATH[] = WIFI_EXT_MODULE_PATH; |
| 129 | #endif |
| 130 | |
Dmitry Shmidt | 29a4d4d | 2011-07-19 15:59:13 -0700 | [diff] [blame] | 131 | #ifndef WIFI_DRIVER_FW_PATH_PARAM |
| 132 | #define WIFI_DRIVER_FW_PATH_PARAM "/sys/module/wlan/parameters/fwpath" |
| 133 | #endif |
| 134 | |
Dmitry Shmidt | ed84872 | 2010-02-25 12:34:42 -0800 | [diff] [blame] | 135 | #define WIFI_DRIVER_LOADER_DELAY 1000000 |
| 136 | |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 137 | static const char IFACE_DIR[] = "/data/system/wpa_supplicant"; |
Dmitry Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 138 | #ifdef WIFI_DRIVER_MODULE_PATH |
Dmitry Shmidt | 243af8b | 2009-04-20 09:06:40 -0700 | [diff] [blame] | 139 | static const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME; |
| 140 | static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " "; |
| 141 | static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH; |
| 142 | static const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG; |
Steve Kondik | 56be709 | 2012-12-20 20:39:18 -0800 | [diff] [blame] | 143 | static const char DRIVER_MODULE_AP_ARG[] = WIFI_DRIVER_MODULE_AP_ARG; |
Dmitry Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 144 | #endif |
Dmitry Shmidt | 243af8b | 2009-04-20 09:06:40 -0700 | [diff] [blame] | 145 | static const char FIRMWARE_LOADER[] = WIFI_FIRMWARE_LOADER; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 146 | static const char DRIVER_PROP_NAME[] = "wlan.driver.status"; |
| 147 | static const char SUPPLICANT_NAME[] = "wpa_supplicant"; |
| 148 | static const char SUPP_PROP_NAME[] = "init.svc.wpa_supplicant"; |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 149 | static const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant"; |
| 150 | static const char P2P_PROP_NAME[] = "init.svc.p2p_supplicant"; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 151 | static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf"; |
| 152 | static const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf"; |
Irfan Sheriff | 67ba227 | 2011-08-26 14:39:38 -0700 | [diff] [blame] | 153 | static const char P2P_CONFIG_FILE[] = "/data/misc/wifi/p2p_supplicant.conf"; |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 154 | static const char CONTROL_IFACE_PATH[] = "/data/misc/wifi/sockets"; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 155 | static const char MODULE_FILE[] = "/proc/modules"; |
| 156 | |
Dmitry Shmidt | ec05760 | 2013-05-29 10:34:39 -0700 | [diff] [blame] | 157 | static const char IFNAME[] = "IFNAME="; |
| 158 | #define IFNAMELEN (sizeof(IFNAME) - 1) |
| 159 | static const char WPA_EVENT_IGNORE[] = "CTRL-EVENT-IGNORE "; |
| 160 | |
Dmitry Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 161 | static const char SUPP_ENTROPY_FILE[] = WIFI_ENTROPY_FILE; |
Dmitry Shmidt | 07a629e | 2011-10-06 13:28:32 -0700 | [diff] [blame] | 162 | static 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 Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 166 | |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 167 | /* Is either SUPPLICANT_NAME or P2P_SUPPLICANT_NAME */ |
| 168 | static char supplicant_name[PROPERTY_VALUE_MAX]; |
| 169 | /* Is either SUPP_PROP_NAME or P2P_PROP_NAME */ |
| 170 | static char supplicant_prop_name[PROPERTY_KEY_MAX]; |
| 171 | |
Ricardo Cerqueira | 0b7cb77 | 2013-11-01 20:35:09 +0000 | [diff] [blame] | 172 | #ifdef SAMSUNG_WIFI |
| 173 | char* 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 Chen | 2da3d27 | 2013-07-31 16:41:56 -0700 | [diff] [blame] | 193 | if (strncmp(buf, "semcosh", 7) == 0) |
| 194 | return "_semcosh"; |
| 195 | |
Christopher N. Hesse | d6f4b6b | 2015-01-26 22:01:59 +0100 | [diff] [blame] | 196 | if (strncmp(buf, "semco", 5) == 0) |
| 197 | return "_semco"; |
| 198 | |
Ricardo Cerqueira | 0b7cb77 | 2013-11-01 20:35:09 +0000 | [diff] [blame] | 199 | return NULL; |
| 200 | } |
| 201 | #endif |
| 202 | |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 203 | int insmod(const char *filename, const char *args) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 204 | { |
Ravi Kumar Siddojigari | 02bd5eb | 2016-06-24 21:54:26 +0530 | [diff] [blame] | 205 | /* 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 210 | return -1; |
Ravi Kumar Siddojigari | 02bd5eb | 2016-06-24 21:54:26 +0530 | [diff] [blame] | 211 | } |
| 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 218 | } |
| 219 | |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 220 | int rmmod(const char *modname) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 221 | { |
| 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 Block | b381b93 | 2011-12-20 16:25:34 +0000 | [diff] [blame] | 234 | ALOGD("Unable to unload driver module \"%s\": %s\n", |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 235 | modname, strerror(errno)); |
| 236 | return ret; |
| 237 | } |
| 238 | |
Jean-Baptiste Queru | 445591d | 2010-06-21 13:15:01 -0700 | [diff] [blame] | 239 | int 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 Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 242 | if (strcmp(primary_iface, WIFI_TEST_INTERFACE) == 0) |
Jean-Baptiste Queru | 445591d | 2010-06-21 13:15:01 -0700 | [diff] [blame] | 243 | return 0; |
| 244 | |
| 245 | if (ifc_init() < 0) |
| 246 | return -1; |
| 247 | |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 248 | if (do_dhcp(primary_iface) < 0) { |
Jean-Baptiste Queru | 445591d | 2010-06-21 13:15:01 -0700 | [diff] [blame] | 249 | 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 | |
| 257 | const char *get_dhcp_error_string() { |
| 258 | return dhcp_lasterror(); |
| 259 | } |
| 260 | |
Maddest Chang | da1c7fa | 2015-07-10 19:39:05 +0800 | [diff] [blame] | 261 | #ifdef WIFI_DRIVER_STATE_CTRL_PARAM |
| 262 | int 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 Sheriff | 2bb990b | 2010-07-27 12:16:08 -0700 | [diff] [blame] | 285 | int is_wifi_driver_loaded() { |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 286 | char driver_status[PROPERTY_VALUE_MAX]; |
Dmitry Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 287 | #ifdef WIFI_DRIVER_MODULE_PATH |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 288 | FILE *proc; |
| 289 | char line[sizeof(DRIVER_MODULE_TAG)+10]; |
Dmitry Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 290 | #endif |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 291 | |
| 292 | if (!property_get(DRIVER_PROP_NAME, driver_status, NULL) |
| 293 | || strcmp(driver_status, "ok") != 0) { |
| 294 | return 0; /* driver not loaded */ |
| 295 | } |
Dmitry Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 296 | #ifdef WIFI_DRIVER_MODULE_PATH |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 297 | /* |
| 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 Block | 64cca04 | 2012-01-05 23:27:53 +0000 | [diff] [blame] | 304 | ALOGW("Could not open %s: %s", MODULE_FILE, strerror(errno)); |
Dmitry Shmidt | 243af8b | 2009-04-20 09:06:40 -0700 | [diff] [blame] | 305 | property_set(DRIVER_PROP_NAME, "unloaded"); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 306 | 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 Lansky | 79a0eb4 | 2016-08-07 11:39:11 +0300 | [diff] [blame] | 311 | return 1; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 312 | } |
| 313 | } |
| 314 | fclose(proc); |
| 315 | property_set(DRIVER_PROP_NAME, "unloaded"); |
| 316 | return 0; |
Dmitry Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 317 | #else |
| 318 | return 1; |
| 319 | #endif |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 320 | } |
| 321 | |
| 322 | int wifi_load_driver() |
| 323 | { |
Dmitry Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 324 | #ifdef WIFI_DRIVER_MODULE_PATH |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 325 | char driver_status[PROPERTY_VALUE_MAX]; |
| 326 | int count = 100; /* wait at most 20 seconds for completion */ |
Ricardo Cerqueira | 0b7cb77 | 2013-11-01 20:35:09 +0000 | [diff] [blame] | 327 | char module_arg2[256]; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 328 | |
Irfan Sheriff | 2bb990b | 2010-07-27 12:16:08 -0700 | [diff] [blame] | 329 | if (is_wifi_driver_loaded()) { |
Dedy Lansky | 79a0eb4 | 2016-08-07 11:39:11 +0300 | [diff] [blame] | 330 | return wifi_fst_load_driver(); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 331 | } |
| 332 | |
Ricardo Cerqueira | 0b7cb77 | 2013-11-01 20:35:09 +0000 | [diff] [blame] | 333 | #ifdef SAMSUNG_WIFI |
| 334 | char* type = get_samsung_wifi_type(); |
codeworkx | 6e7ecf1 | 2012-12-22 13:04:14 +0100 | [diff] [blame] | 335 | |
| 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 Cerqueira | 0b7cb77 | 2013-11-01 20:35:09 +0000 | [diff] [blame] | 341 | |
| 342 | if (insmod(DRIVER_MODULE_PATH, module_arg2) < 0) { |
| 343 | #else |
jerpelea | 94ac271 | 2011-11-22 09:40:37 +0200 | [diff] [blame] | 344 | |
Michaël Burtin | ece9465 | 2012-01-15 22:43:31 +0100 | [diff] [blame] | 345 | property_set(DRIVER_PROP_NAME, "loading"); |
| 346 | |
jerpelea | 94ac271 | 2011-11-22 09:40:37 +0200 | [diff] [blame] | 347 | #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 Cerqueira | 0b7cb77 | 2013-11-01 20:35:09 +0000 | [diff] [blame] | 353 | 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 359 | return -1; |
Ricardo Cerqueira | 0b7cb77 | 2013-11-01 20:35:09 +0000 | [diff] [blame] | 360 | } |
Dmitry Shmidt | 243af8b | 2009-04-20 09:06:40 -0700 | [diff] [blame] | 361 | |
| 362 | if (strcmp(FIRMWARE_LOADER,"") == 0) { |
Dmitry Shmidt | 8fb5f74 | 2010-09-14 15:11:22 -0700 | [diff] [blame] | 363 | /* usleep(WIFI_DRIVER_LOADER_DELAY); */ |
Dmitry Shmidt | 243af8b | 2009-04-20 09:06:40 -0700 | [diff] [blame] | 364 | property_set(DRIVER_PROP_NAME, "ok"); |
| 365 | } |
| 366 | else { |
| 367 | property_set("ctl.start", FIRMWARE_LOADER); |
| 368 | } |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 369 | sched_yield(); |
| 370 | while (count-- > 0) { |
| 371 | if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) { |
| 372 | if (strcmp(driver_status, "ok") == 0) |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 373 | return wifi_fst_load_driver(); |
Ajay Dudani | 85bff33 | 2015-05-03 17:32:49 -0700 | [diff] [blame] | 374 | else if (strcmp(driver_status, "failed") == 0) { |
Dmitry Shmidt | 7b43699 | 2009-07-28 11:03:31 -0700 | [diff] [blame] | 375 | wifi_unload_driver(); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 376 | return -1; |
Dmitry Shmidt | 7b43699 | 2009-07-28 11:03:31 -0700 | [diff] [blame] | 377 | } |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 378 | } |
| 379 | usleep(200000); |
| 380 | } |
| 381 | property_set(DRIVER_PROP_NAME, "timeout"); |
Dmitry Shmidt | 7b43699 | 2009-07-28 11:03:31 -0700 | [diff] [blame] | 382 | wifi_unload_driver(); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 383 | return -1; |
Dmitry Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 384 | #else |
Maddest Chang | da1c7fa | 2015-07-10 19:39:05 +0800 | [diff] [blame] | 385 | #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 Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 393 | property_set(DRIVER_PROP_NAME, "ok"); |
| 394 | return 0; |
| 395 | #endif |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 396 | } |
| 397 | |
| 398 | int wifi_unload_driver() |
| 399 | { |
Dmitry Shmidt | 4c1a1fe | 2011-06-13 10:32:08 -0700 | [diff] [blame] | 400 | usleep(200000); /* allow to finish interface down */ |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 401 | |
| 402 | wifi_fst_unload_driver(); |
| 403 | |
Dmitry Shmidt | 953c114 | 2011-08-23 15:44:23 -0700 | [diff] [blame] | 404 | #ifdef WIFI_DRIVER_MODULE_PATH |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 405 | if (rmmod(DRIVER_MODULE_NAME) == 0) { |
Dmitry Shmidt | 953c114 | 2011-08-23 15:44:23 -0700 | [diff] [blame] | 406 | int count = 20; /* wait at most 10 seconds for completion */ |
Dmitry Shmidt | 0e9f488 | 2011-01-04 16:35:18 -0800 | [diff] [blame] | 407 | while (count-- > 0) { |
| 408 | if (!is_wifi_driver_loaded()) |
| 409 | break; |
| 410 | usleep(500000); |
| 411 | } |
Dmitry Shmidt | 953c114 | 2011-08-23 15:44:23 -0700 | [diff] [blame] | 412 | usleep(500000); /* allow card removal */ |
Dmitry Shmidt | 0e9f488 | 2011-01-04 16:35:18 -0800 | [diff] [blame] | 413 | if (count) { |
jerpelea | 94ac271 | 2011-11-22 09:40:37 +0200 | [diff] [blame] | 414 | #ifdef WIFI_EXT_MODULE_NAME |
| 415 | if (rmmod(EXT_MODULE_NAME) == 0) |
| 416 | #endif |
Dmitry Shmidt | 0e9f488 | 2011-01-04 16:35:18 -0800 | [diff] [blame] | 417 | return 0; |
| 418 | } |
| 419 | return -1; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 420 | } else |
| 421 | return -1; |
Dmitry Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 422 | #else |
Maddest Chang | da1c7fa | 2015-07-10 19:39:05 +0800 | [diff] [blame] | 423 | #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 Shmidt | d301cb7 | 2011-06-29 16:22:28 -0700 | [diff] [blame] | 429 | property_set(DRIVER_PROP_NAME, "unloaded"); |
| 430 | return 0; |
| 431 | #endif |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 432 | } |
| 433 | |
Dmitry Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 434 | int 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 Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 443 | ALOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); |
Dmitry Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 444 | return -1; |
| 445 | } |
| 446 | return 0; |
| 447 | } |
Kenny Root | cf449e1 | 2012-03-15 13:10:19 -0700 | [diff] [blame] | 448 | destfd = TEMP_FAILURE_RETRY(open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660)); |
Dmitry Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 449 | if (destfd < 0) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 450 | ALOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); |
Dmitry Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 451 | return -1; |
| 452 | } |
| 453 | |
Kenny Root | cf449e1 | 2012-03-15 13:10:19 -0700 | [diff] [blame] | 454 | if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 455 | ALOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); |
Dmitry Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 456 | 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 Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 463 | ALOGE("Error changing permissions of %s to 0660: %s", |
Dmitry Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 464 | 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 Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 470 | ALOGE("Error changing group ownership of %s to %d: %s", |
Dmitry Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 471 | SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno)); |
| 472 | unlink(SUPP_ENTROPY_FILE); |
| 473 | return -1; |
| 474 | } |
| 475 | return 0; |
| 476 | } |
| 477 | |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 478 | int ensure_config_file_exists(const char *config_file, const char *config_file_template) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 479 | { |
| 480 | char buf[2048]; |
| 481 | int srcfd, destfd; |
Irfan Sheriff | 8a5b197 | 2010-12-16 16:17:29 -0800 | [diff] [blame] | 482 | struct stat sb; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 483 | int nread; |
Dmitry Shmidt | 89ae703 | 2011-03-07 15:30:53 -0800 | [diff] [blame] | 484 | int ret; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 485 | |
Irfan Sheriff | 67ba227 | 2011-08-26 14:39:38 -0700 | [diff] [blame] | 486 | ret = access(config_file, R_OK|W_OK); |
Dmitry Shmidt | 89ae703 | 2011-03-07 15:30:53 -0800 | [diff] [blame] | 487 | if ((ret == 0) || (errno == EACCES)) { |
| 488 | if ((ret != 0) && |
Irfan Sheriff | 67ba227 | 2011-08-26 14:39:38 -0700 | [diff] [blame] | 489 | (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 490 | ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno)); |
Dmitry Shmidt | 89ae703 | 2011-03-07 15:30:53 -0800 | [diff] [blame] | 491 | return -1; |
| 492 | } |
Dmitry Shmidt | c6bb3b5 | 2013-10-04 15:49:11 -0700 | [diff] [blame] | 493 | return 0; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 494 | } else if (errno != ENOENT) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 495 | ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno)); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 496 | return -1; |
| 497 | } |
| 498 | |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 499 | srcfd = TEMP_FAILURE_RETRY(open(config_file_template, O_RDONLY)); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 500 | if (srcfd < 0) { |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 501 | ALOGE("Cannot open \"%s\": %s", config_file_template, strerror(errno)); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 502 | return -1; |
| 503 | } |
| 504 | |
Kenny Root | cf449e1 | 2012-03-15 13:10:19 -0700 | [diff] [blame] | 505 | destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT|O_RDWR, 0660)); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 506 | if (destfd < 0) { |
| 507 | close(srcfd); |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 508 | ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno)); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 509 | return -1; |
| 510 | } |
| 511 | |
Kenny Root | cf449e1 | 2012-03-15 13:10:19 -0700 | [diff] [blame] | 512 | while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) { |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 513 | if (nread < 0) { |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 514 | ALOGE("Error reading \"%s\": %s", config_file_template, strerror(errno)); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 515 | close(srcfd); |
| 516 | close(destfd); |
Irfan Sheriff | 67ba227 | 2011-08-26 14:39:38 -0700 | [diff] [blame] | 517 | unlink(config_file); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 518 | return -1; |
| 519 | } |
Kenny Root | cf449e1 | 2012-03-15 13:10:19 -0700 | [diff] [blame] | 520 | TEMP_FAILURE_RETRY(write(destfd, buf, nread)); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 521 | } |
| 522 | |
| 523 | close(destfd); |
| 524 | close(srcfd); |
| 525 | |
Dmitry Shmidt | 24bf7fc | 2010-08-09 11:04:49 -0700 | [diff] [blame] | 526 | /* chmod is needed because open() didn't set permisions properly */ |
Irfan Sheriff | 67ba227 | 2011-08-26 14:39:38 -0700 | [diff] [blame] | 527 | if (chmod(config_file, 0660) < 0) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 528 | ALOGE("Error changing permissions of %s to 0660: %s", |
Irfan Sheriff | 67ba227 | 2011-08-26 14:39:38 -0700 | [diff] [blame] | 529 | config_file, strerror(errno)); |
| 530 | unlink(config_file); |
Dmitry Shmidt | 24bf7fc | 2010-08-09 11:04:49 -0700 | [diff] [blame] | 531 | return -1; |
| 532 | } |
| 533 | |
Irfan Sheriff | 67ba227 | 2011-08-26 14:39:38 -0700 | [diff] [blame] | 534 | if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 535 | ALOGE("Error changing group ownership of %s to %d: %s", |
Irfan Sheriff | 67ba227 | 2011-08-26 14:39:38 -0700 | [diff] [blame] | 536 | config_file, AID_WIFI, strerror(errno)); |
| 537 | unlink(config_file); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 538 | return -1; |
| 539 | } |
Dmitry Shmidt | c6bb3b5 | 2013-10-04 15:49:11 -0700 | [diff] [blame] | 540 | return 0; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 541 | } |
| 542 | |
Ricardo Cerqueira | ec79cde | 2013-11-01 20:36:26 +0000 | [diff] [blame] | 543 | #ifdef USES_TI_MAC80211 |
| 544 | static 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 | |
| 576 | out_cache_free: |
| 577 | nl_cache_free(nl_cache); |
| 578 | out_handle_destroy: |
| 579 | nl_socket_free(nl_soc); |
| 580 | return err; |
| 581 | } |
| 582 | |
| 583 | static 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 |
| 591 | static 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 |
| 601 | int 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 | |
| 636 | int 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 | |
| 643 | int nl_finish_handler(struct nl_msg *msg, void *arg) |
| 644 | { |
| 645 | int *ret = (int *)arg; |
| 646 | *ret = 0; |
| 647 | return NL_SKIP; |
| 648 | } |
| 649 | |
| 650 | int nl_ack_handler(struct nl_msg *msg, void *arg) |
| 651 | { |
| 652 | int *ret = (int *)arg; |
| 653 | *ret = 0; |
| 654 | return NL_STOP; |
| 655 | } |
| 656 | |
| 657 | static 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); |
| 715 | out: |
| 716 | nl_cb_put(cb); |
| 717 | out_free_msg: |
| 718 | nlmsg_free(msg); |
| 719 | return err; |
| 720 | nla_put_failure: |
| 721 | ALOGW("building message failed"); |
| 722 | return 2; |
| 723 | } |
| 724 | |
| 725 | int 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 | |
| 751 | cleanup: |
| 752 | deinit_nl(); |
| 753 | return ret; |
| 754 | } |
| 755 | #endif /* USES_TI_MAC80211 */ |
| 756 | |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 757 | int wifi_start_supplicant(int p2p_supported) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 758 | { |
| 759 | char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; |
| 760 | int count = 200; /* wait at most 20 seconds for completion */ |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 761 | const prop_info *pi; |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 762 | unsigned serial = 0, i; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 763 | |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 764 | if (wifi_start_fstman(0)) { |
| 765 | return -1; |
| 766 | } |
| 767 | |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 768 | 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 Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 773 | if (ensure_config_file_exists(P2P_CONFIG_FILE, SUPP_CONFIG_TEMPLATE) < 0) { |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 774 | 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 783 | /* Check whether already running */ |
Jonathan DE CESCO | eed817e | 2012-11-20 18:59:34 +0100 | [diff] [blame] | 784 | if (property_get(supplicant_prop_name, supp_status, NULL) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 785 | && strcmp(supp_status, "running") == 0) { |
| 786 | return 0; |
| 787 | } |
| 788 | |
| 789 | /* Before starting the daemon, make sure its config file exists */ |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 790 | if (ensure_config_file_exists(SUPP_CONFIG_FILE, SUPP_CONFIG_TEMPLATE) < 0) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 791 | ALOGE("Wi-Fi will not be enabled"); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 792 | return -1; |
| 793 | } |
| 794 | |
Dmitry Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 795 | if (ensure_entropy_file_exists() < 0) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 796 | ALOGE("Wi-Fi entropy file was not created"); |
Dmitry Shmidt | 3ab3e66 | 2011-07-25 10:46:00 -0700 | [diff] [blame] | 797 | } |
| 798 | |
Ricardo Cerqueira | ec79cde | 2013-11-01 20:36:26 +0000 | [diff] [blame] | 799 | #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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 806 | /* Clear out any stale socket files that might be left over. */ |
Dmitry Shmidt | de9abff | 2013-05-22 16:45:57 -0700 | [diff] [blame] | 807 | wpa_ctrl_cleanup(); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 808 | |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 809 | /* Reset sockets used for exiting from hung state */ |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 810 | exit_sockets[0] = exit_sockets[1] = -1; |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 811 | |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 812 | /* |
| 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 Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 819 | pi = __system_property_find(supplicant_prop_name); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 820 | if (pi != NULL) { |
Colin Cross | 14c02f2 | 2013-02-04 12:34:20 -0800 | [diff] [blame] | 821 | serial = __system_property_serial(pi); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 822 | } |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 823 | property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE); |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 824 | |
| 825 | property_set("ctl.start", supplicant_name); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 826 | sched_yield(); |
| 827 | |
| 828 | while (count-- > 0) { |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 829 | if (pi == NULL) { |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 830 | pi = __system_property_find(supplicant_prop_name); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 831 | } |
| 832 | if (pi != NULL) { |
jiaguo | 4431a1c | 2014-03-13 18:49:14 +0800 | [diff] [blame] | 833 | /* |
| 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 843 | } |
| 844 | } |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 845 | usleep(100000); |
| 846 | } |
| 847 | return -1; |
| 848 | } |
| 849 | |
Irfan Sheriff | 745e7fd | 2012-11-03 23:21:39 -0700 | [diff] [blame] | 850 | int wifi_stop_supplicant(int p2p_supported) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 851 | { |
| 852 | char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; |
| 853 | int count = 50; /* wait at most 5 seconds for completion */ |
| 854 | |
Irfan Sheriff | 745e7fd | 2012-11-03 23:21:39 -0700 | [diff] [blame] | 855 | 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 863 | /* Check whether supplicant already stopped */ |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 864 | if (property_get(supplicant_prop_name, supp_status, NULL) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 865 | && strcmp(supp_status, "stopped") == 0) { |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 866 | wifi_stop_fstman(0); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 867 | return 0; |
| 868 | } |
| 869 | |
Ricardo Cerqueira | ec79cde | 2013-11-01 20:36:26 +0000 | [diff] [blame] | 870 | #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 Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 877 | property_set("ctl.stop", supplicant_name); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 878 | sched_yield(); |
| 879 | |
| 880 | while (count-- > 0) { |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 881 | if (property_get(supplicant_prop_name, supp_status, NULL)) { |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 882 | if (strcmp(supp_status, "stopped") == 0) { |
| 883 | wifi_stop_fstman(0); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 884 | return 0; |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 885 | } |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 886 | } |
| 887 | usleep(100000); |
| 888 | } |
Irfan Sheriff | 745e7fd | 2012-11-03 23:21:39 -0700 | [diff] [blame] | 889 | ALOGE("Failed to stop supplicant"); |
Dedy Lansky | 8dcf57a | 2015-09-10 17:09:49 +0300 | [diff] [blame] | 890 | wifi_stop_fstman(0); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 891 | return -1; |
| 892 | } |
| 893 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 894 | int wifi_connect_on_socket_path(const char *path) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 895 | { |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 896 | char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; |
| 897 | |
| 898 | /* Make sure supplicant is running */ |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 899 | if (!property_get(supplicant_prop_name, supp_status, NULL) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 900 | || strcmp(supp_status, "running") != 0) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 901 | ALOGE("Supplicant not running, cannot connect"); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 902 | return -1; |
| 903 | } |
| 904 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 905 | ctrl_conn = wpa_ctrl_open(path); |
| 906 | if (ctrl_conn == NULL) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 907 | ALOGE("Unable to open connection to supplicant on \"%s\": %s", |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 908 | path, strerror(errno)); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 909 | return -1; |
| 910 | } |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 911 | 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 915 | return -1; |
| 916 | } |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 917 | 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 921 | return -1; |
| 922 | } |
Irfan Sheriff | 025321a | 2011-09-19 15:03:45 -0700 | [diff] [blame] | 923 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 924 | 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 Sheriff | 025321a | 2011-09-19 15:03:45 -0700 | [diff] [blame] | 928 | return -1; |
| 929 | } |
| 930 | |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 931 | return 0; |
| 932 | } |
| 933 | |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 934 | /* Establishes the control and monitor socket connections on the interface */ |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 935 | int wifi_connect_to_supplicant() |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 936 | { |
Dmitry Shmidt | ec05760 | 2013-05-29 10:34:39 -0700 | [diff] [blame] | 937 | static char path[PATH_MAX]; |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 938 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 939 | if (access(IFACE_DIR, F_OK) == 0) { |
| 940 | snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface); |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 941 | } else { |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 942 | snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface); |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 943 | } |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 944 | return wifi_connect_on_socket_path(path); |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 945 | } |
| 946 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 947 | int wifi_send_command(const char *cmd, char *reply, size_t *reply_len) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 948 | { |
| 949 | int ret; |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 950 | if (ctrl_conn == NULL) { |
Steve Block | 6a70518 | 2011-10-20 11:56:19 +0100 | [diff] [blame] | 951 | ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 952 | return -1; |
| 953 | } |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 954 | ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 955 | if (ret == -2) { |
Steve Block | b381b93 | 2011-12-20 16:25:34 +0000 | [diff] [blame] | 956 | ALOGD("'%s' command timed out.\n", cmd); |
Irfan Sheriff | 025321a | 2011-09-19 15:03:45 -0700 | [diff] [blame] | 957 | /* unblocks the monitor receive socket for termination */ |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 958 | TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1)); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 959 | 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 | |
Mahesh | ff6902d | 2014-05-14 18:56:15 +0530 | [diff] [blame] | 969 | int 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 Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 981 | int wifi_ctrl_recv(char *reply, size_t *reply_len) |
Irfan Sheriff | 025321a | 2011-09-19 15:03:45 -0700 | [diff] [blame] | 982 | { |
| 983 | int res; |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 984 | int ctrlfd = wpa_ctrl_get_fd(monitor_conn); |
Dmitry Shmidt | 45bf8a6 | 2011-09-27 17:20:11 -0700 | [diff] [blame] | 985 | struct pollfd rfds[2]; |
Irfan Sheriff | 025321a | 2011-09-19 15:03:45 -0700 | [diff] [blame] | 986 | |
Dmitry Shmidt | 45bf8a6 | 2011-09-27 17:20:11 -0700 | [diff] [blame] | 987 | memset(rfds, 0, 2 * sizeof(struct pollfd)); |
| 988 | rfds[0].fd = ctrlfd; |
| 989 | rfds[0].events |= POLLIN; |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 990 | rfds[1].fd = exit_sockets[1]; |
Dmitry Shmidt | 45bf8a6 | 2011-09-27 17:20:11 -0700 | [diff] [blame] | 991 | rfds[1].events |= POLLIN; |
Mahesh | ff6902d | 2014-05-14 18:56:15 +0530 | [diff] [blame] | 992 | 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 Shmidt | 45bf8a6 | 2011-09-27 17:20:11 -0700 | [diff] [blame] | 1007 | if (rfds[0].revents & POLLIN) { |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1008 | return wpa_ctrl_recv(monitor_conn, reply, reply_len); |
Irfan Sheriff | 025321a | 2011-09-19 15:03:45 -0700 | [diff] [blame] | 1009 | } |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1010 | |
| 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 Sheriff | 897f6dd | 2012-10-10 15:41:13 -0700 | [diff] [blame] | 1014 | return -2; |
Irfan Sheriff | 025321a | 2011-09-19 15:03:45 -0700 | [diff] [blame] | 1015 | } |
| 1016 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1017 | int wifi_wait_on_socket(char *buf, size_t buflen) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1018 | { |
| 1019 | size_t nread = buflen - 1; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1020 | int result; |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1021 | char *match, *match2; |
Dmitry Shmidt | 0e9f488 | 2011-01-04 16:35:18 -0800 | [diff] [blame] | 1022 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1023 | if (monitor_conn == NULL) { |
Mahesh | 0ef9a33 | 2014-05-13 13:59:05 +0530 | [diff] [blame] | 1024 | return snprintf(buf, buflen, "IFNAME=%s %s - connection closed", |
| 1025 | primary_iface, WPA_EVENT_TERMINATING); |
Irfan Sheriff | 2631f99 | 2010-01-27 15:35:28 -0800 | [diff] [blame] | 1026 | } |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1027 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1028 | result = wifi_ctrl_recv(buf, &nread); |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 1029 | |
| 1030 | /* Terminate reception on exit socket */ |
| 1031 | if (result == -2) { |
Mahesh | 0ef9a33 | 2014-05-13 13:59:05 +0530 | [diff] [blame] | 1032 | return snprintf(buf, buflen, "IFNAME=%s %s - connection closed", |
| 1033 | primary_iface, WPA_EVENT_TERMINATING); |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 1034 | } |
| 1035 | |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1036 | if (result < 0) { |
Steve Block | b381b93 | 2011-12-20 16:25:34 +0000 | [diff] [blame] | 1037 | ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno)); |
Mahesh | 0ef9a33 | 2014-05-13 13:59:05 +0530 | [diff] [blame] | 1038 | return snprintf(buf, buflen, "IFNAME=%s %s - recv error", |
| 1039 | primary_iface, WPA_EVENT_TERMINATING); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1040 | } |
| 1041 | buf[nread] = '\0'; |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1042 | /* Check for EOF on the socket */ |
| 1043 | if (result == 0 && nread == 0) { |
| 1044 | /* Fabricate an event to pass up */ |
Steve Block | b381b93 | 2011-12-20 16:25:34 +0000 | [diff] [blame] | 1045 | ALOGD("Received EOF on supplicant socket\n"); |
Mahesh | 0ef9a33 | 2014-05-13 13:59:05 +0530 | [diff] [blame] | 1046 | return snprintf(buf, buflen, "IFNAME=%s %s - signal 0 received", |
| 1047 | primary_iface, WPA_EVENT_TERMINATING); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1048 | } |
| 1049 | /* |
| 1050 | * Events strings are in the format |
| 1051 | * |
Dmitry Shmidt | ec05760 | 2013-05-29 10:34:39 -0700 | [diff] [blame] | 1052 | * IFNAME=iface <N>CTRL-EVENT-XXX |
| 1053 | * or |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1054 | * <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 Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1060 | |
Dmitry Shmidt | ec05760 | 2013-05-29 10:34:39 -0700 | [diff] [blame] | 1061 | if (strncmp(buf, IFNAME, IFNAMELEN) == 0) { |
| 1062 | match = strchr(buf, ' '); |
| 1063 | if (match != NULL) { |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1064 | 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 Shmidt | ec05760 | 2013-05-29 10:34:39 -0700 | [diff] [blame] | 1070 | } |
Dmitry Shmidt | ec05760 | 2013-05-29 10:34:39 -0700 | [diff] [blame] | 1071 | } else { |
| 1072 | return snprintf(buf, buflen, "%s", WPA_EVENT_IGNORE); |
| 1073 | } |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1074 | } else if (buf[0] == '<') { |
Dmitry Shmidt | ec05760 | 2013-05-29 10:34:39 -0700 | [diff] [blame] | 1075 | match = strchr(buf, '>'); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1076 | if (match != NULL) { |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1077 | 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1080 | } |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1081 | } 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 Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1084 | } |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 1085 | |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1086 | return nread; |
| 1087 | } |
| 1088 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1089 | int wifi_wait_for_event(char *buf, size_t buflen) |
Irfan Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 1090 | { |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1091 | return wifi_wait_on_socket(buf, buflen); |
| 1092 | } |
| 1093 | |
| 1094 | void 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 Sheriff | da52930 | 2011-12-27 13:50:07 -0800 | [diff] [blame] | 1114 | } |
| 1115 | } |
| 1116 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1117 | void wifi_close_supplicant_connection() |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1118 | { |
Irfan Sheriff | 5a8a2d2 | 2011-08-22 13:27:56 -0700 | [diff] [blame] | 1119 | char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; |
| 1120 | int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */ |
| 1121 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1122 | wifi_close_sockets(); |
Irfan Sheriff | 025321a | 2011-09-19 15:03:45 -0700 | [diff] [blame] | 1123 | |
Irfan Sheriff | 5a8a2d2 | 2011-08-22 13:27:56 -0700 | [diff] [blame] | 1124 | while (count-- > 0) { |
Irfan Sheriff | 096e49c | 2012-01-10 16:24:51 -0800 | [diff] [blame] | 1125 | if (property_get(supplicant_prop_name, supp_status, NULL)) { |
Irfan Sheriff | 5a8a2d2 | 2011-08-22 13:27:56 -0700 | [diff] [blame] | 1126 | if (strcmp(supp_status, "stopped") == 0) |
| 1127 | return; |
| 1128 | } |
| 1129 | usleep(100000); |
| 1130 | } |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1131 | } |
| 1132 | |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1133 | int wifi_command(const char *command, char *reply, size_t *reply_len) |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1134 | { |
Vinit Deshapnde | 0f33048 | 2013-08-08 10:39:25 -0700 | [diff] [blame] | 1135 | return wifi_send_command(command, reply, reply_len); |
The Android Open Source Project | cc49016 | 2009-03-03 19:32:14 -0800 | [diff] [blame] | 1136 | } |
Dmitry Shmidt | 4b7ffa0 | 2011-07-01 11:03:43 -0700 | [diff] [blame] | 1137 | |
| 1138 | const 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 Shmidt | 29a4d4d | 2011-07-19 15:59:13 -0700 | [diff] [blame] | 1150 | |
| 1151 | int 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 Root | cf449e1 | 2012-03-15 13:10:19 -0700 | [diff] [blame] | 1159 | fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY)); |
Dmitry Shmidt | 29a4d4d | 2011-07-19 15:59:13 -0700 | [diff] [blame] | 1160 | if (fd < 0) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 1161 | ALOGE("Failed to open wlan fw path param (%s)", strerror(errno)); |
Dmitry Shmidt | 29a4d4d | 2011-07-19 15:59:13 -0700 | [diff] [blame] | 1162 | return -1; |
| 1163 | } |
| 1164 | len = strlen(fwpath) + 1; |
Kenny Root | cf449e1 | 2012-03-15 13:10:19 -0700 | [diff] [blame] | 1165 | if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) { |
Steve Block | 5efbd42 | 2012-01-08 10:18:02 +0000 | [diff] [blame] | 1166 | ALOGE("Failed to write wlan fw path param (%s)", strerror(errno)); |
Dmitry Shmidt | 29a4d4d | 2011-07-19 15:59:13 -0700 | [diff] [blame] | 1167 | ret = -1; |
| 1168 | } |
| 1169 | close(fd); |
| 1170 | return ret; |
| 1171 | } |
Steve Kondik | 56be709 | 2012-12-20 20:39:18 -0800 | [diff] [blame] | 1172 | |
| 1173 | int wifi_set_mode(int mode) { |
| 1174 | wifi_mode = mode; |
| 1175 | return 0; |
| 1176 | } |