#ifdef CONFIG_CTRL_IFACE
#ifdef CONFIG_CTRL_IFACE_UNIX
+#include <sys/stat.h>
+#include <fcntl.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef ANDROID
#include <dirent.h>
+#include <sys/stat.h>
#include <cutils/sockets.h>
#include "private/android_filesystem_config.h"
#endif /* ANDROID */
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+ return wpa_ctrl_open2(ctrl_path, NULL);
+}
+
+
+struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
+ const char *cli_path)
{
struct wpa_ctrl *ctrl;
static int counter = 0;
ctrl->local.sun_family = AF_UNIX;
counter++;
try_again:
- ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
- CONFIG_CTRL_IFACE_CLIENT_DIR "/"
- CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
- (int) getpid(), counter);
+ if (cli_path && cli_path[0] == '/') {
+ ret = os_snprintf(ctrl->local.sun_path,
+ sizeof(ctrl->local.sun_path),
+ "%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
+ cli_path, (int) getpid(), counter);
+ } else {
+ ret = os_snprintf(ctrl->local.sun_path,
+ sizeof(ctrl->local.sun_path),
+ CONFIG_CTRL_IFACE_CLIENT_DIR "/"
+ CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
+ (int) getpid(), counter);
+ }
if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
tries++;
+#ifdef ANDROID
+ /* Set client socket file permissions so that bind() creates the client
+ * socket with these permissions and there is no need to try to change
+ * them with chmod() after bind() which would have potential issues with
+ * race conditions. These permissions are needed to make sure the server
+ * side (wpa_supplicant or hostapd) can reply to the control interface
+ * messages.
+ *
+ * The lchown() calls below after bind() are also part of the needed
+ * operations to allow the response to go through. Those are using the
+ * no-deference-symlinks version to avoid races. */
+ fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+#endif /* ANDROID */
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
if (errno == EADDRINUSE && tries < 2) {
}
#ifdef ANDROID
- chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
- chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
+ /* Set group even if we do not have privileges to change owner */
+ lchown(ctrl->local.sun_path, -1, AID_WIFI);
+ lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
if (socket_local_client_connect(
void wpa_ctrl_cleanup(void)
{
DIR *dir;
- struct dirent entry;
struct dirent *result;
size_t dirnamelen;
size_t maxcopy;
}
namep = pathname + dirnamelen;
maxcopy = PATH_MAX - dirnamelen;
- while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
- if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+ while ((result = readdir(dir)) != NULL) {
+ if (os_strlcpy(namep, result->d_name, maxcopy) < maxcopy)
unlink(pathname);
}
closedir(dir);
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+ if (res < 0 && errno == EINTR)
+ continue;
if (res < 0)
return res;
if (FD_ISSET(ctrl->s, &rfds)) {
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
- if (res > 0 && reply[0] == '<') {
+ if ((res > 0 && reply[0] == '<') ||
+ (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
/* This is an unsolicited message from
* wpa_supplicant, not the reply to the
* request. Use msg_cb to report this to the