> Date: Sat, 22 Feb 2020 12:44:12 +0100
> From: Stefan Sperling <[email protected]>
>
> 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?
IMHO it is a bad idea to make the output of ifconfig locale-dependent.
> 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);
>
>