3 * Copyright 2009-2015 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 #define _GNU_SOURCE /* for asprintf */
29 #include <sys/socket.h>
50 (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
53 #define CLAMP(x, low, high) \
54 (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
57 wpa_open(const char *ifname, char **path)
62 struct passwd pwd, *tpwd;
65 struct sockaddr_un sun;
72 pwdbufsize = (size_t)sysconf(_SC_GETPW_R_SIZE_MAX);
73 pwdbuf = malloc(pwdbufsize);
76 if (getpwuid_r(geteuid(), &pwd, pwdbuf, pwdbufsize, &tpwd) != 0)
78 if (asprintf(&tmpdir, "%s-%s", DHCPCD_TMP_DIR, pwd.pw_name) == -1)
81 if (mkdir(tmpdir, DHCPCD_TMP_DIR_PERM) == -1 && errno != EEXIST)
84 if ((fd = socket(AF_UNIX,
85 SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1)
87 memset(&sun, 0, sizeof(sun));
88 sun.sun_family = AF_UNIX;
89 snprintf(sun.sun_path, sizeof(sun.sun_path),
90 "%s/libdhcpcd-wpa-%d.%d", tmpdir, getpid(), counter++);
91 *path = strdup(sun.sun_path);
92 len = (socklen_t)SUN_LEN(&sun);
93 if (bind(fd, (struct sockaddr *)&sun, len) == -1)
95 snprintf(sun.sun_path, sizeof(sun.sun_path),
96 WPA_CTRL_DIR "/%s", ifname);
97 len = (socklen_t)SUN_LEN(&sun);
98 if (connect(fd, (struct sockaddr *)&sun, len) == -1)
120 wpa_cmd(int fd, const char *cmd, char *buffer, size_t len)
128 bytes = write(fd, cmd, strlen(cmd));
131 if (buffer == NULL || len == 0)
134 pfd.events = POLLIN | POLLHUP;
136 retval = poll(&pfd, 1, 2000);
139 if (retval == 0 || !(pfd.revents & (POLLIN | POLLHUP)))
142 bytes = read(fd, buffer, len == 1 ? 1 : len - 1);
144 buffer[bytes] = '\0';
149 dhcpcd_wpa_command(DHCPCD_WPA *wpa, const char *cmd)
154 bytes = wpa_cmd(wpa->command_fd, cmd, buf, sizeof(buf));
155 return (bytes == -1 || bytes == 0 ||
156 strcmp(buf, "OK\n")) ? false : true;
160 dhcpcd_wpa_update_status(DHCPCD_WPA *wpa, unsigned int status)
163 if (wpa->status != status) {
164 wpa->status = status;
165 if (wpa->con->wpa_status_cb)
166 wpa->con->wpa_status_cb(wpa,
167 wpa->status, dhcpcd_cstates[wpa->status],
168 wpa->con->wpa_status_context);
173 dhcpcd_wpa_ping(DHCPCD_WPA *wpa)
178 bytes = wpa_cmd(wpa->command_fd, "PING", buf, sizeof(buf));
179 return (bytes == -1 || bytes == 0 ||
180 strcmp(buf, "PONG\n")) ? false : true;
184 dhcpcd_wpa_command_arg(DHCPCD_WPA *wpa, const char *cmd, const char *arg)
188 cmdlen = strlen(cmd);
189 nlen = cmdlen + strlen(arg) + 2;
190 if (!dhcpcd_realloc(wpa->con, nlen))
192 strlcpy(wpa->con->buf, cmd, wpa->con->buflen);
193 wpa->con->buf[cmdlen] = ' ';
194 strlcpy(wpa->con->buf + cmdlen + 1, arg, wpa->con->buflen - 1 - cmdlen);
195 return dhcpcd_wpa_command(wpa, wpa->con->buf);
199 dhcpcd_attach_detach(DHCPCD_WPA *wpa, bool attach)
204 if (wpa->attached == attach)
207 bytes = wpa_cmd(wpa->listen_fd, attach > 0 ? "ATTACH" : "DETACH",
209 if (bytes == -1 || bytes == 0 || strcmp(buf, "OK\n"))
212 wpa->attached = attach;
216 #define UNUSED(x) (void)(x)
218 dhcpcd_wpa_can_background_scan(DHCPCD_WPA *wpa)
221 UNUSED(wpa); /* BSD will use this moving forwards */
230 dhcpcd_wpa_scan(DHCPCD_WPA *wpa)
233 return dhcpcd_wpa_command(wpa, "SCAN");
237 dhcpcd_wi_associated(DHCPCD_IF *i, DHCPCD_WI_SCAN *scan)
243 return (i->up && i->ssid && strcmp(i->ssid, scan->ssid) == 0);
247 dhcpcd_wi_scans_free(DHCPCD_WI_SCAN *wis)
259 dhcpcd_strtoi(int *val, const char *s)
263 l = strtol(s, NULL, 0);
264 if (l >= INT_MIN && l <= INT_MAX)
271 dhcpcd_wpa_hex2num(char c)
274 if (c >= '0' && c <= '9')
276 if (c >= 'a' && c <= 'f')
278 if (c >= 'A' && c <= 'F')
284 dhcpcd_wpa_hex2byte(const char *src)
288 if ((h = dhcpcd_wpa_hex2num(*src++)) == -1 ||
289 (l = dhcpcd_wpa_hex2num(*src)) == -1)
295 dhcpcd_wpa_decode_ssid(char *dst, size_t dlen, const char *src)
319 case '"': *dst++ = esc; break;
320 case 'n': *dst++ = '\n'; break;
321 case 'r': *dst++ = '\r'; break;
322 case 't': *dst++ = '\t'; break;
323 case 'e': *dst++ = '\033'; break;
325 if (src[0] == '\0' || src[1] == '\0') {
329 if ((xb = dhcpcd_wpa_hex2byte(src)) == -1)
335 default: errno = EINVAL; return -1;
338 default: *dst++ = c; break;
349 static DHCPCD_WI_SCAN *
350 dhcpcd_wpa_scans_read(DHCPCD_WPA *wpa)
354 DHCPCD_WI_SCAN *wis, *w, *l;
355 char *s, *p, buf[32];
356 char wssid[sizeof(w->ssid)];
359 if (!dhcpcd_realloc(wpa->con, 2048))
362 for (i = 0; i < 1000; i++) {
363 snprintf(buf, sizeof(buf), "BSS %zu", i);
364 bytes = wpa_cmd(wpa->command_fd, buf,
365 wpa->con->buf, wpa->con->buflen);
366 if (bytes == 0 || bytes == -1 ||
367 strncmp(wpa->con->buf, "FAIL", 4) == 0)
370 w = calloc(1, sizeof(*w));
375 while ((s = strsep(&p, "\n"))) {
378 if (strncmp(s, "bssid=", 6) == 0)
379 strlcpy(w->bssid, s + 6, sizeof(w->bssid));
380 else if (strncmp(s, "freq=", 5) == 0)
381 dhcpcd_strtoi(&w->frequency, s + 5);
382 // else if (strncmp(s, "beacon_int=", 11) == 0)
384 else if (strncmp(s, "qual=", 5) == 0)
385 dhcpcd_strtoi(&w->quality.value, s + 5);
386 else if (strncmp(s, "noise=", 6) == 0)
387 dhcpcd_strtoi(&w->noise.value, s + 6);
388 else if (strncmp(s, "level=", 6) == 0)
389 dhcpcd_strtoi(&w->level.value, s + 6);
390 else if (strncmp(s, "flags=", 6) == 0)
391 strlcpy(w->wpa_flags, s + 6,
392 sizeof(w->wpa_flags));
393 else if (strncmp(s, "ssid=", 5) == 0) {
394 /* Decode it from \xNN to \NNN
395 * so we're consistent */
396 dl = dhcpcd_wpa_decode_ssid(wssid,
397 sizeof(wssid), s + 5);
400 dl = dhcpcd_encode_string_escape(w->ssid,
401 sizeof(w->ssid), wssid, (size_t)dl);
417 if ((proto = strstr(w->wpa_flags, "[WPA-")) ||
418 (proto = strstr(w->wpa_flags, "[WPA2-")) ||
419 (proto = strstr(w->wpa_flags, "[RSN-")))
421 const char *endp, *psk;
423 w->flags = WSF_WPA | WSF_SECURE;
424 endp = strchr(proto, ']');
425 if ((psk = strstr(proto, "-PSK]")) ||
426 (psk = strstr(proto, "-PSK-")) ||
427 (psk = strstr(proto, "-PSK+")))
433 if (strstr(w->wpa_flags, "[WEP]"))
434 w->flags = WSF_WEP | WSF_PSK | WSF_SECURE;
436 w->strength.value = w->level.value;
438 if (w->strength.value > 110 && w->strength.value < 256)
439 /* Convert WEXT level to dBm */
440 w->strength.value -= 256;
443 if (w->strength.value < 0) {
446 abs(CLAMP(w->strength.value, -100, -40) + 40);
448 100 - ((100 * w->strength.value) / 60);
450 /* Assume quality percentage */
451 w->strength.value = CLAMP(w->strength.value, 0, 100);
458 dhcpcd_wi_scan_compare(DHCPCD_WI_SCAN *a, DHCPCD_WI_SCAN *b)
462 /* Fist sort non case sensitive, then case sensitive */
463 cmp = strcasecmp(a->ssid, b->ssid);
465 cmp = strcmp(a->ssid, b->ssid);
467 /* If still the same, return strongest first */
469 cmp = b->strength.value - a->strength.value;
475 * This function is copyright 2001 Simon Tatham.
477 * Permission is hereby granted, free of charge, to any person
478 * obtaining a copy of this software and associated documentation
479 * files (the "Software"), to deal in the Software without
480 * restriction, including without limitation the rights to use,
481 * copy, modify, merge, publish, distribute, sublicense, and/or
482 * sell copies of the Software, and to permit persons to whom the
483 * Software is furnished to do so, subject to the following
486 * The above copyright notice and this permission notice shall be
487 * included in all copies or substantial portions of the Software.
489 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
490 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
491 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
492 * NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
493 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
494 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
495 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
498 static DHCPCD_WI_SCAN *
499 dhcpcd_wi_scans_sort(DHCPCD_WI_SCAN *list)
501 DHCPCD_WI_SCAN *p, *q, *e, *tail;
502 size_t insize, nmerges, psize, qsize, i;
504 /* Silly special case: if `list' was passed in as NULL, return
505 * NULL immediately. */
514 nmerges = 0; /* count number of merges we do in this pass */
517 nmerges++; /* there exists a merge to be done */
518 /* step `insize' places along from p */
521 for (i = 0; i < insize; i++) {
528 /* if q hasn't fallen off end,
529 * we have two lists to merge */
532 /* now we have two lists; merge them */
533 while (psize > 0 || (qsize > 0 && q)) {
534 /* decide whether next element of merge comes
537 /* p is empty; e must come from q. */
538 e = q; q = q->next; qsize--;
539 } else if (qsize == 0 || !q) {
540 /* q is empty; e must come from p. */
541 e = p; p = p->next; psize--;
542 } else if (dhcpcd_wi_scan_compare(p, q) <= 0) {
543 /* First element of p is lower
544 * (or same); e must come from p. */
545 e = p; p = p->next; psize--;
547 /* First element of q is lower;
548 * e must come from q. */
549 e = q; q = q->next; qsize--;
552 /* add the next element to the merged list */
560 /* now p has stepped `insize' places along,
566 /* If we have done only one merge, we're finished. */
567 if (nmerges <= 1) /* allow for nmerges==0, the empty list */
570 /* Otherwise repeat, merging lists twice the size */
576 dhcpcd_wi_freqflags(DHCPCD_WI_SCAN *w)
579 if (WPA_FREQ_IS_2G(w->frequency))
581 if (WPA_FREQ_IS_5G(w->frequency))
583 /* Unknown frequency */
588 dhcpcd_wi_scans(DHCPCD_IF *i)
591 DHCPCD_WI_SCAN *wis, *w, *n, *p;
593 DHCPCD_WI_HIST *h, *hl;
595 wpa = dhcpcd_wpa_find(i->con, i->ifname);
598 wis = dhcpcd_wpa_scans_read(wpa);
600 /* Sort the resultant list alphabetically and then by strength */
601 wis = dhcpcd_wi_scans_sort(wis);
604 for (w = wis; w && (n = w->next, 1); w = n) {
605 /* Currently we don't support non SSID broadcasting APs */
606 if (*w->ssid == '\0') {
614 /* Strip duplicated SSIDs, only show the strongest */
615 if (p && strcmp(p->ssid, w->ssid) == 0) {
616 /* Set frequency flag from the duplicate */
617 p->flags |= dhcpcd_wi_freqflags(w);
622 /* Remember this as the previous next time */
625 /* Set frequency flags */
626 p->flags |= dhcpcd_wi_freqflags(w);
630 w->quality.average = w->quality.value;
631 w->noise.average = w->noise.value;
632 w->level.average = w->level.value;
633 w->strength.average = w->strength.value;
635 for (h = wpa->con->wi_history; h; h = h->next) {
636 if (strcmp(h->ifname, i->ifname) == 0 &&
637 strcmp(h->bssid, wis->bssid) == 0)
639 w->quality.average += h->quality;
640 w->noise.average += h->noise;
641 w->level.average += h->level;
642 w->strength.average += h->strength;
643 if (++nh == DHCPCD_WI_HIST_MAX) {
653 w->quality.average /= nh;
654 w->noise.average /= nh;
655 w->level.average /= nh;
656 w->strength.average /= nh;
658 h = malloc(sizeof(*h));
660 strlcpy(h->ifname, i->ifname, sizeof(h->ifname));
661 strlcpy(h->bssid, w->bssid, sizeof(h->bssid));
662 h->quality = w->quality.value;
663 h->noise = w->noise.value;
664 h->level = w->level.value;
665 h->strength = w->strength.value;
666 h->next = wpa->con->wi_history;
667 wpa->con->wi_history = h;
675 dhcpcd_wpa_reconfigure(DHCPCD_WPA *wpa)
678 return dhcpcd_wpa_command(wpa, "RECONFIGURE");
682 dhcpcd_wpa_reassociate(DHCPCD_WPA *wpa)
685 return dhcpcd_wpa_command(wpa, "REASSOCIATE");
689 dhcpcd_wpa_disconnect(DHCPCD_WPA *wpa)
692 return dhcpcd_wpa_command(wpa, "DISCONNECT");
696 dhcpcd_wpa_config_write(DHCPCD_WPA *wpa)
699 return dhcpcd_wpa_command(wpa, "SAVE_CONFIG");
703 dhcpcd_wpa_network(DHCPCD_WPA *wpa, const char *cmd, int id)
707 len = strlen(cmd) + 32;
708 if (!dhcpcd_realloc(wpa->con, len))
710 snprintf(wpa->con->buf, wpa->con->buflen, "%s %d", cmd, id);
711 return dhcpcd_wpa_command(wpa, wpa->con->buf);
715 dhcpcd_wpa_network_disable(DHCPCD_WPA *wpa, int id)
718 return dhcpcd_wpa_network(wpa, "DISABLE_NETWORK", id);
722 dhcpcd_wpa_network_enable(DHCPCD_WPA *wpa, int id)
725 return dhcpcd_wpa_network(wpa, "ENABLE_NETWORK", id);
729 dhcpcd_wpa_network_select(DHCPCD_WPA *wpa, int id)
732 return dhcpcd_wpa_network(wpa, "SELECT_NETWORK", id);
736 dhcpcd_wpa_network_remove(DHCPCD_WPA *wpa, int id)
739 return dhcpcd_wpa_network(wpa, "REMOVE_NETWORK", id);
743 dhcpcd_wpa_network_get(DHCPCD_WPA *wpa, int id, const char *param)
747 if (!dhcpcd_realloc(wpa->con, 2048))
749 snprintf(wpa->con->buf, wpa->con->buflen, "GET_NETWORK %d %s",
751 bytes = wpa_cmd(wpa->command_fd, wpa->con->buf,
752 wpa->con->buf, wpa->con->buflen);
753 if (bytes == 0 || bytes == -1)
755 if (strcmp(wpa->con->buf, "FAIL\n") == 0) {
759 return wpa->con->buf;
763 dhcpcd_wpa_network_set(DHCPCD_WPA *wpa, int id,
764 const char *param, const char *value)
768 len = strlen("SET_NETWORK") + 32 + strlen(param) + strlen(value) + 3;
769 if (!dhcpcd_realloc(wpa->con, len))
771 snprintf(wpa->con->buf, wpa->con->buflen, "SET_NETWORK %d %s %s",
773 return dhcpcd_wpa_command(wpa, wpa->con->buf);
777 dhcpcd_wpa_network_find(DHCPCD_WPA *wpa, const char *fssid)
779 ssize_t bytes, dl, tl;
781 char *s, *t, *ssid, *bssid, *flags;
782 char dssid[IF_SSIDSIZE], tssid[IF_SSIDSIZE];
785 dhcpcd_realloc(wpa->con, 2048);
786 bytes = wpa_cmd(wpa->command_fd, "LIST_NETWORKS",
787 wpa->con->buf, wpa->con->buflen);
788 if (bytes == 0 || bytes == -1)
793 s = strchr(wpa->con->buf, '\n');
796 while ((t = strsep(&s, "\b\n"))) {
799 ssid = strchr(t, '\t');
803 bssid = strchr(ssid, '\t');
807 flags = strchr(bssid, '\t');
811 l = strtol(t, NULL, 0);
812 if (l < 0 || l > INT_MAX) {
817 /* Decode the wpa_supplicant SSID into raw chars and
818 * then encode into our octal escaped string to
820 dl = dhcpcd_wpa_decode_ssid(dssid, sizeof(dssid), ssid);
823 tl = dhcpcd_encode_string_escape(tssid,
824 sizeof(tssid), dssid, (size_t)dl);
827 if ((size_t)tl == fl && memcmp(tssid, fssid, (size_t)tl) == 0)
835 dhcpcd_wpa_network_new(DHCPCD_WPA *wpa)
840 dhcpcd_realloc(wpa->con, 32);
841 bytes = wpa_cmd(wpa->command_fd, "ADD_NETWORK",
842 wpa->con->buf, sizeof(wpa->con->buf));
843 if (bytes == 0 || bytes == -1)
845 l = strtol(wpa->con->buf, NULL, 0);
846 if (l < 0 || l > INT_MAX) {
853 static const char hexchrs[] = "0123456789abcdef";
855 dhcpcd_wpa_network_find_new(DHCPCD_WPA *wpa, const char *ssid)
858 char dssid[IF_SSIDSIZE], essid[IF_SSIDSIZE], *ep;
862 id = dhcpcd_wpa_network_find(wpa, ssid);
866 dl = dhcpcd_decode_string_escape(dssid, sizeof(dssid), ssid);
870 for (i = 0; i < dl; i++) {
871 if (!isascii((int)dssid[i]) && !isprint((int)dssid[i]))
877 /* Non standard characters found! Encode as hex string */
881 c = (unsigned char)*dp++;
882 *ep++ = hexchrs[(c & 0xf0) >> 4];
883 *ep++ = hexchrs[(c & 0x0f)];
889 while (*++dp != '\0');
894 id = dhcpcd_wpa_network_new(wpa);
896 dhcpcd_wpa_network_set(wpa, id, "ssid", essid);
901 dhcpcd_wpa_close(DHCPCD_WPA *wpa)
906 if (wpa->command_fd == -1)
909 dhcpcd_attach_detach(wpa, false);
911 if (wpa->status != DHC_DOWN) {
912 shutdown(wpa->command_fd, SHUT_RDWR);
913 shutdown(wpa->listen_fd, SHUT_RDWR);
914 dhcpcd_wpa_update_status(wpa, DHC_DOWN);
917 close(wpa->command_fd);
918 wpa->command_fd = -1;
919 close(wpa->listen_fd);
921 unlink(wpa->command_path);
922 free(wpa->command_path);
923 wpa->command_path = NULL;
924 unlink(wpa->listen_path);
925 free(wpa->listen_path);
926 wpa->listen_path = NULL;
930 dhcpcd_wpa_find(DHCPCD_CONNECTION *con, const char *ifname)
934 for (wpa = con->wpa; wpa; wpa = wpa->next) {
935 if (strcmp(wpa->ifname, ifname) == 0)
943 dhcpcd_wpa_new(DHCPCD_CONNECTION *con, const char *ifname)
947 wpa = dhcpcd_wpa_find(con, ifname);
951 wpa = calloc(1, sizeof(*wpa));
956 strlcpy(wpa->ifname, ifname, sizeof(wpa->ifname));
957 wpa->status = DHC_DOWN;
958 wpa->command_fd = wpa->listen_fd = -1;
959 wpa->command_path = wpa->listen_path = NULL;
960 wpa->next = con->wpa;
966 dhcpcd_wpa_connection(DHCPCD_WPA *wpa)
974 dhcpcd_wpa_if(DHCPCD_WPA *wpa)
978 return dhcpcd_get_if(wpa->con, wpa->ifname, DHT_LINK);
982 dhcpcd_wpa_if_freq(DHCPCD_WPA *wpa)
986 i = dhcpcd_wpa_if(wpa);
988 i->freq = dhcpcd_wpa_freq(wpa);
992 dhcpcd_wpa_if_freq_zero(DHCPCD_WPA *wpa)
996 i = dhcpcd_wpa_if(wpa);
1002 dhcpcd_wpa_open(DHCPCD_WPA *wpa)
1004 int cmd_fd, list_fd = -1;
1005 char *cmd_path = NULL, *list_path = NULL;
1007 if (wpa->listen_fd != -1) {
1008 if (wpa->status == DHC_CONNECTED)
1009 return wpa->listen_fd;
1014 cmd_fd = wpa_open(wpa->ifname, &cmd_path);
1018 list_fd = wpa_open(wpa->ifname, &list_path);
1022 wpa->status = DHC_CONNECTING;
1023 wpa->attached = false;
1024 wpa->command_fd = cmd_fd;
1025 wpa->command_path = cmd_path;
1026 wpa->listen_fd = list_fd;
1027 wpa->listen_path = list_path;
1028 if (!dhcpcd_attach_detach(wpa, true)) {
1029 dhcpcd_wpa_close(wpa);
1033 dhcpcd_wpa_if_freq(wpa);
1035 dhcpcd_wpa_update_status(wpa, DHC_CONNECTED);
1036 if (wpa->con->wi_scanresults_cb)
1037 wpa->con->wi_scanresults_cb(wpa,
1038 wpa->con->wi_scanresults_context);
1040 return wpa->listen_fd;
1056 dhcpcd_wpa_status(DHCPCD_WPA *wpa, const char **status_msg)
1061 *status_msg = dhcpcd_cstates[wpa->status];
1066 dhcpcd_wpa_get_fd(DHCPCD_WPA *wpa)
1070 return wpa->listen_fd;
1074 dhcpcd_wpa_set_scan_callback(DHCPCD_CONNECTION *con,
1075 void (*cb)(DHCPCD_WPA *, void *), void *context)
1079 con->wi_scanresults_cb = cb;
1080 con->wi_scanresults_context = context;
1084 void dhcpcd_wpa_set_status_callback(DHCPCD_CONNECTION * con,
1085 void (*cb)(DHCPCD_WPA *, unsigned int, const char *, void *),
1090 con->wpa_status_cb = cb;
1091 con->wpa_status_context = context;
1095 dhcpcd_wpa_dispatch(DHCPCD_WPA *wpa)
1097 char buffer[256], *p;
1101 bytes = (size_t)read(wpa->listen_fd, buffer, sizeof(buffer));
1102 if ((ssize_t)bytes == -1) {
1103 dhcpcd_wpa_close(wpa);
1107 buffer[bytes] = '\0';
1108 bytes = strlen(buffer);
1109 if (buffer[bytes - 1] == ' ')
1110 buffer[--bytes] = '\0';
1111 for (p = buffer + 1; *p != '\0'; p++) {
1118 #define CE_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS"
1119 #define CE_CONNECTED "CTRL-EVENT-CONNECTED"
1120 #define CE_DISCONNECTED "CTRL-EVENT-DISCONNECTED"
1121 #define CE_TERMINATING "CTRL-EVENT-TERMINATING"
1122 if (strncmp(p, CE_SCAN_RESULTS, strlen(CE_SCAN_RESULTS)) == 0 &&
1123 wpa->con->wi_scanresults_cb)
1124 wpa->con->wi_scanresults_cb(wpa,
1125 wpa->con->wi_scanresults_context);
1126 else if (strncmp(p, CE_CONNECTED, strlen(CE_CONNECTED)) == 0)
1127 dhcpcd_wpa_if_freq(wpa);
1128 else if (strncmp(p, CE_DISCONNECTED, strlen(CE_DISCONNECTED)) == 0)
1129 dhcpcd_wpa_if_freq_zero(wpa);
1130 else if (strncmp(p, CE_TERMINATING, strlen(CE_TERMINATING)) == 0)
1131 dhcpcd_wpa_close(wpa);
1135 dhcpcd_wpa_if_event(DHCPCD_IF *i)
1140 if (i->type == DHT_LINK) {
1141 if (i->state == DHS_STOPPED || i->state == DHS_DEPARTED) {
1142 wpa = dhcpcd_wpa_find(i->con, i->ifname);
1144 dhcpcd_wpa_close(wpa);
1145 } else if (i->wireless && i->con->wpa_started) {
1146 wpa = dhcpcd_wpa_new(i->con, i->ifname);
1148 if (wpa->listen_fd == -1)
1149 dhcpcd_wpa_open(wpa);
1150 i->freq = dhcpcd_wpa_freq(wpa);
1157 dhcpcd_wpa_start(DHCPCD_CONNECTION *con)
1162 con->wpa_started = true;
1164 for (i = con->interfaces; i; i = i->next)
1165 dhcpcd_wpa_if_event(i);
1169 dhcpcd_wpa_var_psk(DHCPCD_WI_SCAN *s)
1172 if (s->flags & WSF_WEP)
1174 else if ((s->flags & (WSF_WPA | WSF_PSK)) == (WSF_WPA | WSF_PSK))
1180 dhcpcd_wpa_var_mgmt(DHCPCD_WI_SCAN *s)
1183 if (s->flags & WSF_WPA) {
1184 if (s->flags & WSF_PSK)
1191 dhcpcd_wpa_configure1(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s, const char *psk)
1193 const char *mgmt, *var;
1199 if (!dhcpcd_wpa_disconnect(wpa))
1200 return DHCPCD_WPA_ERR_DISCONN;
1202 /* reload the configuration so that when we don't save
1203 * the disabled networks to the config file. */
1204 if (!dhcpcd_wpa_reconfigure(wpa))
1205 return DHCPCD_WPA_ERR_RECONF;
1207 id = dhcpcd_wpa_network_find_new(wpa, s->ssid);
1209 return DHCPCD_WPA_ERR;
1211 mgmt = dhcpcd_wpa_var_mgmt(s);
1212 if (mgmt && !dhcpcd_wpa_network_set(wpa, id, "key_mgmt", mgmt))
1213 return DHCPCD_WPA_ERR_SET;
1215 var = dhcpcd_wpa_var_psk(s);
1219 psk_len = strlen(psk);
1222 npsk = malloc(psk_len + 3);
1224 return DHCPCD_WPA_ERR;
1227 memcpy(npsk + 1, psk, psk_len);
1228 npsk[psk_len + 1] = '"';
1229 npsk[psk_len + 2] = '\0';
1230 r = dhcpcd_wpa_network_set(wpa, id, var, npsk);
1233 return DHCPCD_WPA_ERR_SET_PSK;
1236 if (!dhcpcd_wpa_network_enable(wpa, id))
1237 return DHCPCD_WPA_ERR_ENABLE;
1238 if (dhcpcd_wpa_config_write(wpa))
1239 retval = DHCPCD_WPA_SUCCESS;
1241 retval = DHCPCD_WPA_ERR_WRITE;
1242 /* Selecting a network disables the others.
1243 * This should not be saved. */
1244 if (!dhcpcd_wpa_network_select(wpa, id) && retval == DHCPCD_WPA_SUCCESS)
1245 return DHCPCD_WPA_ERR_SELECT;
1250 dhcpcd_wpa_configure(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s, const char *psk)
1254 retval = dhcpcd_wpa_configure1(wpa, s, psk);
1255 /* Always reassociate */
1256 if (!dhcpcd_wpa_reassociate(wpa)) {
1257 if (retval == DHCPCD_WPA_SUCCESS)
1258 retval = DHCPCD_WPA_ERR_ASSOC;
1264 dhcpcd_wpa_select(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s)
1271 id = dhcpcd_wpa_network_find(wpa, s->ssid);
1273 return DHCPCD_WPA_ERR;
1275 if (!dhcpcd_wpa_disconnect(wpa))
1276 retval = DHCPCD_WPA_ERR_DISCONN;
1277 else if (!dhcpcd_wpa_network_select(wpa, id))
1278 retval = DHCPCD_WPA_ERR_SELECT;
1280 retval = DHCPCD_WPA_SUCCESS;
1282 /* Always reassociate */
1283 if (!dhcpcd_wpa_reassociate(wpa)) {
1284 if (retval == DHCPCD_WPA_SUCCESS)
1285 retval = DHCPCD_WPA_ERR_ASSOC;
1291 dhcpcd_wpa_freq(DHCPCD_WPA *wpa)
1293 char buf[256], *p, *s;
1297 bytes = wpa_cmd(wpa->command_fd, "STATUS", buf, sizeof(buf));
1298 if (bytes == 0 || bytes == -1)
1302 while ((s = strsep(&p, "\n"))) {
1305 if (strncmp(s, "freq=", 5) == 0) {
1306 dhcpcd_strtoi(&freq, s + 5);
1316 dhcpcd_wi_print_tooltip(char *buf, size_t buflen, DHCPCD_WI_SCAN *s,
1317 unsigned int options)
1321 /* Provide a default */
1323 options = WST_BSSID | WST_FREQ;
1325 #define TOOLTIP(fmt, ...) do { \
1326 r = snprintf(buf, buflen, fmt, __VA_ARGS__); \
1327 if (r == -1 || (size_t)r > buflen) \
1328 return printed + r; \
1330 buflen -= (size_t)r; \
1332 } while (0 /* CONSTCOND */)
1334 if (options & WST_BSSID)
1335 TOOLTIP("%s", s->bssid);
1336 if (options & WST_FLAGS && s->wpa_flags[0] != '\0')
1337 TOOLTIP(" %s", s->wpa_flags);
1338 if (options & WST_FREQ) {
1339 if (s->flags & WSF_2G)
1340 TOOLTIP(" %s", "2G");
1341 if (s->flags & WSF_5G)
1342 TOOLTIP(" %s", "5G");