3 * Copyright 2009-2014 Roy Marples <roy@marples.name>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/socket.h>
47 (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
50 #define CLAMP(x, low, high) \
51 (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
54 wpa_open(const char *ifname, char **path)
59 struct sockaddr_un sun;
61 if ((fd = socket(AF_UNIX,
62 SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1)
64 memset(&sun, 0, sizeof(sun));
65 sun.sun_family = AF_UNIX;
66 snprintf(sun.sun_path, sizeof(sun.sun_path),
67 "/tmp/libdhcpcd-wpa-%d.%d", getpid(), counter++);
68 *path = strdup(sun.sun_path);
69 len = (socklen_t)SUN_LEN(&sun);
70 if (bind(fd, (struct sockaddr *)&sun, len) == -1) {
77 snprintf(sun.sun_path, sizeof(sun.sun_path),
78 WPA_CTRL_DIR "/%s", ifname);
79 len = (socklen_t)SUN_LEN(&sun);
80 if (connect(fd, (struct sockaddr *)&sun, len) == -1) {
92 wpa_cmd(int fd, const char *cmd, char *buffer, size_t len)
100 bytes = write(fd, cmd, strlen(cmd));
103 if (buffer == NULL || len == 0)
106 pfd.events = POLLIN | POLLHUP;
108 retval = poll(&pfd, 1, 2000);
111 if (retval == 0 || !(pfd.revents & (POLLIN | POLLHUP)))
114 bytes = read(fd, buffer, len == 1 ? 1 : len - 1);
116 buffer[bytes] = '\0';
121 dhcpcd_wpa_command(DHCPCD_WPA *wpa, const char *cmd)
126 bytes = wpa_cmd(wpa->command_fd, cmd, buf, sizeof(buf));
127 return (bytes == -1 || bytes == 0 ||
128 strcmp(buf, "OK\n")) ? false : true;
132 dhcpcd_wpa_ping(DHCPCD_WPA *wpa)
137 bytes = wpa_cmd(wpa->command_fd, "PING", buf, sizeof(buf));
138 return (bytes == -1 || bytes == 0 ||
139 strcmp(buf, "PONG\n")) ? false : true;
143 dhcpcd_wpa_command_arg(DHCPCD_WPA *wpa, const char *cmd, const char *arg)
147 cmdlen = strlen(cmd);
148 nlen = cmdlen + strlen(arg) + 2;
149 if (!dhcpcd_realloc(wpa->con, nlen))
151 strlcpy(wpa->con->buf, cmd, wpa->con->buflen);
152 wpa->con->buf[cmdlen] = ' ';
153 strlcpy(wpa->con->buf + cmdlen + 1, arg, wpa->con->buflen - 1 - cmdlen);
154 return dhcpcd_wpa_command(wpa, wpa->con->buf);
158 dhcpcd_attach_detach(DHCPCD_WPA *wpa, bool attach)
163 if (wpa->attached == attach)
166 bytes = wpa_cmd(wpa->listen_fd, attach > 0 ? "ATTACH" : "DETACH",
168 if (bytes == -1 || bytes == 0 || strcmp(buf, "OK\n"))
171 wpa->attached = attach;
176 dhcpcd_wpa_scan(DHCPCD_WPA *wpa)
179 return dhcpcd_wpa_command(wpa, "SCAN");
183 dhcpcd_wi_associated(DHCPCD_IF *i, DHCPCD_WI_SCAN *scan)
189 return (i->up && i->ssid && strcmp(i->ssid, scan->ssid) == 0);
193 dhcpcd_wi_scans_free(DHCPCD_WI_SCAN *wis)
205 dhcpcd_strtoi(int *val, const char *s)
209 l = strtol(s, NULL, 0);
210 if (l >= INT_MIN && l <= INT_MAX)
217 dhcpcd_wpa_hex2num(char c)
220 if (c >= '0' && c <= '9')
222 if (c >= 'a' && c <= 'f')
224 if (c >= 'A' && c <= 'F')
230 dhcpcd_wpa_hex2byte(const char *src)
234 if ((h = dhcpcd_wpa_hex2num(*src++)) == -1 ||
235 (l = dhcpcd_wpa_hex2num(*src)) == -1)
241 dhcpcd_wpa_decode_ssid(char *dst, size_t dlen, const char *src)
265 case '"': *dst++ = esc; break;
266 case 'n': *dst++ = '\n'; break;
267 case 'r': *dst++ = '\r'; break;
268 case 't': *dst++ = '\t'; break;
269 case 'e': *dst++ = '\033'; break;
271 if (src[0] == '\0' || src[1] == '\0') {
275 if ((xb = dhcpcd_wpa_hex2byte(src)) == -1)
280 default: errno = EINVAL; return -1;
282 default: *dst++ = c; break;
293 static DHCPCD_WI_SCAN *
294 dhcpcd_wpa_scans_read(DHCPCD_WPA *wpa)
298 DHCPCD_WI_SCAN *wis, *w, *l;
299 char *s, *p, buf[32];
300 char wssid[sizeof(w->ssid)];
303 if (!dhcpcd_realloc(wpa->con, 2048))
306 for (i = 0; i < 1000; i++) {
307 snprintf(buf, sizeof(buf), "BSS %zu", i);
308 bytes = wpa_cmd(wpa->command_fd, buf,
309 wpa->con->buf, wpa->con->buflen);
310 if (bytes == 0 || bytes == -1 ||
311 strncmp(wpa->con->buf, "FAIL", 4) == 0)
314 w = calloc(1, sizeof(*w));
319 while ((s = strsep(&p, "\n"))) {
322 if (strncmp(s, "bssid=", 6) == 0)
323 strlcpy(w->bssid, s + 6, sizeof(w->bssid));
324 else if (strncmp(s, "freq=", 5) == 0)
325 dhcpcd_strtoi(&w->frequency, s + 5);
326 // else if (strncmp(s, "beacon_int=", 11) == 0)
328 else if (strncmp(s, "qual=", 5) == 0)
329 dhcpcd_strtoi(&w->quality.value, s + 5);
330 else if (strncmp(s, "noise=", 6) == 0)
331 dhcpcd_strtoi(&w->noise.value, s + 6);
332 else if (strncmp(s, "level=", 6) == 0)
333 dhcpcd_strtoi(&w->level.value, s + 6);
334 else if (strncmp(s, "flags=", 6) == 0)
335 strlcpy(w->wpa_flags, s + 6,
336 sizeof(w->wpa_flags));
337 else if (strncmp(s, "ssid=", 5) == 0) {
338 /* Decode it from \xNN to \NNN
339 * so we're consistent */
340 dl = dhcpcd_wpa_decode_ssid(wssid,
341 sizeof(wssid), s + 5);
344 dl = dhcpcd_encode_string_escape(w->ssid,
345 sizeof(w->ssid), wssid, (size_t)dl);
361 if ((proto = strstr(w->wpa_flags, "[WPA-")) ||
362 (proto = strstr(w->wpa_flags, "[WPA2-")) ||
363 (proto = strstr(w->wpa_flags, "[RSN-")))
365 const char *endp, *psk;
367 w->flags = WSF_WPA | WSF_SECURE;
368 endp = strchr(proto, ']');
369 if ((psk = strstr(proto, "-PSK]")) ||
370 (psk = strstr(proto, "-PSK-")) ||
371 (psk = strstr(proto, "-PSK+")))
377 if (strstr(w->wpa_flags, "[WEP]"))
378 w->flags = WSF_WEP | WSF_PSK | WSF_SECURE;
380 w->strength.value = w->level.value;
381 if (w->strength.value > 110 && w->strength.value < 256)
382 /* Convert WEXT level to dBm */
383 w->strength.value -= 256;
385 if (w->strength.value < 0) {
388 abs(CLAMP(w->strength.value, -100, -40) + 40);
390 100 - ((100 * w->strength.value) / 60);
392 /* Assume quality percentage */
393 w->strength.value = CLAMP(w->strength.value, 0, 100);
400 dhcpcd_wi_scan_compare(DHCPCD_WI_SCAN *a, DHCPCD_WI_SCAN *b)
404 /* Fist sort non case sensitive, then case sensitive */
405 cmp = strcasecmp(a->ssid, b->ssid);
407 cmp = strcmp(a->ssid, b->ssid);
409 /* If still the same, return strongest first */
411 cmp = b->strength.value - a->strength.value;
417 * This function is copyright 2001 Simon Tatham.
419 * Permission is hereby granted, free of charge, to any person
420 * obtaining a copy of this software and associated documentation
421 * files (the "Software"), to deal in the Software without
422 * restriction, including without limitation the rights to use,
423 * copy, modify, merge, publish, distribute, sublicense, and/or
424 * sell copies of the Software, and to permit persons to whom the
425 * Software is furnished to do so, subject to the following
428 * The above copyright notice and this permission notice shall be
429 * included in all copies or substantial portions of the Software.
431 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
432 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
433 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
434 * NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
435 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
436 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
437 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
440 static DHCPCD_WI_SCAN *
441 dhcpcd_wi_scans_sort(DHCPCD_WI_SCAN *list)
443 DHCPCD_WI_SCAN *p, *q, *e, *tail;
444 size_t insize, nmerges, psize, qsize, i;
446 /* Silly special case: if `list' was passed in as NULL, return
447 * NULL immediately. */
456 nmerges = 0; /* count number of merges we do in this pass */
459 nmerges++; /* there exists a merge to be done */
460 /* step `insize' places along from p */
463 for (i = 0; i < insize; i++) {
470 /* if q hasn't fallen off end,
471 * we have two lists to merge */
474 /* now we have two lists; merge them */
475 while (psize > 0 || (qsize > 0 && q)) {
476 /* decide whether next element of merge comes
479 /* p is empty; e must come from q. */
480 e = q; q = q->next; qsize--;
481 } else if (qsize == 0 || !q) {
482 /* q is empty; e must come from p. */
483 e = p; p = p->next; psize--;
484 } else if (dhcpcd_wi_scan_compare(p, q) <= 0) {
485 /* First element of p is lower
486 * (or same); e must come from p. */
487 e = p; p = p->next; psize--;
489 /* First element of q is lower;
490 * e must come from q. */
491 e = q; q = q->next; qsize--;
494 /* add the next element to the merged list */
502 /* now p has stepped `insize' places along,
508 /* If we have done only one merge, we're finished. */
509 if (nmerges <= 1) /* allow for nmerges==0, the empty list */
512 /* Otherwise repeat, merging lists twice the size */
518 dhcpcd_wi_scans(DHCPCD_IF *i)
521 DHCPCD_WI_SCAN *wis, *w, *n, *p;
523 DHCPCD_WI_HIST *h, *hl;
525 wpa = dhcpcd_wpa_find(i->con, i->ifname);
528 wis = dhcpcd_wpa_scans_read(wpa);
530 /* Sort the resultant list alphabetically and then by strength */
531 wis = dhcpcd_wi_scans_sort(wis);
534 for (w = wis; w && (n = w->next, 1); w = n) {
535 /* Currently we don't support non SSID broadcasting APs */
536 if (*w->ssid == '\0') {
544 /* Strip duplicated SSIDs, only show the strongest */
545 if (p && strcmp(p->ssid, w->ssid) == 0) {
550 /* Remember this as the previos next time */
555 w->quality.average = w->quality.value;
556 w->noise.average = w->noise.value;
557 w->level.average = w->level.value;
558 w->strength.average = w->strength.value;
560 for (h = wpa->con->wi_history; h; h = h->next) {
561 if (strcmp(h->ifname, i->ifname) == 0 &&
562 strcmp(h->bssid, wis->bssid) == 0)
564 w->quality.average += h->quality;
565 w->noise.average += h->noise;
566 w->level.average += h->level;
567 w->strength.average += h->strength;
568 if (++nh == DHCPCD_WI_HIST_MAX) {
578 w->quality.average /= nh;
579 w->noise.average /= nh;
580 w->level.average /= nh;
581 w->strength.average /= nh;
583 h = malloc(sizeof(*h));
585 strlcpy(h->ifname, i->ifname, sizeof(h->ifname));
586 strlcpy(h->bssid, w->bssid, sizeof(h->bssid));
587 h->quality = w->quality.value;
588 h->noise = w->noise.value;
589 h->level = w->level.value;
590 h->strength = w->strength.value;
591 h->next = wpa->con->wi_history;
592 wpa->con->wi_history = h;
600 dhcpcd_wpa_reconfigure(DHCPCD_WPA *wpa)
603 return dhcpcd_wpa_command(wpa, "RECONFIGURE");
607 dhcpcd_wpa_reassociate(DHCPCD_WPA *wpa)
610 return dhcpcd_wpa_command(wpa, "REASSOCIATE");
614 dhcpcd_wpa_disconnect(DHCPCD_WPA *wpa)
617 return dhcpcd_wpa_command(wpa, "DISCONNECT");
621 dhcpcd_wpa_config_write(DHCPCD_WPA *wpa)
624 return dhcpcd_wpa_command(wpa, "SAVE_CONFIG");
628 dhcpcd_wpa_network(DHCPCD_WPA *wpa, const char *cmd, int id)
632 len = strlen(cmd) + 32;
633 if (!dhcpcd_realloc(wpa->con, len))
635 snprintf(wpa->con->buf, wpa->con->buflen, "%s %d", cmd, id);
636 return dhcpcd_wpa_command(wpa, wpa->con->buf);
640 dhcpcd_wpa_network_disable(DHCPCD_WPA *wpa, int id)
643 return dhcpcd_wpa_network(wpa, "DISABLE_NETWORK", id);
647 dhcpcd_wpa_network_enable(DHCPCD_WPA *wpa, int id)
650 return dhcpcd_wpa_network(wpa, "ENABLE_NETWORK", id);
654 dhcpcd_wpa_network_select(DHCPCD_WPA *wpa, int id)
657 return dhcpcd_wpa_network(wpa, "SELECT_NETWORK", id);
661 dhcpcd_wpa_network_remove(DHCPCD_WPA *wpa, int id)
664 return dhcpcd_wpa_network(wpa, "REMOVE_NETWORK", id);
668 dhcpcd_wpa_network_get(DHCPCD_WPA *wpa, int id, const char *param)
672 if (!dhcpcd_realloc(wpa->con, 2048))
674 snprintf(wpa->con->buf, wpa->con->buflen, "GET_NETWORK %d %s",
676 bytes = wpa_cmd(wpa->command_fd, wpa->con->buf,
677 wpa->con->buf, wpa->con->buflen);
678 if (bytes == 0 || bytes == -1)
680 if (strcmp(wpa->con->buf, "FAIL\n") == 0) {
684 return wpa->con->buf;
688 dhcpcd_wpa_network_set(DHCPCD_WPA *wpa, int id,
689 const char *param, const char *value)
693 len = strlen("SET_NETWORK") + 32 + strlen(param) + strlen(value) + 3;
694 if (!dhcpcd_realloc(wpa->con, len))
696 snprintf(wpa->con->buf, wpa->con->buflen, "SET_NETWORK %d %s %s",
698 return dhcpcd_wpa_command(wpa, wpa->con->buf);
702 dhcpcd_wpa_network_find(DHCPCD_WPA *wpa, const char *fssid)
704 ssize_t bytes, dl, tl;
706 char *s, *t, *ssid, *bssid, *flags;
707 char dssid[IF_SSIDSIZE], tssid[IF_SSIDSIZE];
710 dhcpcd_realloc(wpa->con, 2048);
711 bytes = wpa_cmd(wpa->command_fd, "LIST_NETWORKS",
712 wpa->con->buf, wpa->con->buflen);
713 if (bytes == 0 || bytes == -1)
718 s = strchr(wpa->con->buf, '\n');
721 while ((t = strsep(&s, "\b\n"))) {
724 ssid = strchr(t, '\t');
728 bssid = strchr(ssid, '\t');
732 flags = strchr(bssid, '\t');
736 l = strtol(t, NULL, 0);
737 if (l < 0 || l > INT_MAX) {
742 /* Decode the wpa_supplicant SSID into raw chars and
743 * then encode into our octal escaped string to
745 dl = dhcpcd_wpa_decode_ssid(dssid, sizeof(dssid), ssid);
748 tl = dhcpcd_encode_string_escape(tssid,
749 sizeof(tssid), dssid, (size_t)dl);
752 if ((size_t)tl == fl && memcmp(tssid, fssid, (size_t)tl) == 0)
760 dhcpcd_wpa_network_new(DHCPCD_WPA *wpa)
765 dhcpcd_realloc(wpa->con, 32);
766 bytes = wpa_cmd(wpa->command_fd, "ADD_NETWORK",
767 wpa->con->buf, sizeof(wpa->con->buf));
768 if (bytes == 0 || bytes == -1)
770 l = strtol(wpa->con->buf, NULL, 0);
771 if (l < 0 || l > INT_MAX) {
778 static const char hexchrs[] = "0123456789abcdef";
780 dhcpcd_wpa_network_find_new(DHCPCD_WPA *wpa, const char *ssid)
783 char dssid[IF_SSIDSIZE], essid[IF_SSIDSIZE], *ep;
787 id = dhcpcd_wpa_network_find(wpa, ssid);
791 dl = dhcpcd_decode_string_escape(dssid, sizeof(dssid), ssid);
795 for (i = 0; i < dl; i++) {
796 if (!isascii((int)dssid[i]) && !isprint((int)dssid[i]))
802 /* Non standard characters found! Encode as hex string */
806 c = (unsigned char)*dp++;
807 *ep++ = hexchrs[(c & 0xf0) >> 4];
808 *ep++ = hexchrs[(c & 0x0f)];
814 while (*++dp != '\0');
819 id = dhcpcd_wpa_network_new(wpa);
821 dhcpcd_wpa_network_set(wpa, id, "ssid", essid);
826 dhcpcd_wpa_close(DHCPCD_WPA *wpa)
831 if (wpa->command_fd == -1 || !wpa->open)
835 dhcpcd_attach_detach(wpa, false);
836 shutdown(wpa->command_fd, SHUT_RDWR);
837 shutdown(wpa->listen_fd, SHUT_RDWR);
839 if (wpa->con->wpa_status_cb)
840 wpa->con->wpa_status_cb(wpa, "down",
841 wpa->con->wpa_status_context);
843 close(wpa->command_fd);
844 wpa->command_fd = -1;
845 close(wpa->listen_fd);
847 unlink(wpa->command_path);
848 free(wpa->command_path);
849 wpa->command_path = NULL;
850 unlink(wpa->listen_path);
851 free(wpa->listen_path);
852 wpa->listen_path = NULL;
856 dhcpcd_wpa_find(DHCPCD_CONNECTION *con, const char *ifname)
860 for (wpa = con->wpa; wpa; wpa = wpa->next) {
861 if (strcmp(wpa->ifname, ifname) == 0)
869 dhcpcd_wpa_new(DHCPCD_CONNECTION *con, const char *ifname)
873 wpa = dhcpcd_wpa_find(con, ifname);
877 wpa = malloc(sizeof(*wpa));
882 strlcpy(wpa->ifname, ifname, sizeof(wpa->ifname));
883 wpa->command_fd = wpa->listen_fd = -1;
884 wpa->command_path = wpa->listen_path = NULL;
885 wpa->next = con->wpa;
891 dhcpcd_wpa_connection(DHCPCD_WPA *wpa)
899 dhcpcd_wpa_if(DHCPCD_WPA *wpa)
903 return dhcpcd_get_if(wpa->con, wpa->ifname, "link");
907 dhcpcd_wpa_open(DHCPCD_WPA *wpa)
909 int cmd_fd, list_fd = -1;
910 char *cmd_path = NULL, *list_path = NULL;
912 if (wpa->listen_fd != -1) {
917 return wpa->listen_fd;
920 cmd_fd = wpa_open(wpa->ifname, &cmd_path);
924 list_fd = wpa_open(wpa->ifname, &list_path);
929 wpa->attached = false;
930 wpa->command_fd = cmd_fd;
931 wpa->command_path = cmd_path;
932 wpa->listen_fd = list_fd;
933 wpa->listen_path = list_path;
934 if (!dhcpcd_attach_detach(wpa, true)) {
935 dhcpcd_wpa_close(wpa);
939 if (wpa->con->wi_scanresults_cb)
940 wpa->con->wi_scanresults_cb(wpa,
941 wpa->con->wi_scanresults_context);
943 return wpa->listen_fd;
959 dhcpcd_wpa_get_fd(DHCPCD_WPA *wpa)
963 return wpa->open ? wpa->listen_fd : -1;
967 dhcpcd_wpa_set_scan_callback(DHCPCD_CONNECTION *con,
968 void (*cb)(DHCPCD_WPA *, void *), void *context)
972 con->wi_scanresults_cb = cb;
973 con->wi_scanresults_context = context;
977 void dhcpcd_wpa_set_status_callback(DHCPCD_CONNECTION * con,
978 void (*cb)(DHCPCD_WPA *, const char *, void *), void *context)
982 con->wpa_status_cb = cb;
983 con->wpa_status_context = context;
987 dhcpcd_wpa_dispatch(DHCPCD_WPA *wpa)
989 char buffer[256], *p;
993 bytes = (size_t)read(wpa->listen_fd, buffer, sizeof(buffer));
994 if ((ssize_t)bytes == -1) {
995 dhcpcd_wpa_close(wpa);
999 buffer[bytes] = '\0';
1000 bytes = strlen(buffer);
1001 if (buffer[bytes - 1] == ' ')
1002 buffer[--bytes] = '\0';
1003 for (p = buffer + 1; *p != '\0'; p++) {
1010 if (strcmp(p, "CTRL-EVENT-SCAN-RESULTS") == 0 &&
1011 wpa->con->wi_scanresults_cb)
1012 wpa->con->wi_scanresults_cb(wpa,
1013 wpa->con->wi_scanresults_context);
1014 else if (strcmp(p, "CTRL-EVENT-TERMINATING") == 0)
1015 dhcpcd_wpa_close(wpa);
1019 dhcpcd_wpa_if_event(DHCPCD_IF *i)
1024 if (strcmp(i->type, "link") == 0) {
1025 if (strcmp(i->reason, "STOPPED") == 0 ||
1026 strcmp(i->reason, "DEPARTED") == 0)
1028 wpa = dhcpcd_wpa_find(i->con, i->ifname);
1030 dhcpcd_wpa_close(wpa);
1031 } else if (i->wireless && i->con->wpa_started) {
1032 wpa = dhcpcd_wpa_new(i->con, i->ifname);
1033 if (wpa && wpa->listen_fd == -1)
1034 dhcpcd_wpa_open(wpa);
1040 dhcpcd_wpa_start(DHCPCD_CONNECTION *con)
1045 con->wpa_started = true;
1047 for (i = con->interfaces; i; i = i->next)
1048 dhcpcd_wpa_if_event(i);
1052 dhcpcd_wpa_var_psk(DHCPCD_WI_SCAN *s)
1055 if (s->flags & WSF_WEP)
1057 else if ((s->flags & (WSF_WPA | WSF_PSK)) == (WSF_WPA | WSF_PSK))
1063 dhcpcd_wpa_var_mgmt(DHCPCD_WI_SCAN *s)
1066 if (s->flags & WSF_WPA) {
1067 if (s->flags & WSF_PSK)
1074 dhcpcd_wpa_configure1(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s, const char *psk)
1076 const char *mgmt, *var;
1082 if (!dhcpcd_wpa_disconnect(wpa))
1083 return DHCPCD_WPA_ERR_DISCONN;
1085 /* reload the configuration so that when we don't save
1086 * the disabled networks to the config file. */
1087 if (!dhcpcd_wpa_reconfigure(wpa))
1088 return DHCPCD_WPA_ERR_RECONF;
1090 id = dhcpcd_wpa_network_find_new(wpa, s->ssid);
1092 return DHCPCD_WPA_ERR;
1094 mgmt = dhcpcd_wpa_var_mgmt(s);
1095 var = dhcpcd_wpa_var_psk(s);
1097 if (!dhcpcd_wpa_network_set(wpa, id, "key_mgmt", mgmt))
1098 return DHCPCD_WPA_ERR_SET;
1101 psk_len = strlen(psk);
1104 npsk = malloc(psk_len + 3);
1106 return DHCPCD_WPA_ERR;
1109 memcpy(npsk + 1, psk, psk_len);
1110 npsk[psk_len + 1] = '"';
1111 npsk[psk_len + 2] = '\0';
1112 r = dhcpcd_wpa_network_set(wpa, id, var, npsk);
1115 return DHCPCD_WPA_ERR_SET_PSK;
1118 if (!dhcpcd_wpa_network_enable(wpa, id))
1119 return DHCPCD_WPA_ERR_ENABLE;
1120 if (dhcpcd_wpa_config_write(wpa))
1121 retval = DHCPCD_WPA_SUCCESS;
1123 retval = DHCPCD_WPA_ERR_WRITE;
1124 /* Selecting a network disables the others.
1125 * This should not be saved. */
1126 if (!dhcpcd_wpa_network_select(wpa, id) && retval == DHCPCD_WPA_SUCCESS)
1127 return DHCPCD_WPA_ERR_SELECT;
1132 dhcpcd_wpa_configure(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s, const char *psk)
1136 retval = dhcpcd_wpa_configure1(wpa, s, psk);
1137 /* Always reassociate */
1138 if (!dhcpcd_wpa_reassociate(wpa)) {
1139 if (retval == DHCPCD_WPA_SUCCESS)
1140 retval = DHCPCD_WPA_ERR_ASSOC;
1146 dhcpcd_wpa_select(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s)
1153 id = dhcpcd_wpa_network_find(wpa, s->ssid);
1155 return DHCPCD_WPA_ERR;
1157 if (!dhcpcd_wpa_disconnect(wpa))
1158 retval = DHCPCD_WPA_ERR_DISCONN;
1159 else if (!dhcpcd_wpa_network_select(wpa, id))
1160 retval = DHCPCD_WPA_ERR_SELECT;
1162 retval = DHCPCD_WPA_SUCCESS;
1164 /* Always reassociate */
1165 if (!dhcpcd_wpa_reassociate(wpa)) {
1166 if (retval == DHCPCD_WPA_SUCCESS)
1167 retval = DHCPCD_WPA_ERR_ASSOC;