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;
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 */
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 */
return wis;
}
+int
+dhcpcd_wi_scan_compare(DHCPCD_WI_SCAN *a, DHCPCD_WI_SCAN *b)
+{
+ int cmp;
+
+ /* Fist sort non case sensitive, then case sensitive */
+ cmp = strcasecmp(a->ssid, b->ssid);
+ if (cmp == 0)
+ cmp = strcmp(a->ssid, b->ssid);
+
+ /* If still the same, return strongest first */
+ if (cmp == 0)
+ cmp = b->strength.value - a->strength.value;
+
+ return cmp;
+}
+
/*
* This function is copyright 2001 Simon Tatham.
*
* SOFTWARE.
*/
static DHCPCD_WI_SCAN *
-dhcpcd_wi_scan_sort(DHCPCD_WI_SCAN *list)
+dhcpcd_wi_scans_sort(DHCPCD_WI_SCAN *list)
{
DHCPCD_WI_SCAN *p, *q, *e, *tail;
size_t insize, nmerges, psize, qsize, i;
} else if (qsize == 0 || !q) {
/* q is empty; e must come from p. */
e = p; p = p->next; psize--;
- } else if (strcasecmp(p->ssid,q->ssid) <= 0) {
+ } else if (dhcpcd_wi_scan_compare(p, q) <= 0) {
/* First element of p is lower
* (or same); e must come from p. */
e = p; p = p->next; psize--;
dhcpcd_wi_scans(DHCPCD_IF *i)
{
DHCPCD_WPA *wpa;
- DHCPCD_WI_SCAN *wis, *w;
+ DHCPCD_WI_SCAN *wis, *w, *n, *p;
int nh;
DHCPCD_WI_HIST *h, *hl;
return NULL;
wis = dhcpcd_wpa_scans_read(wpa);
- /* Sort the resultant list alphabetically */
- wis = dhcpcd_wi_scan_sort(wis);
+ /* Sort the resultant list alphabetically and then by strength */
+ wis = dhcpcd_wi_scans_sort(wis);
+
+ p = NULL;
+ for (w = wis; w && (n = w->next, 1); w = n) {
+ /* Currently we don't support non SSID broadcasting APs */
+ if (*w->ssid == '\0') {
+ if (p == NULL)
+ wis = n;
+ else
+ p->next = n;
+ free(w);
+ continue;
+ }
+ /* Strip duplicated SSIDs, only show the strongest */
+ if (p && strcmp(p->ssid, w->ssid) == 0) {
+ p->next = n;
+ free(w);
+ continue;
+ }
+ /* Remember this as the previos next time */
+ p = w;
- for (w = wis; w; w = w->next) {
nh = 1;
hl = NULL;
w->quality.average = w->quality.value;
}
bool
+dhcpcd_wpa_reconfigure(DHCPCD_WPA *wpa)
+{
+
+ return dhcpcd_wpa_command(wpa, "RECONFIGURE");
+}
+
+bool
dhcpcd_wpa_reassociate(DHCPCD_WPA *wpa)
{
}
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)
{
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');
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;
}