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