This is another attempt at improving usability with non-ASCII network IDs.

Previous attempts have been rejected in part because entering UTF-8 strings
is difficult to do for Americans and, to a lesser extent, Canadians.

It occurred to me that the real issue might have been that previous attempts
were erasing the hex string representation in favour of UTF-8, instead of
amending the hex string with a human-readable representation of that string.

With the diff below ifconfig shows both representations, provided the UTF-8
locale is active and the string can be successfully decoded, and fits NWID
length restrictions, and contains printable Unicode only.

We still need to enter a hex ID to use a network, but at least it becomes
much easier to tell which one to use.

Before:

$ ifconfig iwm0 scan
iwm0: flags=808843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,AUTOCONF4> mtu 1500
[...]
                nwid 0x6162616374c3a97269c3a96d69717565 chan 4 bssid 
xx:xx:xx:xx:xx:xx 68% HT-MCS7 privacy,short_preamble,short_slottime,wpa2 
                nwid 0x00000000000000000000000000000000000000000000 chan 6 
bssid xx:xx:xx:xx:xx:xx 25% HT-MCS15 privacy,short_slottime,wpa2 


After:

$ ifconfig iwm0 scan iwm0: 
flags=808843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,AUTOCONF4> mtu 1500
[...]
                nwid 0x6162616374c3a97269c3a96d69717565 ("abactériémique") chan 
4 bssid xx:xx:xx:xx:xx:xx 68% HT-MCS7 
privacy,short_preamble,short_slottime,wpa2 
                nwid 0x00000000000000000000000000000000000000000000 chan 6 
bssid xx:xx:xx:xx:xx:xx 25% HT-MCS15 privacy,short_slottime,wpa2 


I'm making the man page point out that 'ifconfig nwid' accepts only
*printable ASCII* strings or hex. Based on that it should be clear what
the user needs to do with information shown in the scan result list.

This feature also works with 'ifconfig joinlist'. While here fix a bug
where non-ASCII IDs on this list were improperly truncated to 32 columns
when displayed. The hexstring can be up to 66 colomns in length so capping
joinlist SSIDs to IEEE80211_NWID_LEN - 1 columns is wrong.
A human-readable representation needs additional space to be displayed.

Since print_string() and len_string() are only used with NWIDs nowadays I
am renaming them to print_nwid() and width_nwid() (the latter function is
being used to compute a display width, not a string length in bytes).

Is this acceptable or are there objections to the idea?


diff c20bd74017ceeadb2db0f78a352ed1f1e2b77c2b /usr/src
blob - 3fb0780ba7cf1333894f5c3485a95e71885fbd6d
file + sbin/ifconfig/ifconfig.8
--- sbin/ifconfig/ifconfig.8
+++ sbin/ifconfig/ifconfig.8
@@ -972,8 +972,9 @@ list if they are found during a scan.
 .Pp
 The
 .Ar id
-can either be any text string up to 32 characters in length,
-or a series of hexadecimal digits up to 64 digits.
+can either be a printable ASCII string up to 32 characters in length,
+or a series of hexadecimal digits up to 64 digits preceded by
+.Dq 0x .
 If
 .Ar id
 is the empty string
@@ -1077,6 +1078,12 @@ Remove specified flag.
 .It Cm nwid Ar id
 Connect to the network with NWID/ESSID
 .Ar id .
+The
+.Ar id
+can either be a printable ASCII string up to 32 characters in length,
+or a series of hexadecimal digits up to 64 digits preceded by
+.Dq 0x .
+.Pp
 Unlike
 .Cm join ,
 the
blob - e1dc9dbb07bf109c3ec7f5fd4d851a7dbb5692f1
file + sbin/ifconfig/ifconfig.c
--- sbin/ifconfig/ifconfig.c
+++ sbin/ifconfig/ifconfig.c
@@ -110,6 +110,12 @@
 #ifndef SMALL
 #include <dev/usb/mbim.h>
 #include <dev/usb/if_umb.h>
+
+/* UTF-8 support */
+#include <langinfo.h>
+#include <locale.h>
+#include <wctype.h>
+#include <wchar.h>
 #endif /* SMALL */
 
 #include "ifconfig.h"
@@ -156,6 +162,7 @@ struct      ifaliasreq      addreq;
 
 int    wconfig = 0;
 int    wcwconfig = 0;
+int    is_utf8_locale = 0;
 #endif /* SMALL */
 
 char   ifname[IFNAMSIZ];
@@ -654,8 +661,9 @@ const char *get_linkstate(int, int);
 void   status(int, struct sockaddr_dl *, int);
 __dead void    usage(void);
 const char *get_string(const char *, const char *, u_int8_t *, int *);
-int    len_string(const u_int8_t *, int);
-int    print_string(const u_int8_t *, int);
+int    utf8_nwid(const u_int8_t *, int);
+int    width_nwid(const u_int8_t *, int);
+int    print_nwid(const u_int8_t *, int);
 char   *sec2str(time_t);
 
 const char *get_media_type_string(uint64_t);
@@ -731,6 +739,10 @@ main(int argc, char *argv[])
        int found_rulefile = 0;
        int i;
 
+#ifndef SMALL
+       setlocale(LC_CTYPE, "");
+       is_utf8_locale = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0);
+#endif
        /* If no args at all, print all interfaces.  */
        if (argc < 2) {
                /* no filesystem visibility */
@@ -1678,9 +1690,44 @@ get_string(const char *val, const char *sep, u_int8_t 
        return val;
 }
 
+/*
+ * Attempt to create a human-readable representation of an NWID in UTF-8.
+ * Return the width of the representation (amount of terminal columns used)
+ * and optionally print to stdout.
+ */
 int
-len_string(const u_int8_t *buf, int len)
+utf8_nwid(const u_int8_t *buf, int print_nwid)
 {
+#ifndef SMALL
+       wchar_t wcid[IEEE80211_NWID_LEN + 1];
+       size_t nwc;
+       int width, i;
+
+       if (!is_utf8_locale)
+               return 0;
+
+       nwc = mbstowcs(wcid, buf, IEEE80211_NWID_LEN);
+       if (nwc == (size_t)-1 || nwc > IEEE80211_NWID_LEN)
+               return 0;
+       wcid[nwc] = L'\0';
+       for (i = 0; i < nwc; i++) {
+               if (!iswprint(wcid[i]))
+                       return 0;
+       }
+       width = wcswidth(wcid, IEEE80211_NWID_LEN);
+       if (width == 0 || width == -1)
+               return 0;
+       if (print_nwid)
+               printf(" (\"%ls\")", wcid);
+       return width + 5;
+#else
+       return 0;       
+#endif
+}
+
+int
+width_nwid(const u_int8_t *buf, int len)
+{
        int i = 0, hasspc = 0;
 
        if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
@@ -1698,11 +1745,11 @@ len_string(const u_int8_t *buf, int len)
                else
                        return len;
        } else
-               return (len * 2) + 2;
+               return (len * 2) + 2 + utf8_nwid(buf, 0);
 }
 
 int
-print_string(const u_int8_t *buf, int len)
+print_nwid(const u_int8_t *buf, int len)
 {
        int i = 0, hasspc = 0;
 
@@ -1727,7 +1774,7 @@ print_string(const u_int8_t *buf, int len)
                printf("0x");
                for (i = 0; i < len; i++)
                        printf("%02x", buf[i]);
-               return (len * 2) + 2;
+               return (len * 2) + 2 + utf8_nwid(buf, 1);
        }
 }
 
@@ -2440,7 +2487,7 @@ ieee80211_status(void)
                        fputs(" join ", stdout);
                else
                        fputs(" nwid ", stdout);
-               print_string(nwid.i_nwid, len);
+               print_nwid(nwid.i_nwid, len);
        }
 
        if (ichan == 0 && channel.i_channel != 0 &&
@@ -2571,18 +2618,16 @@ join_status(void)
 
        maxlen = 0;
        for (i = 0; i < ja.ja_nodes; i++) {
-               len = len_string(jn[i].i_nwid, jn[i].i_len);
+               len = width_nwid(jn[i].i_nwid, jn[i].i_len);
                if (len > maxlen)
                        maxlen = len;
        }
-       if (maxlen > IEEE80211_NWID_LEN)
-               maxlen = IEEE80211_NWID_LEN - 1;
 
        for (i = 0; i < ja.ja_nodes; i++) {
                printf("\t      ");
                if (jn[i].i_len > IEEE80211_NWID_LEN)
                        jn[i].i_len = IEEE80211_NWID_LEN;
-               len = print_string(jn[i].i_nwid, jn[i].i_len);
+               len = print_nwid(jn[i].i_nwid, jn[i].i_len);
                printf("%-*s", maxlen - len, " ");
                if (jn[i].i_flags) {
                        const char *sep;
@@ -2717,7 +2762,7 @@ ieee80211_printnode(struct ieee80211_nodereq *nr)
                if (len > IEEE80211_NWID_LEN)
                        len = IEEE80211_NWID_LEN;
                printf("nwid ");
-               print_string(nr->nr_nwid, len);
+               print_nwid(nr->nr_nwid, len);
                putchar(' ');
 
                printf("chan %u ", nr->nr_channel);

Reply via email to