nl80211: don't guess if a name is an ifname
[project/iwinfo.git] / iwinfo_nl80211.c
index c17aaa2f9f70f4fb8364624c6534eed2ff5bfcde..545c56c5322d92317aa0ade3e70740f71608618a 100644 (file)
@@ -22,6 +22,7 @@
  * Parts of this code are derived from the Linux iw utility.
  */
 
+#include <sys/stat.h>
 #include <limits.h>
 #include <glob.h>
 #include <fnmatch.h>
@@ -411,6 +412,15 @@ out:
        return idx;
 }
 
+static bool nl80211_is_ifname(const char *name)
+{
+       struct stat st;
+       char buffer[PATH_MAX];
+
+       snprintf(buffer, sizeof(buffer), "/sys/class/net/%s", name);
+       return !lstat(buffer, &st);
+}
+
 static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname,
                                                  int cmd, int flags)
 {
@@ -426,10 +436,10 @@ static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname,
 
        if (!strncmp(ifname, "mon.", 4))
                ifidx = if_nametoindex(&ifname[4]);
-       else
+       else if (nl80211_is_ifname(ifname))
                ifidx = if_nametoindex(ifname);
-
-       if (!ifidx) {
+       else
+       {
                phyidx = nl80211_phy_idx_from_phy(ifname);
                if (phyidx < 0)
                        phyidx = nl80211_phy_idx_from_uci(ifname);
@@ -935,8 +945,19 @@ static int nl80211_wpactl_connect(const char *ifname, struct sockaddr_un *local)
 
        remote.sun_family = AF_UNIX;
        remote_length = sizeof(remote.sun_family) +
-               sprintf(remote.sun_path, "/var/run/wpa_supplicant-%s/%s",
-                       ifname, ifname);
+               sprintf(remote.sun_path, "/var/run/wpa_supplicant/%s", ifname);
+
+       /* 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(sock, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
 
        if (fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC) < 0)
        {
@@ -946,14 +967,8 @@ static int nl80211_wpactl_connect(const char *ifname, struct sockaddr_un *local)
 
        if (connect(sock, (struct sockaddr *)&remote, remote_length))
        {
-               remote_length = sizeof(remote.sun_family) +
-                       sprintf(remote.sun_path, "/var/run/wpa_supplicant/%s", ifname);
-
-               if (connect(sock, (struct sockaddr *)&remote, remote_length))
-               {
-                       close(sock);
-                       return -1;
-               }
+               close(sock);
+               return -1;
        }
 
        local->sun_family = AF_UNIX;
@@ -966,6 +981,10 @@ static int nl80211_wpactl_connect(const char *ifname, struct sockaddr_un *local)
                return -1;
        }
 
+       /* Set group even if we do not have privileges to change owner */
+       lchown(local->sun_path, -1, 101);
+       lchown(local->sun_path, 101, 101);
+
        return sock;
 }
 
@@ -3052,7 +3071,7 @@ struct nl80211_modes
        uint16_t he_phy_cap[6];
 };
 
-static int nl80211_eval_modelist(struct nl80211_modes *m)
+static void nl80211_eval_modelist(struct nl80211_modes *m)
 {
        /* Treat any nonzero capability as 11n */
        if (m->nl_ht > 0)
@@ -3459,7 +3478,9 @@ static int nl80211_get_hardware_id(const char *ifname, char *buf)
                { "vendor", &id->vendor_id },
                { "device", &id->device_id },
                { "subsystem_vendor", &id->subsystem_vendor_id },
-               { "subsystem_device", &id->subsystem_device_id }
+               { "subsystem_device", &id->subsystem_device_id },
+               { "../idVendor", &id->subsystem_vendor_id },
+               { "../idProduct", &id->subsystem_device_id }
        };
 
        memset(id, 0, sizeof(*id));
@@ -3478,12 +3499,14 @@ static int nl80211_get_hardware_id(const char *ifname, char *buf)
        }
 
        /* Failed to obtain hardware IDs, try FDT */
-       if (id->vendor_id == 0 || id->device_id == 0)
+       if (id->vendor_id == 0 && id->device_id == 0 &&
+           id->subsystem_vendor_id == 0 && id->subsystem_device_id == 0)
                if (!nl80211_hardware_id_from_fdt(id, ifname))
                        return 0;
 
        /* Failed to obtain hardware IDs, search board config */
-       if (id->vendor_id == 0 || id->device_id == 0)
+       if (id->vendor_id == 0 && id->device_id == 0 &&
+           id->subsystem_vendor_id == 0 && id->subsystem_device_id == 0)
                return iwinfo_hardware_id_from_mtd(id);
 
        return 0;