• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
21  #include <dirent.h>
22  #include <sys/socket.h>
23  #include <unistd.h>
24  #include <poll.h>
25  
26  #include "hardware_legacy/wifi.h"
27  #ifdef LIBWPA_CLIENT_EXISTS
28  #include "libwpa_client/wpa_ctrl.h"
29  #endif
30  
31  #define LOG_TAG "WifiHW"
32  #include "cutils/log.h"
33  #include "cutils/memory.h"
34  #include "cutils/misc.h"
35  #include "cutils/properties.h"
36  #include "private/android_filesystem_config.h"
37  #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
38  #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
39  #include <sys/_system_properties.h>
40  #endif
41  
42  extern int do_dhcp();
43  extern int ifc_init();
44  extern void ifc_close();
45  extern char *dhcp_lasterror();
46  extern void get_dhcp_info();
47  extern int init_module(void *, unsigned long, const char *);
48  extern int delete_module(const char *, unsigned int);
49  void wifi_close_sockets();
50  
51  #ifndef LIBWPA_CLIENT_EXISTS
52  #define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
53  struct wpa_ctrl {};
wpa_ctrl_cleanup(void)54  void wpa_ctrl_cleanup(void) {}
wpa_ctrl_open(const char * ctrl_path)55  struct wpa_ctrl *wpa_ctrl_open(const char *ctrl_path) { return NULL; }
wpa_ctrl_close(struct wpa_ctrl * ctrl)56  void wpa_ctrl_close(struct wpa_ctrl *ctrl) {}
wpa_ctrl_request(struct wpa_ctrl * ctrl,const char * cmd,size_t cmd_len,char * reply,size_t * reply_len,void (* msg_cb)(char * msg,size_t len))57  int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
58  	char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len))
59  	{ return 0; }
wpa_ctrl_attach(struct wpa_ctrl * ctrl)60  int wpa_ctrl_attach(struct wpa_ctrl *ctrl) { return 0; }
wpa_ctrl_detach(struct wpa_ctrl * ctrl)61  int wpa_ctrl_detach(struct wpa_ctrl *ctrl) { return 0; }
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)62  int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
63  	{ return 0; }
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)64  int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) { return 0; }
65  #endif
66  
67  static struct wpa_ctrl *ctrl_conn;
68  static struct wpa_ctrl *monitor_conn;
69  
70  /* socket pair used to exit from a blocking read */
71  static int exit_sockets[2];
72  
73  static char primary_iface[PROPERTY_VALUE_MAX];
74  // TODO: use new ANDROID_SOCKET mechanism, once support for multiple
75  // sockets is in
76  
77  #ifndef WIFI_DRIVER_MODULE_ARG
78  #define WIFI_DRIVER_MODULE_ARG          ""
79  #endif
80  #ifndef WIFI_FIRMWARE_LOADER
81  #define WIFI_FIRMWARE_LOADER		""
82  #endif
83  #define WIFI_TEST_INTERFACE		"sta"
84  
85  #ifndef WIFI_DRIVER_FW_PATH_STA
86  #define WIFI_DRIVER_FW_PATH_STA		NULL
87  #endif
88  #ifndef WIFI_DRIVER_FW_PATH_AP
89  #define WIFI_DRIVER_FW_PATH_AP		NULL
90  #endif
91  #ifndef WIFI_DRIVER_FW_PATH_P2P
92  #define WIFI_DRIVER_FW_PATH_P2P		NULL
93  #endif
94  
95  #ifndef WIFI_DRIVER_FW_PATH_PARAM
96  #define WIFI_DRIVER_FW_PATH_PARAM	"/sys/module/wlan/parameters/fwpath"
97  #endif
98  
99  #define WIFI_DRIVER_LOADER_DELAY	1000000
100  
101  static const char IFACE_DIR[]           = "/data/system/wpa_supplicant";
102  #ifdef WIFI_DRIVER_MODULE_PATH
103  static const char DRIVER_MODULE_NAME[]  = WIFI_DRIVER_MODULE_NAME;
104  static const char DRIVER_MODULE_TAG[]   = WIFI_DRIVER_MODULE_NAME " ";
105  static const char DRIVER_MODULE_PATH[]  = WIFI_DRIVER_MODULE_PATH;
106  static const char DRIVER_MODULE_ARG[]   = WIFI_DRIVER_MODULE_ARG;
107  #endif
108  static const char FIRMWARE_LOADER[]     = WIFI_FIRMWARE_LOADER;
109  static const char DRIVER_PROP_NAME[]    = "wlan.driver.status";
110  static const char SUPPLICANT_NAME[]     = "wpa_supplicant";
111  static const char SUPP_PROP_NAME[]      = "init.svc.wpa_supplicant";
112  static const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant";
113  static const char P2P_PROP_NAME[]       = "init.svc.p2p_supplicant";
114  static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf";
115  static const char SUPP_CONFIG_FILE[]    = "/data/misc/wifi/wpa_supplicant.conf";
116  static const char P2P_CONFIG_FILE[]     = "/data/misc/wifi/p2p_supplicant.conf";
117  static const char CONTROL_IFACE_PATH[]  = "/data/misc/wifi/sockets";
118  static const char MODULE_FILE[]         = "/proc/modules";
119  
120  static const char IFNAME[]              = "IFNAME=";
121  #define IFNAMELEN			(sizeof(IFNAME) - 1)
122  static const char WPA_EVENT_IGNORE[]    = "CTRL-EVENT-IGNORE ";
123  
124  static const char SUPP_ENTROPY_FILE[]   = WIFI_ENTROPY_FILE;
125  static unsigned char dummy_key[21] = { 0x02, 0x11, 0xbe, 0x33, 0x43, 0x35,
126                                         0x68, 0x47, 0x84, 0x99, 0xa9, 0x2b,
127                                         0x1c, 0xd3, 0xee, 0xff, 0xf1, 0xe2,
128                                         0xf3, 0xf4, 0xf5 };
129  
130  /* Is either SUPPLICANT_NAME or P2P_SUPPLICANT_NAME */
131  static char supplicant_name[PROPERTY_VALUE_MAX];
132  /* Is either SUPP_PROP_NAME or P2P_PROP_NAME */
133  static char supplicant_prop_name[PROPERTY_KEY_MAX];
134  
insmod(const char * filename,const char * args)135  static int insmod(const char *filename, const char *args)
136  {
137      void *module;
138      unsigned int size;
139      int ret;
140  
141      module = load_file(filename, &size);
142      if (!module)
143          return -1;
144  
145      ret = init_module(module, size, args);
146  
147      free(module);
148  
149      return ret;
150  }
151  
rmmod(const char * modname)152  static int rmmod(const char *modname)
153  {
154      int ret = -1;
155      int maxtry = 10;
156  
157      while (maxtry-- > 0) {
158          ret = delete_module(modname, O_NONBLOCK | O_EXCL);
159          if (ret < 0 && errno == EAGAIN)
160              usleep(500000);
161          else
162              break;
163      }
164  
165      if (ret != 0)
166          ALOGD("Unable to unload driver module \"%s\": %s\n",
167               modname, strerror(errno));
168      return ret;
169  }
170  
do_dhcp_request(int * ipaddr,int * gateway,int * mask,int * dns1,int * dns2,int * server,int * lease)171  int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
172                      int *dns1, int *dns2, int *server, int *lease) {
173      /* For test driver, always report success */
174      if (strcmp(primary_iface, WIFI_TEST_INTERFACE) == 0)
175          return 0;
176  
177      if (ifc_init() < 0)
178          return -1;
179  
180      if (do_dhcp(primary_iface) < 0) {
181          ifc_close();
182          return -1;
183      }
184      ifc_close();
185      get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease);
186      return 0;
187  }
188  
get_dhcp_error_string()189  const char *get_dhcp_error_string() {
190      return dhcp_lasterror();
191  }
192  
is_wifi_driver_loaded()193  int is_wifi_driver_loaded() {
194      char driver_status[PROPERTY_VALUE_MAX];
195  #ifdef WIFI_DRIVER_MODULE_PATH
196      FILE *proc;
197      char line[sizeof(DRIVER_MODULE_TAG)+10];
198  #endif
199  
200      if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
201              || strcmp(driver_status, "ok") != 0) {
202          return 0;  /* driver not loaded */
203      }
204  #ifdef WIFI_DRIVER_MODULE_PATH
205      /*
206       * If the property says the driver is loaded, check to
207       * make sure that the property setting isn't just left
208       * over from a previous manual shutdown or a runtime
209       * crash.
210       */
211      if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
212          ALOGW("Could not open %s: %s", MODULE_FILE, strerror(errno));
213          property_set(DRIVER_PROP_NAME, "unloaded");
214          return 0;
215      }
216      while ((fgets(line, sizeof(line), proc)) != NULL) {
217          if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
218              fclose(proc);
219              return 1;
220          }
221      }
222      fclose(proc);
223      property_set(DRIVER_PROP_NAME, "unloaded");
224      return 0;
225  #else
226      return 1;
227  #endif
228  }
229  
wifi_load_driver()230  int wifi_load_driver()
231  {
232  #ifdef WIFI_DRIVER_MODULE_PATH
233      char driver_status[PROPERTY_VALUE_MAX];
234      int count = 100; /* wait at most 20 seconds for completion */
235  
236      if (is_wifi_driver_loaded()) {
237          return 0;
238      }
239  
240      if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0)
241          return -1;
242  
243      if (strcmp(FIRMWARE_LOADER,"") == 0) {
244          /* usleep(WIFI_DRIVER_LOADER_DELAY); */
245          property_set(DRIVER_PROP_NAME, "ok");
246      }
247      else {
248          property_set("ctl.start", FIRMWARE_LOADER);
249      }
250      sched_yield();
251      while (count-- > 0) {
252          if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
253              if (strcmp(driver_status, "ok") == 0)
254                  return 0;
255              else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) {
256                  wifi_unload_driver();
257                  return -1;
258              }
259          }
260          usleep(200000);
261      }
262      property_set(DRIVER_PROP_NAME, "timeout");
263      wifi_unload_driver();
264      return -1;
265  #else
266      property_set(DRIVER_PROP_NAME, "ok");
267      return 0;
268  #endif
269  }
270  
wifi_unload_driver()271  int wifi_unload_driver()
272  {
273      usleep(200000); /* allow to finish interface down */
274  #ifdef WIFI_DRIVER_MODULE_PATH
275      if (rmmod(DRIVER_MODULE_NAME) == 0) {
276          int count = 20; /* wait at most 10 seconds for completion */
277          while (count-- > 0) {
278              if (!is_wifi_driver_loaded())
279                  break;
280              usleep(500000);
281          }
282          usleep(500000); /* allow card removal */
283          if (count) {
284              return 0;
285          }
286          return -1;
287      } else
288          return -1;
289  #else
290      property_set(DRIVER_PROP_NAME, "unloaded");
291      return 0;
292  #endif
293  }
294  
ensure_entropy_file_exists()295  int ensure_entropy_file_exists()
296  {
297      int ret;
298      int destfd;
299  
300      ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK);
301      if ((ret == 0) || (errno == EACCES)) {
302          if ((ret != 0) &&
303              (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
304              ALOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
305              return -1;
306          }
307          return 0;
308      }
309      destfd = TEMP_FAILURE_RETRY(open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660));
310      if (destfd < 0) {
311          ALOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
312          return -1;
313      }
314  
315      if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) {
316          ALOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
317          close(destfd);
318          return -1;
319      }
320      close(destfd);
321  
322      /* chmod is needed because open() didn't set permisions properly */
323      if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) {
324          ALOGE("Error changing permissions of %s to 0660: %s",
325               SUPP_ENTROPY_FILE, strerror(errno));
326          unlink(SUPP_ENTROPY_FILE);
327          return -1;
328      }
329  
330      if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) {
331          ALOGE("Error changing group ownership of %s to %d: %s",
332               SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno));
333          unlink(SUPP_ENTROPY_FILE);
334          return -1;
335      }
336      return 0;
337  }
338  
ensure_config_file_exists(const char * config_file)339  int ensure_config_file_exists(const char *config_file)
340  {
341      char buf[2048];
342      int srcfd, destfd;
343      struct stat sb;
344      int nread;
345      int ret;
346  
347      ret = access(config_file, R_OK|W_OK);
348      if ((ret == 0) || (errno == EACCES)) {
349          if ((ret != 0) &&
350              (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
351              ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno));
352              return -1;
353          }
354          return 0;
355      } else if (errno != ENOENT) {
356          ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno));
357          return -1;
358      }
359  
360      srcfd = TEMP_FAILURE_RETRY(open(SUPP_CONFIG_TEMPLATE, O_RDONLY));
361      if (srcfd < 0) {
362          ALOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
363          return -1;
364      }
365  
366      destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT|O_RDWR, 0660));
367      if (destfd < 0) {
368          close(srcfd);
369          ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno));
370          return -1;
371      }
372  
373      while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) {
374          if (nread < 0) {
375              ALOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
376              close(srcfd);
377              close(destfd);
378              unlink(config_file);
379              return -1;
380          }
381          TEMP_FAILURE_RETRY(write(destfd, buf, nread));
382      }
383  
384      close(destfd);
385      close(srcfd);
386  
387      /* chmod is needed because open() didn't set permisions properly */
388      if (chmod(config_file, 0660) < 0) {
389          ALOGE("Error changing permissions of %s to 0660: %s",
390               config_file, strerror(errno));
391          unlink(config_file);
392          return -1;
393      }
394  
395      if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) {
396          ALOGE("Error changing group ownership of %s to %d: %s",
397               config_file, AID_WIFI, strerror(errno));
398          unlink(config_file);
399          return -1;
400      }
401      return 0;
402  }
403  
wifi_start_supplicant(int p2p_supported)404  int wifi_start_supplicant(int p2p_supported)
405  {
406      char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
407      int count = 200; /* wait at most 20 seconds for completion */
408  #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
409      const prop_info *pi;
410      unsigned serial = 0, i;
411  #endif
412  
413      if (p2p_supported) {
414          strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
415          strcpy(supplicant_prop_name, P2P_PROP_NAME);
416  
417          /* Ensure p2p config file is created */
418          if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) {
419              ALOGE("Failed to create a p2p config file");
420              return -1;
421          }
422  
423      } else {
424          strcpy(supplicant_name, SUPPLICANT_NAME);
425          strcpy(supplicant_prop_name, SUPP_PROP_NAME);
426      }
427  
428      /* Check whether already running */
429      if (property_get(supplicant_prop_name, supp_status, NULL)
430              && strcmp(supp_status, "running") == 0) {
431          return 0;
432      }
433  
434      /* Before starting the daemon, make sure its config file exists */
435      if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) {
436          ALOGE("Wi-Fi will not be enabled");
437          return -1;
438      }
439  
440      if (ensure_entropy_file_exists() < 0) {
441          ALOGE("Wi-Fi entropy file was not created");
442      }
443  
444      /* Clear out any stale socket files that might be left over. */
445      wpa_ctrl_cleanup();
446  
447      /* Reset sockets used for exiting from hung state */
448      exit_sockets[0] = exit_sockets[1] = -1;
449  
450  #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
451      /*
452       * Get a reference to the status property, so we can distinguish
453       * the case where it goes stopped => running => stopped (i.e.,
454       * it start up, but fails right away) from the case in which
455       * it starts in the stopped state and never manages to start
456       * running at all.
457       */
458      pi = __system_property_find(supplicant_prop_name);
459      if (pi != NULL) {
460          serial = __system_property_serial(pi);
461      }
462  #endif
463      property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
464  
465      property_set("ctl.start", supplicant_name);
466      sched_yield();
467  
468      while (count-- > 0) {
469  #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
470          if (pi == NULL) {
471              pi = __system_property_find(supplicant_prop_name);
472          }
473          if (pi != NULL) {
474              /*
475               * property serial updated means that init process is scheduled
476               * after we sched_yield, further property status checking is based on this */
477              if (__system_property_serial(pi) != serial) {
478                  __system_property_read(pi, NULL, supp_status);
479                  if (strcmp(supp_status, "running") == 0) {
480                      return 0;
481                  } else if (strcmp(supp_status, "stopped") == 0) {
482                      return -1;
483                  }
484              }
485          }
486  #else
487          if (property_get(supplicant_prop_name, supp_status, NULL)) {
488              if (strcmp(supp_status, "running") == 0)
489                  return 0;
490          }
491  #endif
492          usleep(100000);
493      }
494      return -1;
495  }
496  
wifi_stop_supplicant(int p2p_supported)497  int wifi_stop_supplicant(int p2p_supported)
498  {
499      char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
500      int count = 50; /* wait at most 5 seconds for completion */
501  
502      if (p2p_supported) {
503          strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
504          strcpy(supplicant_prop_name, P2P_PROP_NAME);
505      } else {
506          strcpy(supplicant_name, SUPPLICANT_NAME);
507          strcpy(supplicant_prop_name, SUPP_PROP_NAME);
508      }
509  
510      /* Check whether supplicant already stopped */
511      if (property_get(supplicant_prop_name, supp_status, NULL)
512          && strcmp(supp_status, "stopped") == 0) {
513          return 0;
514      }
515  
516      property_set("ctl.stop", supplicant_name);
517      sched_yield();
518  
519      while (count-- > 0) {
520          if (property_get(supplicant_prop_name, supp_status, NULL)) {
521              if (strcmp(supp_status, "stopped") == 0)
522                  return 0;
523          }
524          usleep(100000);
525      }
526      ALOGE("Failed to stop supplicant");
527      return -1;
528  }
529  
wifi_connect_on_socket_path(const char * path)530  int wifi_connect_on_socket_path(const char *path)
531  {
532      char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
533  
534      /* Make sure supplicant is running */
535      if (!property_get(supplicant_prop_name, supp_status, NULL)
536              || strcmp(supp_status, "running") != 0) {
537          ALOGE("Supplicant not running, cannot connect");
538          return -1;
539      }
540  
541      ctrl_conn = wpa_ctrl_open(path);
542      if (ctrl_conn == NULL) {
543          ALOGE("Unable to open connection to supplicant on \"%s\": %s",
544               path, strerror(errno));
545          return -1;
546      }
547      monitor_conn = wpa_ctrl_open(path);
548      if (monitor_conn == NULL) {
549          wpa_ctrl_close(ctrl_conn);
550          ctrl_conn = NULL;
551          return -1;
552      }
553      if (wpa_ctrl_attach(monitor_conn) != 0) {
554          wpa_ctrl_close(monitor_conn);
555          wpa_ctrl_close(ctrl_conn);
556          ctrl_conn = monitor_conn = NULL;
557          return -1;
558      }
559  
560      if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
561          wpa_ctrl_close(monitor_conn);
562          wpa_ctrl_close(ctrl_conn);
563          ctrl_conn = monitor_conn = NULL;
564          return -1;
565      }
566  
567      return 0;
568  }
569  
570  /* Establishes the control and monitor socket connections on the interface */
wifi_connect_to_supplicant()571  int wifi_connect_to_supplicant()
572  {
573      static char path[PATH_MAX];
574  
575      if (access(IFACE_DIR, F_OK) == 0) {
576          snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
577      } else {
578          snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface);
579      }
580      return wifi_connect_on_socket_path(path);
581  }
582  
wifi_send_command(const char * cmd,char * reply,size_t * reply_len)583  int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
584  {
585      int ret;
586      if (ctrl_conn == NULL) {
587          ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
588          return -1;
589      }
590      ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
591      if (ret == -2) {
592          ALOGD("'%s' command timed out.\n", cmd);
593          /* unblocks the monitor receive socket for termination */
594          TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
595          return -2;
596      } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
597          return -1;
598      }
599      if (strncmp(cmd, "PING", 4) == 0) {
600          reply[*reply_len] = '\0';
601      }
602      return 0;
603  }
604  
wifi_supplicant_connection_active()605  int wifi_supplicant_connection_active()
606  {
607      char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
608  
609      if (property_get(supplicant_prop_name, supp_status, NULL)) {
610          if (strcmp(supp_status, "stopped") == 0)
611              return -1;
612      }
613  
614      return 0;
615  }
616  
wifi_ctrl_recv(char * reply,size_t * reply_len)617  int wifi_ctrl_recv(char *reply, size_t *reply_len)
618  {
619      int res;
620      int ctrlfd = wpa_ctrl_get_fd(monitor_conn);
621      struct pollfd rfds[2];
622  
623      memset(rfds, 0, 2 * sizeof(struct pollfd));
624      rfds[0].fd = ctrlfd;
625      rfds[0].events |= POLLIN;
626      rfds[1].fd = exit_sockets[1];
627      rfds[1].events |= POLLIN;
628      do {
629          res = TEMP_FAILURE_RETRY(poll(rfds, 2, 30000));
630          if (res < 0) {
631              ALOGE("Error poll = %d", res);
632              return res;
633          } else if (res == 0) {
634              /* timed out, check if supplicant is active
635               * or not ..
636               */
637              res = wifi_supplicant_connection_active();
638              if (res < 0)
639                  return -2;
640          }
641      } while (res == 0);
642  
643      if (rfds[0].revents & POLLIN) {
644          return wpa_ctrl_recv(monitor_conn, reply, reply_len);
645      }
646  
647      /* it is not rfds[0], then it must be rfts[1] (i.e. the exit socket)
648       * or we timed out. In either case, this call has failed ..
649       */
650      return -2;
651  }
652  
wifi_wait_on_socket(char * buf,size_t buflen)653  int wifi_wait_on_socket(char *buf, size_t buflen)
654  {
655      size_t nread = buflen - 1;
656      int result;
657      char *match, *match2;
658  
659      if (monitor_conn == NULL) {
660          return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
661                          primary_iface, WPA_EVENT_TERMINATING);
662      }
663  
664      result = wifi_ctrl_recv(buf, &nread);
665  
666      /* Terminate reception on exit socket */
667      if (result == -2) {
668          return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
669                          primary_iface, WPA_EVENT_TERMINATING);
670      }
671  
672      if (result < 0) {
673          ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno));
674          return snprintf(buf, buflen, "IFNAME=%s %s - recv error",
675                          primary_iface, WPA_EVENT_TERMINATING);
676      }
677      buf[nread] = '\0';
678      /* Check for EOF on the socket */
679      if (result == 0 && nread == 0) {
680          /* Fabricate an event to pass up */
681          ALOGD("Received EOF on supplicant socket\n");
682          return snprintf(buf, buflen, "IFNAME=%s %s - signal 0 received",
683                          primary_iface, WPA_EVENT_TERMINATING);
684      }
685      /*
686       * Events strings are in the format
687       *
688       *     IFNAME=iface <N>CTRL-EVENT-XXX
689       *        or
690       *     <N>CTRL-EVENT-XXX
691       *
692       * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
693       * etc.) and XXX is the event name. The level information is not useful
694       * to us, so strip it off.
695       */
696  
697      if (strncmp(buf, IFNAME, IFNAMELEN) == 0) {
698          match = strchr(buf, ' ');
699          if (match != NULL) {
700              if (match[1] == '<') {
701                  match2 = strchr(match + 2, '>');
702                  if (match2 != NULL) {
703                      nread -= (match2 - match);
704                      memmove(match + 1, match2 + 1, nread - (match - buf) + 1);
705                  }
706              }
707          } else {
708              return snprintf(buf, buflen, "%s", WPA_EVENT_IGNORE);
709          }
710      } else if (buf[0] == '<') {
711          match = strchr(buf, '>');
712          if (match != NULL) {
713              nread -= (match + 1 - buf);
714              memmove(buf, match + 1, nread + 1);
715              ALOGV("supplicant generated event without interface - %s\n", buf);
716          }
717      } else {
718          /* let the event go as is! */
719          ALOGW("supplicant generated event without interface and without message level - %s\n", buf);
720      }
721  
722      return nread;
723  }
724  
wifi_wait_for_event(char * buf,size_t buflen)725  int wifi_wait_for_event(char *buf, size_t buflen)
726  {
727      return wifi_wait_on_socket(buf, buflen);
728  }
729  
wifi_close_sockets()730  void wifi_close_sockets()
731  {
732      if (ctrl_conn != NULL) {
733          wpa_ctrl_close(ctrl_conn);
734          ctrl_conn = NULL;
735      }
736  
737      if (monitor_conn != NULL) {
738          wpa_ctrl_close(monitor_conn);
739          monitor_conn = NULL;
740      }
741  
742      if (exit_sockets[0] >= 0) {
743          close(exit_sockets[0]);
744          exit_sockets[0] = -1;
745      }
746  
747      if (exit_sockets[1] >= 0) {
748          close(exit_sockets[1]);
749          exit_sockets[1] = -1;
750      }
751  }
752  
wifi_close_supplicant_connection()753  void wifi_close_supplicant_connection()
754  {
755      char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
756      int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */
757  
758      wifi_close_sockets();
759  
760      while (count-- > 0) {
761          if (property_get(supplicant_prop_name, supp_status, NULL)) {
762              if (strcmp(supp_status, "stopped") == 0)
763                  return;
764          }
765          usleep(100000);
766      }
767  }
768  
wifi_command(const char * command,char * reply,size_t * reply_len)769  int wifi_command(const char *command, char *reply, size_t *reply_len)
770  {
771      return wifi_send_command(command, reply, reply_len);
772  }
773  
wifi_get_fw_path(int fw_type)774  const char *wifi_get_fw_path(int fw_type)
775  {
776      switch (fw_type) {
777      case WIFI_GET_FW_PATH_STA:
778          return WIFI_DRIVER_FW_PATH_STA;
779      case WIFI_GET_FW_PATH_AP:
780          return WIFI_DRIVER_FW_PATH_AP;
781      case WIFI_GET_FW_PATH_P2P:
782          return WIFI_DRIVER_FW_PATH_P2P;
783      }
784      return NULL;
785  }
786  
wifi_change_fw_path(const char * fwpath)787  int wifi_change_fw_path(const char *fwpath)
788  {
789      int len;
790      int fd;
791      int ret = 0;
792  
793      if (!fwpath)
794          return ret;
795      fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY));
796      if (fd < 0) {
797          ALOGE("Failed to open wlan fw path param (%s)", strerror(errno));
798          return -1;
799      }
800      len = strlen(fwpath) + 1;
801      if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) {
802          ALOGE("Failed to write wlan fw path param (%s)", strerror(errno));
803          ret = -1;
804      }
805      close(fd);
806      return ret;
807  }
808