Allow a blank psk to just select the network.
[dhcpcd-ui] / src / libdhcpcd / wpa.c
index c74f682514e774a1537df5e472f81586db31c1c2..358b37333d653a69ba9fbef6012bedc57dbbf98c 100644 (file)
@@ -277,6 +277,7 @@ dhcpcd_wpa_scans_read(DHCPCD_WPA *wpa)
        DHCPCD_WI_SCAN *wis, *w, *l;
        char *s, *p, buf[32];
        char wssid[sizeof(w->ssid)];
+       const char *proto;
 
        if (!dhcpcd_realloc(wpa->con, 2048))
                return NULL;
@@ -310,7 +311,8 @@ dhcpcd_wpa_scans_read(DHCPCD_WPA *wpa)
                        else if (strncmp(s, "level=", 6) == 0)
                                dhcpcd_strtoi(&w->level.value, s + 6);
                        else if (strncmp(s, "flags=", 6) == 0)
-                               strlcpy(w->flags, s + 6, sizeof(w->flags));
+                               strlcpy(w->wpa_flags, s + 6,
+                                   sizeof(w->wpa_flags));
                        else if (strncmp(s, "ssid=", 5) == 0) {
                                /* Decode it from \xNN to \NNN
                                 * so we're consistent */
@@ -335,6 +337,25 @@ dhcpcd_wpa_scans_read(DHCPCD_WPA *wpa)
                        l->next = w;
                l = w;
 
+               if ((proto = strstr(w->wpa_flags, "[WPA-")) ||
+                   (proto = strstr(w->wpa_flags, "[WPA2-")) ||
+                   (proto = strstr(w->wpa_flags, "[RSN-")))
+               {
+                       const char *endp, *psk;
+
+                       w->flags = WSF_WPA | WSF_SECURE;
+                       endp = strchr(proto, ']');
+                       if ((psk = strstr(proto, "-PSK]")) ||
+                           (psk = strstr(proto, "-PSK-")) ||
+                           (psk = strstr(proto, "-PSK+")))
+                       {
+                               if (psk < endp)
+                                       w->flags |= WSF_PSK;
+                       }
+               }
+               if (strstr(w->wpa_flags, "[WEP]"))
+                       w->flags = WSF_WEP | WSF_PSK | WSF_SECURE;
+
                w->strength.value = w->level.value;
                if (w->strength.value > 110 && w->strength.value < 256)
                        /* Convert WEXT level to dBm */
@@ -354,7 +375,7 @@ dhcpcd_wpa_scans_read(DHCPCD_WPA *wpa)
        return wis;
 }
 
-static int
+int
 dhcpcd_wi_scan_compare(DHCPCD_WI_SCAN *a, DHCPCD_WI_SCAN *b)
 {
        int cmp;
@@ -555,6 +576,13 @@ dhcpcd_wi_scans(DHCPCD_IF *i)
 }
 
 bool
+dhcpcd_wpa_reconfigure(DHCPCD_WPA *wpa)
+{
+
+       return dhcpcd_wpa_command(wpa, "RECONFIGURE");
+}
+
+bool
 dhcpcd_wpa_reassociate(DHCPCD_WPA *wpa)
 {
 
@@ -602,6 +630,13 @@ dhcpcd_wpa_network_enable(DHCPCD_WPA *wpa, int id)
 }
 
 bool
+dhcpcd_wpa_network_select(DHCPCD_WPA *wpa, int id)
+{
+
+       return dhcpcd_wpa_network(wpa, "SELECT_NETWORK", id);
+}
+
+bool
 dhcpcd_wpa_network_remove(DHCPCD_WPA *wpa, int id)
 {
 
@@ -662,7 +697,7 @@ dhcpcd_wpa_network_find(DHCPCD_WPA *wpa, const char *fssid)
        s = strchr(wpa->con->buf, '\n');
        if (s == NULL)
                return -1;
-       while ((t = strsep(&s, "\b"))) {
+       while ((t = strsep(&s, "\b\n"))) {
                if (*t == '\0')
                        continue;
                ssid = strchr(t, '\t');
@@ -988,55 +1023,123 @@ dhcpcd_wpa_start(DHCPCD_CONNECTION *con)
                dhcpcd_wpa_if_event(i);
 }
 
-int
-dhcpcd_wpa_configure_psk(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s, const char *psk)
+static const char *
+dhcpcd_wpa_var_psk(DHCPCD_WI_SCAN *s)
+{
+
+       if (s->flags & WSF_WEP)
+               return "wep_key0";
+       else if ((s->flags & (WSF_WPA | WSF_PSK)) == (WSF_WPA | WSF_PSK))
+               return "psk";
+       return NULL;
+}
+
+static const char *
+dhcpcd_wpa_var_mgmt(DHCPCD_WI_SCAN *s)
+{
+
+       if (s->flags & WSF_WPA) {
+               if (s->flags & WSF_PSK)
+                       return "WPA-PSK";
+       }
+       return "NONE";
+}
+
+static int
+dhcpcd_wpa_configure1(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s, const char *psk)
 {
        const char *mgmt, *var;
-       int id;
+       int id, retval;
        char *npsk;
        size_t psk_len;
        bool r;
 
-       assert(wpa);
-       assert(s);
+       if (!dhcpcd_wpa_disconnect(wpa))
+               return DHCPCD_WPA_ERR_DISCONN;
+
+       /* reload the configuration so that when we don't save
+        * the disabled networks to the config file. */
+       if (!dhcpcd_wpa_reconfigure(wpa))
+               return DHCPCD_WPA_ERR_RECONF;
 
        id = dhcpcd_wpa_network_find_new(wpa, s->ssid);
        if (id == -1)
                return DHCPCD_WPA_ERR;
 
-       if (strcmp(s->flags, "[WEP]") == 0) {
-               mgmt = "NONE";
-               var = "wep_key0";
-       } else {
-               mgmt = "WPA-PSK";
-               var = "psk";
-       }
+       mgmt = dhcpcd_wpa_var_mgmt(s);
+       var = dhcpcd_wpa_var_psk(s);
+       if (mgmt && var) {
+               if (!dhcpcd_wpa_network_set(wpa, id, "key_mgmt", mgmt))
+                       return DHCPCD_WPA_ERR_SET;
 
-       if (!dhcpcd_wpa_network_set(wpa, id, "key_mgmt", mgmt))
-               return DHCPCD_WPA_ERR_SET;
+               if (psk)
+                       psk_len = strlen(psk);
+               else
+                       psk_len = 0;
+               npsk = malloc(psk_len + 3);
+               if (npsk == NULL)
+                       return DHCPCD_WPA_ERR;
+               npsk[0] = '"';
+               if (psk_len)
+                       memcpy(npsk + 1, psk, psk_len);
+               npsk[psk_len + 1] = '"';
+               npsk[psk_len + 2] = '\0';
+               r = dhcpcd_wpa_network_set(wpa, id, var, npsk);
+               free(npsk);
+               if (!r)
+                       return DHCPCD_WPA_ERR_SET_PSK;
+       }
 
-       if (psk)
-               psk_len = strlen(psk);
+       if (!dhcpcd_wpa_network_enable(wpa, id))
+               return DHCPCD_WPA_ERR_ENABLE;
+       if (dhcpcd_wpa_config_write(wpa))
+               retval = DHCPCD_WPA_SUCCESS;
        else
-               psk_len = 0;
-       npsk = malloc(psk_len + 3);
-       if (npsk == NULL)
+               retval = DHCPCD_WPA_ERR_WRITE;
+       /* Selecting a network disbales the others.
+        * This should not be saved. */
+       if (!dhcpcd_wpa_network_select(wpa, id))
+               return DHCPCD_WPA_ERR_SELECT;
+       return retval;
+}
+
+int
+dhcpcd_wpa_configure(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s, const char *psk)
+{
+       int retval;
+
+       retval = dhcpcd_wpa_configure1(wpa, s, psk);
+       /* Always reassociate */
+       if (!dhcpcd_wpa_reassociate(wpa)) {
+               if (retval == DHCPCD_WPA_SUCCESS)
+                       retval = DHCPCD_WPA_ERR_ASSOC;
+       }
+       return retval;
+}
+
+int
+dhcpcd_wpa_select(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s)
+{
+       int id, retval;
+
+       assert(wpa);
+       assert(s);
+
+       id = dhcpcd_wpa_network_find(wpa, s->ssid);
+       if (id == -1)
                return DHCPCD_WPA_ERR;
-       npsk[0] = '"';
-       if (psk_len)
-               memcpy(npsk + 1, psk, psk_len);
-       npsk[psk_len + 1] = '"';
-       npsk[psk_len + 2] = '\0';
-       r = dhcpcd_wpa_network_set(wpa, id, var, npsk);
-       free(npsk);
-       if (!r)
-               return DHCPCD_WPA_ERR_SET_PSK;
 
-       if (!dhcpcd_wpa_network_enable(wpa, id))
-               return DHCPCD_WPA_ERR_ENABLE;
-       if (!dhcpcd_wpa_reassociate(wpa))
-               return DHCPCD_WPA_ERR_ASSOC;
-       if (!dhcpcd_wpa_config_write(wpa))
-               return DHCPCD_WPA_ERR_WRITE;
-       return DHCPCD_WPA_SUCCESS;
+       if (!dhcpcd_wpa_disconnect(wpa))
+               retval = DHCPCD_WPA_ERR_DISCONN;
+       else if (!dhcpcd_wpa_network_select(wpa, id))
+               retval = DHCPCD_WPA_ERR_SELECT;
+       else
+               retval = DHCPCD_WPA_SUCCESS;
+
+       /* Always reassociate */
+       if (!dhcpcd_wpa_reassociate(wpa)) {
+               if (retval == DHCPCD_WPA_SUCCESS)
+                       retval = DHCPCD_WPA_ERR_ASSOC;
+       }
+       return retval;
 }