wpa: add better frequency support.
authorRoy Marples <roy@marples.name>
Mon, 26 Feb 2018 22:19:09 +0000 (22:19 +0000)
committerRoy Marples <roy@marples.name>
Mon, 26 Feb 2018 22:19:09 +0000 (22:19 +0000)
Add flags indicate if a given AP is 2G, 5G or both.
When a wpa_supplicant connection is made, set the frequency
for the connected interface.

src/dhcpcd-gtk/menu.c
src/libdhcpcd/dhcpcd.c
src/libdhcpcd/dhcpcd.h
src/libdhcpcd/wpa.c

index 1c554baf42134de1c14f2d1345fec863bbadbf87..96d0893b299f76f72c4c40cdbfe3575c35bcbe85 100644 (file)
@@ -101,7 +101,7 @@ is_associated(WI_SCAN *wi, DHCPCD_WI_SCAN *scan)
 }
 
 static bool
-get_security_icon(int flags, const char **icon)
+get_security_icon(unsigned int flags, const char **icon)
 {
        bool active;
 
@@ -124,6 +124,9 @@ update_item(WI_SCAN *wi, WI_MENU *m, DHCPCD_WI_SCAN *scan)
        const char *icon;
        GtkWidget *sel;
        bool active;
+#if 0
+       char tip[256];
+#endif
 
        m->scan = scan;
 
@@ -159,14 +162,8 @@ update_item(WI_SCAN *wi, WI_MENU *m, DHCPCD_WI_SCAN *scan)
                GTK_ICON_SIZE_MENU);
 
 #if 0
-       if (scan->wpa_flags[0] == '\0')
-               gtk_widget_set_tooltip_text(m->menu, scan->bssid);
-       else {
-               char *tip = g_strconcat(scan->bssid, " ", scan->wpa_flags,
-                   NULL);
-               gtk_widget_set_tooltip_text(m->menu, tip);
-               g_free(tip);
-       }
+       dhcpcd_wi_print_tooltip(tip, sizeof(tip), scan, 0);
+       gtk_widget_set_tooltip_text(m->menu, tip);
 #endif
 
        g_object_set_data(G_OBJECT(m->menu), "dhcpcd_wi_scan", scan);
index 64dfb235fb238d8016846a883f7cf02d7e364238..62b21ea6c35f5fab12de9e7703736aa0c038929e 100644 (file)
@@ -401,6 +401,7 @@ dhcpcd_decode_string_escape(char *dst, size_t dlen, const char *src)
                                }
                                if (dst)
                                        *dst++ = (char)oct;
+                               break;
                        default:
                                errno = EINVAL;
                                return -1;
@@ -831,6 +832,7 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len)
                i->up = strtobool(dhcpcd_get_value(i, "if_up"));
        i->wireless = strtobool(dhcpcd_get_value(i, "ifwireless"));
        i->ssid = dhcpcd_get_value(i, "ifssid");
+       i->freq = 0; /* wpa_supplicant will set this when opened */
        if (i->ssid == NULL && i->wireless)
                i->ssid = dhcpcd_get_value(i, i->up ? "new_ssid" : "old_ssid");
 
index cc7e989c759cbb87693932ad1c5025875abaaeb8..ed9eb5431ea3f79426e8e85562fd297ac5a782e7 100644 (file)
@@ -67,6 +67,9 @@ extern "C" {
 #define TYPESIZE               8
 #define REASONSIZE             16
 
+#define WPA_FREQ_IS_2G(f)      ((f) >= 2402 && (f) <= 2472)
+#define WPA_FREQ_IS_5G(f)      ((f) >= 5170 && (f) <= 5835)
+
 #define DHC_UNKNOWN             0
 #define DHC_DOWN                1
 #define DHC_OPENED              2
@@ -121,11 +124,13 @@ typedef struct dhcpcd_wi_avs {
 typedef struct dhcpcd_wi_scan {
        struct dhcpcd_wi_scan *next;
        char bssid[IF_BSSIDSIZE];
-       int flags;
-#define WSF_SECURE             0x01
-#define WSF_PSK                        0x02
-#define WSF_WEP                        0x10
-#define WSF_WPA                        0x20
+       unsigned int flags;
+#define WSF_SECURE             0x001
+#define WSF_PSK                        0x002
+#define WSF_WEP                        0x010
+#define WSF_WPA                        0x020
+#define WSF_2G                 0x100
+#define WSF_5G                 0x200
        int frequency;
        DHCPCD_WI_AV quality;
        DHCPCD_WI_AV noise;
@@ -147,6 +152,7 @@ typedef struct dhcpcd_if {
        bool up;
        bool wireless;
        const char *ssid;
+       int freq;
 
        char *data;
        size_t data_len;
@@ -167,6 +173,7 @@ typedef struct dhcpcd_if {
        bool up;
        bool wireless;
        const char *ssid;
+       int freq;
 } DHCPCD_IF;
 #endif
 
@@ -304,6 +311,11 @@ int dhcpcd_wpa_find_network_new(DHCPCD_WPA *, const char *);
 bool dhcpcd_wpa_command(DHCPCD_WPA *, const char *);
 bool dhcpcd_wpa_command_arg(DHCPCD_WPA *, const char *, const char *);
 unsigned int dhcpcd_wpa_status(DHCPCD_WPA *, const char **);
+int dhcpcd_wpa_freq(DHCPCD_WPA *);
+#define WST_BSSID      0x01
+#define WST_FLAGS      0x02
+#define WST_FREQ       0x03
+int dhcpcd_wi_print_tooltip(char *, size_t, DHCPCD_WI_SCAN *, unsigned int);
 
 bool dhcpcd_wpa_ping(DHCPCD_WPA *);
 bool dhcpcd_wpa_can_background_scan(DHCPCD_WPA *);
index baf674bf11a6c6df9d2773ee9d499405ef539ea8..f872ea5b40b0d9e2b55cff08fd7d8352a9981d46 100644 (file)
@@ -69,7 +69,7 @@ wpa_open(const char *ifname, char **path)
        fd = r = -1;
        *path = NULL;
 
-       pwdbufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+       pwdbufsize = (size_t)sysconf(_SC_GETPW_R_SIZE_MAX);
        pwdbuf = malloc(pwdbufsize);
        if (pwdbuf == NULL)
                goto out;
@@ -570,6 +570,18 @@ dhcpcd_wi_scans_sort(DHCPCD_WI_SCAN *list)
        }
 }
 
+static unsigned int
+dhcpcd_wi_freqflags(DHCPCD_WI_SCAN *w)
+{
+
+       if (WPA_FREQ_IS_2G(w->frequency))
+               return WSF_2G;
+       if (WPA_FREQ_IS_5G(w->frequency))
+               return WSF_5G;
+       /* Unknown frequency */
+       return 0;
+}
+
 DHCPCD_WI_SCAN *
 dhcpcd_wi_scans(DHCPCD_IF *i)
 {
@@ -599,13 +611,18 @@ dhcpcd_wi_scans(DHCPCD_IF *i)
                }
                /* Strip duplicated SSIDs, only show the strongest */
                if (p && strcmp(p->ssid, w->ssid) == 0) {
+                       /* Set frequency flag from the duplicate */
+                       p->flags |= dhcpcd_wi_freqflags(w);
                        p->next = n;
                        free(w);
                        continue;
                }
-               /* Remember this as the previos next time */
+               /* Remember this as the previous next time */
                p = w;
 
+               /* Set frequency flags */
+               p->flags |= dhcpcd_wi_freqflags(w);
+
                nh = 1;
                hl = NULL;
                w->quality.average = w->quality.value;
@@ -959,6 +976,26 @@ dhcpcd_wpa_if(DHCPCD_WPA *wpa)
        return dhcpcd_get_if(wpa->con, wpa->ifname, DHT_LINK);
 }
 
+static void
+dhcpcd_wpa_if_freq(DHCPCD_WPA *wpa)
+{
+       DHCPCD_IF *i;
+
+       i = dhcpcd_wpa_if(wpa);
+       if (i != NULL)
+               i->freq = dhcpcd_wpa_freq(wpa);
+}
+
+static void
+dhcpcd_wpa_if_freq_zero(DHCPCD_WPA *wpa)
+{
+       DHCPCD_IF *i;
+
+       i = dhcpcd_wpa_if(wpa);
+       if (i != NULL)
+               i->freq = 0;
+}
+
 int
 dhcpcd_wpa_open(DHCPCD_WPA *wpa)
 {
@@ -991,6 +1028,8 @@ dhcpcd_wpa_open(DHCPCD_WPA *wpa)
                return -1;
        }
 
+       dhcpcd_wpa_if_freq(wpa);
+
        dhcpcd_wpa_update_status(wpa, DHC_CONNECTED);
        if (wpa->con->wi_scanresults_cb)
                wpa->con->wi_scanresults_cb(wpa,
@@ -1078,6 +1117,10 @@ dhcpcd_wpa_dispatch(DHCPCD_WPA *wpa)
            wpa->con->wi_scanresults_cb)
                wpa->con->wi_scanresults_cb(wpa,
                    wpa->con->wi_scanresults_context);
+       else if (strcmp(p, "CTRL-EVENT-CONNECTED") == 0)
+               dhcpcd_wpa_if_freq(wpa);
+       else if (strcmp(p, "CTRL-EVENT-DISCONNECTED") == 0)
+               dhcpcd_wpa_if_freq_zero(wpa);
        else if (strcmp(p, "CTRL-EVENT-TERMINATING") == 0)
                dhcpcd_wpa_close(wpa);
 }
@@ -1234,3 +1277,61 @@ dhcpcd_wpa_select(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s)
        }
        return retval;
 }
+
+int
+dhcpcd_wpa_freq(DHCPCD_WPA *wpa)
+{
+       char buf[256], *p, *s;
+       ssize_t bytes;
+       int freq;
+
+       bytes = wpa_cmd(wpa->command_fd, "STATUS", buf, sizeof(buf));
+       if (bytes == 0 || bytes == -1)
+               return false;
+
+       p = buf;
+       while ((s = strsep(&p, "\n"))) {
+               if (*s == '\0')
+                       continue;
+               if (strncmp(s, "freq=", 5) == 0) {
+                       dhcpcd_strtoi(&freq, s + 5);
+                       return freq;
+               }
+       }
+
+       errno = ENOENT;
+       return 0;
+}
+
+int
+dhcpcd_wi_print_tooltip(char *buf, size_t buflen, DHCPCD_WI_SCAN *s,
+    unsigned int options)
+{
+       int r, printed = 0;
+
+       /* Provide a default */
+       if (options == 0)
+               options = WST_BSSID | WST_FREQ;
+
+#define        TOOLTIP(fmt, ...) do {  \
+       r = snprintf(buf, buflen, fmt, __VA_ARGS__);    \
+       if (r == -1 || (size_t)r > buflen)              \
+               return printed + r;                     \
+       buf += r;                                       \
+       buflen -= (size_t)r;                            \
+       printed += r;                                   \
+       } while (0 /* CONSTCOND */)
+
+       if (options & WST_BSSID)
+               TOOLTIP("%s", s->bssid);
+       if (options & WST_FLAGS && s->wpa_flags[0] != '\0')
+               TOOLTIP(" %s", s->wpa_flags);
+       if (options & WST_FREQ) {
+               if (s->flags & WSF_2G)
+                       TOOLTIP(" %s", "2G");
+               if (s->flags & WSF_5G)
+                       TOOLTIP(" %s", "5G");
+       }
+
+       return printed;
+}