(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif
+#define CLAMP(x, low, high) \
+ (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+
static int
wpa_open(const char *ifname, char **path)
{
}
static bool
-dhcpcd_attach_detach(DHCPCD_WPA *wpa, int attach)
+dhcpcd_attach_detach(DHCPCD_WPA *wpa, bool attach)
{
char buf[10];
ssize_t bytes;
dhcpcd_wpa_scans_read(DHCPCD_WPA *wpa)
{
size_t i;
- ssize_t bytes;
+ ssize_t bytes, dl;
DHCPCD_WI_SCAN *wis, *w, *l;
char *s, *p, buf[32];
+ char wssid[sizeof(w->ssid)], tssid[sizeof(w->ssid)];
if (!dhcpcd_realloc(wpa->con, 2048))
return NULL;
dhcpcd_strtoi(&w->level.value, s + 6);
else if (strncmp(s, "flags=", 6) == 0)
strlcpy(w->flags, s + 6, sizeof(w->flags));
- else if (strncmp(s, "ssid=", 5) == 0)
- strlcpy(w->ssid, s + 5, sizeof(w->ssid));
+ else if (strncmp(s, "ssid=", 5) == 0) {
+ /* Decode it from \xNN to \NNN
+ * so we're consistent */
+ strlcpy(wssid, s + 5, sizeof(wssid));
+ dl = dhcpcd_decode(tssid, sizeof(tssid), wssid);
+ dhcpcd_encode(w->ssid, sizeof(w->ssid),
+ tssid, (size_t)dl);
+ }
+ }
+
+ w->strength.value = w->level.value;
+ if (w->strength.value > 110 && w->strength.value < 256)
+ /* Convert WEXT level to dBm */
+ w->strength.value -= 256;
+
+ if (w->strength.value < 0) {
+ /* Assume dBm */
+ w->strength.value =
+ abs(CLAMP(w->strength.value, -100, -40) + 40);
+ w->strength.value =
+ 100 - ((100 * w->strength.value) / 60);
+ } else {
+ /* Assume quality percentage */
+ w->strength.value = CLAMP(w->strength.value, 0, 100);
}
+
}
return wis;
}
w->quality.average = w->quality.value;
w->noise.average = w->noise.value;
w->level.average = w->level.value;
+ w->strength.average = w->strength.value;
for (h = wpa->con->wi_history; h; h = h->next) {
if (strcmp(h->ifname, i->ifname) == 0 &&
w->quality.average += h->quality;
w->noise.average += h->noise;
w->level.average += h->level;
+ w->strength.average += h->strength;
if (++nh == DHCPCD_WI_HIST_MAX) {
hl->next = h->next;
free(h);
w->quality.average /= nh;
w->noise.average /= nh;
w->level.average /= nh;
+ w->strength.average /= nh;
}
h = malloc(sizeof(*h));
if (h) {
h->quality = w->quality.value;
h->noise = w->noise.value;
h->level = w->level.value;
+ h->strength = w->strength.value;
h->next = wpa->con->wi_history;
wpa->con->wi_history = h;
}
static int
dhcpcd_wpa_network_find(DHCPCD_WPA *wpa, const char *fssid)
{
- ssize_t bytes;
+ ssize_t bytes, dl, tl;
char *s, *t, *ssid, *bssid, *flags;
+ char dssid[IF_SSIDSIZE], tssid[IF_SSIDSIZE];
long l;
dhcpcd_realloc(wpa->con, 2048);
if (bytes == 0 || bytes == -1)
return -1;
+ if ((dl = dhcpcd_decode(dssid, sizeof(dssid), fssid)) == -1)
+ return -1;
+
s = strchr(wpa->con->buf, '\n');
if (s == NULL)
return -1;
errno = ERANGE;
break;
}
- if (strcmp(ssid, fssid) == 0)
+
+ if ((tl = dhcpcd_decode(tssid, sizeof(tssid), ssid)) == -1)
+ return -1;
+ if (tl == dl && memcmp(tssid, dssid, (size_t)tl) == 0)
return (int)l;
}
errno = ENOENT;
return (int)l;
}
+static const char hexstr[] = "0123456789ABCDEF";
int
dhcpcd_wpa_network_find_new(DHCPCD_WPA *wpa, const char *ssid)
{
int id;
+ char dssid[IF_SSIDSIZE], essid[IF_SSIDSIZE], *ep;
+ ssize_t dl;
id = dhcpcd_wpa_network_find(wpa, ssid);
- if (id == -1)
- id = dhcpcd_wpa_network_new(wpa);
+ if (id != -1)
+ return id;
+
+ dl = dhcpcd_decode(dssid, sizeof(dssid), ssid);
+ if (dl == -1)
+ return -1;
+
+ ep = essid;
+ if ((size_t)dl != strlen(ssid) || memcmp(dssid, ssid, (size_t)dl)) {
+ /* Non standard characters found! Encode as hex string */
+ char *dp;
+ unsigned char c;
+
+ dp = dssid;
+ for (; dl; dl--) {
+ c = (unsigned char)*dp++;
+ *ep++ = hexstr[c >> 4];
+ *ep++ = hexstr[c & 0xf];
+ }
+ } else {
+ *ep++ = '\"';
+ ep = stpcpy(ep, ssid);
+ *ep++ = '\"';
+ }
+ *ep = '\0';
+
+ id = dhcpcd_wpa_network_new(wpa);
+ if (id != -1)
+ dhcpcd_wpa_network_set(wpa, id, "ssid", essid);
return id;
}
dhcpcd_wpa_close(DHCPCD_WPA *wpa)
{
- if (wpa->command_fd == -1)
+ assert(wpa);
+
+ if (wpa->command_fd == -1 || !wpa->open)
return;
- dhcpcd_attach_detach(wpa, -1);
+ wpa->open = false;
+ dhcpcd_attach_detach(wpa, false);
shutdown(wpa->command_fd, SHUT_RDWR);
- wpa->command_fd = -1;
shutdown(wpa->listen_fd, SHUT_RDWR);
+
+ if (wpa->con->wpa_status_cb)
+ wpa->con->wpa_status_cb(wpa, "down",
+ wpa->con->wpa_status_context);
+
+ close(wpa->command_fd);
+ wpa->command_fd = -1;
+ close(wpa->listen_fd);
wpa->listen_fd = -1;
unlink(wpa->command_path);
free(wpa->command_path);
unlink(wpa->listen_path);
free(wpa->listen_path);
wpa->listen_path = NULL;
-
- if (wpa->con->wpa_status_cb)
- wpa->con->wpa_status_cb(wpa, "down",
- wpa->con->wpa_status_context);
-
}
DHCPCD_WPA *
if (strcmp(wpa->ifname, ifname) == 0)
return wpa;
}
+ errno = ENOENT;
return NULL;
}
dhcpcd_wpa_connection(DHCPCD_WPA *wpa)
{
+ assert(wpa);
return wpa->con;
}
int cmd_fd, list_fd = -1;
char *cmd_path = NULL, *list_path = NULL;
- if (wpa->listen_fd != -1)
+ if (wpa->listen_fd != -1) {
+ if (!wpa->open) {
+ errno = EISCONN;
+ return -1;
+ }
return wpa->listen_fd;
+ }
cmd_fd = wpa_open(wpa->ifname, &cmd_path);
if (cmd_fd == -1)
if (list_fd == -1)
goto fail;
- wpa->attached = 0;
+ wpa->open = true;
+ wpa->attached = false;
wpa->command_fd = cmd_fd;
wpa->command_path = cmd_path;
wpa->listen_fd = list_fd;
wpa->listen_path = list_path;
- if (!dhcpcd_attach_detach(wpa, 1)) {
+ if (!dhcpcd_attach_detach(wpa, true)) {
dhcpcd_wpa_close(wpa);
return -1;
}
dhcpcd_wpa_get_fd(DHCPCD_WPA *wpa)
{
- return wpa->listen_fd;
+ assert(wpa);
+ return wpa->open ? wpa->listen_fd : -1;
}
void
void (*cb)(DHCPCD_WPA *, void *), void *context)
{
+ assert(con);
con->wi_scanresults_cb = cb;
con->wi_scanresults_context = context;
}
+
+void dhcpcd_wpa_set_status_callback(DHCPCD_CONNECTION * con,
+ void (*cb)(DHCPCD_WPA *, const char *, void *), void *context)
+{
+
+ assert(con);
+ con->wpa_status_cb = cb;
+ con->wpa_status_context = context;
+}
+
void
dhcpcd_wpa_dispatch(DHCPCD_WPA *wpa)
{
char buffer[256], *p;
size_t bytes;
+ assert(wpa);
bytes = (size_t)read(wpa->listen_fd, buffer, sizeof(buffer));
if ((ssize_t)bytes == -1 || bytes == 0) {
dhcpcd_wpa_close(wpa);
DHCPCD_WPA *wpa;
assert(i);
- if (i->wireless && strcmp(i->type, "link") == 0) {
- if (strcmp(i->reason, "STOPPED") == 0) {
+ if (strcmp(i->type, "link") == 0) {
+ if (strcmp(i->reason, "STOPPED") == 0 ||
+ strcmp(i->reason, "DEPARTED") == 0)
+ {
wpa = dhcpcd_wpa_find(i->con, i->ifname);
if (wpa)
dhcpcd_wpa_close(wpa);
- } else if (i->up) {
+ } else if (i->wireless && i->con->wpa_started) {
wpa = dhcpcd_wpa_new(i->con, i->ifname);
if (wpa && wpa->listen_fd == -1)
dhcpcd_wpa_open(wpa);
}
}
}
+
+void
+dhcpcd_wpa_start(DHCPCD_CONNECTION *con)
+{
+ DHCPCD_IF *i;
+
+ assert(con);
+ con->wpa_started = true;
+
+ for (i = con->interfaces; i; i = i->next)
+ dhcpcd_wpa_if_event(i);
+}
+
+int
+dhcpcd_wpa_configure_psk(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s, const char *psk)
+{
+ const char *mgmt, *var;
+ int id;
+ char *npsk;
+ size_t psk_len;
+ bool r;
+
+ assert(wpa);
+ assert(s);
+
+ 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";
+ }
+
+ 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 (!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;
+}