]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bsdconfig/share/media/wlan.subr
MFV r337220: 8375 Kernel memory leak in nvpair code
[FreeBSD/FreeBSD.git] / usr.sbin / bsdconfig / share / media / wlan.subr
1 if [ ! "$_MEDIA_WLAN_SUBR" ]; then _MEDIA_WLAN_SUBR=1
2 #
3 # Copyright (c) 2013-2016 Devin Teske
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 #    notice, this list of conditions and the following disclaimer in the
13 #    documentation and/or other materials provided with the distribution.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 # SUCH DAMAGE.
26 #
27 # $FreeBSD$
28 #
29 ############################################################ INCLUDES
30
31 BSDCFG_SHARE="/usr/share/bsdconfig"
32 . $BSDCFG_SHARE/common.subr || exit 1
33 f_dprintf "%s: loading includes..." media/wlan.subr
34 f_include $BSDCFG_SHARE/device.subr
35 f_include $BSDCFG_SHARE/dialog.subr
36 f_include $BSDCFG_SHARE/strings.subr
37 f_include $BSDCFG_SHARE/sysrc.subr
38
39 BSDCFG_LIBE="/usr/libexec/bsdconfig"
40 f_include_lang $BSDCFG_LIBE/include/messages.subr
41
42 ############################################################ GLOBALS
43
44 NWIRELESS_CONFIGS=0
45 NWSCAN_RESULTS=0
46
47 #
48 # Settings used while interacting with various dialog(1) menus
49 #
50 : ${DIALOG_MENU_WLAN_SCAN_DURATION:=5}
51 : ${DIALOG_MENU_WLAN_SHOW_ALL=}
52 : ${DIALOG_MENU_WLAN_SHOW_CONFIGURED=1}
53 : ${DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS=1}
54
55
56 # Structure to contain the wpa_supplicant.conf(5) default overrides
57 #
58 f_struct_define WPA_DEFAULTS \
59         ap_scan                 \
60         ctrl_interface          \
61         ctrl_interface_group    \
62         eapol_version           \
63         fast_reauth
64
65 #
66 # Structure of wpa_supplicant.conf(5) network={ ... } entry
67 #
68 f_struct_define WPA_NETWORK \
69         anonymous_identity      \
70         auth_alg                \
71         bssid                   \
72         ca_cert                 \
73         ca_cert2                \
74         client_cert             \
75         client_cert2            \
76         dh_file                 \
77         dh_file2                \
78         eap                     \
79         eap_workaround          \
80         eapol_flags             \
81         eappsk                  \
82         engine                  \
83         engine_id               \
84         frequency               \
85         group                   \
86         identity                \
87         key_id                  \
88         key_mgmt                \
89         mixed_cell              \
90         mode                    \
91         nai                     \
92         pac_file                \
93         pairwise                \
94         password                \
95         pcsc                    \
96         phase1                  \
97         phase2                  \
98         pin                     \
99         priority                \
100         private_key             \
101         private_key2            \
102         private_key2_passwd     \
103         private_key_passwd      \
104         proto                   \
105         psk                     \
106         scan_ssid               \
107         server_nai              \
108         ssid                    \
109         subject_match           \
110         subject_match2          \
111         wep_key0                \
112         wep_key1                \
113         wep_key2                \
114         wep_key3                \
115         wpa_ptk_rekey           \
116         wep_tx_keyidx
117
118 #
119 # The following properties are ``Lists'' and as such should not be quoted.
120 # Everything else should be quoted.
121 #
122 WPA_NETWORK_LIST_PROPERTIES="
123         auth_algo
124         eap
125         group
126         key_mgmt
127         pairwise
128         proto
129 " # END-QUOTE
130
131 #
132 # Structure of wpa_cli(8) `scan_results' entry
133 #
134 f_struct_define WPA_SCAN_RESULT \
135         bssid   \
136         flags   \
137         freq    \
138         siglev  \
139         ssid
140
141 #
142 # Structure of a menu item in the wireless editor
143 #
144 f_struct_define WLAN_MENU_ITEM \
145         letter          \
146         ssid            \
147         nconfigs        \
148         nfound          \
149         help
150
151 ############################################################ FUNCTIONS
152
153 # f_wpa_supplicant_init $file
154 #
155 # Initialize $file with basic contents of new wpa_supplicant.conf(5).
156 #
157 f_wpa_supplicant_init()
158 {
159         local funcname=f_wpa_supplicant_init
160         local conf_file="$1" tmpfile
161
162         # Create a temporary file
163         f_eval_catch -k tmpfile $funcname mktemp 'mktemp -t "%s"' "$pgm" ||
164                 return $FAILURE
165
166         # Make it unreadable by anyone but ourselves
167         f_eval_catch $funcname chmod \
168                 'chmod 0600 "%s"' "$tmpfile" || return $FAILURE
169
170         # Make it owned by root/wheel
171         f_eval_catch $funcname chown \
172                 'chown 0:0 "%s"' "$tmpfile" || return $FAILURE
173
174         # Populate it
175         cat <<-EOF >> "$tmpfile"
176         ctrl_interface=/var/run/wpa_supplicant
177         eapol_version=2
178         ap_scan=1
179         fast_reauth=1
180         EOF
181         echo >> "$tmpfile"
182
183         # Move it into place
184         f_eval_catch $funcname mv 'mv "%s" "%s"' "$tmpfile" "$conf_file"
185 }
186
187 # f_wpa_supplicant_parse $file [struct_prefix [count_var]]
188 #
189 # Parse wpa_supplicant.conf(5) $file. Default overrides are stored in a struct
190 # (see struct.subr for additional details) named `{struct_prefix}defaults'. See
191 # WPA_DEFAULTS struct definition in the GLOBALS section above.
192 #
193 # In addition, for each one of the wireless networks we parse from $file,
194 # create a struct named `struct_prefixN' where `N' is a number starting from 1
195 # and ending in $count_var (zero means no networks). See WPA_NETWORK struct
196 # definition in the GLOBALS section above.
197 #
198 # If a `blob-base64-*={ ... }' entry appears, a struct named
199 # `{struct_prefix}blob_base64_*' is created and the `data' property holds the
200 # base64 encoded binary data without whitespace.
201 #
202 # Custom `*={ ... }' definitions are also supported, but should be unique
203 # (unlike the `network' definition). A struct named `{struct_prefix}*' is
204 # created if at least one property is defined in the block.
205 #
206 f_wpa_supplicant_parse()
207 {
208         local file="$1" struct_prefix="$2" count_var="$3"
209
210         [ "$count_var" ] && setvar "$count_var" 0
211
212         [ "$file" ] || file=$( f_sysrc_get wpa_supplicant_conf_file )
213         if [ ! -e "$file" ]; then
214                 f_dprintf "%s: No such file or directory" "$file"
215                 return $FAILURE
216         fi
217
218         local list_properties
219         f_replaceall "$WPA_NETWORK_LIST_PROPERTIES" "$NL" "" list_properties
220         eval "$( awk \
221                 -v count_var="$count_var"         \
222                 -v struct_prefix="$struct_prefix" \
223                 -v list_properties="$list_properties" '
224         BEGIN {
225                 if (!count_var && !struct_prefix) exit
226                 blob = count = custom_struct = network = 0
227                 split(list_properties, lists, FS)
228         }
229         function set_value(struct, prop, value)
230         {
231                 quoted = substr(value, 0, 1) == "\""
232                 for (l in lists) if (list = prop == lists[l]) break
233                 # Remove data after whitespace if unquoted and not a list
234                 if (!quoted && !list) sub("[[:space:]].*", "", value)
235                 # Otherwise if quoted and not a list, remove the quotes
236                 # NB: wep_keyN needs to retain quoting if/when present
237                 else if (quoted && !list && prop !~ /^wep_key[[:digit:]]+/) {
238                         sub("^\"", "", value)
239                         sub("\".*", "", value)
240                 }
241                 gsub(/'\''/, "'\''\\'\'\''", value) # Sanitize the value
242                 if (!created[struct]) {
243                         print "debug= f_struct_free", struct
244                         print "debug= f_struct_new WPA_NETWORK", struct
245                         created[struct] = 1
246                 }
247                 printf "debug= %s set %s '\'%s\''\n", struct, prop, value
248         }
249         {
250                 if ($1 ~ /^network={/) {
251                         empty = 1 # We do not increment count unless !empty
252                         network = 1
253                         next
254                 } else if (match($1, "^blob-base64-[[:alnum:]_./-]+={")) {
255                         blob = 1
256                         blob_data = ""
257                         struct = struct_prefix "blob_bas64_"
258                         struct = struct substr($1, 13, RLENGTH - 14)
259                         next
260                 } else if (match($1, "^[[:alnum:]_./-]+={")) {
261                         empty = 1
262                         custom_struct = 1
263                         struct = struct_prefix substr($1, 0, RLENGTH - 2)
264                         gsub(/[^[:alnum:]_]/, "_", struct)
265                         next
266                 } else if ($1 ~ /^}/) {
267                         if (blob) {
268                                 gsub("[[:space:]]", "", blob_data)
269                                 set_value(struct, "data", blob_data)
270                         }
271                         blob = custom_struct = network = 0
272                         next
273                 } else if (!match($0, /^[[:space:]]*[[:alnum:]_]+=/))
274                         next
275
276                 if (blob) {
277                         blob_data = blob_data $0
278                         next
279                 } else if (network) {
280                         if (empty) { count++; empty = 0 }
281                         struct = struct_prefix count
282                 } else if (!custom_struct)
283                         struct = struct_prefix "defaults"
284
285                 if (!struct_prefix) next
286
287                 prop = substr($0, 0, RLENGTH - 1)
288                 sub(/^[[:space:]]*/, "", prop)
289                 value = substr($0, RSTART + RLENGTH)
290
291                 set_value(struct, prop, value)
292         }
293         END { if (count_var) print count_var "=" count }' "$file" )"
294 }
295
296 # f_wpa_scan_results_parse [struct_prefix [count_var]]
297 #
298 # Parse the results of wpa_cli(8) `scan_results' into a series of structs (see
299 # struct.subr for additional details) named `struct_prefixN' where `N' is a
300 # number starting from 1 and ending in $count_var (zero means no results). See
301 # WPA_SCAN_RESULT struct definition in the GLOBALS section above.
302 #
303 f_wpa_scan_results_parse()
304 {
305         local struct_prefix="$1" count_var="$2"
306
307         [ "$count_var" ] && setvar "$count_var" 0
308
309         eval "$( wpa_cli scan_results 2> /dev/null | awk \
310                 -v count_var="$count_var" \
311                 -v struct_prefix="$struct_prefix" '
312         BEGIN {
313                 if (!count_var && !struct_prefix) exit
314                 count = 0
315                 seg = "[[:xdigit:]][[:xdigit:]]"
316                 bssid = seg":"seg":"seg":"seg":"seg":"seg
317                 freq = siglev = flags = "[^[:space:]]+"
318                 S = "[[:space:]]+"
319                 line = bssid S freq S siglev S flags
320                 line = "^[[:space:]]*" line "[[:space:]]*"
321         }
322         function set_value(struct, prop, value)
323         {
324                 gsub(/'\''/, "'\''\\'\'\''", value) # Sanitize the value
325                 if (!created[struct]) {
326                         print "debug= f_struct_free", struct
327                         print "debug= f_struct_new WPA_SCAN_RESULT", struct
328                         created[struct] = 1
329                 }
330                 printf "debug= %s set %s '\'%s\''\n", struct, prop, value
331         }
332         {
333                 if (!match($0, line)) next
334                 ssid = substr($0, RLENGTH + 1)
335
336                 count++
337                 if (!struct_prefix) next
338
339                 struct = struct_prefix count
340                 set_value(struct, "ssid", ssid)
341                 set_value(struct, "bssid",  $1)
342                 set_value(struct, "freq",   $2)
343                 set_value(struct, "siglev", $3)
344                 set_value(struct, "flags",  $4)
345         }
346         END { if (count_var) print count_var "=" count }' )"
347 }
348
349 # f_wpa_scan_match_network WPA_SCAN_RESULT WPA_NETWORK
350 #
351 # Compares a WPA_SCAN_RESULT struct to a WPA_NETWORK struct. If they appear to
352 # be a match returns success, otherwise failure.
353 #
354 f_wpa_scan_match_network()
355 {
356         local scan_struct="$1" wireless_struct="$2"
357         local cp debug=
358
359         f_struct "$scan_struct" || return $FAILURE
360         f_struct "$wireless_struct" || return $FAILURE
361
362         local scan_ssid scan_bssid
363         $scan_struct get ssid scan_ssid
364         $scan_struct get bssid scan_bssid
365         local wireless_ssid wireless_bssid
366         $wireless_struct get ssid wireless_ssid
367         $wireless_struct get bssid wireless_bssid
368
369         local id_matched=
370         if [ "$wireless_ssid" -a "$wireless_bssid" ]; then
371                 # Must match both SSID and BSSID
372                 [ "$scan_ssid" = "$wireless_ssid" -a \
373                   "$scan_bssid" = "$wireless_bssid" ] && id_matched=1
374         elif [ "$wireless_ssid" ]; then
375                 # Must match SSID only
376                 [ "$scan_ssid" = "$wireless_ssid" ] && id_matched=1
377         elif [ "$wireless_bssid" ]; then
378                 # Must match BSSID only
379                 [ "$scan_bssid" = "$wireless_bssid" ] && id_matched=1
380         fi
381         [ "$id_matched" ] || return $FAILURE
382
383
384         #
385         # Get the scanned flags for the next few comparisons
386         #
387         local flags
388         $scan_struct get flags flags
389
390         #
391         # Compare configured key management against scanned network
392         #
393         if $wireless_struct get key_mgmt cp && [ "$cp" -a "$cp" != "NONE" ]
394         then
395                 local mgmt mgmt_matched=
396                 for mgmt in $cp; do
397                         local mgmt2="$mgmt"
398                         [ "$mgmt" != "${mgmt#WPA-}" ] &&
399                                 mgmt2="WPA2${mgmt#WPA}"
400                         case "$flags" in
401                         "$mgmt"|"$mgmt"-*|*-"$mgmt"|*-"$mgmt"-*)
402                                 mgmt_matched=1 break ;;
403                         "$mgmt2"|"$mgmt2"-*|*-"$mgmt2"|*-"$mgmt2"-*)
404                                 mgmt_matched=1 break ;;
405                         esac
406                 done
407                 [ "$mgmt_matched" ] || return $FAILURE
408         fi
409
410         local enc type flag
411
412         #
413         # Compare configured encryption against scanned network
414         #
415         for enc in psk:PSK eap:EAP \
416                 wep_key0:WEP wep_key1:WEP wep_key2:WEP wep_key3:WEP
417         do
418                 type=${enc%%:*}
419                 flag=${enc#*:}
420                 { debug= $wireless_struct get $type cp && [ "$cp" ]; } ||
421                         continue
422                 # Configured network requires encryption
423                 case "$flags" in "[$flag]"|*"-$flag-"*)
424                         break # Success; stop after first match
425                 esac
426                 return $FAILURE
427         done
428         cp="" # sensitive info
429
430         #
431         # Compare scanned network encryption against configuration
432         # NB: Scanned network flags indicates _one_ of PSK EAP or WEP
433         # NB: Otherwise, no encryption (so encryption won't match)
434         #
435         local enc_wanted=
436         for enc in -PSK-:psk -EAP-:eap; do
437                 flag=${enc%%:*}
438                 type=${enc#*:}
439                 case "$flags" in *"$flag"*)
440                         enc_wanted=1
441                         { debug= $wireless_struct get $type cp &&
442                                 [ "$cp" ]; } || return $FAILURE
443                         break # success
444                 esac
445         done
446         case "$flags" in *"[WEP]"*)
447                 enc_wanted=1
448                 local wep_found=
449                 for type in wep_key0 wep_key1 wep_key2 wep_key3; do
450                         debug= $wireless_struct get $type cp && [ "$cp" ] &&
451                                 wep_found=1 break
452                 done
453                 [ "$wep_found" ] || return $FAILURE
454         esac
455         if [ ! "$enc_wanted" ]; then
456                 # No match if the network specifies encryption
457                 for type in psk eap wep_key0 wep_key1 wep_key2 wep_key3; do
458                         debug= $wireless_struct get $type cp && [ "$cp" ] &&
459                                 return $FAILURE
460                 done
461         fi
462         cp="" # sensitive info
463
464         return $SUCCESS
465 }
466
467 # f_wpa_scan_find_matches scans_prefix $scans_count \
468 #                         wireless_prefix $wireless_count
469 #
470 # For each struct from `{scans_prefix}1' up to `{scans_prefix}$scans_count'
471 # (see struct.subr for additional details) compare the wireless network info
472 # (defined as struct WPA_SCAN_RESULT) to that of each configured wireless 
473 # stored in `{wireless_prefix}1' (defined as struct WPA_NETWORK) up to
474 # `{wireless_prefix}$wireless_count'.
475 #
476 # If a scanned network is deemed to be a match to a configured wireless
477 # network, a new `match' property is set on the WPA_NETWORK struct with a value
478 # of `{scans_prefix}N' (where N represents the scanned network that matched).
479 # At the same time, a new `matched' property is set on the WPA_SCAN_RESULT
480 # struct with a value of 1, indicating that this network has been matched to a
481 # stored [known] configuration and that it should not be displayed in menus.
482 #
483 # NB: If a matching entry is not correct, the user can optionally `Forget' the
484 # network and that will cause the WPA_SCAN_RESULT to no longer match anything,
485 # causing it to appear in the menus again.
486 #
487 # Return status should be ignored.
488 #
489 f_wpa_scan_find_matches()
490 {
491         local scans_prefix="$1" scans_count="$2"
492         local wireless_prefix="$3" wireless_count="$4"
493         local matches
494
495         [ "$scans_count" -a "$wireless_count" ] || return $SUCCESS
496         f_isinteger "$scans_count" || return $FAILURE
497         f_isinteger "$wireless_count" || return $FAILURE
498
499         #
500         # Go through and eradicate any flags we set in a prior run, as things
501         # might have changed on us (either from the config side or scan side)
502         #
503         local w=1
504         while [ $w -le $wireless_count ]; do
505                 f_struct "$wireless_prefix$w" set matches ""
506                 w=$(( $w + 1 ))
507         done
508
509         #
510         # Find matches and set match data on structs
511         #
512         local s=1
513         while [ $s -le $scans_count ]; do
514                 f_struct "$scans_prefix$s" set matched ""
515                 w=1
516                 while [ $w -le $wireless_count ]; do
517                         if f_wpa_scan_match_network \
518                                 "$scans_prefix$s" "$wireless_prefix$w"
519                         then
520                                 f_struct "$scans_prefix$s" set matched 1
521                                 debug= f_struct "$wireless_prefix$w" \
522                                          get matches matches
523                                 matches="$matches${matches:+ }$scans_prefix$s"
524                                 f_struct "$wireless_prefix$w" \
525                                          set matches "$matches"
526                                 break # to next scan result
527                         fi
528                         w=$(( $w + 1 ))
529                 done
530                 s=$(( $s + 1 ))
531         done
532 }
533
534 # f_dialog_menu_wlandev_edit $wlandev [$defaultitem]
535 #
536 # Display a list of wireless network devices (wlan*) associated with
537 # $wlandev (e.g., `iwn0'). Allow the user to create and destroy wlan interfaces
538 # while selecting ones to be cloned at startup (by setting `wlans_$wlandev').
539 #
540 f_dialog_menu_wlandev_edit()
541 {
542         local funcname=f_dialog_menu_wlandev_edit
543         local wlandev="$1" defaultitem="$2"
544         local title="$DIALOG_TITLE"
545         local btitle="$DIALOG_BACKTITLE"
546         local prompt # Calculated below
547         local hline="$hline_arrows_tab_enter"
548
549         [ "$wlandev" ] || return $FAILURE
550
551         f_sprintf prompt "$msg_select_wlan_interfaces_for" "wlandev"
552
553         #
554         # Initially mark wlan devices with a %parent of $wlandev
555         #
556         local dev devs if list_to_save=
557         f_device_find "" $DEVICE_TYPE_NETWORK devs
558         for dev in $devs; do
559                 f_struct "$dev" get name if || continue
560                 case "$if" in wlan[0-9]*)
561                         parent=$( sysctl -n net.wlan.${if#wlan}.%parent \
562                                 2> /dev/null )
563                         if [ "$parent" = "$if" ]; then
564                                 local _wlanmark_$if="X"
565                                 list_to_save="$list_to_save $if"
566                         fi
567                 esac
568         done
569         list_to_save="${list_to_save# }"
570
571         #
572         # Operate in a loop so we can create/destroy interfaces from here
573         #
574         while :; do
575                 #
576                 # Refresh list of wlan interfaces
577                 #
578                 local wlanlist=
579                 f_device_rescan_network
580                 f_device_find "" $DEVICE_TYPE_NETWORK devs
581                 for dev in $devs; do
582                         f_struct "$dev" get name if || continue
583                         case "$if" in wlan[0-9]*)
584                                 wlanlist="$wlanlist $if"
585                         esac
586                 done
587
588                 #
589                 # Build menu list of wlan devices
590                 #
591                 local menu_list="
592                         '> $msg_save_exit'  '$msg_return_to_previous_menu'
593                         '> $msg_create_new' 'wlan'
594                         '> $msg_destroy'    '...'
595                 " # END-QUOTE
596                 local parent X
597                 for if in $wlanlist; do
598                         f_getvar _wlanmark_$if-" " X
599                         menu_list="$menu_list '[$X] $if' '%parent: $parent'"
600                         [ "$defaultitem" = "$if" ] && defaultitem="[$X] $if"
601                 done 
602
603                 #
604                 # Ask user to make a choice
605                 #
606                 local height width rows
607                 eval f_dialog_menu_size height width rows \
608                         \"\$title\" \"\$btitle\" \"\$prompt\" \"\$hline\" \
609                         $menu_list
610                 local menu_choice
611                 menu_choice=$( eval $DIALOG \
612                         --title \"\$title\"              \
613                         --backtitle \"\$btitle\"         \
614                         --hline \"\$hline\"              \
615                         --ok-label \"\$msg_select\"      \
616                         --cancel-label \"\$msg_cancel\"  \
617                         --default-item \"\$defaultitem\" \
618                         --menu \"\$prompt\"              \
619                         $height $width $rows             \
620                         $menu_list                       \
621                         2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
622                 ) || return $FAILURE
623                 f_dialog_data_sanitize menu_choice
624
625                 case "$menu_choice" in
626                 "> $msg_save_exit") # Save list to rc.conf(5) `wlans_$wlandev'
627                         f_eval_catch $funcname f_sysrc_set \
628                                 'f_sysrc_set "wlans_%s" "%s"' \
629                                 "$wlandev" "$list_to_save" || continue
630                         break # to success
631                         ;;
632                 "> $msg_create_new") # Create new wlan interface for wlandev
633                         local wlan
634                         f_eval_catch -k wlan $funcname ifconfig \
635                                 'ifconfig wlan create wlandev "%s"' \
636                                 "$wlandev" || continue
637                         local _wlanmark_$wlan="X"
638                         list_to_save="$list_to_save${list_to_save:+ }$wlan"
639                         ;;
640                 "> $msg_destroy") # Display a menu to pick one item to destroy
641                         [ "$wlanlist" ] || continue # Nothing to destroy
642
643                         menu_list=
644                         for if in $wlanlist; do
645                                 menu_list="$menu_list '$if' ''"
646                         done
647                         local msg="$msg_pick_an_interface_to_destroy"
648                         eval f_dialog_menu_size height width rows \
649                             \"\$title\" \"$btitle\" \"\$msg\" \"\" $menu_list
650                         menu_choice=$( eval $DIALOG \
651                                 --title \"\$title\"             \
652                                 --backtitle \"\$btitle\"        \
653                                 --ok-label \"\$msg_destroy\"    \
654                                 --cancel-label \"\$msg_cancel\" \
655                                 --menu \"\$msg\"                \
656                                 $height $width $rows            \
657                                 $menu_list                      \
658                                 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
659                         ) || continue
660                         f_dialog_data_sanitize menu_choice
661                         f_eval_catch $funcname ifconfig \
662                                 'ifconfig "%s" destroy' "$menu_choice"
663                         ;;
664                 "[ ] wlan"[0-9]*) # Unmarked; Mark
665                         if="${menu_choice#??? }"
666                         local _wlanmark_$if="X"
667                         list_to_save="$list_to_save${list_to_save:+ }$if"
668                         ;;
669                 "[X] wlan"[0-9]*) # Marked; Unmark
670                         menu_choice="${menu_choice#??? }"
671                         local _wlanmark_$menu_choice=" "
672                         local new_list_to_save=
673                         for if in $list_to_save; do
674                                 [ "$if" = "$menu_choice" ] && continue
675                                 new_list_to_save="$new_list_to_save $if"
676                         done
677                         list_to_save="${new_list_to_save# }"
678                         ;;
679                 esac
680         done
681
682         return $SUCCESS
683 }
684
685 # f_dialog_scan_wireless
686 #
687 # Initiate a scan for wireless networks. If wpa_supplicant(8) is not running
688 # but a wlan interface has been created, start an instance of wpa_supplicant(8)
689 # with the first wlan(4) interface we find. After initiating the scan, displays
690 # a message for 5 seconds (with option to dismiss). Returns failure if an error
691 # occurs, otherwise success.
692 #
693 f_dialog_scan_wireless()
694 {
695         local funcname=f_dialog_scan_wireless
696
697         #
698         # Try to communicate with a running wpa_supplicant(8)
699         #
700         if ! f_eval_catch -d $funcname wpa_cli 'wpa_cli ping'; then
701
702                 # If there is indeed one running, bail!
703                 if ps axo ucomm= | grep -qw wpa_supplicant; then
704                         f_show_msg "$msg_failed_to_reach_wpa_supplicant" \
705                                    "$msg_wpa_cli_ping_failed"
706                         return $FAILURE
707                 fi
708
709                 # Try and find a wlan device so we can start wpa_supplicant
710                 local dev devs if wlan=
711                 f_device_rescan_network
712                 f_device_find "" $DEVICE_TYPE_NETWORK devs
713                 for dev in $devs; do
714                         f_struct "$dev" get name if || continue
715                         case "$if" in wlan[0-9]*)
716                                 wlan=$if
717                                 break
718                         esac
719                 done
720                 if [ ! "$wlan" ]; then
721                         # We can't start wpa_supplicant without wlan interface
722                         # Tell the user they have to create one by navigating
723                         # to a Wireless device to create a wlan interface. But
724                         # let's go one step further and find an interface that
725                         # we can provide in the prompt text.
726                         local wlandev=
727                         for if in $devs; do
728                                 case "$if" in wlan[0-9]*) next; esac
729                                 if f_device_is_wireless $if; then
730                                         wlandev=$if
731                                         break
732                                 fi
733                         done
734                         if [ "$wlandev" ]; then
735                                 f_show_msg "$msg_cant_start_wpa_supplicant" \
736                                            "$wlandev"
737                         else
738                                 # Warn user, appears no wireless available
739                                 f_show_msg "$msg_warning_no_wireless_devices"
740                         fi
741                         return $FAILURE
742                 fi
743
744                 # NB: Before we can proceed to fire up wpa_supplicant(8), let's
745                 # make sure there is a bare-bones wpa_supplicant.conf(5) for it
746                 local conf_file
747                 conf_file=$( f_sysrc_get wpa_supplicant_conf_file )
748                 if [ ! -e "$conf_file" ]; then
749                         f_wpa_supplicant_init "$conf_file" || return $FAILURE
750                         f_eval_catch -d $funcname wpa_cli 'wpa_cli reconfigure'
751                 fi
752
753                 # Try and start wpa_supplicant(8)
754                 f_eval_catch $funcname wpa_supplicant \
755                         '/etc/rc.d/wpa_supplicant start "%s"' "$wlan" ||
756                         return $FAILURE
757
758                 # Try to reach this new wpa_supplicant(8)
759                 if ! f_eval_catch -d $funcname wpa_cli 'wpa_cli ping'; then
760                         f_show_msg "$msg_failed_to_reach_wpa_supplicant" \
761                                    "$msg_wpa_cli_ping_failed"
762                         return $FAILURE
763                 fi
764
765         fi # ! f_quietly wpa_cli ping
766
767         # If we reach hear, then it should be OK to scan the airwaves
768         f_eval_catch -d $funcname wpa_cli 'wpa_cli scan' || return $FAILURE
769
770         # Return immediately if a duration is: null or not a number >= 1
771         local duration="$DIALOG_MENU_WLAN_SCAN_DURATION"
772         f_isinteger "$duration" || return $SUCCESS
773         [ $duration -gt 0 ] || return $SUCCESS
774
775         # Display a message that times-out if not dismissed manually
776         local prompt
777         f_sprintf prompt "$msg_scanning_wireless_pausing" "$duration"
778         f_dialog_pause "$prompt" "$duration"
779 }
780
781 # f_dialog_wireless_edit $ssid
782 #
783 # Display a menu to allow the user to either create a new entry for the
784 # wpa_supplicants.conf(5) file, or to edit values for an existing entry.
785 #
786 # If more than one wireless network is found to match $ssid, a sub-menu is
787 # presented, allowing the user to select the desired network.
788 #
789 f_dialog_wireless_edit()
790 {
791         local title="$DIALOG_TITLE"
792         local btitle="$DIALOG_BACKTITLE"
793         local prompt1="$msg_select_the_configuration_you_would_like"
794         local prompt2 # Calculated below
795         local hline="$hline_alnum_arrows_punc_tab_enter"
796         local ssid="$1" bssid="$2"
797
798         f_sprintf prompt2 "$msg_wireless_network_configuration_for" "$ssid"
799
800         #
801         # Find one or more configurations that match the SSID selection
802         #
803         local height1 width1 rows1 menu_list1=
804         local n=0 nmatches=0 tag wssid wbssid help matches=
805         while [ $n -lt $NWIRELESS_CONFIGS ]; do
806                 n=$(( $n + 1 ))
807
808                 debug= f_struct WIRELESS_$n get ssid wssid
809                 [ "$ssid" = "$wssid" ] || continue
810                 debug= f_struct WIRELESS_$n get bssid wbssid
811                 [ "${bssid:-$wbssid}" = "$wbssid" ] || continue
812
813                 nmatches=$(( $nmatches + 1 ))
814                 [ $nmatches -le ${#DIALOG_MENU_TAGS} ] || break
815                 f_substr -v tag "$DIALOG_MENU_TAGS" $nmatches 1
816
817                 f_wireless_describe WIRELESS_$n help
818                 menu_list1="$menu_list1
819                         '$tag $wssid' '$wbssid' '$help'
820                 " # END-QUOTE
821
822                 matches="$matches WIRELESS_$n"
823         done
824         if [ $nmatches -eq 0 ]; then
825                 f_show_msg "$msg_cannot_edit_wireless_ssid" "$ssid"
826                 return $FAILURE
827         elif [ $nmatches -eq 1 ]; then
828                 struct=${matches# }
829         else
830                 eval f_dialog_menu_with_help_size height1 width1 rows1 \
831                         \"\$title\" \"\$btitle\" \"\$prompt1\" \"\$hline\" \
832                         $menu_list1
833         fi
834
835         #
836         # Operate in a loop; for the case of $nmatches > 1, we can cycle back
837         # to allow the user to make another choice after inspecting each one.
838         #
839         local menu_choice index struct defaultitem1=
840         while :; do
841                 if [ $nmatches -gt 1 ]; then
842                         menu_choice=$( eval $DIALOG \
843                                 --title \"\$title\"               \
844                                 --backtitle \"\$btitle\"          \
845                                 --hline \"\$hline\"               \
846                                 --ok-label \"\$msg_select\"       \
847                                 --cancel-label \"\$msg_cancel\"   \
848                                 --item-help                       \
849                                 --default-item \"\$defaultitem1\" \
850                                 --menu \"\$prompt1\"              \
851                                 $height1 $width1 $rows1           \
852                                 $menu_list1                       \
853                                 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
854                         ) || return $FAILURE
855                         f_dialog_data_sanitize menu_choice
856                         defaultitem1="$menu_choice"
857                         index=$( eval f_dialog_menutag2index_with_help \
858                                 \"\$menu_choice\" $menu_list1 )
859                         struct=$( set -- $matches; eval echo \${$index} )
860                 fi
861
862                 #
863                 # Operate within another loop to allow editing multiple values
864                 #
865                 local menu_list2 height2 width2 rows2 member
866                 while :; do
867                         menu_list2="
868                                 '> $msg_save_exit'
869                                         '$msg_return_to_previous_menu'
870                         " # END-QUOTE
871                         n=0
872                         for member in $_struct_typedef_WPA_NETWORK; do
873                                 [ "$member" = "ssid" ] && continue
874                                 debug= $struct get $member value || continue
875                                 n=$(( $n + 1 ))
876                                 [ $n -le ${#DIALOG_MENU_TAGS} ] || break
877                                 f_substr -v tag "$DIALOG_MENU_TAGS" $n 1
878                                 if [ ${#value} -gt 32 ]; then
879                                         f_snprintf value 29 "%s" "$value"
880                                         value="$value..."
881                                 fi
882                                 case "$member" in
883                                 password|pin|private_key_passwd|psk|wep_key*)
884                                         f_replaceall "$value" "?" "*" value ;;
885                                 esac
886                                 f_shell_escape "$value" value
887                                 menu_list2="$menu_list2
888                                         '$tag $member' '$value'
889                                 " # END-QUOTE
890                         done
891                         eval f_dialog_menu_size height2 width2 rows2 \
892                                 \"\$title\" \"\$btitle\" \"\$prompt2\" \
893                                 \"\$hline\" $menu_list2
894                         menu_choice=$( eval $DIALOG \
895                                 --title \"\$title\"               \
896                                 --backtitle \"\$btitle\"          \
897                                 --hline \"\$hline\"               \
898                                 --ok-label \"\$msg_select\"       \
899                                 --cancel-label \"\$msg_cancel\"   \
900                                 --default-item \"\$defaultitem2\" \
901                                 --menu \"\$prompt2\"              \
902                                 $height2 $width2 $rows2           \
903                                 $menu_list2                       \
904                                 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
905                         ) || break
906                         f_dialog_data_sanitize menu_choice
907                         defaultitem2="$menu_choice"
908
909                         # XXXDT Unfinished
910                 done
911                 [ $nmatches -eq 1 ] && break
912         done
913
914         #
915         # XXXDT Unfinished
916         # This is where we display a menu that edits the entry
917         # And then we modify the wpa_supplicants.conf(5) config file
918         # XXXDT Unfinished
919         #
920
921         return $FAILURE # XXXDT Simulating DIALOG_CANCEL to mean ``no changes''
922 }
923
924 # f_wireless_describe WPA_NETWORK [$var_to_set]
925 #
926 # Provide a description of the WPA_NETWORK struct. If $var_to_set is missing or
927 # NULL, the description is provided on standard output (which is less preferred
928 # due to performance; e.g., if called in a loop).
929 #
930 f_wireless_describe()
931 {
932         local __struct="$1" __var_to_set="$2" debug=
933
934         [ "$__var_to_set" ] && setvar "$__var_to_set" ""
935         f_struct "$__struct" || return $FAILURE
936
937         #
938         # Basic description is `proto key_mgmt group eap'
939         #
940         local __member __cp __desc=
941         for __member in proto key_mgmt group eap; do
942                 $__struct get $__member __cp && [ "$__cp" ] &&
943                         __desc="$__desc${__desc:+ }$__cp"
944         done
945
946         local __check __kk
947
948         #
949         # Make sure we add WEP40/WEP140 even if omitted from the key_mgmt
950         # section of entry
951         #
952         local __wep_keyN __f_wireless_describe_first_char __length
953         for __wep_keyN in wep_key0 wep_key1 wep_key2 wep_key3; do
954                 $__struct get $__wep_keyN __kk
955                 [ "$__kk" ] || continue
956
957                 # What type is it? ASCII or HEX?
958                 __check=WEP
959                 f_substr -v __f_wireless_describe_first_char "$__kk" 1 1
960                 case "$__f_wireless_describe_first_char" in
961                 \") # ASCII
962                         __length=$(( ${#__kk} - 2 ))
963                         if [ $__length -le 5 ]; then
964                                 __check=WEP40
965                         elif [ $__length -le 13 ]; then
966                                 __check=WEP104
967                         fi ;;
968                 *) # HEX
969                         __length=${#__kk}
970                         if [ $__length -eq 10 ]; then
971                                 __check=WEP40
972                         elif [ $__length -le 26 ]; then
973                                 __check=WEP104
974                         fi
975                 esac
976                 __kk="" # sensitive info
977
978                 case "$__desc" in
979                 *"$__check"*) : already there ;;
980                 *) __desc="$__desc${__desc:+ }$__check"
981                 esac
982         done
983
984         #
985         # Make sure we display PSK even if omitted
986         # from the key_mgmt section of the entry
987         #
988         $__struct get psk __kk
989         if [ "$__kk" ]; then
990                 __kk="" # sensitive info
991                 __check=PSK
992                 case "$__desc" in
993                 *"$__check"*) : already there ;;
994                 *) __desc="$__desc${__desc:+ }$__check"
995                 esac
996         fi
997
998         #
999         # Produce results
1000         #
1001         if [ "$__var_to_set" ]; then
1002                 setvar "$__var_to_set" "${__desc:-NONE}"
1003         else
1004                 echo "$__desc"
1005         fi
1006 }
1007
1008 # f_menu_wireless_configs
1009 #
1010 # Generates the tag/item/help triplets for wireless network menu (`--item-help'
1011 # required) from wpa_supplicant.conf(5) [WPA_NETWORK] structs.
1012 #
1013 f_menu_wireless_configs()
1014 {
1015         [ "$DIALOG_MENU_WLAN_SHOW_CONFIGURED" ] || return $SUCCESS
1016
1017         echo "' - $msg_configured_ssids -' ' - $msg_details -' ''"
1018
1019         local n=0 nunique=0 debug=
1020         local ssid ussid matches nmatches nconfigs nfound help desc w
1021         while [ $n -lt $NWIRELESS_CONFIGS ]; do
1022                 n=$(( $n + 1 ))
1023
1024                 f_struct WIRELESS_$n get ssid ssid
1025                 [ ! "$DIALOG_MENU_WLAN_SHOW_ALL" -a ! "$ssid" ] && continue
1026
1027                 local u=0 unique=1
1028                 while [ $u -lt $nunique ]; do
1029                         u=$(( $u + 1 ))
1030                         menuitem_$u get ssid ussid
1031                         [ "$ssid" != "$ussid" ] || unique= break
1032                 done
1033                 if [ "$unique" ]; then
1034                         nunique=$(( $nunique + 1 ))
1035                         u=$nunique
1036
1037                         # Set SSID and initialize number of configs found (1)
1038                         f_struct_new WLAN_MENU_ITEM menuitem_$u
1039                         menuitem_$u set ssid "$ssid"
1040                         menuitem_$u set nconfigs 1
1041
1042                         # Set number of wireless networks that match config
1043                         WIRELESS_$n get matches matches
1044                         f_count nmatches $matches
1045                         menuitem_$u set nfound $nmatches
1046
1047                         # Set help to description of the wireless config
1048                         f_wireless_describe WIRELESS_$n desc
1049                         menuitem_$u set help "$desc"
1050                 else
1051                         # Increment number of configs found with this SSID
1052                         menuitem_$u get nconfigs nconfigs
1053                         nconfigs=$(( $nconfigs + 1 ))
1054                         menuitem_$u set nconfigs $nconfigs
1055
1056                         # Add number of matched networks to existing count
1057                         WIRELESS_$n get matches matches
1058                         f_count nmatches $matches
1059                         menuitem_$u get nfound nfound
1060                         nfound=$(( $nfound + $nmatches ))
1061                         menuitem_$u set nfound $nfound
1062
1063                         # Combine description with existing help
1064                         menuitem_$u get help help
1065                         f_wireless_describe WIRELESS_$n desc
1066                         for w in $desc; do
1067                                 case "$help" in
1068                                 "$w"|"$w "*|*" $w"|*" $w "*) : already there ;;
1069                                 *) help="$help $w"
1070                                 esac
1071                         done
1072                         menuitem_$u set help "${help# }"
1073                 fi
1074         done
1075
1076         n=0
1077         while [ $n -lt $nunique ]; do
1078                 n=$(( $n + 1 ))
1079                 menuitem_$n get ssid ssid
1080
1081                 menuitem_$n get nconfigs nconfigs
1082                 desc="$nconfigs $msg_configured_lc"
1083                 [ $nconfigs -lt 10 ] && desc=" $desc"
1084                 menuitem_$n get nfound nfound
1085                 [ $nfound -gt 0 ] && desc="$desc $nfound $msg_found"
1086
1087                 menuitem_$n get help help
1088                 echo "'[X] $ssid' '$desc' '$help'"
1089         done | sort -bf | awk 'BEGIN { prefix = "" }
1090         {
1091                 cur_prefix = toupper(substr($0, 6, 1))
1092                 if (cur_prefix != "'\''" && prefix != cur_prefix ) {
1093                         prefix = cur_prefix
1094                         printf "'\''%c%s\n", prefix, substr($0, 2)
1095                 } else
1096                         printf "'\'' %s\n", substr($0, 2)
1097         }'
1098 }
1099
1100 # f_menu_wpa_scan_results
1101 #
1102 # Generates the tag/item/help triplets for wireless network menu (`--item-help'
1103 # required) from wpa_cli(8) `scan_results' [WPA_SCAN_RESULT] structs.
1104 #
1105 f_menu_wpa_scan_results()
1106 {
1107         [ "$DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS" ] || return $SUCCESS
1108
1109         if [ "$DIALOG_MENU_WLAN_SHOW_ALL" ]; then
1110                 echo "' - $msg_discovered_ssids -' ' - $msg_details -' ''"
1111         else
1112                 echo "' - $msg_discovered_ssids -' '' ''"
1113         fi
1114
1115         local n=0 nunique=0 debug=
1116         local ssid ussid matched nfound help flags f
1117         while [ $n -lt $NWSCAN_RESULTS ]; do
1118                 n=$(( $n + 1 ))
1119
1120                 WSCANS_$n get ssid ssid
1121                 [ ! "$DIALOG_MENU_WLAN_SHOW_ALL" -a ! "$ssid" ] && continue
1122
1123                 WSCANS_$n get matched matched
1124                 [ "$DIALOG_MENU_WLAN_SHOW_CONFIGURED" -a "$matched" ] &&
1125                         continue
1126
1127                 local u=0 unique=1
1128                 while [ $u -lt $nunique ]; do
1129                         u=$(( $u + 1 ))
1130                         menuitem_$u get ssid ussid
1131                         [ "$ssid" != "$ussid" ] || unique= break
1132                 done
1133                 if [ "$unique" ]; then
1134                         nunique=$(( $nunique + 1 ))
1135                         u=$nunique
1136
1137                         # Set SSID and initialize number of networks found (1)
1138                         f_struct_new WLAN_MENU_ITEM menuitem_$u
1139                         menuitem_$u set ssid "$ssid"
1140                         menuitem_$u set nfound 1
1141
1142                         # Set help to flags
1143                         WSCANS_$n get flags flags
1144                         f_replaceall "$flags" "[" " " flags
1145                         f_replaceall "$flags" "]" "" flags
1146                         flags="${flags# }"
1147                         case "$flags" in
1148                         "") flags="NONE" ;;
1149                         ESS) flags="NONE ESS" ;;
1150                         esac
1151                         menuitem_$u set help "$flags"
1152                 else
1153                         # Increment number of networks found with this SSID
1154                         menuitem_$u get nfound nfound
1155                         nfound=$(( $nfound + 1 ))
1156                         menuitem_$u set nfound $nfound
1157
1158                         # Combine flags into existing help
1159                         WSCANS_$n get flags flags
1160                         f_replaceall "$flags" "[" " " flags
1161                         f_replaceall "$flags" "]" "" flags
1162                         local flags_ess=
1163                         case "$flags" in *" ESS")
1164                                 flags_ess=1
1165                                 flags="${flags% ESS}"
1166                         esac
1167                         local help_ess=
1168                         menuitem_$u get help help
1169                         case "$help" in *" ESS")
1170                                 help_ess=1
1171                                 help="${help% ESS}"
1172                         esac
1173                         for f in ${flags:-NONE}; do 
1174                                 case "$help" in
1175                                 "$f"|"$f "*|*" $f"|*" $f "*) : already there ;;
1176                                 *) help="$help $f"
1177                                 esac
1178                         done
1179                         [ "$flags_ess" -a ! "$help_ess" ] && help="$help ESS"
1180                         menuitem_$u set help "${help# }"
1181                 fi
1182         done
1183
1184         local desc n=0
1185         while [ $n -lt $nunique ]; do
1186                 n=$(( $n + 1 ))
1187                 menuitem_$n get ssid ssid
1188
1189                 desc=
1190                 if [ "$DIALOG_MENU_WLAN_SHOW_ALL" ]; then
1191                         menuitem_$n get nfound nfound
1192                         desc="$nfound $msg_found"
1193                         [ $nfound -lt 10 ] && desc=" $desc"
1194                 fi
1195
1196                 menuitem_$n get help help
1197                 echo "'[ ] $ssid' '$desc' '$help'"
1198         done | sort -bf | awk 'BEGIN { prefix = "" }
1199         {
1200                 cur_prefix = toupper(substr($0, 6, 1))
1201                 if (cur_prefix != "'\''" && prefix != cur_prefix ) {
1202                         prefix = cur_prefix
1203                         printf "'\''%c%s\n", prefix, substr($0, 2)
1204                 } else
1205                         printf "'\'' %s\n", substr($0, 2)
1206         }'
1207 }
1208
1209 # f_dialog_menu_wireless_edit
1210 #
1211 # Display a list of wireless networks configured in wpa_supplicants.conf(5) and
1212 # (if wpa_supplicant(8) is running) also displays scan results for unconfigured
1213 # wireless networks.
1214 #
1215 f_dialog_menu_wireless_edit()
1216 {
1217         local funcname=f_dialog_menu_wireless_edit
1218         local title="$DIALOG_TITLE"
1219         local btitle="$DIALOG_BACKTITLE"
1220         local prompt="$msg_wireless_networks_text"
1221         local menu_list # Calculated below
1222         local defaultitem= # Calculated below
1223         local hline="$hline_alnum_arrows_punc_tab_enter"
1224
1225         f_show_info "$msg_loading_wireless_menu"
1226
1227         local conf_file
1228         conf_file=$( f_sysrc_get wpa_supplicant_conf_file )
1229
1230         #
1231         # Operate in a loop so we can edit wpa_supplicant.conf(5) and rescan
1232         # for new wireless networks from here.
1233         #
1234         local do_parse=1 remake_menu=1 item
1235         while :; do
1236                 #
1237                 # If this is the first time here, parse wpa_supplicant.conf(5),
1238                 # scan the airwaves, and compare to find matches.
1239                 #
1240                 if [ "$do_parse" -a "$DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS" ]
1241                 then
1242                         f_dprintf "$funcname: Parsing wireless scan results"
1243                         f_dialog_scan_wireless &&
1244                                 f_wpa_scan_results_parse WSCANS_ NWSCAN_RESULTS
1245                         f_dprintf "$funcname: Parsed %i scanned networks" \
1246                                   $NWSCAN_RESULTS
1247                 fi
1248                 if [ "$do_parse" -a "$DIALOG_MENU_WLAN_SHOW_CONFIGURED" ]
1249                 then
1250                         f_dprintf "$funcname: Parsing wpa_supplicants.conf(5)"
1251                         f_wpa_supplicant_parse "$conf_file" \
1252                                                WIRELESS_ NWIRELESS_CONFIGS
1253                         f_dprintf "%s: Parsed %i wireless configurations" \
1254                                   $funcname $NWIRELESS_CONFIGS
1255                         f_wpa_scan_find_matches WSCANS_ $NWSCAN_RESULTS \
1256                                                 WIRELESS_ $NWIRELESS_CONFIGS
1257                 fi
1258                 do_parse=
1259
1260                 if [ "$remake_menu" ]; then
1261                         remake_menu=
1262
1263                         #
1264                         # Add both items scanned from the airwaves and networks
1265                         # parsed from wpa_supplicants.conf(5). Latter items are
1266                         # marked, sorted, and added to top of list above the
1267                         # former (which are unmarked and sorted separately).
1268                         #
1269                         f_dprintf "$funcname: Building menu list..."
1270                         menu_list=$( 
1271                                 # Process wpa_supplicant.conf(5) structs
1272                                 f_menu_wireless_configs
1273                                 # Process wpa_cli(8) `scan_results' structs
1274                                 f_menu_wpa_scan_results
1275                         )
1276                         f_dprintf "$funcname: menu list built."
1277
1278                         #
1279                         # Add static top-level menu items
1280                         #
1281                         local XA=" " XC=" " XS=" "
1282                         [ "$DIALOG_MENU_WLAN_SHOW_ALL"          ] && XA="X"
1283                         [ "$DIALOG_MENU_WLAN_SHOW_CONFIGURED"   ] && XC="X"
1284                         [ "$DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS" ] && XS="X"
1285                         menu_list="
1286                                 '> $msg_exit' '$msg_return_to_previous_menu'
1287                                         ''
1288                                 '> $msg_rescan_wireless'   '*'
1289                                         '$msg_rescan_wireless_help'
1290                                 '> $msg_forget_all'        '*'
1291                                         '$msg_forget_all_help'
1292                                 '> $msg_show_configured'   '[$XC]'
1293                                         '$msg_show_configured_help'
1294                                 '> $msg_show_scan_results' '[$XS]'
1295                                         '$msg_show_scan_results_help'
1296                                 '> $msg_show_all'          '[$XA]'
1297                                         '$msg_show_all_help'
1298                                 '> $msg_manually_connect'  '...'
1299                                         '$msg_manually_connect_help'
1300                         $menu_list" # END-QUOTE
1301                 fi
1302
1303                 local height width rows
1304                 eval f_dialog_menu_with_help_size height width rows \
1305                         \"\$title\" \"\$btitle\" \"\$prompt\" \"\$hline\" \
1306                         $menu_list
1307
1308                 local menu_choice
1309                 menu_choice=$( eval $DIALOG \
1310                         --title \"\$title\"              \
1311                         --backtitle \"\$btitle\"         \
1312                         --hline \"\$hline\"              \
1313                         --ok-label \"\$msg_select\"      \
1314                         --cancel-label \"\$msg_cancel\"  \
1315                         --item-help                      \
1316                         --default-item \"\$defaultitem\" \
1317                         --menu \"\$prompt\"              \
1318                         $height $width $rows             \
1319                         $menu_list                       \
1320                         2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1321                 ) || break
1322                 f_dialog_data_sanitize menu_choice
1323                 defaultitem="$menu_choice"
1324
1325                 case "$menu_choice" in
1326                 "> $msg_exit") break ;;
1327                 "> $msg_rescan_wireless") do_parse=1 remake_menu=1 ;;
1328                 "> $msg_forget_all")
1329                         if f_noyes "$msg_forget_all_confirm"; then
1330                                 f_eval_catch $funcname rm \
1331                                         'rm -f "%s"' "$conf_file" || continue
1332                                 f_wpa_supplicant_init "$conf_file" || continue
1333                                 f_eval_catch -d $funcname wpa_cli \
1334                                         'wpa_cli reconfigure'
1335                                 f_wpa_supplicant_parse "$conf_file" \
1336                                         WIRELESS_ NWIRELESS_CONFIGS
1337                                 f_wpa_scan_find_matches \
1338                                         WSCANS_ $NWSCAN_RESULTS \
1339                                         WIRELESS_ $NWIRELESS_CONFIGS
1340                                 do_parse=1 remake_menu=1
1341                         fi ;;
1342                 "> $msg_show_configured")
1343                         item=$( eval f_dialog_menutag2item_with_help \
1344                                                 \"\$menu_choice\" $menu_list )
1345                         if [ "$item" = "[ ]" ]; then
1346                                 DIALOG_MENU_WLAN_SHOW_CONFIGURED=1
1347                         else
1348                                 DIALOG_MENU_WLAN_SHOW_CONFIGURED=
1349                         fi
1350                         remake_menu=1 ;;
1351                 "> $msg_show_scan_results")
1352                         item=$( eval f_dialog_menutag2item_with_help \
1353                                                 \"\$menu_choice\" $menu_list )
1354                         if [ "$item" = "[ ]" ]; then
1355                                 DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS=1
1356                         else
1357                                 DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS=
1358                         fi
1359                         remake_menu=1 ;;
1360                 "> $msg_show_all")
1361                         item=$( eval f_dialog_menutag2item_with_help \
1362                                                 \"\$menu_choice\" $menu_list )
1363                         if [ "$item" = "[ ]" ]; then
1364                                 DIALOG_MENU_WLAN_SHOW_ALL=1
1365                         else
1366                                 DIALOG_MENU_WLAN_SHOW_ALL=
1367                         fi
1368                         remake_menu=1 ;;
1369                 "> $msg_manually_connect")
1370                         f_dialog_wireless_edit && remake_menu=1 ;;
1371                 ?"[X] "*)
1372                         ssid="${menu_choice#??X? }"
1373                         f_dialog_wireless_edit "$ssid" || continue
1374                         do_parse=1 remake_menu=1 ;;
1375                 "[ ] "*)
1376                         :
1377                         : XXXDT Unfinished
1378                         :
1379                         ;;
1380                 esac
1381         done
1382
1383         #
1384         # XXXDT Unfinished
1385         #
1386 }
1387
1388 ############################################################ MAIN
1389
1390 f_dprintf "%s: Successfully loaded." media/wlan.subr
1391
1392 fi # ! $_MEDIA_WLAN_SUBR