• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016, 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 "hardware_legacy/wifi.h"
18 
19 #include <fcntl.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <time.h>
23 
24 #include <android-base/logging.h>
25 #include <cutils/misc.h>
26 #include <cutils/properties.h>
27 #include <sys/syscall.h>
28 
29 extern "C" int init_module(void *, unsigned long, const char *);
30 extern "C" int delete_module(const char *, unsigned int);
31 
32 #ifndef WIFI_DRIVER_FW_PATH_STA
33 #define WIFI_DRIVER_FW_PATH_STA NULL
34 #endif
35 #ifndef WIFI_DRIVER_FW_PATH_AP
36 #define WIFI_DRIVER_FW_PATH_AP NULL
37 #endif
38 #ifndef WIFI_DRIVER_FW_PATH_P2P
39 #define WIFI_DRIVER_FW_PATH_P2P NULL
40 #endif
41 
42 #ifndef WIFI_DRIVER_MODULE_ARG
43 #define WIFI_DRIVER_MODULE_ARG ""
44 #endif
45 
46 static const char DRIVER_PROP_NAME[] = "wlan.driver.status";
47 static bool is_driver_loaded = false;
48 #ifdef WIFI_DRIVER_MODULE_PATH
49 static const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME;
50 static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " ";
51 static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH;
52 static const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG;
53 static const char MODULE_FILE[] = "/proc/modules";
54 #endif
55 
56 #ifdef WIFI_DRIVER_STATE_CTRL_PARAM
57 int kDriverStateAccessRetrySleepMillis = 200;
58 #endif
59 
insmod(const char * filename,const char * args)60 static int insmod(const char *filename, const char *args) {
61   int ret;
62   int fd;
63 
64   fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
65   if (fd < 0) {
66     PLOG(ERROR) << "Failed to open " << filename;
67     return -1;
68   }
69 
70   ret = syscall(__NR_finit_module, fd, args, 0);
71 
72   close(fd);
73   if (ret < 0) {
74     PLOG(ERROR) << "finit_module return: " << ret;
75   }
76 
77   return ret;
78 }
79 
rmmod(const char * modname)80 static int rmmod(const char *modname) {
81   int ret = -1;
82   int maxtry = 10;
83 
84   while (maxtry-- > 0) {
85     ret = delete_module(modname, O_NONBLOCK | O_EXCL);
86     if (ret < 0 && errno == EAGAIN)
87       usleep(500000);
88     else
89       break;
90   }
91 
92   if (ret != 0)
93     PLOG(DEBUG) << "Unable to unload driver module '" << modname << "'";
94   return ret;
95 }
96 
97 #ifdef WIFI_DRIVER_STATE_CTRL_PARAM
wifi_change_driver_state(const char * state)98 int wifi_change_driver_state(const char *state) {
99   int len;
100   int fd;
101   int ret = 0;
102   struct timespec req;
103   req.tv_sec = 0;
104   req.tv_nsec = kDriverStateAccessRetrySleepMillis * 1000000L;
105   int count = 5; /* wait at most 1 second for completion. */
106 
107   if (!state) return -1;
108   do {
109     if (access(WIFI_DRIVER_STATE_CTRL_PARAM, W_OK) == 0)
110       break;
111     nanosleep(&req, (struct timespec *)NULL);
112   } while (--count > 0);
113   if (count == 0) {
114     PLOG(ERROR) << "Failed to access driver state control param "
115                 << strerror(errno) << ", " << errno;
116     return -1;
117   }
118   fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_STATE_CTRL_PARAM, O_WRONLY));
119   if (fd < 0) {
120     PLOG(ERROR) << "Failed to open driver state control param";
121     return -1;
122   }
123   len = strlen(state) + 1;
124   if (TEMP_FAILURE_RETRY(write(fd, state, len)) != len) {
125     PLOG(ERROR) << "Failed to write driver state control param";
126     ret = -1;
127   }
128   close(fd);
129   return ret;
130 }
131 #endif
132 
is_wifi_driver_loaded()133 int is_wifi_driver_loaded() {
134   char driver_status[PROPERTY_VALUE_MAX];
135 #ifdef WIFI_DRIVER_MODULE_PATH
136   FILE *proc;
137   char line[sizeof(DRIVER_MODULE_TAG) + 10];
138 #endif
139 
140   if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
141     return 0; /* driver not loaded */
142   }
143 
144   if (!is_driver_loaded) {
145     return 0;
146   } /* driver not loaded */
147 
148 #ifdef WIFI_DRIVER_MODULE_PATH
149   /*
150    * If the property says the driver is loaded, check to
151    * make sure that the property setting isn't just left
152    * over from a previous manual shutdown or a runtime
153    * crash.
154    */
155   if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
156     PLOG(WARNING) << "Could not open " << MODULE_FILE;
157     is_driver_loaded = false;
158     if (strcmp(driver_status, "unloaded") != 0) {
159       property_set(DRIVER_PROP_NAME, "unloaded");
160     }
161     return 0;
162   }
163   while ((fgets(line, sizeof(line), proc)) != NULL) {
164     if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
165       fclose(proc);
166       return 1;
167     }
168   }
169   fclose(proc);
170   is_driver_loaded = false;
171   if (strcmp(driver_status, "unloaded") != 0) {
172     property_set(DRIVER_PROP_NAME, "unloaded");
173   }
174   return 0;
175 #else
176   return 1;
177 #endif
178 }
179 
wifi_load_driver()180 int wifi_load_driver() {
181 #ifdef WIFI_DRIVER_MODULE_PATH
182   if (is_wifi_driver_loaded()) {
183     return 0;
184   }
185 
186   if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) return -1;
187 #endif
188 
189 #ifdef WIFI_DRIVER_STATE_CTRL_PARAM
190   if (is_wifi_driver_loaded()) {
191     return 0;
192   }
193 
194   if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0) {
195 #ifdef WIFI_DRIVER_MODULE_PATH
196     PLOG(WARNING) << "Driver unloading, err='fail to change driver state'";
197     if (rmmod(DRIVER_MODULE_NAME) == 0) {
198       PLOG(DEBUG) << "Driver unloaded";
199     } else {
200       // Set driver prop to "ok", expect HL to restart Wi-Fi.
201       PLOG(DEBUG) << "Driver unload failed! set driver prop to 'ok'.";
202       property_set(DRIVER_PROP_NAME, "ok");
203     }
204 #endif
205     return -1;
206   }
207 #endif
208   is_driver_loaded = true;
209   return 0;
210 }
211 
wifi_unload_driver()212 int wifi_unload_driver() {
213   if (!is_wifi_driver_loaded()) {
214     return 0;
215   }
216 #ifdef WIFI_DRIVER_MODULE_PATH
217   if (rmmod(DRIVER_MODULE_NAME) == 0) {
218     int count = 20; /* wait at most 10 seconds for completion */
219     while (count-- > 0) {
220       if (!is_wifi_driver_loaded()) break;
221       usleep(500000);
222     }
223     usleep(500000); /* allow card removal */
224     if (count) {
225       return 0;
226     }
227     return -1;
228   } else
229     return -1;
230 #else
231 #ifdef WIFI_DRIVER_STATE_CTRL_PARAM
232   if (is_wifi_driver_loaded()) {
233     if (wifi_change_driver_state(WIFI_DRIVER_STATE_OFF) < 0) return -1;
234   }
235 #endif
236   is_driver_loaded = false;
237   property_set(DRIVER_PROP_NAME, "unloaded");
238   return 0;
239 #endif
240 }
241 
wifi_get_fw_path(int fw_type)242 const char *wifi_get_fw_path(int fw_type) {
243   switch (fw_type) {
244     case WIFI_GET_FW_PATH_STA:
245       return WIFI_DRIVER_FW_PATH_STA;
246     case WIFI_GET_FW_PATH_AP:
247       return WIFI_DRIVER_FW_PATH_AP;
248     case WIFI_GET_FW_PATH_P2P:
249       return WIFI_DRIVER_FW_PATH_P2P;
250   }
251   return NULL;
252 }
253 
wifi_change_fw_path(const char * fwpath)254 int wifi_change_fw_path(const char *fwpath) {
255   int len;
256   int fd;
257   int ret = 0;
258 
259   if (!fwpath) return ret;
260   fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY));
261   if (fd < 0) {
262     PLOG(ERROR) << "Failed to open wlan fw path param";
263     return -1;
264   }
265   len = strlen(fwpath) + 1;
266   if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) {
267     PLOG(ERROR) << "Failed to write wlan fw path param";
268     ret = -1;
269   }
270   close(fd);
271   return ret;
272 }
273