1cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project/*
2cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * Copyright 2008, The Android Open Source Project
3cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project *
4cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * you may not use this file except in compliance with the License.
6cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * You may obtain a copy of the License at
7cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project *
8cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
9cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project *
10cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * See the License for the specific language governing permissions and
14cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * limitations under the License.
15cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project */
16cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
17cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include <stdlib.h>
18cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include <fcntl.h>
19cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include <errno.h>
20cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include <string.h>
21eea19f1d855b9434313fbb9447a23caf8123aa58Dmitry Shmidt#include <dirent.h>
2245bf8a6f0bbf148ca5a1a626ab1c5c38a0855e13Dmitry Shmidt#include <sys/socket.h>
23cf449e140874e4f57f120a88411c7b642172ecf2Kenny Root#include <unistd.h>
2445bf8a6f0bbf148ca5a1a626ab1c5c38a0855e13Dmitry Shmidt#include <poll.h>
25cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
26cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include "hardware_legacy/wifi.h"
2741d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt#ifdef LIBWPA_CLIENT_EXISTS
28cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include "libwpa_client/wpa_ctrl.h"
2941d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt#endif
30cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
31cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#define LOG_TAG "WifiHW"
32cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include "cutils/log.h"
33cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include "cutils/memory.h"
34cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include "cutils/misc.h"
35cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include "cutils/properties.h"
36cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include "private/android_filesystem_config.h"
37cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
38cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
39cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#include <sys/_system_properties.h>
40cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#endif
41cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
42445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queruextern int do_dhcp();
43445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queruextern int ifc_init();
44445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queruextern void ifc_close();
45445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queruextern char *dhcp_lasterror();
46445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queruextern void get_dhcp_info();
47cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectextern int init_module(void *, unsigned long, const char *);
48cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectextern int delete_module(const char *, unsigned int);
490f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapndevoid wifi_close_sockets();
50cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
5141d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt#ifndef LIBWPA_CLIENT_EXISTS
5241d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
5341d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtstruct wpa_ctrl {};
5441d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtvoid wpa_ctrl_cleanup(void) {}
5541d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtstruct wpa_ctrl *wpa_ctrl_open(const char *ctrl_path) { return NULL; }
5641d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtvoid wpa_ctrl_close(struct wpa_ctrl *ctrl) {}
5741d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtint wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
5841d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt	char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len))
5941d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt	{ return 0; }
6041d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtint wpa_ctrl_attach(struct wpa_ctrl *ctrl) { return 0; }
6141d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtint wpa_ctrl_detach(struct wpa_ctrl *ctrl) { return 0; }
6241d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtint wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
6341d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt	{ return 0; }
6441d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtint wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) { return 0; }
6541d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt#endif
6641d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt
6741d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtstatic struct wpa_ctrl *ctrl_conn;
6841d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtstatic struct wpa_ctrl *monitor_conn;
6941d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt
7041d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt/* socket pair used to exit from a blocking read */
7141d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidtstatic int exit_sockets[2];
7241d81d174858ca39ead245e12a8e2547e0314201Dmitry Shmidt
73da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriffstatic char primary_iface[PROPERTY_VALUE_MAX];
74cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project// TODO: use new ANDROID_SOCKET mechanism, once support for multiple
75cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project// sockets is in
76cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
77243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt#ifndef WIFI_DRIVER_MODULE_ARG
78243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt#define WIFI_DRIVER_MODULE_ARG          ""
79243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt#endif
80243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt#ifndef WIFI_FIRMWARE_LOADER
81243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt#define WIFI_FIRMWARE_LOADER		""
82243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt#endif
83243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt#define WIFI_TEST_INTERFACE		"sta"
84243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt
854b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt#ifndef WIFI_DRIVER_FW_PATH_STA
864b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt#define WIFI_DRIVER_FW_PATH_STA		NULL
874b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt#endif
884b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt#ifndef WIFI_DRIVER_FW_PATH_AP
894b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt#define WIFI_DRIVER_FW_PATH_AP		NULL
904b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt#endif
914b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt#ifndef WIFI_DRIVER_FW_PATH_P2P
924b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt#define WIFI_DRIVER_FW_PATH_P2P		NULL
934b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt#endif
944b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt
9529a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt#ifndef WIFI_DRIVER_FW_PATH_PARAM
9629a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt#define WIFI_DRIVER_FW_PATH_PARAM	"/sys/module/wlan/parameters/fwpath"
9729a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt#endif
9829a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt
99ed8487244b1c9f72fb5d22c7a18918ac34063ceeDmitry Shmidt#define WIFI_DRIVER_LOADER_DELAY	1000000
100ed8487244b1c9f72fb5d22c7a18918ac34063ceeDmitry Shmidt
101cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectstatic const char IFACE_DIR[]           = "/data/system/wpa_supplicant";
102d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#ifdef WIFI_DRIVER_MODULE_PATH
103243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidtstatic const char DRIVER_MODULE_NAME[]  = WIFI_DRIVER_MODULE_NAME;
104243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidtstatic const char DRIVER_MODULE_TAG[]   = WIFI_DRIVER_MODULE_NAME " ";
105243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidtstatic const char DRIVER_MODULE_PATH[]  = WIFI_DRIVER_MODULE_PATH;
106243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidtstatic const char DRIVER_MODULE_ARG[]   = WIFI_DRIVER_MODULE_ARG;
107d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#endif
108243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidtstatic const char FIRMWARE_LOADER[]     = WIFI_FIRMWARE_LOADER;
109cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectstatic const char DRIVER_PROP_NAME[]    = "wlan.driver.status";
110cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectstatic const char SUPPLICANT_NAME[]     = "wpa_supplicant";
111cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectstatic const char SUPP_PROP_NAME[]      = "init.svc.wpa_supplicant";
112096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriffstatic const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant";
113096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriffstatic const char P2P_PROP_NAME[]       = "init.svc.p2p_supplicant";
114cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectstatic const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf";
115cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectstatic const char SUPP_CONFIG_FILE[]    = "/data/misc/wifi/wpa_supplicant.conf";
11667ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriffstatic const char P2P_CONFIG_FILE[]     = "/data/misc/wifi/p2p_supplicant.conf";
117096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriffstatic const char CONTROL_IFACE_PATH[]  = "/data/misc/wifi/sockets";
118cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectstatic const char MODULE_FILE[]         = "/proc/modules";
119cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
120ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidtstatic const char IFNAME[]              = "IFNAME=";
121ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt#define IFNAMELEN			(sizeof(IFNAME) - 1)
122ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidtstatic const char WPA_EVENT_IGNORE[]    = "CTRL-EVENT-IGNORE ";
123ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt
1243ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidtstatic const char SUPP_ENTROPY_FILE[]   = WIFI_ENTROPY_FILE;
12507a629e27cc35868e2b7601983c7044cf8df0709Dmitry Shmidtstatic unsigned char dummy_key[21] = { 0x02, 0x11, 0xbe, 0x33, 0x43, 0x35,
12607a629e27cc35868e2b7601983c7044cf8df0709Dmitry Shmidt                                       0x68, 0x47, 0x84, 0x99, 0xa9, 0x2b,
12707a629e27cc35868e2b7601983c7044cf8df0709Dmitry Shmidt                                       0x1c, 0xd3, 0xee, 0xff, 0xf1, 0xe2,
12807a629e27cc35868e2b7601983c7044cf8df0709Dmitry Shmidt                                       0xf3, 0xf4, 0xf5 };
1293ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt
130096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff/* Is either SUPPLICANT_NAME or P2P_SUPPLICANT_NAME */
131096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriffstatic char supplicant_name[PROPERTY_VALUE_MAX];
132096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff/* Is either SUPP_PROP_NAME or P2P_PROP_NAME */
133096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriffstatic char supplicant_prop_name[PROPERTY_KEY_MAX];
134096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff
135243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidtstatic int insmod(const char *filename, const char *args)
136cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
137cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    void *module;
138cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    unsigned int size;
139cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    int ret;
140cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
141cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    module = load_file(filename, &size);
142cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (!module)
143cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
144cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
145243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt    ret = init_module(module, size, args);
146cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
147cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    free(module);
148cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
149cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    return ret;
150cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
151cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
152cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectstatic int rmmod(const char *modname)
153cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
154cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    int ret = -1;
155cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    int maxtry = 10;
156cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
157cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    while (maxtry-- > 0) {
158cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        ret = delete_module(modname, O_NONBLOCK | O_EXCL);
159cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        if (ret < 0 && errno == EAGAIN)
160cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            usleep(500000);
161cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        else
162cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            break;
163cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
164cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
165cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (ret != 0)
166b381b932acfa441da5607f37ac4ef6573ed5be96Steve Block        ALOGD("Unable to unload driver module \"%s\": %s\n",
167cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project             modname, strerror(errno));
168cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    return ret;
169cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
170cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
171445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queruint do_dhcp_request(int *ipaddr, int *gateway, int *mask,
172445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru                    int *dns1, int *dns2, int *server, int *lease) {
173445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru    /* For test driver, always report success */
174da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff    if (strcmp(primary_iface, WIFI_TEST_INTERFACE) == 0)
175445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru        return 0;
176445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru
177445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru    if (ifc_init() < 0)
178445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru        return -1;
179445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru
180da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff    if (do_dhcp(primary_iface) < 0) {
181445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru        ifc_close();
182445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru        return -1;
183445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru    }
184445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru    ifc_close();
185445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru    get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease);
186445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru    return 0;
187445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru}
188445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru
189445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queruconst char *get_dhcp_error_string() {
190445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru    return dhcp_lasterror();
191445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru}
192445591dded5753cf72dcf329a56af732776de97dJean-Baptiste Queru
1932bb990bfd2580f9be93a413e3a5325057977a828Irfan Sheriffint is_wifi_driver_loaded() {
194cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    char driver_status[PROPERTY_VALUE_MAX];
195d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#ifdef WIFI_DRIVER_MODULE_PATH
196cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    FILE *proc;
197cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    char line[sizeof(DRIVER_MODULE_TAG)+10];
198d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#endif
199cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
200cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
201cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            || strcmp(driver_status, "ok") != 0) {
202cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return 0;  /* driver not loaded */
203cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
204d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#ifdef WIFI_DRIVER_MODULE_PATH
205cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    /*
206cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * If the property says the driver is loaded, check to
207cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * make sure that the property setting isn't just left
208cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * over from a previous manual shutdown or a runtime
209cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * crash.
210cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     */
211cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
21264cca04dcbf4e21a51131224b9d0f0c596f876d4Steve Block        ALOGW("Could not open %s: %s", MODULE_FILE, strerror(errno));
213243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt        property_set(DRIVER_PROP_NAME, "unloaded");
214cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return 0;
215cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
216cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    while ((fgets(line, sizeof(line), proc)) != NULL) {
217cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
218cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            fclose(proc);
219cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            return 1;
220cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        }
221cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
222cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    fclose(proc);
223cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    property_set(DRIVER_PROP_NAME, "unloaded");
224cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    return 0;
225d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#else
226d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt    return 1;
227d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#endif
228cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
229cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
230cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectint wifi_load_driver()
231cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
232d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#ifdef WIFI_DRIVER_MODULE_PATH
233cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    char driver_status[PROPERTY_VALUE_MAX];
234cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    int count = 100; /* wait at most 20 seconds for completion */
235cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
2362bb990bfd2580f9be93a413e3a5325057977a828Irfan Sheriff    if (is_wifi_driver_loaded()) {
237cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return 0;
238cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
239cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
240243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt    if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0)
241cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
242243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt
243243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt    if (strcmp(FIRMWARE_LOADER,"") == 0) {
2448fb5f74df7b25051e007a67eea22b984ef7dc76aDmitry Shmidt        /* usleep(WIFI_DRIVER_LOADER_DELAY); */
245243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt        property_set(DRIVER_PROP_NAME, "ok");
246243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt    }
247243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt    else {
248243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt        property_set("ctl.start", FIRMWARE_LOADER);
249243af8b84968ec4f5afb628c43a2c541c4feee7bDmitry Shmidt    }
250cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    sched_yield();
251cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    while (count-- > 0) {
252cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
253cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            if (strcmp(driver_status, "ok") == 0)
254cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project                return 0;
2557b43699180e593b19092eb2a091c4bca105aca77Dmitry Shmidt            else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) {
2567b43699180e593b19092eb2a091c4bca105aca77Dmitry Shmidt                wifi_unload_driver();
257cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project                return -1;
2587b43699180e593b19092eb2a091c4bca105aca77Dmitry Shmidt            }
259cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        }
260cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        usleep(200000);
261cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
262cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    property_set(DRIVER_PROP_NAME, "timeout");
2637b43699180e593b19092eb2a091c4bca105aca77Dmitry Shmidt    wifi_unload_driver();
264cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    return -1;
265d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#else
266d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt    property_set(DRIVER_PROP_NAME, "ok");
267d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt    return 0;
268d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#endif
269cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
270cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
271cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectint wifi_unload_driver()
272cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
2734c1a1fedd632791580c4b483c31abc4e583eae16Dmitry Shmidt    usleep(200000); /* allow to finish interface down */
274953c1140659ae935e4718d4fd48662db178814f6Dmitry Shmidt#ifdef WIFI_DRIVER_MODULE_PATH
275cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (rmmod(DRIVER_MODULE_NAME) == 0) {
276953c1140659ae935e4718d4fd48662db178814f6Dmitry Shmidt        int count = 20; /* wait at most 10 seconds for completion */
2770e9f488e672abf0d14580261998cfd9c7211c112Dmitry Shmidt        while (count-- > 0) {
2780e9f488e672abf0d14580261998cfd9c7211c112Dmitry Shmidt            if (!is_wifi_driver_loaded())
2790e9f488e672abf0d14580261998cfd9c7211c112Dmitry Shmidt                break;
2800e9f488e672abf0d14580261998cfd9c7211c112Dmitry Shmidt            usleep(500000);
2810e9f488e672abf0d14580261998cfd9c7211c112Dmitry Shmidt        }
282953c1140659ae935e4718d4fd48662db178814f6Dmitry Shmidt        usleep(500000); /* allow card removal */
2830e9f488e672abf0d14580261998cfd9c7211c112Dmitry Shmidt        if (count) {
2840e9f488e672abf0d14580261998cfd9c7211c112Dmitry Shmidt            return 0;
2850e9f488e672abf0d14580261998cfd9c7211c112Dmitry Shmidt        }
2860e9f488e672abf0d14580261998cfd9c7211c112Dmitry Shmidt        return -1;
287cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    } else
288cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
289d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#else
290d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt    property_set(DRIVER_PROP_NAME, "unloaded");
291d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt    return 0;
292d301cb7a5e76f82d265f8a7d408bec3159614f0bDmitry Shmidt#endif
293cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
294cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
2953ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidtint ensure_entropy_file_exists()
2963ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt{
2973ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    int ret;
2983ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    int destfd;
2993ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt
3003ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK);
3013ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    if ((ret == 0) || (errno == EACCES)) {
3023ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt        if ((ret != 0) &&
3033ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt            (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
3045efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block            ALOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
3053ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt            return -1;
3063ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt        }
3073ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt        return 0;
3083ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    }
309cf449e140874e4f57f120a88411c7b642172ecf2Kenny Root    destfd = TEMP_FAILURE_RETRY(open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660));
3103ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    if (destfd < 0) {
3115efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
3123ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt        return -1;
3133ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    }
3143ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt
315cf449e140874e4f57f120a88411c7b642172ecf2Kenny Root    if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) {
3165efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
3173ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt        close(destfd);
3183ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt        return -1;
3193ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    }
3203ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    close(destfd);
3213ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt
3223ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    /* chmod is needed because open() didn't set permisions properly */
3233ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) {
3245efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Error changing permissions of %s to 0660: %s",
3253ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt             SUPP_ENTROPY_FILE, strerror(errno));
3263ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt        unlink(SUPP_ENTROPY_FILE);
3273ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt        return -1;
3283ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    }
3293ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt
3303ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) {
3315efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Error changing group ownership of %s to %d: %s",
3323ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt             SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno));
3333ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt        unlink(SUPP_ENTROPY_FILE);
3343ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt        return -1;
3353ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    }
3363ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    return 0;
3373ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt}
3383ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt
33967ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriffint ensure_config_file_exists(const char *config_file)
34067ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff{
34167ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff    char buf[2048];
342cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    int srcfd, destfd;
3438a5b197b3d5878e3f1cf49c9c38c090456107e87Irfan Sheriff    struct stat sb;
344cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    int nread;
34589ae703cd6d4b2bc86c4bd281a8e460fd5679891Dmitry Shmidt    int ret;
346cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
34767ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff    ret = access(config_file, R_OK|W_OK);
34889ae703cd6d4b2bc86c4bd281a8e460fd5679891Dmitry Shmidt    if ((ret == 0) || (errno == EACCES)) {
34989ae703cd6d4b2bc86c4bd281a8e460fd5679891Dmitry Shmidt        if ((ret != 0) &&
35067ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff            (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
3515efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block            ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno));
35289ae703cd6d4b2bc86c4bd281a8e460fd5679891Dmitry Shmidt            return -1;
35389ae703cd6d4b2bc86c4bd281a8e460fd5679891Dmitry Shmidt        }
354c6bb3b5e1e06aa7798342f4ca8d4cc6364f5ec9aDmitry Shmidt        return 0;
355cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    } else if (errno != ENOENT) {
3565efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno));
357cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
358cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
359cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
360cf449e140874e4f57f120a88411c7b642172ecf2Kenny Root    srcfd = TEMP_FAILURE_RETRY(open(SUPP_CONFIG_TEMPLATE, O_RDONLY));
361cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (srcfd < 0) {
3625efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
363cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
364cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
365cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
366cf449e140874e4f57f120a88411c7b642172ecf2Kenny Root    destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT|O_RDWR, 0660));
367cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (destfd < 0) {
368cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        close(srcfd);
3695efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno));
370cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
371cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
372cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
373cf449e140874e4f57f120a88411c7b642172ecf2Kenny Root    while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) {
374cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        if (nread < 0) {
3755efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block            ALOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
376cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            close(srcfd);
377cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            close(destfd);
37867ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff            unlink(config_file);
379cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            return -1;
380cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        }
381cf449e140874e4f57f120a88411c7b642172ecf2Kenny Root        TEMP_FAILURE_RETRY(write(destfd, buf, nread));
382cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
383cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
384cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    close(destfd);
385cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    close(srcfd);
386cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
38724bf7fc4e02b552650f299d16303eca0825dd8c8Dmitry Shmidt    /* chmod is needed because open() didn't set permisions properly */
38867ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff    if (chmod(config_file, 0660) < 0) {
3895efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Error changing permissions of %s to 0660: %s",
39067ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff             config_file, strerror(errno));
39167ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff        unlink(config_file);
39224bf7fc4e02b552650f299d16303eca0825dd8c8Dmitry Shmidt        return -1;
39324bf7fc4e02b552650f299d16303eca0825dd8c8Dmitry Shmidt    }
39424bf7fc4e02b552650f299d16303eca0825dd8c8Dmitry Shmidt
39567ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff    if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) {
3965efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Error changing group ownership of %s to %d: %s",
39767ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff             config_file, AID_WIFI, strerror(errno));
39867ba2276b9a5232685e14d416fea0b1250515594Irfan Sheriff        unlink(config_file);
399cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
400cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
401c6bb3b5e1e06aa7798342f4ca8d4cc6364f5ec9aDmitry Shmidt    return 0;
402cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
403cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
404096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriffint wifi_start_supplicant(int p2p_supported)
405cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
406cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
407cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    int count = 200; /* wait at most 20 seconds for completion */
408cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
409cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    const prop_info *pi;
410da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff    unsigned serial = 0, i;
411cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#endif
412cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
413096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    if (p2p_supported) {
414096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff        strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
415096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff        strcpy(supplicant_prop_name, P2P_PROP_NAME);
416096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff
417096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff        /* Ensure p2p config file is created */
418096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff        if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) {
419096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff            ALOGE("Failed to create a p2p config file");
420096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff            return -1;
421096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff        }
422096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff
423096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    } else {
424096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff        strcpy(supplicant_name, SUPPLICANT_NAME);
425096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff        strcpy(supplicant_prop_name, SUPP_PROP_NAME);
426096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    }
427096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff
428cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    /* Check whether already running */
429eed817e46ee7351f21673118eda9a5960a483120Jonathan DE CESCO    if (property_get(supplicant_prop_name, supp_status, NULL)
430cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            && strcmp(supp_status, "running") == 0) {
431cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return 0;
432cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
433cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
434cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    /* Before starting the daemon, make sure its config file exists */
435096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) {
4365efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Wi-Fi will not be enabled");
437cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
438cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
439cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
4403ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    if (ensure_entropy_file_exists() < 0) {
4415efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Wi-Fi entropy file was not created");
4423ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt    }
4433ab3e6696757541c098a251981c074fc980f4dc7Dmitry Shmidt
444cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    /* Clear out any stale socket files that might be left over. */
445de9abffc3815449cbd8d756937030cb0353fb9f2Dmitry Shmidt    wpa_ctrl_cleanup();
446cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
447da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff    /* Reset sockets used for exiting from hung state */
4480f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    exit_sockets[0] = exit_sockets[1] = -1;
449da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff
450cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
451cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    /*
452cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * Get a reference to the status property, so we can distinguish
453cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * the case where it goes stopped => running => stopped (i.e.,
454cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * it start up, but fails right away) from the case in which
455cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * it starts in the stopped state and never manages to start
456cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * running at all.
457cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     */
458096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    pi = __system_property_find(supplicant_prop_name);
459cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (pi != NULL) {
46014c02f245e56687b765487d25a034d71196d33b6Colin Cross        serial = __system_property_serial(pi);
461cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
462cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#endif
463da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff    property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
464096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff
465096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    property_set("ctl.start", supplicant_name);
466cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    sched_yield();
467cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
468cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    while (count-- > 0) {
469007404c68f5cf6328e30b6d0edac3fd52ef36abbDmitry Shmidt#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
470cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        if (pi == NULL) {
471096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff            pi = __system_property_find(supplicant_prop_name);
472cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        }
473cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        if (pi != NULL) {
4744431a1c34d1a9c36b7251217a2783d09ee1a7ac3jiaguo            /*
4754431a1c34d1a9c36b7251217a2783d09ee1a7ac3jiaguo             * property serial updated means that init process is scheduled
4764431a1c34d1a9c36b7251217a2783d09ee1a7ac3jiaguo             * after we sched_yield, further property status checking is based on this */
4774431a1c34d1a9c36b7251217a2783d09ee1a7ac3jiaguo            if (__system_property_serial(pi) != serial) {
4784431a1c34d1a9c36b7251217a2783d09ee1a7ac3jiaguo                __system_property_read(pi, NULL, supp_status);
4794431a1c34d1a9c36b7251217a2783d09ee1a7ac3jiaguo                if (strcmp(supp_status, "running") == 0) {
4804431a1c34d1a9c36b7251217a2783d09ee1a7ac3jiaguo                    return 0;
4814431a1c34d1a9c36b7251217a2783d09ee1a7ac3jiaguo                } else if (strcmp(supp_status, "stopped") == 0) {
4824431a1c34d1a9c36b7251217a2783d09ee1a7ac3jiaguo                    return -1;
4834431a1c34d1a9c36b7251217a2783d09ee1a7ac3jiaguo                }
484cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            }
485cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        }
486cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#else
487096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff        if (property_get(supplicant_prop_name, supp_status, NULL)) {
488cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            if (strcmp(supp_status, "running") == 0)
489cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project                return 0;
490cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        }
491cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project#endif
492cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        usleep(100000);
493cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
494cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    return -1;
495cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
496cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
497745e7fd4e09db2b47371338ee54c54255e286473Irfan Sheriffint wifi_stop_supplicant(int p2p_supported)
498cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
499cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
500cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    int count = 50; /* wait at most 5 seconds for completion */
501cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
502745e7fd4e09db2b47371338ee54c54255e286473Irfan Sheriff    if (p2p_supported) {
503745e7fd4e09db2b47371338ee54c54255e286473Irfan Sheriff        strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
504745e7fd4e09db2b47371338ee54c54255e286473Irfan Sheriff        strcpy(supplicant_prop_name, P2P_PROP_NAME);
505745e7fd4e09db2b47371338ee54c54255e286473Irfan Sheriff    } else {
506745e7fd4e09db2b47371338ee54c54255e286473Irfan Sheriff        strcpy(supplicant_name, SUPPLICANT_NAME);
507745e7fd4e09db2b47371338ee54c54255e286473Irfan Sheriff        strcpy(supplicant_prop_name, SUPP_PROP_NAME);
508745e7fd4e09db2b47371338ee54c54255e286473Irfan Sheriff    }
509745e7fd4e09db2b47371338ee54c54255e286473Irfan Sheriff
510cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    /* Check whether supplicant already stopped */
511096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    if (property_get(supplicant_prop_name, supp_status, NULL)
512cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        && strcmp(supp_status, "stopped") == 0) {
513cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return 0;
514cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
515cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
516096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    property_set("ctl.stop", supplicant_name);
517cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    sched_yield();
518cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
519cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    while (count-- > 0) {
520096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff        if (property_get(supplicant_prop_name, supp_status, NULL)) {
521cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            if (strcmp(supp_status, "stopped") == 0)
522cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project                return 0;
523cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        }
524cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        usleep(100000);
525cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
526745e7fd4e09db2b47371338ee54c54255e286473Irfan Sheriff    ALOGE("Failed to stop supplicant");
527cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    return -1;
528cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
529cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
5300f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapndeint wifi_connect_on_socket_path(const char *path)
531cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
532cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
533cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
534cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    /* Make sure supplicant is running */
535096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    if (!property_get(supplicant_prop_name, supp_status, NULL)
536cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project            || strcmp(supp_status, "running") != 0) {
5375efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Supplicant not running, cannot connect");
538cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
539cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
540cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
5410f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    ctrl_conn = wpa_ctrl_open(path);
5420f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (ctrl_conn == NULL) {
5435efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Unable to open connection to supplicant on \"%s\": %s",
544da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff             path, strerror(errno));
545cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
546cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
5470f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    monitor_conn = wpa_ctrl_open(path);
5480f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (monitor_conn == NULL) {
5490f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        wpa_ctrl_close(ctrl_conn);
5500f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        ctrl_conn = NULL;
551cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
552cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
5530f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (wpa_ctrl_attach(monitor_conn) != 0) {
5540f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        wpa_ctrl_close(monitor_conn);
5550f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        wpa_ctrl_close(ctrl_conn);
5560f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        ctrl_conn = monitor_conn = NULL;
557cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
558cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
559025321a09dbe7820870125acf771e1da02684605Irfan Sheriff
5600f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
5610f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        wpa_ctrl_close(monitor_conn);
5620f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        wpa_ctrl_close(ctrl_conn);
5630f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        ctrl_conn = monitor_conn = NULL;
564025321a09dbe7820870125acf771e1da02684605Irfan Sheriff        return -1;
565025321a09dbe7820870125acf771e1da02684605Irfan Sheriff    }
566025321a09dbe7820870125acf771e1da02684605Irfan Sheriff
567cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    return 0;
568cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
569cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
570da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff/* Establishes the control and monitor socket connections on the interface */
5710f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapndeint wifi_connect_to_supplicant()
572da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff{
573ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt    static char path[PATH_MAX];
574da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff
5750f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (access(IFACE_DIR, F_OK) == 0) {
5760f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
577da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff    } else {
5780f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface);
579da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff    }
5800f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    return wifi_connect_on_socket_path(path);
581da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff}
582da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff
5830f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapndeint wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
584cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
585cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    int ret;
5860f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (ctrl_conn == NULL) {
5876a70518b93928d1c91457ff805e375c82d76b0e5Steve Block        ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
588cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
589cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
5900f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
591cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (ret == -2) {
592b381b932acfa441da5607f37ac4ef6573ed5be96Steve Block        ALOGD("'%s' command timed out.\n", cmd);
593025321a09dbe7820870125acf771e1da02684605Irfan Sheriff        /* unblocks the monitor receive socket for termination */
5940f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
595cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -2;
596cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
597cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        return -1;
598cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
599cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (strncmp(cmd, "PING", 4) == 0) {
600cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        reply[*reply_len] = '\0';
601cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
602cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    return 0;
603cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
604cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
605ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Maheshint wifi_supplicant_connection_active()
606ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh{
607ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
608ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh
609ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh    if (property_get(supplicant_prop_name, supp_status, NULL)) {
610ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh        if (strcmp(supp_status, "stopped") == 0)
611ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh            return -1;
612ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh    }
613ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh
614ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh    return 0;
615ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh}
616ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh
6170f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapndeint wifi_ctrl_recv(char *reply, size_t *reply_len)
618025321a09dbe7820870125acf771e1da02684605Irfan Sheriff{
619025321a09dbe7820870125acf771e1da02684605Irfan Sheriff    int res;
6200f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    int ctrlfd = wpa_ctrl_get_fd(monitor_conn);
62145bf8a6f0bbf148ca5a1a626ab1c5c38a0855e13Dmitry Shmidt    struct pollfd rfds[2];
62245bf8a6f0bbf148ca5a1a626ab1c5c38a0855e13Dmitry Shmidt
62345bf8a6f0bbf148ca5a1a626ab1c5c38a0855e13Dmitry Shmidt    memset(rfds, 0, 2 * sizeof(struct pollfd));
62445bf8a6f0bbf148ca5a1a626ab1c5c38a0855e13Dmitry Shmidt    rfds[0].fd = ctrlfd;
62545bf8a6f0bbf148ca5a1a626ab1c5c38a0855e13Dmitry Shmidt    rfds[0].events |= POLLIN;
6260f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    rfds[1].fd = exit_sockets[1];
62745bf8a6f0bbf148ca5a1a626ab1c5c38a0855e13Dmitry Shmidt    rfds[1].events |= POLLIN;
628ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh    do {
629ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh        res = TEMP_FAILURE_RETRY(poll(rfds, 2, 30000));
630ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh        if (res < 0) {
631ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh            ALOGE("Error poll = %d", res);
632ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh            return res;
633ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh        } else if (res == 0) {
634ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh            /* timed out, check if supplicant is active
635ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh             * or not ..
636ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh             */
637ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh            res = wifi_supplicant_connection_active();
638ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh            if (res < 0)
639ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh                return -2;
640ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh        }
641ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh    } while (res == 0);
642ff6902dc4f034d67d6c3cbdddbe04f61913d5b79Mahesh
64345bf8a6f0bbf148ca5a1a626ab1c5c38a0855e13Dmitry Shmidt    if (rfds[0].revents & POLLIN) {
6440f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        return wpa_ctrl_recv(monitor_conn, reply, reply_len);
645025321a09dbe7820870125acf771e1da02684605Irfan Sheriff    }
6460f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde
6470f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    /* it is not rfds[0], then it must be rfts[1] (i.e. the exit socket)
6480f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde     * or we timed out. In either case, this call has failed ..
6490f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde     */
650897f6dd64224d22c22c8f7a497331bf5bc335e4cIrfan Sheriff    return -2;
651025321a09dbe7820870125acf771e1da02684605Irfan Sheriff}
652025321a09dbe7820870125acf771e1da02684605Irfan Sheriff
6530f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapndeint wifi_wait_on_socket(char *buf, size_t buflen)
654cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
655cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    size_t nread = buflen - 1;
656cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    int result;
6570f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    char *match, *match2;
6580e9f488e672abf0d14580261998cfd9c7211c112Dmitry Shmidt
6590f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (monitor_conn == NULL) {
6600ef9a33a471c239824bb3958a99a9dea8a89ee69Mahesh        return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
6610ef9a33a471c239824bb3958a99a9dea8a89ee69Mahesh                        primary_iface, WPA_EVENT_TERMINATING);
6622631f993753d726c8c6a85ab66a83db79e54f0bbIrfan Sheriff    }
663cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
6640f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    result = wifi_ctrl_recv(buf, &nread);
665096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff
666096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    /* Terminate reception on exit socket */
667096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    if (result == -2) {
6680ef9a33a471c239824bb3958a99a9dea8a89ee69Mahesh        return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
6690ef9a33a471c239824bb3958a99a9dea8a89ee69Mahesh                        primary_iface, WPA_EVENT_TERMINATING);
670096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff    }
671096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff
672cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (result < 0) {
673b381b932acfa441da5607f37ac4ef6573ed5be96Steve Block        ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno));
6740ef9a33a471c239824bb3958a99a9dea8a89ee69Mahesh        return snprintf(buf, buflen, "IFNAME=%s %s - recv error",
6750ef9a33a471c239824bb3958a99a9dea8a89ee69Mahesh                        primary_iface, WPA_EVENT_TERMINATING);
676cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
677cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    buf[nread] = '\0';
678cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    /* Check for EOF on the socket */
679cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    if (result == 0 && nread == 0) {
680cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        /* Fabricate an event to pass up */
681b381b932acfa441da5607f37ac4ef6573ed5be96Steve Block        ALOGD("Received EOF on supplicant socket\n");
6820ef9a33a471c239824bb3958a99a9dea8a89ee69Mahesh        return snprintf(buf, buflen, "IFNAME=%s %s - signal 0 received",
6830ef9a33a471c239824bb3958a99a9dea8a89ee69Mahesh                        primary_iface, WPA_EVENT_TERMINATING);
684cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
685cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    /*
686cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * Events strings are in the format
687cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     *
688ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt     *     IFNAME=iface <N>CTRL-EVENT-XXX
689ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt     *        or
690cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     *     <N>CTRL-EVENT-XXX
691cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     *
692cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
693cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * etc.) and XXX is the event name. The level information is not useful
694cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * to us, so strip it off.
695cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     */
6960f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde
697ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt    if (strncmp(buf, IFNAME, IFNAMELEN) == 0) {
698ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt        match = strchr(buf, ' ');
699ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt        if (match != NULL) {
7000f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde            if (match[1] == '<') {
7010f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde                match2 = strchr(match + 2, '>');
7020f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde                if (match2 != NULL) {
7030f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde                    nread -= (match2 - match);
7040f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde                    memmove(match + 1, match2 + 1, nread - (match - buf) + 1);
7050f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde                }
706ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt            }
707ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt        } else {
708ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt            return snprintf(buf, buflen, "%s", WPA_EVENT_IGNORE);
709ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt        }
7100f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    } else if (buf[0] == '<') {
711ec0576034bb5c1b0aed1b23120b71f9599d2bb73Dmitry Shmidt        match = strchr(buf, '>');
712cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        if (match != NULL) {
7130f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde            nread -= (match + 1 - buf);
7140f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde            memmove(buf, match + 1, nread + 1);
7150f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde            ALOGV("supplicant generated event without interface - %s\n", buf);
716cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project        }
7170f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    } else {
7180f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        /* let the event go as is! */
7190f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        ALOGW("supplicant generated event without interface and without message level - %s\n", buf);
720cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
721096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff
722cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    return nread;
723cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
724cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
7250f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapndeint wifi_wait_for_event(char *buf, size_t buflen)
726cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
7270f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    return wifi_wait_on_socket(buf, buflen);
728da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff}
7295a8a2d2b130644f0f4abad8586f0a245e4c15be8Irfan Sheriff
7300f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapndevoid wifi_close_sockets()
731da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff{
7320f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (ctrl_conn != NULL) {
7330f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        wpa_ctrl_close(ctrl_conn);
7340f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        ctrl_conn = NULL;
735cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
736da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff
7370f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (monitor_conn != NULL) {
7380f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        wpa_ctrl_close(monitor_conn);
7390f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        monitor_conn = NULL;
740da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff    }
741da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff
7420f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (exit_sockets[0] >= 0) {
7430f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        close(exit_sockets[0]);
7440f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        exit_sockets[0] = -1;
745cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    }
7465a8a2d2b130644f0f4abad8586f0a245e4c15be8Irfan Sheriff
7470f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    if (exit_sockets[1] >= 0) {
7480f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        close(exit_sockets[1]);
7490f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde        exit_sockets[1] = -1;
750025321a09dbe7820870125acf771e1da02684605Irfan Sheriff    }
751da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff}
752da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff
7530f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapndevoid wifi_close_supplicant_connection()
754da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff{
755da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
756da52930b89bb0e03948f3981e75f8727ea023587Irfan Sheriff    int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */
757025321a09dbe7820870125acf771e1da02684605Irfan Sheriff
7580f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    wifi_close_sockets();
759025321a09dbe7820870125acf771e1da02684605Irfan Sheriff
7605a8a2d2b130644f0f4abad8586f0a245e4c15be8Irfan Sheriff    while (count-- > 0) {
761096e49c869cdb297f1ea99289ae44c2a0e487fcfIrfan Sheriff        if (property_get(supplicant_prop_name, supp_status, NULL)) {
7625a8a2d2b130644f0f4abad8586f0a245e4c15be8Irfan Sheriff            if (strcmp(supp_status, "stopped") == 0)
7635a8a2d2b130644f0f4abad8586f0a245e4c15be8Irfan Sheriff                return;
7645a8a2d2b130644f0f4abad8586f0a245e4c15be8Irfan Sheriff        }
7655a8a2d2b130644f0f4abad8586f0a245e4c15be8Irfan Sheriff        usleep(100000);
7665a8a2d2b130644f0f4abad8586f0a245e4c15be8Irfan Sheriff    }
767cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
768cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
7690f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapndeint wifi_command(const char *command, char *reply, size_t *reply_len)
770cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project{
7710f330488afcfff031bc0ba88de826f998f7cfaf9Vinit Deshapnde    return wifi_send_command(command, reply, reply_len);
772cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project}
7734b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt
7744b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidtconst char *wifi_get_fw_path(int fw_type)
7754b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt{
7764b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt    switch (fw_type) {
7774b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt    case WIFI_GET_FW_PATH_STA:
7784b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt        return WIFI_DRIVER_FW_PATH_STA;
7794b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt    case WIFI_GET_FW_PATH_AP:
7804b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt        return WIFI_DRIVER_FW_PATH_AP;
7814b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt    case WIFI_GET_FW_PATH_P2P:
7824b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt        return WIFI_DRIVER_FW_PATH_P2P;
7834b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt    }
7844b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt    return NULL;
7854b7ffa08be8d58932841c52ce253ae6ca886a4f2Dmitry Shmidt}
78629a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt
78729a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidtint wifi_change_fw_path(const char *fwpath)
78829a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt{
78929a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt    int len;
79029a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt    int fd;
79129a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt    int ret = 0;
79229a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt
79329a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt    if (!fwpath)
79429a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt        return ret;
795cf449e140874e4f57f120a88411c7b642172ecf2Kenny Root    fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY));
79629a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt    if (fd < 0) {
7975efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Failed to open wlan fw path param (%s)", strerror(errno));
79829a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt        return -1;
79929a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt    }
80029a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt    len = strlen(fwpath) + 1;
801cf449e140874e4f57f120a88411c7b642172ecf2Kenny Root    if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) {
8025efbd421e0029d6fc44b1cc65c0e5e0d85e5161fSteve Block        ALOGE("Failed to write wlan fw path param (%s)", strerror(errno));
80329a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt        ret = -1;
80429a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt    }
80529a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt    close(fd);
80629a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt    return ret;
80729a4d4d74b512e450a7d2ae97d4222c24a13b87eDmitry Shmidt}
808