commit b1360be37d7346ae086539b0846acd36f5f43255
Author: Marcos Mendoza <mmendoza@netgate.com>
Date:   Fri Sep 27 15:02:49 2024 -0600

    Clean up diffs

diff --git a/src/etc/inc/config.console.inc b/src/etc/inc/config.console.inc
index bb75cfaf05..011a0e0111 100644
--- a/src/etc/inc/config.console.inc
+++ b/src/etc/inc/config.console.inc
@@ -490,6 +490,30 @@ function check_for_alternate_interfaces() {
 	// If we recognise the platform, then specify the devices directly.
 	$if_config = config_get_path('interfaces', []);
 	switch ($specplatform['name']) {
+		case '5100':
+			$if_config['wan']['if'] = 'igb0';
+			$if_config['lan']['if'] = 'igb1';
+			$if_config['opt1'] = array(
+				'enable' => true,
+				'if' => 'ix0',
+				'descr' => 'OPT1'
+			);
+			$if_config['opt2'] = array(
+				'enable' => true,
+				'if' => 'ix1',
+				'descr' => 'OPT2'
+			);
+			$if_config['opt3'] = array(
+				'enable' => true,
+				'if' => 'ix2',
+				'descr' => 'OPT3'
+			);
+			$if_config['opt4'] = array(
+				'enable' => true,
+				'if' => 'ix3',
+				'descr' => 'OPT4'
+			);
+			break;
 		case 'alix':
 			$default_device['wan'] = "vr1";
 			$default_device['lan'] = "vr0";
@@ -734,30 +758,6 @@ function check_for_alternate_interfaces() {
 				'descr' => 'OPT4'
 			);
 			break;
-		case '5100':
-			$if_config['wan']['if'] = 'igb0';
-			$if_config['lan']['if'] = 'igb1';
-			$if_config['opt1'] = array(
-				'enable' => true,
-				'if' => 'ix0',
-				'descr' => 'OPT1'
-			);
-			$if_config['opt2'] = array(
-				'enable' => true,
-				'if' => 'ix1',
-				'descr' => 'OPT2'
-			);
-			$if_config['opt3'] = array(
-				'enable' => true,
-				'if' => 'ix2',
-				'descr' => 'OPT3'
-			);
-			$if_config['opt4'] = array(
-				'enable' => true,
-				'if' => 'ix3',
-				'descr' => 'OPT4'
-			);
-			break;
 		default:
 			$default_device['wan'] = "";
 			$default_device['lan'] = "";
diff --git a/src/etc/inc/config.lib.inc b/src/etc/inc/config.lib.inc
index c04301c260..72343c9dee 100644
--- a/src/etc/inc/config.lib.inc
+++ b/src/etc/inc/config.lib.inc
@@ -28,6 +28,7 @@
 
 require_once("xmlparse.inc");
 require_once('util.inc');
+require_once('globals.inc');
 
 /****f* config/encrypted_configxml
  * NAME
@@ -713,31 +714,27 @@ function reset_factory_defaults($lock = false, $reboot_required = true) {
 	return 0;
 }
 
-function config_restore($conffile) {
-	global $g;
-
-	if (!file_exists($conffile)) {
-		return 1;
+function config_restore(string $path, string $descr): bool {
+	if (!file_exists($path) || !backup_config()) {
+		return false;
 	}
 
-	backup_config();
-
 	$lockkey = lock('config', LOCK_EX);
 	if (!isset($lockkey)) {
-		return 1;
+		return false;
 	}
 	unlink_if_exists(g_get('tmp_path'). '/config.cache');
-	$copy_result = copy($conffile, "{$g['cf_conf_path']}/config.xml");
+	$copy_result = copy($path, g_get('cf_conf_path') . '/config.xml');
 	unlock($lockkey);
 
 	if ($copy_result) {
 		disable_security_checks();
 		config_read_file(true);
-		write_config(sprintf(gettext("Reverted to %s."), array_pop(explode("/", $conffile))), false);
-		return 0;
+		write_config(sprintf(gettext('Reverted to "%s"'), $descr), false);
+		return true;
 	}
 
-	return 1;
+	return false;
 }
 
 function config_install($conffile) {
@@ -934,38 +931,32 @@ function get_backups() {
 	return $toreturn;
 }
 
-function backup_config() {
-	global $g;
+function backup_config(): bool
+{
+	$backup_dir = g_get('cf_conf_path') . '/backup';
 
 	/* Create backup directory if needed */
-	safe_mkdir("{$g['cf_conf_path']}/backup");
-	if (config_get_path('revision/time') == "") {
-		$baktime = 0;
-	} else {
-		$baktime = config_get_path('revision/time');
-	}
+	safe_mkdir($backup_dir);
 
-	if (config_get_path('revision/description') == "") {
-		$bakdesc = "Unknown";
-	} else {
-		$bakdesc = config_get_path('revision/description');
-	}
+	/* Generate config backup file name */
+	$backup_time = config_get_path('revision/time', 0);
+	$backup_file = $backup_dir . '/config-' . $backup_time . '.xml';
 
+	/* Handle backup cache */
+	$bakdesc = config_get_path('revision/description', 'Unknown');
 	$bakver = config_get_path('version', "?");
-	$bakfilename = g_get('cf_conf_path') . '/backup/config-' . $baktime . '.xml';
-	copy(g_get('cf_conf_path') . '/config.xml', $bakfilename);
-
 	if (file_exists(g_get('cf_conf_path') . '/backup/backup.cache')) {
 		$backupcache = unserialize_data(file_get_contents(g_get('cf_conf_path') . '/backup/backup.cache'), []);
 	} else {
 		$backupcache = array();
 	}
-	$backupcache[$baktime] = array('description' => $bakdesc, 'version' => $bakver, 'filesize' => filesize($bakfilename));
+	$backupcache[$backup_time] = array('description' => $bakdesc, 'version' => $bakver, 'filesize' => filesize($backup_file));
 	$bakout = fopen(g_get('cf_conf_path') . '/backup/backup.cache', "w");
 	fwrite($bakout, serialize($backupcache));
 	fclose($bakout);
 
-	return true;
+	/* Do the backup */
+	return copy(g_get('cf_conf_path') . '/config.xml', $backup_file);
 }
 
 function backup_info($backup_info, $number) {
diff --git a/src/etc/inc/filter.inc b/src/etc/inc/filter.inc
index f723eaa3ca..10db346d38 100644
--- a/src/etc/inc/filter.inc
+++ b/src/etc/inc/filter.inc
@@ -515,6 +515,7 @@ function filter_configure_sync($delete_states_if_needed = true) {
 	 * 'cpzoneid_X_auth' - add PASS tag to authenticated client
 	 */
 	$rules .= filter_captiveportal_ether();
+	$rules .= PHP_EOL;
 
 	update_filter_reload_status(gettext("Setting up SCRUB information"));
 	$rules .= filter_generate_scrubbing();
diff --git a/src/etc/inc/openvpn.inc b/src/etc/inc/openvpn.inc
index f6362ba8ab..ce14bf1f85 100644
--- a/src/etc/inc/openvpn.inc
+++ b/src/etc/inc/openvpn.inc
@@ -864,7 +864,7 @@ function openvpn_reconfigure($mode, $settings) {
 	$pfile = g_get('varrun_path') . "/openvpn_{$mode_id}.pid";
 	$proto = strtolower($settings['protocol']);
 	if (substr($settings['protocol'], 0, 3) == "TCP") {
-			$proto = "{$proto}-{$mode}";
+		$proto = "{$proto}-{$mode}";
 	}
 	$dev_mode = $settings['dev_mode'];
 	$fbcipher = $settings['data_ciphers_fallback'];
@@ -1391,6 +1391,7 @@ function openvpn_reconfigure($mode, $settings) {
 	if ($settings['mode'] == "p2p_shared_key") {
 		$conf .= "cipher {$fbcipher}\n";
 	} else {
+		/* Build data ciphers list from configuration. */
 		$conf .= "data-ciphers " . str_replace(',', ':', openvpn_build_data_cipher_list($settings['data_ciphers'], $fbcipher)) . "\n";
 		$conf .= "data-ciphers-fallback {$fbcipher}\n";
 	}
@@ -1445,7 +1446,9 @@ function openvpn_reconfigure($mode, $settings) {
 	}
 
 	// If the server is not a TLS server or it has a tunnel network CIDR less than a /30, skip this.
-	if (in_array($settings['mode'], $openvpn_tls_server_modes) && (!empty($ip) && !empty($mask) && ($cidr < 30)) && $settings['dev_mode'] != "tap") {
+	if (in_array($settings['mode'], $openvpn_tls_server_modes) &&
+	    (!empty($ip) && !empty($mask) && ($cidr < 30)) &&
+	    ($settings['dev_mode'] != "tap")) {
 		if (empty($settings['topology'])) {
 			$settings['topology'] = "subnet";
 		}
@@ -1535,14 +1538,10 @@ function openvpn_reconfigure($mode, $settings) {
 	}
 }
 
-function openvpn_restart($mode, $settings) {
+function openvpn_stop_process($mode, $settings) {
 	global $g;
 
-	$vpnid = $settings['vpnid'];
 	$mode_id = openvpn_name($mode, $settings, 'generic');
-	$lockhandle = lock("openvpnservice{$mode_id}", LOCK_EX);
-	openvpn_reconfigure($mode, $settings);
-	/* kill the process if running */
 	$pfile = g_get('varrun_path')."/openvpn_{$mode_id}.pid";
 	if (file_exists($pfile)) {
 
@@ -1566,6 +1565,16 @@ function openvpn_restart($mode, $settings) {
 			$i++;
 		}
 	}
+}
+
+function openvpn_restart($mode, $settings) {
+	global $g;
+
+	$vpnid = $settings['vpnid'];
+	$mode_id = openvpn_name($mode, $settings, 'generic');
+	$lockhandle = lock("openvpnservice{$mode_id}", LOCK_EX);
+	openvpn_reconfigure($mode, $settings);
+	openvpn_stop_process($mode, $settings);
 
 	if (isset($settings['disable'])) {
 		openvpn_delete($mode, $settings);
@@ -1602,6 +1611,7 @@ function openvpn_restart($mode, $settings) {
 	$res = mwexec("/usr/local/sbin/openvpn --config " . escapeshellarg($fpath));
 	if ($res == 0) {
 		$i = 0;
+		$pfile = g_get('varrun_path')."/openvpn_{$mode_id}.pid";
 		$pid = "--";
 		while ($i < 3000) {
 			if (isvalidpid($pfile)) {
@@ -1627,17 +1637,7 @@ function openvpn_delete($mode, $settings) {
 	$vpnid = $settings['vpnid'];
 	$mode_id = openvpn_name($mode, $settings, 'generic');
 
-	/* kill the process if running */
-	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
-	if (file_exists($pfile)) {
-
-		/* read the pid file */
-		$pid = trim(file_get_contents($pfile));
-		unlink($pfile);
-
-		/* send a term signal to the process */
-		posix_kill($pid, SIGTERM);
-	}
+	openvpn_stop_process($mode, $settings);
 
 	/* destroy the device */
 	pfSense_interface_destroy(openvpn_name($mode, $settings));
diff --git a/src/etc/inc/pfsense-utils.inc b/src/etc/inc/pfsense-utils.inc
index a58843e25f..a1a3ac24dd 100644
--- a/src/etc/inc/pfsense-utils.inc
+++ b/src/etc/inc/pfsense-utils.inc
@@ -1233,7 +1233,8 @@ function setup_loader_settings($path = "", $upgrade = false) {
 		$vga_only = true;
 	} elseif ($specific_platform['name'] == 'Turbot Dual-E') {
 		$g['primaryconsole_force'] = "video";
-	} elseif ($specific_platform['name'] == 'RCC-VE' ||
+	} elseif (
+	    $specific_platform['name'] == 'RCC-VE' ||
 	    $specific_platform['name'] == 'RCC' ||
 	    $specific_platform['name'] == 'SG-2220' ||
 	    $specific_platform['name'] == 'apu2') {
@@ -2028,7 +2029,10 @@ function compare_hostname_to_dnscache($hostname) {
  * load_crypto() - Load crypto modules if enabled in config.
  */
 function load_crypto() {
-	$crypto_modules = array('aesni', 'cryptodev');
+	$crypto_modules = [
+		'aesni',
+		'cryptodev'
+	];
 
 	$enabled_modules = explode('_', config_get_path('system/crypto_hardware'));
 
diff --git a/src/etc/inc/pkg-utils.inc b/src/etc/inc/pkg-utils.inc
index 271cbdcdc8..f05f09fa6d 100644
--- a/src/etc/inc/pkg-utils.inc
+++ b/src/etc/inc/pkg-utils.inc
@@ -59,13 +59,17 @@ function pkg_valid_name($pkgname) {
 	return preg_match($pattern, $pkgname);
 }
 
-/* Remove pkg_prefix from package name if it's present */
+/* Remove pkg_prefix or flavor_prefix from package name if it's present */
 function pkg_remove_prefix(&$pkg_name) {
-	global $g;
-
-	if (substr($pkg_name, 0, strlen(g_get('pkg_prefix'))) ==
-	    g_get('pkg_prefix')) {
-		$pkg_name = substr($pkg_name, strlen(g_get('pkg_prefix')));
+	$pres = [g_get('pkg_prefix')];
+	if (!is_null(g_get('flavor_prefix'))) {
+		$pres[] = g_get('flavor_prefix');
+	}
+	foreach ( $pres as $pre) {
+		if (str_starts_with($pkg_name, $pre)) {
+			$pkg_name = substr($pkg_name, strlen($pre));
+			break;
+		}
 	}
 }
 
@@ -1556,43 +1560,50 @@ function pkg_switch_repo() {
 function update_repos() {
 	$product_name = g_get('product_name');
 	$pipes = [];
-	$descriptorspec = [
-		1 => ["pipe", "w"], /* stdout */
-		2 => ["pipe", "w"]  /* stderr */
+	$dspec = [
+		1 => ['pipe', 'w'], /* stdout */
+		2 => ['pipe', 'w']  /* stderr */
 	];
 	$rc = -1;
 	/* Default error message for failure cases. */
 	$fail_error = [
 		"error" => 1,
-		"messages" => ["Could not update connect to Netgate servers. Please try again later."]
+		"messages" => [gettext('Could not connect to Netgate servers. Please try again later.')]
 	];
 
 	/* Execute repoc with a full pkg style environment, including proxy
 	 * configuration. */
 	$process = proc_open(sprintf('/usr/local/sbin/%s-repoc -N', $product_name),
-	    $descriptorspec, $pipes, '/', pkg_env());
+	    $dspec, $pipes, '/', pkg_env());
 
 	/* Process failed to start */
 	if (!is_resource($process)) {
 		return $fail_error;
 	}
 
-	/* Read output */
-	$stdout = stream_get_contents($pipes[1]);
-	fclose($pipes[1]);
-	/* If stdout is boolean false, reading stdout failed. */
-	if ($stdout === false) {
-		return $fail_error;
-	}
-
-	/* Read errors */
-	$stderr = stream_get_contents($pipes[2]);
-	fclose($pipes[2]);
+	$timeout = 5; /* seconds */
+	$stdout = '';
+	do {
+		$start = microtime(true);
+		$r = ['stdout' => $pipes[1], 'stderr' => $pipes[2]];
+		$w = $e = null;
+		if (($n = stream_select($r, $w, $e, 0)) === false) {
+			$result = $fail_error;
+			goto error;
+		} else if ($n > 0) {
+			foreach ($r as $var => $fd) {
+				$$var .= fread($fd, 4096);
+			}
+		}
+		if (($timeout -= (microtime(true) - $start)) <= 0) {
+			$result = $fail_error;
+			goto error;
+		}
+	} while (!feof($pipes[1]) && !feof($pipes[2]));
 
 	/* Get return code */
-	$rc = proc_close($process);
 	$result = [
-		"error" => $rc,
+		"error" => proc_close($process),
 		"messages" => []
 	];
 
@@ -1600,13 +1611,18 @@ function update_repos() {
 	$stdout = explode("\n", trim($stdout));
 
 	if ((count($stdout) > 1) &&
-	    ($stdout[0] === "Messages:")) {
+	    ($stdout[0] === 'Messages:')) {
 		/* Copy over message content from the output. */
 		$result['messages'] = array_merge($result['messages'], array_slice($stdout, 1));
 	} elseif (!empty($stderr)) {
 		$result['messages'][] = $stderr;
 	}
 
-	return ($result);
+error:
+	if (is_resource($process)) {
+		proc_close($process);
+	}
+
+	return $result;
 }
 ?>
diff --git a/src/etc/inc/services.inc b/src/etc/inc/services.inc
index 2a0505f892..287764fe73 100644
--- a/src/etc/inc/services.inc
+++ b/src/etc/inc/services.inc
@@ -488,6 +488,8 @@ function services_kea6_configure() {
 	$kea_var_lib = '/var/lib/kea';
 	$kea_var_db = '/var/db/kea';
 
+	$kea6socket = g_get('varrun_path') . '/kea6-ctrl-socket';
+
 	if (g_get('services_dhcp_server_enable') == false) {
 		return;
 	}
@@ -552,7 +554,7 @@ function services_kea6_configure() {
 		'hooks-libraries' => [],
 		'control-socket' => [
 			'socket-type' => 'unix',
-			'socket-name' => '/var/run/kea6-ctrl-socket'
+			'socket-name' => $kea6socket
 		],
 	];
 
@@ -1004,7 +1006,7 @@ kea6_skip_first_pool_options:
 	$known_duids = array_keys($known_duids);
 	foreach ($known_duids as $duid) {
 		$keaconf['Dhcp6']['reservations'][] = [
-			'duid' => $duid
+			'duid' => (string) $duid
 		];
 	}
 
@@ -1126,6 +1128,8 @@ function services_kea4_configure() {
 	$kea_var_run = g_get('varrun_path') . '/kea';
 	$kea_var_lib = '/var/lib/kea';
 
+	$kea4socket = g_get('varrun_path').'/kea4-ctrl-socket';
+
 	if (g_get('services_dhcp_server_enable') == false) {
 		return;
 	}
@@ -1195,7 +1199,7 @@ function services_kea4_configure() {
 		'hooks-libraries' => [],
 		'control-socket' => [
 			'socket-type' => 'unix',
-			'socket-name' => '/var/run/kea4-ctrl-socket'
+			'socket-name' => $kea4socket
 		],
 	];
 
diff --git a/src/etc/inc/syslog.inc b/src/etc/inc/syslog.inc
index 1de736ab86..b40ff334d7 100644
--- a/src/etc/inc/syslog.inc
+++ b/src/etc/inc/syslog.inc
@@ -231,7 +231,6 @@ EOD;
 			@file_put_contents("{$g['varetc_path']}/syslog.d/" . basename($pkg_log_filename) . ".conf", $pkgsyslogconf);
 		}
 	}
-	$facilitylist = implode(',', array_unique($separatelogfacilities));
 
 	$syslogconf .= "!*\n";
 	if (!config_path_enabled('syslog', 'disablelocallogging')) {
@@ -354,6 +353,7 @@ EOD;
 		$syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.*");
 	}
 
+	$facilitylist = implode(',', array_unique($separatelogfacilities));
 	$syslogconf .= "!-{$facilitylist}\n";
 	if (!config_path_enabled('syslog', 'disablelocallogging')) {
 		$syslogconf .= <<<EOD
diff --git a/src/etc/inc/system.inc b/src/etc/inc/system.inc
index 67511ae64d..a72b00026b 100644
--- a/src/etc/inc/system.inc
+++ b/src/etc/inc/system.inc
@@ -26,6 +26,7 @@
  */
 
 require_once('config.lib.inc');
+require_once('services_dhcp.inc');
 require_once('syslog.inc');
 
 function system_hwpstate_active() {
@@ -204,6 +205,31 @@ function activate_sysctls() {
 	set_sysctl($sysctls);
 }
 
+/* Search current tunables for a specific OID and either update the existing
+ * entry or create a new one.
+ * Does not write the config, that's up to the caller. */
+function set_sysctl_config($oid, $value) {
+	$tunables = config_get_path('sysctl/item', []);
+	$updated = false;
+	$found = false;
+	foreach ($tunables as $idx => $tunable) {
+		if ($tunable['tunable'] == $oid) {
+			$found = true;
+			$tunables[$idx]['value'] = $value;
+		}
+	}
+	if (!$found) {
+		$tunables[] = [
+			'tunable' => $oid,
+			'value' => $value,
+		];
+		$updated = true;
+	}
+	if ($updated) {
+		config_set_path('sysctl/item', $tunables);
+	}
+}
+
 function system_resolvconf_generate($dynupdate = false) {
 	global $g;
 
@@ -730,9 +756,8 @@ function system_dhcpleases_configure() {
 }
 
 function system_get_kea6status() {
-	$socket_path = '/var/run/kea6-ctrl-socket';
+	$socket_path = g_get('varrun_path') . '/kea6-ctrl-socket';
 	$rbuf = NULL;
-	$ret = false;
 
 	if (!file_exists($socket_path)) {
 		goto out;
@@ -768,21 +793,15 @@ function system_get_kea6status() {
 		}
 	}
 
-	/* sanity check in case we received malformed json */
-	if (($ret = json_decode($retjson, true)) === false) {
-		goto cleanup;
-	}
-
 cleanup:
 	socket_close($fd);
 out:
-	return ($ret);
+	return (json_decode($retjson, true));
 }
 
 function system_get_kea4status() {
-	$socket_path = '/var/run/kea4-ctrl-socket';
+	$socket_path = g_get('varrun_path') . '/kea4-ctrl-socket';
 	$rbuf = NULL;
-	$ret = false;
 
 	if (!file_exists($socket_path)) {
 		goto out;
@@ -818,19 +837,14 @@ function system_get_kea4status() {
 		}
 	}
 
-	/* sanity check in case we received malformed json */
-	if (($ret = json_decode($retjson, true)) === false) {
-		goto cleanup;
-	}
-
 cleanup:
 	socket_close($fd);
 out:
-	return ($ret);
+	return (json_decode($retjson, true));
 }
 
 function system_clear_all_kea4leases() {
-	$socket_path = '/var/run/kea4-ctrl-socket';
+	$socket_path = g_get('varrun_path') . '/kea4-ctrl-socket';
 	$rbuf = NULL;
 
 	if (!file_exists($socket_path)) {
@@ -843,7 +857,8 @@ function system_clear_all_kea4leases() {
 	}
 
 	if (!socket_connect($fd, $socket_path, 0)) {
-		goto cleanup;
+		socket_close($fd);
+		return;
 	}
 
 	$cmdjson = json_encode(['command' => 'lease4-wipe']);
@@ -851,21 +866,13 @@ function system_clear_all_kea4leases() {
 	socket_send($fd, $cmdjson, strlen($cmdjson), 0);
 
 	/* Kea sends status that we are not really interested in, so just eat it */
-	for (;;) {
-		$bytes = socket_recv($fd, $rbuf, 8192, MSG_WAITALL);
-		if ($bytes > 0) {
-			continue;
-		}
+	while (socket_recv($fd, $rbuf, 8192, MSG_WAITALL) > 0);
 
-		break;
-	}
-
-cleanup:
 	socket_close($fd);
 }
 
 function system_del_kea4lease(string $ip) {
-	$socket_path = '/var/run/kea4-ctrl-socket';
+	$socket_path = g_get('varrun_path') . '/kea4-ctrl-socket';
 	$rbuf = NULL;
 
 	if (!file_exists($socket_path)) {
@@ -878,7 +885,8 @@ function system_del_kea4lease(string $ip) {
 	}
 
 	if (!socket_connect($fd, $socket_path, 0)) {
-		goto cleanup;
+		socket_close($fd);
+		return;
 	}
 
 	$cmdjson = json_encode([
@@ -891,21 +899,13 @@ function system_del_kea4lease(string $ip) {
 	socket_send($fd, $cmdjson, strlen($cmdjson), 0);
 
 	/* Kea sends status that we are not really interested in, so just eat it */
-	for (;;) {
-		$bytes = socket_recv($fd, $rbuf, 8192, MSG_WAITALL);
-		if ($bytes > 0) {
-			continue;
-		}
-
-		break;
-	}
+	while (socket_recv($fd, $rbuf, 8192, MSG_WAITALL) > 0);
 
-cleanup:
 	socket_close($fd);
 }
 
 function system_clear_all_kea6leases() {
-	$socket_path = '/var/run/kea6-ctrl-socket';
+	$socket_path = g_get('varrun_path') . '/kea6-ctrl-socket';
 	$rbuf = NULL;
 
 	if (!file_exists($socket_path)) {
@@ -918,7 +918,8 @@ function system_clear_all_kea6leases() {
 	}
 
 	if (!socket_connect($fd, $socket_path, 0)) {
-		goto cleanup;
+		socket_close($fd);
+		return;
 	}
 
 	$cmdjson = json_encode(['command' => 'lease6-wipe']);
@@ -926,21 +927,13 @@ function system_clear_all_kea6leases() {
 	socket_send($fd, $cmdjson, strlen($cmdjson), 0);
 
 	/* Kea sends status that we are not really interested in, so just eat it */
-	for (;;) {
-		$bytes = socket_recv($fd, $rbuf, 8192, MSG_WAITALL);
-		if ($bytes > 0) {
-			continue;
-		}
-
-		break;
-	}
+	while (socket_recv($fd, $rbuf, 8192, MSG_WAITALL) > 0);
 
-cleanup:
 	socket_close($fd);
 }
 
 function system_del_kea6lease(string $ip) {
-	$socket_path = '/var/run/kea6-ctrl-socket';
+	$socket_path = g_get('varrun_path') . '/kea6-ctrl-socket';
 	$rbuf = NULL;
 
 	if (!file_exists($socket_path)) {
@@ -953,7 +946,8 @@ function system_del_kea6lease(string $ip) {
 	}
 
 	if (!socket_connect($fd, $socket_path, 0)) {
-		goto cleanup;
+		socket_close($fd);
+		return;
 	}
 
 	$cmdjson = json_encode([
@@ -966,26 +960,17 @@ function system_del_kea6lease(string $ip) {
 	socket_send($fd, $cmdjson, strlen($cmdjson), 0);
 
 	/* Kea sends status that we are not really interested in, so just eat it */
-	for (;;) {
-		$bytes = socket_recv($fd, $rbuf, 8192, MSG_WAITALL);
-		if ($bytes > 0) {
-			continue;
-		}
+	while (socket_recv($fd, $rbuf, 8192, MSG_WAITALL) > 0);
 
-		break;
-	}
-
-cleanup:
 	socket_close($fd);
 }
 
-
 function system_get_kea6leases() {
 	$leases = [];
 	$leases['lease'] = [];
 	$leases['failover'] = [];
 
-	$socket_path = '/var/run/kea6-ctrl-socket';
+	$socket_path = g_get('varrun_path') . '/kea6-ctrl-socket';
 	$rbuf = NULL;
 
 	if (!file_exists($socket_path)) {
@@ -3132,7 +3117,8 @@ function system_get_serial() {
 
 	$vm_guest = get_single_sysctl('kern.vm_guest');
 
-	if (strlen($serial) >= 10 && strlen($serial) <= 16 &&
+	$serial = chop($serial);
+	if (strlen($serial) >= 10 && strlen($serial) <= 18 &&
 	    $vm_guest == 'none') {
 		return $serial;
 	}
@@ -3185,7 +3171,7 @@ function system_identify_specific_platform() {
 
 	if ($chassis[0] == "OracleCloud.com") {
 		return (array('name' => 'Oracle', 'descr' => 'Oracle Cloud Infrastructure'));
-	}	
+	}
 
 	if ($maker[0] == "QEMU") {
 		return (array('name' => 'QEMU', 'descr' => 'QEMU Guest'));
@@ -3382,5 +3368,3 @@ function system_get_arp_table($resolve_hostnames = false) {
 
 	return $arp_table;
 }
-
-?>
diff --git a/src/etc/inc/unbound.inc b/src/etc/inc/unbound.inc
index e8b6be3b5f..cee43de56f 100644
--- a/src/etc/inc/unbound.inc
+++ b/src/etc/inc/unbound.inc
@@ -27,6 +27,7 @@
 
 /* include all configuration functions */
 require_once("config.inc");
+require_once("services_dhcp.inc");
 require_once("functions.inc");
 require_once("filter.inc");
 require_once("shaper.inc");
diff --git a/src/etc/inc/upgrade_config.inc b/src/etc/inc/upgrade_config.inc
index 9657ecbd77..8f221a390b 100644
--- a/src/etc/inc/upgrade_config.inc
+++ b/src/etc/inc/upgrade_config.inc
@@ -6515,7 +6515,6 @@ function upgrade_220_to_221() {
 	config_set_path('widgets/sequence', implode(',', $widgets));
 }
 
-/* No functional changes. */
 function upgrade_221_to_222() {
 }
 
diff --git a/src/etc/inc/util.inc b/src/etc/inc/util.inc
index 8bc2d1a8b8..c0db058f40 100644
--- a/src/etc/inc/util.inc
+++ b/src/etc/inc/util.inc
@@ -24,6 +24,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 //require_once('interfaces.inc');
 require_once('Net/IPv6.php');
 define('VIP_ALL', 1);
@@ -48,6 +49,56 @@ define('SPECIALNET_VIPS', 12);
 define('SPECIALNET_CHECKPERM', 98);
 define('SPECIALNET_EXCLUDE', 99);
 
+/**
+ * Test the machine type
+ *
+ * @param string $arch		The architecture to test for
+ * @param bool $strict		Use strict architecture matching
+ *
+ * @return bool
+ */
+function is_arch(string $arch, bool $strict = false): bool
+{
+	$sys_arch = php_uname('m');
+	return (($arch == $sys_arch) || (!$strict && str_contains($sys_arch, $arch)));
+}
+
+/**
+ * Test if the machine type is any arm
+ *
+ * @return bool
+ */
+function is_arm(): bool
+{
+	return (is_arch('arm', false));
+}
+
+/**
+ * Test if the machine type is amd64
+ *
+ * @return bool
+ */
+function is_amd64(): bool
+{
+	return (is_arch('amd64', true));
+}
+
+/**
+ * Test if the machine type is arm64
+ */
+function is_arm64(): bool
+{
+	return (is_arch('arm64', true));
+}
+
+/**
+ * Test if the machine type is any 64bit
+ */
+function is_64bit(): bool
+{
+	return (is_amd64() || is_arm64());
+}
+
 /* kill a process by pid file */
 function killbypid($pidfile, $waitfor = 0) {
 	return sigkillbypid($pidfile, "TERM", $waitfor);
@@ -4674,4 +4725,3 @@ function unserialize_data(?string $path, mixed $default = null, ?array $options
 	return $data;
 }
 
-?>
diff --git a/src/etc/inc/xmlparse.inc b/src/etc/inc/xmlparse.inc
index 7d8f090df4..08c4cf58b3 100644
--- a/src/etc/inc/xmlparse.inc
+++ b/src/etc/inc/xmlparse.inc
@@ -41,8 +41,8 @@ function listtags() {
 		'field', 'fieldname',
 		'gateway_item', 'gateway_group', 'gif', 'gre', 'group',
 		'hash-algorithm-option', 'hosts', 'ifgroupentry', 'igmpentry', 'interface_array', 'item', 'key',
-		'lagg', 'lbaction', 'lbpool', 'l7rules', 'lbprotocol',
-		'member', 'menu', 'tab', 'mobilekey', 'monitor_type', 'mount',
+		'lagg', 'laggroup', 'lbaction', 'lbpool', 'l7rules', 'lbprotocol',
+		'member', 'menu', 'tab', 'mobilekey', 'mobilegroup', 'monitor_type', 'mount',
 		'npt', 'ntpserver',
 		'onetoone', 'openvpn-server', 'openvpn-client', 'openvpn-csc', 'option',
 		'package', 'passthrumac', 'phase1', 'phase2', 'ppp', 'pppoe', 'priv', 'proxyarpnet', 'pool',
diff --git a/src/etc/inc/xmlparse_attr.inc b/src/etc/inc/xmlparse_attr.inc
index 6d7c1e2053..b31914c663 100644
--- a/src/etc/inc/xmlparse_attr.inc
+++ b/src/etc/inc/xmlparse_attr.inc
@@ -168,7 +168,7 @@ function parse_xml_regdomain(&$rdattributes, $rdfile = '', $rootobj = 'regulator
 	return $rdmain;
 }
 
-function parse_xml_config_raw_attr($cffile, $rootobj, &$parsed_attributes, $isstring = "false") {
+function parse_xml_config_raw_attr($cffile, $rootobj, &$parsed_attributes) {
 
 	global $depth, $curpath, $parsedcfg, $havedata, $listtags, $parsedattrs;
 	$parsedcfg = array();
diff --git a/src/etc/pfSense-rc b/src/etc/pfSense-rc
index 34477abbce..21d16d5b3c 100755
--- a/src/etc/pfSense-rc
+++ b/src/etc/pfSense-rc
@@ -209,9 +209,7 @@ fi
 if [ -n "${USE_RAMDISK}" ]; then
 	/etc/rc.embedded
 	# Remount the correct subordinate ZFS datasets to ensure they are used properly
-	if [ -n "${USE_ZFS}" ]; then
-		_be_mount_zfs
-	fi
+	[ -n "${USE_ZFS}" ] && _be_mount_zfs
 fi
 
 # If RAM disks are active, make symlinks for pkg database on UFS
@@ -393,6 +391,9 @@ echo "done."
 /usr/bin/cap_mkdb /etc/login.conf
 
 if [ -f /cf/conf/needs_package_sync ]; then
+	# When restoring a configuration backup:
+	# - do not call pfSense-upgrade on boot
+	# - do not run rc.start_packages
 	skip_packages=1
 fi
 
@@ -553,8 +554,9 @@ if [ "${GMIRROR_STATUS}" != "" ]; then
 	/usr/local/bin/minicron 60 /var/run/gmirror_status_check.pid /usr/local/sbin/gmirror_status_check.php
 fi
 
-[ -z "$skip_packages" ] \
-	&& /usr/local/sbin/${product_name}-upgrade -y -U -b 3
+if [ -z "$skip_packages" ]; then
+	/usr/local/sbin/${product_name}-upgrade -y -U -b 3
+fi
 
 # Start packages
 [ -z "$skip_packages" ] \
@@ -563,17 +565,6 @@ fi
 # Update pkg metadata
 /etc/rc.update_pkg_metadata now
 
-# Log product version to syslog
-get_version
-BUILDTIME=`cat /etc/version.buildtime`
-ARCH=`uname -m`
-echo "$product_label ${version}${version_patch} $ARCH $BUILDTIME"
-
-echo "Bootup complete"
-echo "Bootup complete" | /usr/bin/logger
-
-/usr/local/bin/beep.sh start 2>&1 >/dev/null
-
 # Reset the cache.  read-only requires this.
 /bin/rm -f /tmp/config.cache
 
@@ -593,4 +584,15 @@ if [ -f /etc/rc.local ]; then
 	fi
 fi
 
+# Log product version to syslog
+get_version
+BUILDTIME=`cat /etc/version.buildtime`
+ARCH=`uname -m`
+echo "$product_label ${version}${version_patch} $ARCH $BUILDTIME"
+
+echo "Bootup complete"
+echo "Bootup complete" | /usr/bin/logger
+
+/usr/local/bin/beep.sh start 2>&1 >/dev/null
+
 exit 0
diff --git a/src/etc/rc.banner b/src/etc/rc.banner
index 000a498d31..79eab52b9f 100755
--- a/src/etc/rc.banner
+++ b/src/etc/rc.banner
@@ -33,6 +33,7 @@ $machine = trim(`uname -m`);
 
 /* Export the product variable. */
 if (is_writable("/etc")) {
+	$handle = NULL;
 	if (!file_exists("/etc/product_name") || is_writable("/etc/product_name"))
 		$handle = fopen("/etc/product_name", 'w');
 	if ($handle != NULL)
diff --git a/src/etc/rc.bootup b/src/etc/rc.bootup
index 4000815ae4..b6098a2d16 100755
--- a/src/etc/rc.bootup
+++ b/src/etc/rc.bootup
@@ -122,9 +122,6 @@ echo "done.\n";
 
 mwexec("/usr/sbin/gnid > {$g['vardb_path']}/uniqueid 2>/dev/null");
 
-/* run any early shell commands specified in config.xml */
-system_do_shell_commands(1);
-
 // Only do the alternate interface checks if:
 // 1) The user has not yet run the initial wizard; and
 // 2) The user has not used the console menu to setup interface assignments
@@ -170,11 +167,16 @@ while (is_interface_mismatch() == true) {
 	led_kitt();
 }
 
+/* enable optional crypto modules */
+echo "Loading cryptographic accelerator drivers...";
+load_crypto();
+echo "done.\n";
+
 echo "Checking config backups consistency...";
 cleanup_backupcache(true);
 echo "done.\n";
 
-/* read in /etc/sysctl.conf and set values if needed */
+/* set additional sysctls not defined in loader.conf */
 echo "Setting up extended sysctls...";
 system_setup_sysctl();
 echo "done.\n";
@@ -187,8 +189,10 @@ if (file_exists($file)) {
 	echo "done.\n";
 }
 
-/* enable optional crypto modules */
-load_crypto();
+/* run any early shell commands specified in config.xml */
+echo "Executing early shell commands...";
+system_do_shell_commands(1);
+echo "done.\n";
 
 /* enable optional thermal sensor modules */
 load_thermal_hardware();
diff --git a/src/etc/rc.initial.reboot b/src/etc/rc.initial.reboot
index 80b95e2e3c..4d071818ac 100755
--- a/src/etc/rc.initial.reboot
+++ b/src/etc/rc.initial.reboot
@@ -45,7 +45,7 @@ if (!is_module_loaded("zfs.ko")) {
 
 echo gettext("Enter an option:") . " ";
 
-switch (chop(fgets($fp))) {
+switch (strtoupper(chop(fgets($fp)))) {
 	case "S":
 		mwexec('/sbin/nextboot -o "-s" -k kernel');
 		$msg = sprintf(gettext("%s is rebooting into single user mode now."), $g['product_label']);
@@ -70,7 +70,8 @@ switch (chop(fgets($fp))) {
 		system_reboot_sync(true);
 		break;
 	case "Y":
-	case "y":
+	case "YE":
+	case "YES":
 		$msg = sprintf(gettext("%s is rebooting now."), $g['product_label']);
 		echo "\n" . $msg . "\n";
 		notify_all_remote($msg);
diff --git a/src/etc/rc.php_ini_setup b/src/etc/rc.php_ini_setup
index d11b9132b5..6c6d05dd5e 100755
--- a/src/etc/rc.php_ini_setup
+++ b/src/etc/rc.php_ini_setup
@@ -45,14 +45,16 @@ else
 	AVAILMEM=$(/sbin/dmesg -a |/usr/bin/awk '/avail memory/ { memory=($4 / 1048576); printf("%0.0f\n", memory); exit}')
 fi
 
+# Use hw.physmem if $AVAILMEM is zero
 if [ -z "$AVAILMEM" ]; then
-	MEM=$(/sbin/sysctl -q hw.physmem | cut -d':' -f2)
-	AVAILMEM=$(/bin/expr $MEM / 1048576)
+	AVAILMEM=$(/sbin/sysctl -qn hw.physmem | /usr/bin/awk '{print $1/1048576}' | /usr/bin/awk -F '.' '{print $1}')
 fi
 
-
 # Get amount of ram installed on this system
-REALMEM=$(/sbin/sysctl -q hw.realmem | /usr/bin/awk '{print $2/1048576}' | /usr/bin/awk -F '.' '{print $1}')
+REALMEM=$(/sbin/sysctl -qn hw.realmem | /usr/bin/awk '{print $1/1048576}' | /usr/bin/awk -F '.' '{print $1}')
+if [ -z "$REALMEM" -o "$REALMEM" == "0" ]; then
+	REALMEM=$AVAILMEM
+fi
 export REALMEM
 export LOWMEM
 
@@ -81,6 +83,8 @@ else
 	fi
 fi
 
+PCRE_JIT=1
+
 # Set upload directory
 UPLOADTMPDIR="/tmp"
 
@@ -214,6 +218,9 @@ session.hash_function = 1
 ${error_reporting}
 ${exception_ignore_args}
 
+[Pcre]
+pcre.jit=${PCRE_JIT}
+
 ; Extensions
 
 EOF
diff --git a/src/etc/rc.restore_config_backup b/src/etc/rc.restore_config_backup
index 43c01145e3..8b45ec6946 100755
--- a/src/etc/rc.restore_config_backup
+++ b/src/etc/rc.restore_config_backup
@@ -57,7 +57,7 @@ function choose_backup() {
 	echo " 1-" . count($confvers) . " : ";
 	$number = strtoupper(chop(fgets($fp)));
 	if (is_numeric($number) && ($number > 0) && ($number <= count($confvers))) {
-		return $number;
+		return intval($number);
 	} else {
 		echo gettext("That is not a valid backup number.\n");
 		return -1;
@@ -74,7 +74,7 @@ function restore_history_backup($number) {
 		echo gettext("Y/N?") . " : ";
 		$confirm = strtoupper(chop(fgets($fp)));
 		if ($confirm == gettext("Y")) {
-			if (config_restore($g['conf_path'] . '/backup/config-' . $thisbackup['time'] . '.xml') == 0) {
+			if (config_restore($g['conf_path'] . '/backup/config-' . $thisbackup['time'] . '.xml', $thisbackup['description'])) {
 				echo "\n";
 				echo sprintf(gettext('Successfully reverted to timestamp %1$s with description "%2$s".'), date(gettext("n/j/y H:i:s"), $thisbackup['time']), $thisbackup['description']);
 				echo "\n" . gettext("You may need to reboot the firewall or restart services before the restored configuration is fully active.") . "\n\n";
diff --git a/src/usr/local/pfSense/include/www/backup.inc b/src/usr/local/pfSense/include/www/backup.inc
index 9544114bb1..07c589af98 100644
--- a/src/usr/local/pfSense/include/www/backup.inc
+++ b/src/usr/local/pfSense/include/www/backup.inc
@@ -252,7 +252,7 @@ function execPost($post, $postfiles, $ui = true) {
 					} else {
 
 						/* read the file contents */
-						$data = $ui ? file_get_contents($postfiles['conffile']['tmp_name']) : $postfiles['conffile']['tmp_name'];
+						$data = file_get_contents($postfiles['conffile']['tmp_name']);
 						if (!$data) {
 							$input_errors[] = gettext("Warning, could not read file {$postfiles['conffile']['tmp_name']}");
 						} elseif ($post['decrypt']) {
diff --git a/src/usr/local/pfSense/include/www/services_dhcp.inc b/src/usr/local/pfSense/include/www/services_dhcp.inc
index db5a03b7ab..75107067c3 100644
--- a/src/usr/local/pfSense/include/www/services_dhcp.inc
+++ b/src/usr/local/pfSense/include/www/services_dhcp.inc
@@ -360,7 +360,6 @@ function dhcp_apply_changes(): int {
 		$retvaldns |= services_unbound_configure();
 		if ($retvaldns == 0) {
 			clear_subsystem_dirty('unbound');
-
 			clear_subsystem_dirty('hosts');
 			clear_subsystem_dirty('dhcpd');
 		}
diff --git a/src/usr/local/pfSense/include/www/system_advanced_misc.inc b/src/usr/local/pfSense/include/www/system_advanced_misc.inc
index 01d8d43a66..5d41f575b3 100644
--- a/src/usr/local/pfSense/include/www/system_advanced_misc.inc
+++ b/src/usr/local/pfSense/include/www/system_advanced_misc.inc
@@ -22,6 +22,7 @@
 require_once("config.gui.inc");
 require_once("functions.inc");
 require_once("filter.inc");
+require_once("service-utils.inc");
 require_once("shaper.inc");
 require_once("system.inc");
 require_once("util.inc");
@@ -132,6 +133,21 @@ function getSystemAdvancedMisc($json = false) {
 	return $json ? json_encode($pconfig) : $pconfig;
 }
 
+function getSystemAdvancedMiscCryptoModules() {
+	$platform = system_identify_specific_platform();
+	switch ($platform['name']) {
+		default:
+			$crypto_modules = array(
+				'aesni' => gettext("AES-NI CPU-based Acceleration"),
+				'aesni_cryptodev' => gettext("AES-NI and BSD Crypto Device (aesni, cryptodev)"),
+				'cryptodev' => gettext("BSD Crypto Device (cryptodev)"),
+				'qat' => gettext("Intel QuickAssist (QAT)"),
+			);
+	}
+
+	return $crypto_modules;
+}
+
 function saveSystemAdvancedMisc($post, $json = false) {
 	global $global_gateway_state_kill_modes, $hwpstate_status_descr, $hwpstate_control_levels;
 
@@ -163,7 +179,8 @@ function saveSystemAdvancedMisc($post, $json = false) {
 		'amdtemp' => gettext("AMD K8, K10 and K11 CPU on-die thermal sensor")
 	);
 
-	if (!empty($post['crypto_hardware']) && !array_key_exists($post['crypto_hardware'], $crypto_modules)) {
+	if (!empty($post['crypto_hardware']) && !array_key_exists($post['crypto_hardware'],
+	    getSystemAdvancedMiscCryptoModules())) {
 		$input_errors[] = gettext("Please select a valid Cryptographic Accelerator.");
 	}
 
diff --git a/src/usr/local/www/classes/Form.class.php b/src/usr/local/www/classes/Form.class.php
index c11898f417..90016bffa9 100644
--- a/src/usr/local/www/classes/Form.class.php
+++ b/src/usr/local/www/classes/Form.class.php
@@ -77,6 +77,13 @@ class Form extends Form_Element
 		return $this;
 	}
 
+	public function setMethod($method)
+	{
+		$this->_attributes['method'] = $method;
+
+		return $this;
+	}
+
 	public function addGlobal(Form_Input $input)
 	{
 		array_push($this->_global, $input);
diff --git a/src/usr/local/www/css/logo.css b/src/usr/local/www/css/logo.css
index c8e53a5b2c..4986982519 100644
--- a/src/usr/local/www/css/logo.css
+++ b/src/usr/local/www/css/logo.css
@@ -1,11 +1,18 @@
 .logo-st0 {
 fill:#2B40B5;
 }
-
 .logo-st1 {
 fill:#1475CF;
 }
-
 .logo-st2 {
 fill:#1C1275;
 }
+.logo-st3 {
+  fill:#357cd1;
+}
+.logo-st4 {
+  fill:#2753c0;
+}
+.logo-st5 {
+  fill:#061f7a;
+}
diff --git a/src/usr/local/www/css/pfSense.css b/src/usr/local/www/css/pfSense.css
index d95ce3e2cb..cafc892ba9 100644
--- a/src/usr/local/www/css/pfSense.css
+++ b/src/usr/local/www/css/pfSense.css
@@ -145,15 +145,7 @@ tr.disabled a {
     width: 105px;
 }
 
-.logo-st0 {
-    fill:#FFFFFF;
-}
-
-.logo-st1 {
-    fill:#FFFFFF;
-}
-
-.logo-st2 {
+.logo-st0, .logo-st1, .logo-st2, .logo-st3, .logo-st4, .logo-st5 {
     fill:#FFFFFF;
 }
 
diff --git a/src/usr/local/www/diag_backup.php b/src/usr/local/www/diag_backup.php
index 0142fe2d6d..7a724dbdce 100644
--- a/src/usr/local/www/diag_backup.php
+++ b/src/usr/local/www/diag_backup.php
@@ -117,10 +117,15 @@ function build_area_list($showall) {
 	}
 }
 
-$pgtitle = array(gettext("Diagnostics"), htmlspecialchars(gettext("Backup & Restore")), htmlspecialchars(gettext("Backup & Restore")));
-$pglinks = array("", "@self", "@self");
+$pgtitle = [gettext('Diagnostics'), htmlspecialchars(gettext('Backup & Restore')), htmlspecialchars(gettext('Backup & Restore'))];
+$pglinks = ['', '@self', '@self'];
 include("head.inc");
 
+$tab_array[] = [htmlspecialchars(gettext('Backup & Restore')), true, 'diag_backup.php'];
+$tab_array[] = [gettext('Configuration History'), false, 'diag_confbak.php'];
+
+display_top_tabs($tab_array);
+
 if ($input_errors) {
 	print_input_errors($input_errors);
 }
@@ -140,11 +145,6 @@ if (is_subsystem_dirty('restore')):
 <?php
 endif;
 
-$tab_array = array();
-$tab_array[] = array(htmlspecialchars(gettext("Backup & Restore")), true, "diag_backup.php");
-$tab_array[] = array(gettext("Config History"), false, "diag_confbak.php");
-display_top_tabs($tab_array);
-
 $form = new Form(false);
 $form->setMultipartEncoding();	// Allow file uploads
 
diff --git a/src/usr/local/www/diag_confbak.php b/src/usr/local/www/diag_confbak.php
index 97548bc4aa..8f2a75fe76 100644
--- a/src/usr/local/www/diag_confbak.php
+++ b/src/usr/local/www/diag_confbak.php
@@ -30,11 +30,11 @@
 ##|*MATCH=diag_confbak.php*
 ##|-PRIV
 
-require_once("guiconfig.inc");
+require_once('guiconfig.inc');
 
 if (isset($_POST['backupcount'])) {
 	if (!empty($_POST['backupcount']) && (!is_numericint($_POST['backupcount']) || ($_POST['backupcount'] < 0))) {
-		$input_errors[] = gettext("Invalid Backup Count specified");
+		$input_errors[] = gettext('Invalid Backup Count specified');
 	}
 
 	if (!$input_errors) {
@@ -43,16 +43,16 @@ if (isset($_POST['backupcount'])) {
 			$changedescr = config_get_path('system/backupcount');
 		} elseif (empty($_POST['backupcount'])) {
 			config_del_path('system/backupcount');
-			$changedescr = gettext("(platform default)");
+			$changedescr = gettext('platform default');
 		}
-		write_config(sprintf(gettext("Changed backup revision count to %s"), $changedescr));
+		write_config(sprintf(gettext('Changed backup revision count to %s'), $changedescr));
 	}
 }
 
 $confvers = unserialize_data(file_get_contents(g_get('cf_conf_path') . '/backup/backup.cache'), []);
 
 if ($_POST['newver'] != "") {
-	if (config_restore(g_get('conf_path') . '/backup/config-' . $_POST['newver'] . '.xml') == 0) {
+	if (config_restore(g_get('conf_path') . '/backup/config-' . $_POST['newver'] . '.xml', htmlspecialchars($confvers[$_POST['newver']]['description']))) {
 		$savemsg = sprintf(gettext('Successfully reverted configuration to timestamp %1$s with description "%2$s".%3$s%3$sTo activate the changes, manually reboot or apply/reload relevant features.'), date(gettext("n/j/y H:i:s"), $_POST['newver']), htmlspecialchars($confvers[$_POST['newver']]['description']), '<br/>');
 	} else {
 		$savemsg = gettext("Unable to revert to the selected configuration.");
@@ -71,7 +71,7 @@ if ($_REQUEST['getcfg'] != "") {
 				'config-' . config_get_path('system/hostname') . '.' . config_get_path('system/domain') . "-{$_REQUEST['getcfg']}.xml");
 }
 
-if (($_REQUEST['diff'] == 'Diff') && isset($_REQUEST['oldtime']) && isset($_REQUEST['newtime']) &&
+if (($_REQUEST['compare'] == 'compare') && isset($_REQUEST['oldtime']) && isset($_REQUEST['newtime']) &&
     (is_numeric($_REQUEST['oldtime'])) &&
     (is_numeric($_REQUEST['newtime']) || ($_REQUEST['newtime'] == 'current'))) {
 	$diff = "";
@@ -93,9 +93,9 @@ cleanup_backupcache(false);
 $confvers = get_backups();
 unset($confvers['versions']);
 
-$pgtitle = array(gettext("Diagnostics"), htmlspecialchars(gettext("Backup & Restore")), gettext("Config History"));
-$pglinks = array("", "diag_backup.php", "@self");
-include("head.inc");
+$pgtitle = [gettext('Diagnostics'), htmlspecialchars(gettext('Backup & Restore')), gettext('Config History')];
+$pglinks = ['', 'diag_backup.php', '@self'];
+include('head.inc');
 
 if ($input_errors) {
 	print_input_errors($input_errors);
@@ -106,16 +106,16 @@ if ($savemsg) {
 }
 
 $tab_array = array();
-$tab_array[] = array(htmlspecialchars(gettext("Backup & Restore")), false, "diag_backup.php");
-$tab_array[] = array(gettext("Config History"), true, "diag_confbak.php");
+$tab_array[] = [htmlspecialchars(gettext('Backup & Restore')), false, "diag_backup.php"];
+$tab_array[] = [gettext('Config History'), true, 'diag_confbak.php'];
 display_top_tabs($tab_array);
 
-if ($diff) {
+if ($diff):
 ?>
 <div class="panel panel-default">
 	<div class="panel-heading">
 		<h2 class="panel-title">
-			<?=sprintf(gettext('Configuration Diff from %1$s to %2$s'), date(gettext("n/j/y H:i:s"), $oldtime), date(gettext("n/j/y H:i:s"), $newtime))?>
+			<?=sprintf(gettext('Configuration Difference from %1$s to %2$s'), date(gettext("n/j/y H:i:s"), $oldtime), date(gettext("n/j/y H:i:s"), $newtime))?>
 		</h2>
 	</div>
 	<div class="panel-body table-responsive">
@@ -123,55 +123,47 @@ if ($diff) {
 		<table style="padding-top: 4px; padding-bottom: 4px; vertical-align:middle;">
 
 <?php
-	foreach ($diff as $line) {
-		switch (substr($line, 0, 1)) {
-			case "+":
-				$color = "#caffd3";
-				break;
-			case "-":
-				$color = "#ffe8e8";
-				break;
-			case "@":
-				$color = "#a0a0a0";
-				break;
-			default:
-				$color = "#ffffff";
-		}
+$colors = [
+	'+' => '#caffd3',
+	'-' => '#ffe8e8',
+	'@' => '#a0a0a0'
+];
+	foreach ($diff as $line):
 ?>
 			<tr>
-				<td class="diff-text" style="vertical-align:middle; background-color:<?=$color;?>; white-space:pre-wrap;"><?=htmlentities($line)?></td>
+				<td class="diff-text" style="vertical-align:middle; background-color:<?=$colors[substr($line, 0, 1)] ?? '#ffffff'?>; white-space:pre-wrap;"><?=htmlentities($line)?></td>
 			</tr>
 <?php
-	}
+	endforeach;
 ?>
 		</table>
 	</div>
 </div>
 <?php
-}
+endif;
 
 $form = new Form(false);
 
-$section = new Form_Section('Configuration Backup Cache Settings', 'configsettings', COLLAPSIBLE|SEC_CLOSED);
+$section = new Form_Section(gettext('Configuration Backup Settings'), 'configsettings');
 
 $section->addInput(new Form_Input(
 	'backupcount',
-	'Backup Count',
+	gettext('Maximum Backups'),
 	'number',
 	config_get_path('system/backupcount'),
-	['min' => '0']
-))->setHelp('Maximum number of old configurations to keep in the cache, 0 for no backups, or leave blank for the default value (%s for the current platform).', g_get('default_config_backup_count'));
+	['min' => '0', 'placeholder' => g_get('default_config_backup_count')]
+))->setHelp(gettext('Maximum number of old configuration backups to keep in the cache, 0 for no backups, or leave blank for the default value.'));
 
 $space = exec("/usr/bin/du -sh /conf/backup | /usr/bin/awk '{print $1;}'");
 
 $section->addInput(new Form_StaticText(
-	'Current space used by backups',
+	gettext('Used Space'),
 	$space
 ));
 
 $section->addInput(new Form_Button(
 	'Submit',
-	gettext("Save"),
+	gettext('Save'),
 	null,
 	'fa-solid fa-save'
 ))->addClass('btn-primary');
@@ -188,8 +180,7 @@ if (is_array($confvers)) {
 			gettext(
 				'To view the differences between an older configuration and a newer configuration, ' .
 				'select the older configuration using the left column of radio options and select the newer configuration in the right column, ' .
-				'then press the "Diff" button.'),
-			'info', false); ?>
+				'then press the "Compare" button.'), 'info', false); ?>
 	</div>
 </div>
 <?php
@@ -205,16 +196,16 @@ if (is_array($confvers)):
 			<thead>
 				<tr>
 					<th colspan="2">
-						<button type="submit" name="diff" class="btn btn-info btn-xs" value="Diff">
+						<button type="submit" name="compare" class="btn btn-info btn-xs" value="compare">
 							<i class="fa-solid fa-right-left icon-embed-btn"></i>
-							<?=gettext("Diff"); ?>
+							<?=gettext('Compare'); ?>
 						</button>
 					</th>
-					<th><?=gettext("Date")?></th>
-					<th><?=gettext("Version")?></th>
-					<th><?=gettext("Size")?></th>
-					<th><?=gettext("Configuration Change")?></th>
-					<th><?=gettext("Actions")?></th>
+					<th><?=gettext('Date')?></th>
+					<th><?=gettext('Version')?></th>
+					<th><?=gettext('Size')?></th>
+					<th><?=gettext('Configuration Change')?></th>
+					<th><?=gettext('Actions')?></th>
 				</tr>
 			</thead>
 			<tbody>
@@ -269,9 +260,9 @@ if (is_array($confvers)):
 ?>
 				<tr>
 					<td colspan="2">
-						<button type="submit" name="diff" class="btn btn-info btn-xs" value="Diff">
+						<button type="submit" name="compare" class="btn btn-info btn-xs" value="compare">
 							<i class="fa-solid fa-right-left icon-embed-btn"></i>
-							<?=gettext("Diff"); ?>
+							<?=gettext('Compare'); ?>
 						</button>
 					</td>
 					<td colspan="5"></td>
diff --git a/src/usr/local/www/diag_reboot.php b/src/usr/local/www/diag_reboot.php
index ed1bc76ec9..f326b54604 100644
--- a/src/usr/local/www/diag_reboot.php
+++ b/src/usr/local/www/diag_reboot.php
@@ -46,30 +46,33 @@ $guiretry = 20;		// Seconds to try again if $guitimeout was not long enough
 
 $pgtitle = array(gettext("Diagnostics"), gettext("Reboot"));
 $platform = system_identify_specific_platform();
+
 include("head.inc");
 
-if ($_SERVER['REQUEST_METHOD'] == 'POST'):
+if (isset($_POST['rebootmode'])):
 	if (DEBUG) {
 		print_info_box(gettext("Not actually rebooting (DEBUG is set true)."), 'success');
 	} else {
 		print('<div><pre>');
 		switch ($_POST['rebootmode']) {
-			case 'FSCKReboot':
+			case 'fsckreboot':
 				if ((php_uname('m') != 'arm') && !is_module_loaded("zfs.ko")) {
 					mwexec('/sbin/nextboot -e "pfsense.fsck.force=5"');
 					notify_all_remote(sprintf(gettext("%s is rebooting for a filesystem check now."), g_get('product_label')));
 					system_reboot();
 				}
 				break;
-			case 'Reroot':
+			case 'reroot':
 				notify_all_remote(sprintf(gettext("%s is rerooting now."), g_get('product_label')));
 				system_reboot_sync(true);
 				break;
-			case 'Reboot':
+			case 'reboot':
 				notify_all_remote(sprintf(gettext("%s is rebooting now."), g_get('product_label')));
 				system_reboot();
 				break;
 			default:
+				header('Location: /diag_reboot.php');
+				break;
 		}
 		print('</pre></div>');
 	}
@@ -85,7 +88,7 @@ events.push(function() {
 
 	function checkonline() {
 		$.ajax({
-			url	 : "/index.php", // or other resource
+			url	: "/index.php", // or other resource
 			type : "HEAD"
 		})
 		.done(function() {
@@ -122,26 +125,25 @@ else:
 
 $form = new Form(false);
 
-$help = 'Select "Normal reboot" to reboot the system immediately';
-$modeslist = ['Reboot' => 'Normal reboot'];
-if ((php_uname('m') != 'arm') && !is_module_loaded("zfs.ko")) {
-        $help .= ', "Reboot with Filesystem Check" to reboot and run filesystem check';
-        $modeslist += ['FSCKReboot' => 'Reboot with Filesystem Check'];
-}
+$section = new Form_Section(gettext('Reboot Method'));
 
-$help .= ', or "Reroot" to stop processes, remount disks and re-run startup sequence';
-$modeslist += ['Reroot' => 'Reroot'];
+$help[] = gettext('Select "Normal reboot" to reboot the system immediately.');
+$modeslist['reboot'] = gettext('Normal Reboot');
 
-$help .= '.';
+if ((php_uname('m') != 'arm') && !is_module_loaded("zfs.ko")) {
+	$help[] = gettext('Select "Reboot with Filesystem Check" to reboot and run filesystem check.');
+	$modeslist['fsckreboot'] = gettext('Reboot with Filesystem Check');
+}
 
-$section = new Form_Section('Select reboot method');
+$help[] = gettext('Select "Reroot" to stop processes, remount disks and re-run startup sequence.');
+$modeslist['reroot'] = gettext('Reroot');
 
 $section->addInput(new Form_Select(
         'rebootmode',
-        '*Reboot method',
+        '*'.gettext('Reboot Method'),
         $rebootmode,
         $modeslist
-))->setHelp($help);
+))->setHelp(implode("<br />", $help));
 
 $form->add($section);
 
@@ -152,7 +154,7 @@ $form->addGlobal(new Form_Button(
         'fa-solid fa-wrench'
 ))->addClass('btn-primary');
 
-print $form;
+print($form);
 
 endif;
 
diff --git a/src/usr/local/www/firewall_rules.php b/src/usr/local/www/firewall_rules.php
index ecb8a9042a..0ef8523854 100644
--- a/src/usr/local/www/firewall_rules.php
+++ b/src/usr/local/www/firewall_rules.php
@@ -93,10 +93,10 @@ function print_states($tracker_start, $tracker_end = -1) {
 	$rules = get_pf_rules($rulescnt, $tracker_start, $tracker_end);
 	if (is_array($rules)) {
 		foreach ($rules as $rule) {
+			$evaluations += $rule['evaluations'];
+			$packets += $rule['packets'];
 			$bytes += $rule['bytes'];
 			$states += $rule['states'];
-			$packets += $rule['packets'];
-			$evaluations += $rule['evaluations'];
 			$stcreations += $rule['state creations'];
 			if (strlen($rulesid) > 0) {
 				$rulesid .= ",";
@@ -111,15 +111,17 @@ function print_states($tracker_start, $tracker_end = -1) {
 	}
 	$trackertext .= "<br />";
 
-	printf("<a href=\"diag_dump_states.php?ruleid=%s\" " .
+	$title = (gettext('States details'));
+	$href = ('diag_dump_states.php?ruleid=' . $rulesid);
+	printf("<a href=\"%s\" " .
 	    "data-toggle=\"popover\" data-trigger=\"hover focus\" " .
-	    "title=\"%s\" ", $rulesid, gettext("States details"));
+	    "title=\"%s\" ", $href, $title);
 	printf("data-content=\"{$trackertext}evaluations: %s<br />packets: " .
-	    "%s<br />bytes: %s<br />states: %s<br />state creations: " .
-	    "%s\" data-html=\"true\" usepost>",
-	    format_number($evaluations), format_number($packets),
-	    format_bytes($bytes), format_number($states),
+	    "%s<br />bytes: %s<br />", format_number($evaluations), format_number($packets),
+	    format_bytes($bytes));
+	printf("states: %s<br />state creations: %s", format_number($states),
 	    format_number($stcreations));
+	printf("\" data-html=\"true\" usepost>");
 	printf("%s/%s</a><br />", format_number($states), format_bytes($bytes));
 }
 
@@ -261,7 +263,6 @@ if (isset($_POST['del_x'])) {
 } else if ($_POST['order-store']) {
 	$updated = false;
 	$dirty = false;
-
 	/* update rule order, POST[rule] is an array of ordered IDs */
 	if (is_array($_POST['rule']) && !empty($_POST['rule'])) {
 		$a_filter_new = array();
@@ -373,7 +374,7 @@ if (isset($_POST['del_x'])) {
 	exit;
 }
 
-$tab_array = array(array(gettext("Floating"), ("FloatingRules" == $if), "firewall_rules.php?if=FloatingRules"));
+$tab_array[] = [gettext('Floating'), ($if === 'FloatingRules'), 'firewall_rules.php?if=FloatingRules'];
 
 foreach ($iflist as $ifent => $ifname) {
 	$tab_array[] = array($ifname, ($ifent == $if), "firewall_rules.php?if={$ifent}");
@@ -426,9 +427,9 @@ if (config_path_enabled("interfaces/{$if}", "blockbogons")) {
 }
 
 if (config_path_enabled('system/webgui', 'roworderdragging')) {
-	$rules_header_text = gettext("Rules");
+	$rules_header_text = gettext('Rules');
 } else {
-	$rules_header_text = gettext("Rules (Drag to Change Order)");
+	$rules_header_text = gettext('Rules (Drag to Change Order)');
 }
 
 /* Load the counter data of each pf rule. */
@@ -439,7 +440,7 @@ $columns_in_table = 13;
 
 /* Floating rules tab has one extra column
  * https://redmine.pfsense.org/issues/10667 */
-if ($if == "FloatingRules") {
+if ($if === 'FloatingRules') {
 	$columns_in_table++;
 }
 
@@ -468,24 +469,20 @@ if (isset($if)):
 					<tr>
 						<th><input type="checkbox" id="selectAll" name="selectAll" /></th>
 						<th><!-- status icons --></th>
-						<th><?=gettext("States")?></th>
-				<?php
-					if ('FloatingRules' == $if) {
-				?>
-						<th><?=gettext("Interfaces")?></th>
-				<?php
-					}
-				?>
-						<th><?=gettext("Protocol")?></th>
-						<th><?=gettext("Source")?></th>
-						<th><?=gettext("Port")?></th>
-						<th><?=gettext("Destination")?></th>
-						<th><?=gettext("Port")?></th>
-						<th><?=gettext("Gateway")?></th>
-						<th><?=gettext("Queue")?></th>
-						<th><?=gettext("Schedule")?></th>
-						<th><?=gettext("Description")?></th>
-						<th><?=gettext("Actions")?></th>
+						<th><?=gettext('States')?></th>
+<?php if ($if === 'FloatingRules'): ?>
+						<th><?=gettext('Interfaces')?></th>
+<?php endif; ?>
+						<th><?=gettext('Protocol')?></th>
+						<th><?=gettext('Source')?></th>
+						<th><?=gettext('Port')?></th>
+						<th><?=gettext('Destination')?></th>
+						<th><?=gettext('Port')?></th>
+						<th><?=gettext('Gateway')?></th>
+						<th><?=gettext('Queue')?></th>
+						<th><?=gettext('Schedule')?></th>
+						<th><?=gettext('Description')?></th>
+						<th><?=gettext('Actions')?></th>
 					</tr>
 				</thead>
 
@@ -576,7 +573,8 @@ $a_schedules = config_get_path('schedules/schedule');
 $if_config = config_get_path('interfaces');
 foreach (config_get_path('filter/rule', []) as $filteri => $filterent):
 
-	if (($filterent['interface'] == $if && !isset($filterent['floating'])) || (isset($filterent['floating']) && "FloatingRules" == $if)) {
+	if (($filterent['interface'] == $if && !isset($filterent['floating'])) ||
+	    (isset($filterent['floating']) && $if === 'FloatingRules')) {
 
 		// Display separator(s) for section beginning at rule n
 		if ($seprows[$nrules]) {
@@ -621,7 +619,8 @@ foreach (config_get_path('filter/rule', []) as $filteri => $filterent):
 			print '<i class="fa-solid fa-tasks" title="'. gettext("traffic is logged") .'" style="cursor: pointer;"></i>';
 		}
 
-		if (isset($filterent['direction']) && ($if == "FloatingRules")) {
+		if (isset($filterent['direction']) &&
+		    ($if == "FloatingRules")) {
 			if ($filterent['direction'] == 'in') {
 				print '<i class="fa-regular fa-circle-left" title="'. gettext("direction is in") .'" style="cursor: pointer;"></i>';
 			} elseif ($filterent['direction'] == 'out') {
@@ -778,9 +777,9 @@ foreach (config_get_path('filter/rule', []) as $filteri => $filterent):
 			}
 		}
 	?>
-				<td><?php print_states(intval($filterent['tracker'])); ?></td>
+				<td><?php print_states(intval($filterent['tracker']), -1); ?></td>
 	<?php
-		if ($if == 'FloatingRules') {
+		if ($if === 'FloatingRules') {
 	?>
 			<td onclick="fr_toggle(<?=$nrules;?>)" id="frd<?=$nrules;?>" ondblclick="document.location='firewall_rules_edit.php?id=<?=$i;?>';">
 	<?php
@@ -1018,8 +1017,8 @@ foreach ($seprows as $idx => $sep) {
 <?php if ($nrules == 0): ?>
 	<div class="alert alert-warning" role="alert">
 		<p>
-		<?php if ($_REQUEST['if'] == "FloatingRules"): ?>
-			<?=gettext("No floating rules are currently defined.");?>
+		<?php if ($if === 'FloatingRules'): ?>
+			<?=gettext('No floating rules are currently defined.');?>
 		<?php else: ?>
 			<?=gettext("No rules are currently defined for this interface");?><br />
 			<?=gettext("All incoming connections on this interface will be blocked until pass rules are added.");?>
@@ -1046,7 +1045,7 @@ foreach ($seprows as $idx => $sep) {
 			<i class="fa-solid fa-ban icon-embed-btn"></i>
 			<?=gettext("Toggle"); ?>
 		</button>
-		<?php if ($if != 'FloatingRules'):?>
+		<?php if ($if !== 'FloatingRules'):?>
 		<button id="copy_x" name="copy_x" type="button" class="btn btn-primary btn-sm" value="<?=gettext("Copy selected rules"); ?>" disabled title="<?=gettext('Copy selected rules')?>" data-toggle="modal" data-target="#rulescopy">
 			<i class="fa-regular fa-clone icon-embed-btn"></i>
 			<?=gettext("Copy"); ?>
diff --git a/src/usr/local/www/firewall_rules_edit.php b/src/usr/local/www/firewall_rules_edit.php
index 1338f82319..1dd6a086a2 100644
--- a/src/usr/local/www/firewall_rules_edit.php
+++ b/src/usr/local/www/firewall_rules_edit.php
@@ -212,10 +212,6 @@ if (isset($id) && $a_filter[$id]) {
 		}
 	}
 
-	if (isset($a_filter['floating'])) {
-		$pconfig['floating'] = "yes";
-	}
-
 	if (isset($a_filter[$id]['direction'])) {
 		$pconfig['direction'] = $a_filter[$id]['direction'];
 	}
@@ -333,6 +329,7 @@ if (isset($id) && $a_filter[$id]) {
 	$pconfig['src'] = "any";
 	$pconfig['dst'] = "any";
 }
+
 /* Allow the FloatingRules to work */
 $if = $pconfig['interface'];
 
@@ -371,7 +368,12 @@ if ($_POST['save']) {
 
 	// add validation + input error for $_POST['interface']
 
-	$valid = ($_POST['interface'] == "FloatingRules" || isset($_POST['floating'])) ? ['pass','block','reject', 'match'] : ['pass','block','reject'];
+	if ($_POST['interface'] == 'FloatingRules' || isset($_POST['floating'])) {
+		$valid = ['pass', 'block', 'reject', 'match'];
+	} else {
+		$valid = ['pass', 'block', 'reject'];
+	}
+
 	if (!(is_string($_POST['type'])  && in_array($_POST['type'], $valid))) {
 		$input_errors[] = gettext("A valid rule type is not selected.");
 		unset($_POST['type']);
@@ -874,8 +876,8 @@ if ($_POST['save']) {
 
 		$filterent['type'] = $_POST['type'];
 
-		if (isset($_POST['floating']) && (!isset($_POST['interface']) ||
-		    in_array('any', $_POST['interface']))) {
+		if (isset($_POST['floating']) &&
+		    (!isset($_POST['interface']) || in_array('any', $_POST['interface']))) {
 			$_POST['interface'] = array('any');
 		} else {
 			$filterent['interface'] = $_POST['interface'];
@@ -1064,7 +1066,7 @@ if ($_POST['save']) {
 
 		if (isset($id) && $a_filter[$id]) {
 			$tmpif = $filterent['interface'];
-			if (($tmpif == $if) || (isset($pconfig['floating']))) {
+			if (($tmpif == $if) || isset($pconfig['floating'])) {
 				$a_filter[$id] = $filterent;
 			} else {							// rule moved to different interface
 				// update the previous interface's separators
@@ -1118,9 +1120,9 @@ if ($_POST['save']) {
 		}
 
 		if (isset($_POST['floating'])) {
-			header("Location: firewall_rules.php?if=FloatingRules");
+			header('Location: firewall_rules.php?if=FloatingRules');
 		} else {
-			header("Location: firewall_rules.php?if=" . htmlspecialchars($_POST['interface']));
+			header('Location: firewall_rules.php?if=' . htmlspecialchars($_POST['interface']));
 		}
 		exit;
 	}
@@ -1170,7 +1172,9 @@ function build_flag_table() {
 $pgtitle = array(gettext("Firewall"), gettext("Rules"));
 $pglinks = array("");
 
-if ($if == "FloatingRules" || isset($pconfig['floating'])) {
+$is_floating_rule = (($if === 'FloatingRules') || isset($pconfig['floating']));
+
+if ($is_floating_rule) {
 	$pglinks[] = "firewall_rules.php?if=FloatingRules";
 	$pgtitle[] = gettext('Floating');
 	$pglinks[] = "firewall_rules.php?if=FloatingRules";
@@ -1235,7 +1239,7 @@ $values = array(
 	'reject' => gettext('Reject'),
 );
 
-if ($if == "FloatingRules" || isset($pconfig['floating'])) {
+if ($is_floating_rule) {
 	$values['match'] = gettext('Match');
 }
 
@@ -1258,7 +1262,7 @@ $section->addInput(new Form_Checkbox(
 ))->setHelp('Set this option to disable this rule without removing it from the '.
 	'list.');
 
-if ($if == "FloatingRules" || isset($pconfig['floating'])) {
+if ($is_floating_rule) {
 	$section->addInput(new Form_Checkbox(
 		'quick',
 		'Quick',
@@ -1304,7 +1308,7 @@ if ($edit_disabled) {
 	}
 }
 
-if ($if == "FloatingRules" || isset($pconfig['floating'])) {
+if ($is_floating_rule) {
 	$section->addInput($input = new Form_Select(
 		'interface',
 		'*Interface',
@@ -1321,7 +1325,7 @@ if ($if == "FloatingRules" || isset($pconfig['floating'])) {
 	))->setHelp('Choose the interface from which packets must come to match this rule.');
 }
 
-if ($if == "FloatingRules" || isset($pconfig['floating'])) {
+if ($is_floating_rule) {
 	$section->addInput(new Form_Select(
 		'direction',
 		'*Direction',
@@ -1478,6 +1482,7 @@ foreach (['src' => gettext('Source'), 'dst' => gettext('Destination')] as $type
 
 	$group->addClass(($type == 'src') ? 'srcprtr':'dstprtr');
 	$section->add($group);
+
 	$form->add($section);
 }
 
@@ -1497,7 +1502,7 @@ $section->addInput(new Form_Input(
 	'text',
 	$pconfig['descr']
 ))->setHelp('A description may be entered here for administrative reference. ' .
-	'A maximum of %s characters will be used in the ruleset and displayed in the firewall log.',
+	'A maximum of %s characters will be used in the ruleset label and displayed in the firewall log.',
 	user_rule_descr_maxlen());
 
 $btnadv = new Form_Button(
@@ -1703,8 +1708,7 @@ foreach (get_gateways() as $gwname => $gw) {
 
 foreach ((array)$a_gatewaygroups as $gwg_name => $gwg_data) {
 	$gwjson = $gwjson . "," .'{"name":' . json_encode($gwg_name) . ', "gateway":' .
-	json_encode($gwg_data['name'] . $gwg_name . (empty($gwg_data['descr'])? '' : ' - '. $gwg_data['descr'])) . ',"family":' .
-	json_encode($gwg_data['ipprotocol']) . '}';
+	json_encode($gwg_data['name'] . $gwg_name . (empty($gwg_data['descr'])? '' : ' - '. $gwg_data['descr'])) . ',"family":' . json_encode($gwg_data['ipprotocol']) . '}';
 	$firstgw = false;
 }
 
@@ -2108,7 +2112,7 @@ events.push(function() {
 	});
 
 	$('#icmptype\\[\\]').on('change', function() {
-			icmptype_change();
+		icmptype_change();
 	});
 
 	$('#tcpflags_any').click(function () {
diff --git a/src/usr/local/www/firewall_virtual_ip_edit.php b/src/usr/local/www/firewall_virtual_ip_edit.php
index 767ed9c02e..251b0846fa 100644
--- a/src/usr/local/www/firewall_virtual_ip_edit.php
+++ b/src/usr/local/www/firewall_virtual_ip_edit.php
@@ -85,8 +85,6 @@ $pglinks = array("", "firewall_virtual_ip.php", "@self");
 include("head.inc");
 
 function build_if_list() {
-	$list = array();
-
 	$interfaces = get_configured_interface_with_descr(true);
 	$carplist = get_configured_vip_list('all', VIP_CARP);
 
@@ -195,7 +193,7 @@ $section->addInput(new Form_Select(
 	array_combine(range(1, 255, 1), range(1, 255, 1))
 ))->setHelp('Enter the VHID group that the machines will share.');
 
-$group = new Form_Group('Advertising frequency');
+$group = new Form_Group('Advertising Frequency');
 $group->add(new Form_Select(
 	'advbase',
 	'Base',
@@ -301,7 +299,6 @@ events.push(function() {
 			$('#type').val('single');
 			setRequired('type', false);
 			disableInput('subnet_bits', false);
-
 		} else if (mode == 'carp') {
 			$('#address_note').html("<?=$ipaliashelp?>");
 			disableInput('vhid', false);
diff --git a/src/usr/local/www/guiconfig.inc b/src/usr/local/www/guiconfig.inc
index 3f3931d5d6..4bb925d0af 100644
--- a/src/usr/local/www/guiconfig.inc
+++ b/src/usr/local/www/guiconfig.inc
@@ -528,7 +528,6 @@ function firewall_check_for_advanced_options(&$item) {
 	if ($item['tcpflags_any'] || $item['tcpflags1'] || $item['tcpflags2']) {
 		$item_set .= "tcpflags set";
 	}
-
 	return $item_set;
 }
 
diff --git a/src/usr/local/www/includes/functions.inc.php b/src/usr/local/www/includes/functions.inc.php
index b728c7b382..0f2f1d0a91 100644
--- a/src/usr/local/www/includes/functions.inc.php
+++ b/src/usr/local/www/includes/functions.inc.php
@@ -382,30 +382,30 @@ function get_cpu_crypto_support() {
 
 function get_cpu_crypto_string($crypto) {
 	$machine = get_single_sysctl('hw.machine');
-	$string = "";
+	$string = '';
 
 	switch ($machine) {
 	case 'amd64':
-		$string = "AES-NI CPU Crypto: ";
-		if ($crypto && crypto_accel_get($crypto, "AESNI", "present")) {
-			$string .= "Yes ";
-			$string .= crypto_accel_get($crypto, "AESNI", "enabled") ? "(active)" : "(inactive)";
+		$string = 'AES-NI CPU Crypto: ';
+		if ($crypto && crypto_accel_get($crypto, 'AESNI', 'present')) {
+			$string .= 'Yes ';
+			$string .= crypto_accel_get($crypto, 'AESNI', 'enabled') ? '(active)' : '(inactive)';
 		} else {
-			$string .= "No";
+			$string .= 'No';
 		}
 		$string .= "<br>\n";
-		$string .= "QAT Crypto: ";
-		if ($crypto && crypto_accel_get($crypto, "QAT", "present")) {
-			$string .= "Yes ";
-			$string .= crypto_accel_get($crypto, "QAT", "enabled") ? "(active)" : "(inactive)";
+		$string .= 'QAT Crypto: ';
+		if ($crypto && crypto_accel_get($crypto, 'QAT', 'present')) {
+			$string .= 'Yes ';
+			$string .= crypto_accel_get($crypto, 'QAT', 'enabled') ? '(active)' : '(inactive)';
 		} else {
-			$string .= "No";
+			$string .= 'No';
 		}
 		break;
 	}
 
 	if (strlen($string) == 0) {
-		$string = "CPU Crypto: None/Unknown Platform";
+		$string = 'CPU Crypto: None/Unknown Platform';
 	}
 
 	return ($string);
@@ -417,7 +417,9 @@ function get_cpu_count($show_detail = false) {
 	if ($show_detail) {
 		$cpudetail = "";
 		exec("/usr/bin/grep 'FreeBSD/SMP:.*package' /var/log/dmesg.boot | /usr/bin/cut -f2- -d' '", $cpudetail);
-		$cpucount = $cpudetail[0];
+		if (!empty($cpudetail[0]))  {
+			$cpucount = $cpudetail[0];
+		}
 	}
 	return $cpucount;
 }
@@ -501,4 +503,3 @@ function get_interfacestatus() {
 	return $data;
 }
 
-?>
diff --git a/src/usr/local/www/pkg_mgr_install.php b/src/usr/local/www/pkg_mgr_install.php
index 6eee5ed9ee..9b275652ec 100644
--- a/src/usr/local/www/pkg_mgr_install.php
+++ b/src/usr/local/www/pkg_mgr_install.php
@@ -391,11 +391,11 @@ if (!isvalidpid($gui_pidfile) && !$confirmed && !$completed &&
 		$repos = update_repos();
 		$helpfilename = pkg_get_repo_help();
 
-		$group = new Form_Group("Branch");
+		$group = new Form_Group(gettext('Branch'));
 
 		$field = new Form_Select(
 			'fwbranch',
-			'*Branch',
+			'*'.gettext('Branch'),
 			pkg_get_repo_name(config_get_path('system/pkg_repo_conf_path')),
 			pkg_build_repo_list()
 		);
@@ -415,7 +415,7 @@ if (!isvalidpid($gui_pidfile) && !$confirmed && !$completed &&
 				'<label class="col-sm-2 control-label">' .
 					gettext("Messages") .
 				'</label>' .
-				'<div class="col-sm-10" id="netgate_messages">' 
+				'<div class="col-sm-10" id="netgate_messages">'
 
 			);
 			foreach ($repos['messages'] as $message) {
@@ -443,7 +443,7 @@ if (!isvalidpid($gui_pidfile) && !$confirmed && !$completed &&
 
 				<div class="form-group" id="confirm">
 					<label class="col-sm-2 control-label" id="confirmlabel">
-						<?=gettext("Retrieving")?>
+						<?=gettext('Retrieving')?>
 					</label>
 					<div class="col-sm-10">
 						<input type="hidden" name="id" value="firmware" />
@@ -452,7 +452,7 @@ if (!isvalidpid($gui_pidfile) && !$confirmed && !$completed &&
 							<i class="fa-solid fa-check icon-embed-btn"></i>
 							<?=gettext("Confirm")?>
 						</button>
-						<span id="uptodate"><i class="fa-solid fa-cog fa-spin fa-lg text-warning"></i></span>
+						<span id="uptodate"><i class="fa-solid fa-rotate fa-spin fa-lg text-warning"></i></span>
 					</div>
 				</div>
 <?php
@@ -537,6 +537,12 @@ if ($confirmed || isvalidpid($gui_pidfile)):
 	<br />
 	<div class="panel panel-default">
 		<div class="panel-heading">
+			<div style="float: right;">
+				<label>
+					<input style="margin: 4px 4px 0;" type="checkbox" checked="true" id="autoscroll" />
+				<?=gettext('Auto-scroll')?>
+				</label>
+			</div>
 			<h2 class="panel-title" id="status"><?=$panel_heading_txt?></h2>
 		</div>
 
@@ -821,8 +827,10 @@ function getLogsStatus() {
 	var ajaxRequest;
 	var repeat;
 	var progress;
+	var overrideScroll;
 
 	repeat = true;
+	overrideScroll = false;
 
 	ajaxRequest = $.ajax({
 			url: "pkg_mgr_install.php",
@@ -843,9 +851,15 @@ function getLogsStatus() {
 //		alert("JSON data: " + JSON.stringify(json));
 
 		if (json.log != "not_ready") {
+			var _o = $('#output');
 			// Write the log file to the "output" textarea
-			$('#output').html(json.log);
-			scrollToBottom();
+			_o.html(json.log);
+
+			if ($('#autoscroll').prop('checked')) {
+				overrideScroll = true;
+				_o.scrollTop(_o.prop('scrollHeight'));
+				overrideScroll = false;
+			}
 
 			// Update the progress bar
 			progress = 0;
@@ -906,8 +920,14 @@ function getLogsStatus() {
 	});
 }
 
-function scrollToBottom() {
-	$('#output').scrollTop($('#output')[0].scrollHeight);
+function scrollToBottom(force) {
+	var _o = $('#output');
+	var _d = _o.scrollTop() + _o.outerHeight() * 2;
+	if (force || _d > _o.prop('scrollHeight')) {
+		_o.scrollTop(_o.prop('scrollHeight'));
+		console.log('scroll locked');
+	}
+	console.log('scroll unlocked');
 }
 
 var time = 0;
@@ -961,7 +981,7 @@ events.push(function() {
 		setProgress('progressbar', 100, false);
 		$('#progressbar').addClass("progress-bar-success");
 		show_success();
-		setTimeout(scrollToBottom, 200);
+		setTimeout(scrollToBottom, 200, true); /* force scroll */
 	}
 
 	if ("<?=$firmwareupdate?>") {
diff --git a/src/usr/local/www/services_acb.php b/src/usr/local/www/services_acb.php
index 190d9745fc..9afbaa7212 100644
--- a/src/usr/local/www/services_acb.php
+++ b/src/usr/local/www/services_acb.php
@@ -138,11 +138,9 @@ if ($_REQUEST['newver'] != "") {
 		$data = substr($out, 0, $pos);
 		$data = $data . "</pfsense>\n";
 
-		$fd = fopen("/tmp/config_restore.xml", "w");
-		fwrite($fd, $data);
-		fclose($fd);
+		file_put_contents('/tmp/config_restore.xml', $data);
 
-		$ondisksha256 = trim(shell_exec("/sbin/sha256 /tmp/config_restore.xml | /usr/bin/awk '{ print $4 }'"));
+		$ondisksha256 = hash_file('sha256', '/tmp/config_restore.xml');
 		// We might not have a sha256 on file for older backups
 		if ($sha256 != "0" && $sha256 != "") {
 			if ($ondisksha256 != $sha256) {
@@ -161,7 +159,7 @@ if ($_REQUEST['newver'] != "") {
 		}
 
 		if (!$input_errors && $data) {
-			if (config_restore("/tmp/config_restore.xml") == 0) {
+			if (config_restore("/tmp/config_restore.xml", "/tmp/config_restore.xml")) {
 				$savemsg = "Successfully reverted the pfSense configuration to revision " . urldecode($_REQUEST['newver']) . ".";
 				$savemsg .= <<<EOF
 			<br />
@@ -172,7 +170,7 @@ if ($_REQUEST['newver'] != "") {
 		</form>
 EOF;
 			} else {
-				$savemsg = "Unable to revert to the selected configuration.";
+				$errormsg = gettext('Unable to revert to the selected configuration.');
 			}
 		} else {
 			log_error("There was an error when restoring the AutoConfigBackup item");
@@ -286,6 +284,9 @@ if ($input_errors) {
 if ($savemsg) {
 	print_info_box($savemsg, 'success');
 }
+if ($errormsg) {
+	print_info_box($errormsg, 'danger');
+}
 
 $tab_array = array();
 $tab_array[0] = array("Settings", false, "/services_acb_settings.php");
diff --git a/src/usr/local/www/services_dhcp.php b/src/usr/local/www/services_dhcp.php
index 6ea62737e3..5ed43bb248 100644
--- a/src/usr/local/www/services_dhcp.php
+++ b/src/usr/local/www/services_dhcp.php
@@ -1040,7 +1040,7 @@ if (is_null($pconfig) || !is_array($pconfig)) {
 
 $form = new Form();
 
-$section = new Form_Section(gettext('General DHCP Options'));
+$section = new Form_Section(gettext('General Settings'));
 
 $section->addInput(new Form_StaticText(
 	gettext('DHCP Backend'),
@@ -1909,15 +1909,15 @@ if (!is_numeric($pool) && !($act == "newpool")) {
 				<thead>
 					<tr>
 						<th><?=gettext("Static ARP")?></th>
-						<th><?=gettext("MAC address")?></th>
+						<th><?=gettext("MAC Address")?></th>
 <?php
 	if ($got_cid):
 ?>
-						<th><?=gettext("Client Id")?></th>
+						<th><?=gettext("Client ID")?></th>
 <?php
 	endif;
 ?>
-						<th><?=gettext("IP address")?></th>
+						<th><?=gettext("IP Address")?></th>
 						<th><?=gettext("Hostname")?></th>
 						<th><?=gettext("Description")?></th>
 						<th></th>
@@ -1958,8 +1958,8 @@ if (!is_numeric($pool) && !($act == "newpool")) {
 						<?=htmlspecialchars($mapent['descr'])?>
 					</td>
 					<td>
-						<a class="fa-solid fa-pencil"	title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
-						<a class="fa-solid fa-trash-can"	title="<?=gettext('Delete static mapping')?>"	href="services_dhcp.php?if=<?=htmlspecialchars($if)?>&amp;act=del&amp;id=<?=$i?>" usepost></a>
+						<a class="fa-solid fa-pencil" title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
+						<a class="fa-solid fa-trash-can text-danger" title="<?=gettext('Delete static mapping')?>"	href="services_dhcp.php?if=<?=htmlspecialchars($if)?>&amp;act=del&amp;id=<?=$i?>" usepost></a>
 					</td>
 				</tr>
 <?php
diff --git a/src/usr/local/www/services_dhcp_edit.php b/src/usr/local/www/services_dhcp_edit.php
index 6d0a0e6656..3ea803a1aa 100644
--- a/src/usr/local/www/services_dhcp_edit.php
+++ b/src/usr/local/www/services_dhcp_edit.php
@@ -542,7 +542,7 @@ $section->add($group);
 $cid_help = gettext('An optional identifier to match based on the value sent by the client (RFC 2132).');
 if (dhcp_is_backend('kea')) {
 	$cid_help .= '<br /><br />';
-	$cid_help .= gettext('Kea DHCP will only match on MAC address if both MAC address and client identifier are set for a static reservation.');
+	$cid_help .= gettext('Kea DHCP will match on MAC address if both MAC address and client identifier are set for a static mapping.');
 }
 
 $section->addInput(new Form_Input(
diff --git a/src/usr/local/www/services_dhcp_settings.php b/src/usr/local/www/services_dhcp_settings.php
index aaffd4c4cc..8c61bff9f4 100644
--- a/src/usr/local/www/services_dhcp_settings.php
+++ b/src/usr/local/www/services_dhcp_settings.php
@@ -245,7 +245,7 @@ $section->addInput(new Form_Input(
 	array_get_path($pconfig, 'ha/heartbeatdelay'),
 	['placeholder' => kea_defaults('heartbeatdelay')]
 ))->addClass('advopt')
-  ->setHelp(sprintf(gettext('Specifies a duration in milliseconds between sending the last heartbeat and the next heartbeat.%s' . 
+  ->setHelp(sprintf(gettext('Specifies a duration in milliseconds between sending the last heartbeat and the next heartbeat.%s' .
 			'The heartbeats are sent periodically to gather the status of the partner and to verify whether the partner is still operating.'), '<br/>'));
 
 $section->addInput(new Form_Input(
@@ -255,7 +255,7 @@ $section->addInput(new Form_Input(
 	array_get_path($pconfig, 'ha/maxresponsedelay'),
 	['placeholder' => kea_defaults('maxresponsedelay')]
 ))->addClass('advopt')
-  ->setHelp(sprintf(gettext('Specifies a duration in milliseconds since the last successful communication with the partner, after which the server assumes that communication with the partner is interrupted.%s' . 
+  ->setHelp(sprintf(gettext('Specifies a duration in milliseconds since the last successful communication with the partner, after which the server assumes that communication with the partner is interrupted.%s' .
 			'Notice: This duration should be greater than the heartbeat delay.'), '<br/>'));
 
 $section->addInput(new Form_Input(
@@ -367,7 +367,7 @@ events.push(function() {
 	function update_tls_section() {
 		var tlsshow = $('#ha_tls').prop('checked');
 		var mtlsshow = $('#ha_mutualtls').prop('checked');
-	
+
 		hideInput('ha_scertref', !tlsshow);
 		hideInput('ha_ccertref', !(tlsshow && mtlsshow));
 		hideCheckbox('ha_mutualtls', !tlsshow);
diff --git a/src/usr/local/www/services_dhcpv6.php b/src/usr/local/www/services_dhcpv6.php
index 003596858a..da7b3e79b2 100644
--- a/src/usr/local/www/services_dhcpv6.php
+++ b/src/usr/local/www/services_dhcpv6.php
@@ -699,7 +699,7 @@ if (is_null($pconfig) || !is_array($pconfig)) {
 
 $form = new Form();
 
-$section = new Form_Section(gettext('General DHCPv6 Options'));
+$section = new Form_Section(gettext('General Settings'));
 
 $section->addInput(new Form_StaticText(
 	gettext('DHCP Backend'),
@@ -1383,8 +1383,8 @@ foreach (config_get_path("dhcpdv6/{$if}/staticmap", []) as $mapent):
 					<?=htmlspecialchars($mapent['descr'])?>
 				</td>
 				<td>
-					<a class="fa-solid fa-pencil"	title="<?=gettext('Edit static mapping')?>" href="services_dhcpv6_edit.php?if=<?=$if?>&amp;id=<?=$i?>"></a>
-					<a class="fa-solid fa-trash-can"	title="<?=gettext('Delete static mapping')?>" href="services_dhcpv6.php?if=<?=$if?>&amp;act=del&amp;id=<?=$i?>" usepost></a>
+					<a class="fa-solid fa-pencil" title="<?=gettext('Edit static mapping')?>" href="services_dhcpv6_edit.php?if=<?=$if?>&amp;id=<?=$i?>"></a>
+					<a class="fa-solid fa-trash-can text-danger" title="<?=gettext('Delete static mapping')?>" href="services_dhcpv6.php?if=<?=$if?>&amp;act=del&amp;id=<?=$i?>" usepost></a>
 				</td>
 			</tr>
 <?php
diff --git a/src/usr/local/www/services_dhcpv6_settings.php b/src/usr/local/www/services_dhcpv6_settings.php
index ae043087c4..af4258bb8f 100644
--- a/src/usr/local/www/services_dhcpv6_settings.php
+++ b/src/usr/local/www/services_dhcpv6_settings.php
@@ -263,7 +263,7 @@ $section->addInput(new Form_Input(
 	array_get_path($pconfig, 'ha/heartbeatdelay'),
 	['placeholder' => kea_defaults('heartbeatdelay')]
 ))->addClass('advopt')
-  ->setHelp(sprintf(gettext('Specifies a duration in milliseconds between sending the last heartbeat and the next heartbeat.%s' . 
+  ->setHelp(sprintf(gettext('Specifies a duration in milliseconds between sending the last heartbeat and the next heartbeat.%s' .
 			'The heartbeats are sent periodically to gather the status of the partner and to verify whether the partner is still operating.'), '<br/>'));
 
 $section->addInput(new Form_Input(
@@ -273,7 +273,7 @@ $section->addInput(new Form_Input(
 	array_get_path($pconfig, 'ha/maxresponsedelay'),
 	['placeholder' => kea_defaults('maxresponsedelay')]
 ))->addClass('advopt')
-  ->setHelp(sprintf(gettext('Specifies a duration in milliseconds since the last successful communication with the partner, after which the server assumes that communication with the partner is interrupted.%s' . 
+  ->setHelp(sprintf(gettext('Specifies a duration in milliseconds since the last successful communication with the partner, after which the server assumes that communication with the partner is interrupted.%s' .
 			'Notice: This duration should be greater than the heartbeat delay.'), '<br/>'));
 
 $section->addInput(new Form_Input(
@@ -385,7 +385,7 @@ events.push(function() {
 	function update_tls_section() {
 		var tlsshow = $('#ha_tls').prop('checked');
 		var mtlsshow = $('#ha_mutualtls').prop('checked');
-	
+
 		hideInput('ha_scertref', !tlsshow);
 		hideInput('ha_ccertref', !(tlsshow && mtlsshow));
 		hideCheckbox('ha_mutualtls', !tlsshow);
diff --git a/src/usr/local/www/services_unbound.php b/src/usr/local/www/services_unbound.php
index e279fd469e..1fffca54a1 100644
--- a/src/usr/local/www/services_unbound.php
+++ b/src/usr/local/www/services_unbound.php
@@ -290,14 +290,14 @@ $section = new Form_Section('General DNS Resolver Options');
 
 $section->addInput(new Form_Checkbox(
 	'enable',
-	'Enable',
-	'Enable DNS resolver',
+	gettext('Enable'),
+	gettext('Enable DNS resolver'),
 	$pconfig['enable']
 ));
 
 $section->addInput(new Form_Input(
 	'port',
-	'Listen Port',
+	gettext('Listen Port'),
 	'number',
 	$pconfig['port'],
 	['placeholder' => '53']
@@ -305,30 +305,30 @@ $section->addInput(new Form_Input(
 
 $section->addInput(new Form_Checkbox(
 	'enablessl',
-	'Enable SSL/TLS Service',
-	'Respond to incoming SSL/TLS queries from local clients',
+	gettext('Enable SSL/TLS Service'),
+	gettext('Respond to incoming SSL/TLS queries from local clients'),
 	$pconfig['enablessl']
 ))->setHelp('Configures the DNS Resolver to act as a DNS over SSL/TLS server which can answer queries from clients which also support DNS over TLS. ' .
-		'Activating this option disables automatic interface response routing behavior, thus it works best with specific interface bindings.' );
+		'Activating this option disables automatic interface response routing behavior, thus it works best with specific interface bindings.');
 
 if ($certs_available) {
 	$section->addInput($input = new Form_Select(
 		'sslcertref',
-		'SSL/TLS Certificate',
+		gettext('SSL/TLS Certificate'),
 		$pconfig['sslcertref'],
 		cert_build_list('cert', 'IPsec')
 	))->setHelp('The server certificate to use for SSL/TLS service. The CA chain will be determined automatically.');
 } else {
 	$section->addInput(new Form_StaticText(
 		'SSL/TLS Certificate',
-		sprintf('No Certificates have been defined. A certificate is required before SSL/TLS can be enabled. %1$s Create or Import %2$s a Certificate.',
-		'<a href="system_certmanager.php">', '</a>')
+		sprintf(gettext('No Certificates have been defined. A certificate is required before SSL/TLS can be enabled. %1$s Create or Import %2$s a Certificate.'),
+			'<a href="system_certmanager.php">', '</a>')
 	));
 }
 
 $section->addInput(new Form_Input(
 	'tlsport',
-	'SSL/TLS Listen Port',
+	gettext('SSL/TLS Listen Port'),
 	'number',
 	$pconfig['tlsport'],
 	['placeholder' => '853']
@@ -338,7 +338,7 @@ $activeiflist = build_if_list($pconfig['active_interface']);
 
 $section->addInput(new Form_Select(
 	'active_interface',
-	'*Network Interfaces',
+	'*'.gettext('Network Interfaces'),
 	$activeiflist['selected'],
 	$activeiflist['options'],
 	true
@@ -349,7 +349,7 @@ $outiflist = build_if_list($pconfig['outgoing_interface']);
 
 $section->addInput(new Form_Select(
 	'outgoing_interface',
-	'*Outgoing Network Interfaces',
+	'*'.gettext('Outgoing Network Interfaces'),
 	$outiflist['selected'],
 	$outiflist['options'],
 	true
@@ -357,50 +357,50 @@ $section->addInput(new Form_Select(
 
 $section->addInput(new Form_Checkbox(
 	'strictout',
-	'Strict Outgoing Network Interface Binding',
-	'Do not send recursive queries if none of the selected Outgoing Network Interfaces are available.',
+	gettext('Strict Outgoing Network Interface Binding'),
+	gettext('Do not send recursive queries if none of the selected Outgoing Network Interfaces are available.'),
 	$pconfig['strictout']
 ))->setHelp('By default the DNS Resolver sends recursive DNS requests over any available interfaces if none of the selected Outgoing Network Interfaces are available. This option makes the DNS Resolver refuse recursive queries.');
 
 $section->addInput(new Form_Select(
 	'system_domain_local_zone_type',
-	'*System Domain Local Zone Type',
+	'*'.gettext('System Domain Local Zone Type'),
 	$pconfig['system_domain_local_zone_type'],
 	unbound_local_zone_types()
-))->setHelp('The local-zone type used for the %1$s system domain (System | General Setup | Domain).  Transparent is the default.', g_get('product_label'));
+))->setHelp('The local-zone type used for the %1$s system domain (%2$sSystem &gt; General Setup%3$s). Transparent is the default.', g_get('product_label'), '<a href="system.php">','</a>');
 
 $section->addInput(new Form_Checkbox(
 	'dnssec',
 	'DNSSEC',
-	'Enable DNSSEC Support',
+	gettext('Enable DNSSEC Support'),
 	$pconfig['dnssec']
 ));
 
 $section->addInput(new Form_Checkbox(
 	'python',
-	'Python Module',
-	'Enable Python Module',
+	gettext('Python Module'),
+	gettext('Enable Python Module'),
 	$pconfig['python']
 ))->setHelp('Enable the Python Module.');
 
 $section->addInput(new Form_Select(
 	'python_order',
-	'Python Module Order',
+	gettext('Python Module Order'),
 	$pconfig['python_order'],
 	[ 'pre_validator' => 'Pre Validator', 'post_validator' => 'Post Validator' ]
 ))->setHelp('Select the Python Module ordering.');
 
 $section->addInput(new Form_Select(
 	'python_script',
-	'Python Module Script',
+	gettext('Python Module Script'),
 	$pconfig['python_script'],
 	$python_scripts
 ))->setHelp('Select the Python module script to utilize.');
 
 $section->addInput(new Form_Checkbox(
 	'forwarding',
-	'DNS Query Forwarding',
-	'Enable Forwarding Mode',
+	gettext('DNS Query Forwarding'),
+	gettext('Enable Forwarding Mode'),
 	$pconfig['forwarding']
 ))->setHelp('If this option is set, DNS queries will be forwarded to the upstream DNS servers defined under'.
 					' %1$sSystem &gt; General Setup%2$s or those obtained via dynamic ' .
@@ -410,15 +410,15 @@ $section->addInput(new Form_Checkbox(
 $section->addInput(new Form_Checkbox(
 	'forward_tls_upstream',
 	null,
-	'Use SSL/TLS for outgoing DNS Queries to Forwarding Servers',
+	gettext('Use SSL/TLS for outgoing DNS Queries to Forwarding Servers'),
 	$pconfig['forward_tls_upstream']
 ))->setHelp('When set in conjunction with DNS Query Forwarding, queries to all upstream forwarding DNS servers will be sent using SSL/TLS on the default port of 853. Note that ALL configured forwarding servers MUST support SSL/TLS queries on port 853.');
 
 if (dhcp_is_backend('isc')):
 $section->addInput(new Form_Checkbox(
 	'regdhcp',
-	'DHCP Registration',
-	'Register DHCP leases in the DNS Resolver',
+	gettext('DHCP Registration'),
+	gettext('Register DHCP leases in the DNS Resolver'),
 	$pconfig['regdhcp']
 ))->setHelp('If this option is set, then machines that specify their hostname when requesting an IPv4 DHCP lease will be registered'.
 					' in the DNS Resolver so that their name can be resolved.'.
@@ -427,8 +427,8 @@ $section->addInput(new Form_Checkbox(
 
 $section->addInput(new Form_Checkbox(
 	'regdhcpstatic',
-	'Static DHCP',
-	'Register DHCP static mappings in the DNS Resolver',
+	gettext('Static DHCP'),
+	gettext('Register DHCP static mappings in the DNS Resolver'),
 	$pconfig['regdhcpstatic']
 ))->setHelp('If this option is set, then DHCP static mappings will be registered in the DNS Resolver, so that their name can be resolved. '.
 					'The domain in %1$sSystem &gt; General Setup%2$s should also be set to the proper value.','<a href="system.php">','</a>');
@@ -436,14 +436,14 @@ endif;
 
 $section->addInput(new Form_Checkbox(
 	'regovpnclients',
-	'OpenVPN Clients',
-	'Register connected OpenVPN clients in the DNS Resolver',
+	gettext('OpenVPN Clients'),
+	gettext('Register connected OpenVPN clients in the DNS Resolver'),
 	$pconfig['regovpnclients']
-))->setHelp(sprintf('If this option is set, then the common name (CN) of connected OpenVPN clients will be ' .
+))->setHelp('If this option is set, then the common name (CN) of connected OpenVPN clients will be ' .
 	    'registered in the DNS Resolver, so that their name can be resolved. This only works for OpenVPN ' .
 	    'servers (Remote Access SSL/TLS or User Auth with Username as Common Name option) operating ' .
-	    'in "tun" mode. The domain in %sSystem: General Setup%s should also be set to the proper value.',
-	    '<a href="system.php">','</a>'));
+	    'in "tun" mode. The domain in %1$sSystem &gt; General Setup%2$s should also be set to the proper value.',
+	    '<a href="system.php">','</a>');
 
 $btnadv = new Form_Button(
 	'btnadvcustom',
@@ -599,7 +599,7 @@ endforeach;
 </span>
 
 <nav class="action-buttons">
-	<a href="services_unbound_host_edit.php" class="btn btn-sm btn-success">
+	<a href="services_unbound_host_edit.php" class="btn btn-success">
 		<i class="fa-solid fa-plus icon-embed-btn"></i>
 		<?=gettext('Add')?>
 	</a>
@@ -657,7 +657,7 @@ endforeach;
 </span>
 
 <nav class="action-buttons">
-	<a href="services_unbound_domainoverride_edit.php" class="btn btn-sm btn-success">
+	<a href="services_unbound_domainoverride_edit.php" class="btn btn-success">
 		<i class="fa-solid fa-plus icon-embed-btn"></i>
 		<?=gettext('Add')?>
 	</a>
diff --git a/src/usr/local/www/system_advanced_misc.php b/src/usr/local/www/system_advanced_misc.php
index 9878bd9486..62a6dbe3dc 100644
--- a/src/usr/local/www/system_advanced_misc.php
+++ b/src/usr/local/www/system_advanced_misc.php
@@ -33,13 +33,14 @@
 ##|*MATCH=system_advanced_misc.php*
 ##|-PRIV
 
-require_once("guiconfig.inc");
-require_once("functions.inc");
-require_once("filter.inc");
+require_once('guiconfig.inc');
+require_once('functions.inc');
+require_once('filter.inc');
 require_once("system.inc");
-require_once("shaper.inc");
-require_once("vpn.inc");
-require_once("system_advanced_misc.inc");
+require_once('shaper.inc');
+require_once('util.inc');
+require_once('vpn.inc');
+require_once('system_advanced_misc.inc');
 
 global $hwpstate_status_descr, $hwpstate_control_levels;
 $hwpstate_status = system_has_hwpstate();
@@ -63,11 +64,7 @@ $mds_modes = array(
 
 $pconfig = getSystemAdvancedMisc();
 
-$crypto_modules = array(
-	'aesni' => gettext("AES-NI CPU-based Acceleration"),
-	'cryptodev' => gettext("BSD Crypto Device (cryptodev)"),
-	'aesni_cryptodev' => gettext("AES-NI and BSD Crypto Device (aesni, cryptodev)"),
-);
+$crypto_modules = getSystemAdvancedMiscCryptoModules();
 
 $thermal_hardware_modules = array(
 	'coretemp' => gettext("Intel Core* CPU on-die thermal sensor"),
diff --git a/src/usr/local/www/system_update_settings.php b/src/usr/local/www/system_update_settings.php
index fac67f7365..9dcda57f30 100644
--- a/src/usr/local/www/system_update_settings.php
+++ b/src/usr/local/www/system_update_settings.php
@@ -130,11 +130,11 @@ $helpfilename = pkg_get_repo_help();
 
 $form = new Form();
 
-$section = new Form_Section('Firmware Branch');
+$section = new Form_Section(gettext('Firmware Branch'));
 
 $field = new Form_Select(
 	'fwbranch',
-	'*Branch',
+	'*'.gettext('Branch'),
 	pkg_get_repo_name(config_get_path('system/pkg_repo_conf_path')),
 	pkg_build_repo_list()
 );
@@ -142,23 +142,21 @@ $field = new Form_Select(
 if (file_exists($helpfilename)) {
 	$field->setHelp(file_get_contents($helpfilename));
 } else {
-	$field->setHelp('Please select the branch from which to update the system firmware. %1$s' .
-					'Use of the development version is at your own risk!', '<br />');
+	$field->setHelp(gettext('Please select the branch from which to update the system firmware. %1$s' .
+					'Use of the development version is at your own risk!'), '<br />');
 }
 
 $section->addInput($field);
 
 $form->add($section);
 
-$section = new Form_Section('Updates');
-
+$section = new Form_Section(gettext('Update Settings'));
 $section->addInput(new Form_Checkbox(
 	'disablecheck',
-	'Dashboard check',
-	'Disable the Dashboard auto-update check',
+	gettext('Dashboard Check'),
+	gettext('Disable the dashboard auto-update check.'),
 	isset($curcfg['disablecheck'])
-	));
-
+));
 $form->add($section);
 
 if (file_exists("/usr/local/bin/git")) {
@@ -166,10 +164,10 @@ if (file_exists("/usr/local/bin/git")) {
 
 	$section->addInput(new Form_Checkbox(
 		'synconupgrade',
-		'Auto sync on update',
-		'Enable repository/branch sync before reboot',
+		gettext('Auto sync on update'),
+		gettext('Enable repository/branch sync before reboot'),
 		isset($gitcfg['synconupgrade'])
-		))->setHelp('After updating, sync with the following repository/branch before reboot.');
+		))->setHelp(gettext('After updating, sync with the following repository/branch before reboot.'));
 
 	if (is_dir("/root/pfsense/pfSenseGITREPO/pfSenseGITREPO")) {
 		exec("cd /root/pfsense/pfSenseGITREPO/pfSenseGITREPO && /usr/local/bin/git config remote.origin.url", $output_str);
@@ -181,10 +179,10 @@ if (file_exists("/usr/local/bin/git")) {
 
 	$section->addInput(new Form_Input(
 		'repositoryurl',
-		'Repository URL',
+		gettext('Repository URL'),
 		'text',
 		($gitcfg['repositoryurl'] ? $gitcfg['repositoryurl'] : '')
-		))->setHelp('The most recently used repository was %s. This repository will be used if the field is left blank.', $lastrepositoryurl);
+		))->setHelp(gettext('The most recently used repository was %s. This repository will be used if the field is left blank.'), $lastrepositoryurl);
 
 	if (is_dir("/root/pfsense/pfSenseGITREPO/pfSenseGITREPO")) {
 		exec("cd /root/pfsense/pfSenseGITREPO/pfSenseGITREPO && /usr/local/bin/git branch", $output_str);
@@ -202,50 +200,50 @@ if (file_exists("/usr/local/bin/git")) {
 
 	$section->addInput(new Form_Input(
 		'branch',
-		'Branch name',
+		gettext('Branch Name'),
 		'text',
 		($gitcfg['branch'] ? $gitcfg['branch'] : '')
-		))->setHelp('The most recently used branch was "%1$s". (Usually the branch name is master)' .
-					'%2$sNote: Sync will not be performed if a branch is not specified.', $lastbranch, '<br />');
+		))->setHelp(gettext('The most recently used branch was "%1$s". (Usually the branch name is plus-master)' .
+					'%2$sNote: Sync will not be performed if a branch is not specified.'), $lastbranch, '<br />');
 
-	$group = new Form_Group('Sync options');
+	$group = new Form_Group(gettext('Sync Options'));
 
 	$group->add(new Form_Checkbox(
 		'minimal',
 		null,
-		'Minimal',
+		gettext('Minimal'),
 		isset($gitcfg['minimal'])
-		))->setHelp('Copy of only the updated files.');
+		))->setHelp(gettext('Copy of only the updated files.'));
 
 	$group->add(new Form_Checkbox(
 		'diff',
 		null,
-		'Diff',
+		gettext('Diff'),
 		isset($gitcfg['diff'])
-		))->setHelp('Copy of only the different or missing files.');
+		))->setHelp(gettext('Copy of only the different or missing files.'));
 
 	$group->add(new Form_Checkbox(
 		'show_files',
 		null,
-		'Show Files',
+		gettext('Show Files'),
 		isset($gitcfg['show_files'])
-		))->setHelp('Show different and missing files.%1$sWith \'Diff/Minimal\' option.', '<br />');
+		))->setHelp(gettext('Show different and missing files.%1$sWith \'Diff/Minimal\' option.'), '<br />');
 
 	$group->add(new Form_Checkbox(
 		'show_command',
 		null,
-		'Show Command',
+		gettext('Show Command'),
 		isset($gitcfg['show_command'])
-		))->setHelp('Show constructed command.%1$sWith \'Diff/Minimal\' option.', '<br />');
+		))->setHelp(gettext('Show constructed command.%1$sWith \'Diff/Minimal\' option.'), '<br />');
 
 	$group->add(new Form_Checkbox(
 		'dryrun',
 		null,
-		'Dry Run',
+		gettext('Dry Run'),
 		isset($gitcfg['dryrun'])
-		))->setHelp('Dry-run only.%1$sNo files copied.', '<br />');
+		))->setHelp(gettext('Dry-run only.%1$sNo files copied.'), '<br />');
 
-	$group->setHelp('See "playback gitsync --help" in console "PHP Shell + %s tools" for additional information.', g_get('product_label'));
+	$group->setHelp(gettext('See "playback gitsync --help" in console "PHP Shell + %s tools" for additional information.'), g_get('product_label'));
 	$section->add($group);
 
 	$form->add($section);
diff --git a/src/usr/local/www/vpn_ipsec_keys.php b/src/usr/local/www/vpn_ipsec_keys.php
index db32757884..ae79b5f85b 100644
--- a/src/usr/local/www/vpn_ipsec_keys.php
+++ b/src/usr/local/www/vpn_ipsec_keys.php
@@ -82,12 +82,12 @@ if (is_subsystem_dirty('ipsec')) {
 	print_apply_box(gettext("The IPsec tunnel configuration has been changed.") . "<br />" . gettext("The changes must be applied for them to take effect."));
 }
 
-	$tab_array = array();
-	$tab_array[0] = array(gettext("Tunnels"), false, "vpn_ipsec.php");
-	$tab_array[1] = array(gettext("Mobile Clients"), false, "vpn_ipsec_mobile.php");
-	$tab_array[2] = array(gettext("Pre-Shared Keys"), true, "vpn_ipsec_keys.php");
-	$tab_array[3] = array(gettext("Advanced Settings"), false, "vpn_ipsec_settings.php");
-	display_top_tabs($tab_array);
+$tab_array = array();
+$tab_array[] = array(gettext("Tunnels"), false, "vpn_ipsec.php");
+$tab_array[] = array(gettext("Mobile Clients"), false, "vpn_ipsec_mobile.php");
+$tab_array[] = array(gettext("Pre-Shared Keys"), true, "vpn_ipsec_keys.php");
+$tab_array[] = array(gettext("Advanced Settings"), false, "vpn_ipsec_settings.php");
+display_top_tabs($tab_array);
 ?>
 
 <div class="panel panel-default">
diff --git a/src/usr/local/www/vpn_ipsec_mobile.php b/src/usr/local/www/vpn_ipsec_mobile.php
index 1b12709d52..d04f9f6437 100644
--- a/src/usr/local/www/vpn_ipsec_mobile.php
+++ b/src/usr/local/www/vpn_ipsec_mobile.php
@@ -582,10 +582,10 @@ if ($input_errors) {
 }
 
 $tab_array = array();
-$tab_array[0] = array(gettext("Tunnels"), false, "vpn_ipsec.php");
-$tab_array[1] = array(gettext("Mobile Clients"), true, "vpn_ipsec_mobile.php");
-$tab_array[2] = array(gettext("Pre-Shared Keys"), false, "vpn_ipsec_keys.php");
-$tab_array[3] = array(gettext("Advanced Settings"), false, "vpn_ipsec_settings.php");
+$tab_array[] = array(gettext("Tunnels"), false, "vpn_ipsec.php");
+$tab_array[] = array(gettext("Mobile Clients"), true, "vpn_ipsec_mobile.php");
+$tab_array[] = array(gettext("Pre-Shared Keys"), false, "vpn_ipsec_keys.php");
+$tab_array[] = array(gettext("Advanced Settings"), false, "vpn_ipsec_settings.php");
 display_top_tabs($tab_array);
 
 $form = new Form;
diff --git a/src/usr/local/www/vpn_ipsec_settings.php b/src/usr/local/www/vpn_ipsec_settings.php
index 25de688268..3939fba737 100644
--- a/src/usr/local/www/vpn_ipsec_settings.php
+++ b/src/usr/local/www/vpn_ipsec_settings.php
@@ -126,7 +126,7 @@ if ($_POST['save']) {
 					       	IPsec bypass rule'), htmlspecialchars($source));
 				}
 				if (!is_subnetv4($destination) && !is_subnetv6($destination)) {
-					$input_errors[] = sprintf(gettext('%s is not valid destination IP address 
+					$input_errors[] = sprintf(gettext('%s is not valid destination IP address
 						for IPsec bypass rule'), htmlspecialchars($destination));
 				}
 				if ((is_subnetv4($source) && is_subnetv6($destination)) ||
@@ -137,7 +137,7 @@ if ($_POST['save']) {
 				$bypassrules['rule'][] = array(
 					'source' => $_POST["source{$x}"],
 				       	'srcmask' => $_POST["srcmask{$x}"],
-					'destination' => $_POST["destination{$x}"], 
+					'destination' => $_POST["destination{$x}"],
 					'dstmask' => $_POST["dstmask{$x}"]
 				);
 			}
@@ -407,10 +407,10 @@ if ($input_errors) {
 }
 
 $tab_array = array();
-$tab_array[0] = array(gettext("Tunnels"), false, "vpn_ipsec.php");
-$tab_array[1] = array(gettext("Mobile Clients"), false, "vpn_ipsec_mobile.php");
-$tab_array[2] = array(gettext("Pre-Shared Keys"), false, "vpn_ipsec_keys.php");
-$tab_array[3] = array(gettext("Advanced Settings"), true, "vpn_ipsec_settings.php");
+$tab_array[] = array(gettext("Tunnels"), false, "vpn_ipsec.php");
+$tab_array[] = array(gettext("Mobile Clients"), false, "vpn_ipsec_mobile.php");
+$tab_array[] = array(gettext("Pre-Shared Keys"), false, "vpn_ipsec_keys.php");
+$tab_array[] = array(gettext("Advanced Settings"), true, "vpn_ipsec_settings.php");
 display_top_tabs($tab_array);
 
 $form = new Form;
diff --git a/src/usr/local/www/vpn_openvpn_client.php b/src/usr/local/www/vpn_openvpn_client.php
index 17a7aaf9dc..1ecd80d626 100644
--- a/src/usr/local/www/vpn_openvpn_client.php
+++ b/src/usr/local/www/vpn_openvpn_client.php
@@ -36,6 +36,9 @@ require_once("pkg-utils.inc");
 
 global $openvpn_topologies, $openvpn_tls_modes;
 global $openvpn_sharedkey_warning;
+global $openvpn_prots;
+
+$openvpn_all_data_ciphers = openvpn_get_cipherlist();
 
 config_init_path('openvpn/openvpn-client');
 
@@ -236,6 +239,7 @@ if ($_POST['save']) {
 	    !array_key_exists($pconfig['dev_mode'], $openvpn_dev_mode)) {
 		$input_errors[] = gettext("The selected Device Mode is not valid.");
 	}
+
 	if (!empty($pconfig['protocol']) &&
 	    !array_key_exists($pconfig['protocol'], $openvpn_prots)) {
 		$input_errors[] = gettext("The selected Protocol is not valid.");
@@ -246,7 +250,7 @@ if ($_POST['save']) {
 		$input_errors[] = gettext("The selected Interface is not valid.");
 	}
 
-	$cipher_validation_list = array_keys(openvpn_get_cipherlist());
+	$cipher_validation_list = array_keys($openvpn_all_data_ciphers);
 	if (!in_array($pconfig['data_ciphers_fallback'], $cipher_validation_list)) {
 		$input_errors[] = gettext("The selected Fallback Data Encryption Algorithm is not valid.");
 	}
@@ -427,8 +431,10 @@ if ($_POST['save']) {
 		}
 	}
 
-	if (($pconfig['mode'] == "p2p_shared_key") && strstr($pconfig['data_ciphers_fallback'], "GCM")) {
-		$input_errors[] = gettext("GCM Encryption Algorithms cannot be used with Shared Key mode.");
+	if (($pconfig['mode'] == "p2p_shared_key") &&
+	    (strstr($pconfig['data_ciphers_fallback'], "GCM") ||
+	    strstr($pconfig['data_ciphers_fallback'], "CHACHA"))) {
+		$input_errors[] = gettext("AEAD Encryption Algorithms (GCM, CHACHA) cannot be used with Shared Key mode.");
 	}
 
 	/* If we are not in shared key mode, then we need the CA/Cert. */
@@ -511,7 +517,7 @@ if ($_POST['save']) {
 		$client = array();
 
 		if ($this_client_config &&
-		    $pconfig['dev_mode'] <> $this_client_config['dev_mode']) {
+		    ($pconfig['dev_mode'] != $this_client_config['dev_mode'])) {
 			/*
 			 * delete old interface so a new TUN or TAP interface
 			 * can be created.
@@ -573,7 +579,6 @@ if ($_POST['save']) {
 		} else {
 			$client['shared_key'] = base64_encode($pconfig['shared_key']);
 		}
-		$client['data_ciphers_fallback'] = $pconfig['data_ciphers_fallback'];
 		$client['digest'] = $pconfig['digest'];
 
 		foreach (array('', 'v6') as $ntype) {
@@ -599,6 +604,7 @@ if ($_POST['save']) {
 		if (!empty($pconfig['data_ciphers'])) {
 			$client['data_ciphers'] = implode(",", $pconfig['data_ciphers']);
 		}
+		$client['data_ciphers_fallback'] = $pconfig['data_ciphers_fallback'];
 
 		$client['ping_method'] = $pconfig['ping_method'];
 		$client['keepalive_interval'] = $pconfig['keepalive_interval'];
@@ -928,12 +934,13 @@ if ($act=="new" || $act=="edit"):
 		$data_ciphers_list[$cipher] = $cipher;
 	}
 	$group = new Form_Group('Data Encryption Algorithms');
+	$group->addClass("datacipherlist");
 
 	$group->add(new Form_Select(
 		'availciphers',
 		null,
 		array(),
-		openvpn_get_cipherlist(),
+		$openvpn_all_data_ciphers,
 		true
 	))->setAttribute('size', '10')
 	  ->setHelp('Available Data Encryption Algorithms%1$sClick to add or remove an algorithm from the list', '<br />');
@@ -962,7 +969,7 @@ if ($act=="new" || $act=="edit"):
 		'data_ciphers_fallback',
 		'Fallback Data Encryption Algorithm',
 		$pconfig['data_ciphers_fallback'],
-		openvpn_get_cipherlist()
+		$openvpn_all_data_ciphers
 		))->setHelp('The Fallback Data Encryption Algorithm used for data channel packets when communicating with ' .
 				'clients that do not support data encryption algorithm negotiation (e.g. Shared Key). ' .
 				'This algorithm is automatically included in the Data Encryption Algorithms list.');
@@ -1541,6 +1548,7 @@ events.push(function() {
 
 	function updateCipher(mem) {
 		var found = false;
+		var ciphers_all = <?= json_encode($openvpn_all_data_ciphers) ?>;
 
 		// If the cipher exists, remove it
 		$('[id="data_ciphers[]"] option').each(function() {
@@ -1552,7 +1560,7 @@ events.push(function() {
 
 		// If not, add it
 		if (!found) {
-			$('[id="data_ciphers[]"]').append(new Option(mem , mem));
+			$('[id="data_ciphers[]"]').append(new Option(ciphers_all[mem], mem));
 		}
 	}
 
diff --git a/src/usr/local/www/vpn_openvpn_server.php b/src/usr/local/www/vpn_openvpn_server.php
index cf38b41d95..cdb5913a96 100644
--- a/src/usr/local/www/vpn_openvpn_server.php
+++ b/src/usr/local/www/vpn_openvpn_server.php
@@ -36,6 +36,9 @@ require_once("pkg-utils.inc");
 
 global $openvpn_topologies, $openvpn_tls_modes, $openvpn_exit_notify_server;
 global $openvpn_sharedkey_warning;
+global $openvpn_prots;
+
+$openvpn_all_data_ciphers = openvpn_get_cipherlist();
 
 config_init_path('openvpn/openvpn-server');
 
@@ -335,7 +338,7 @@ if ($_POST['save']) {
 		$input_errors[] = gettext("The selected ECDH Curve is not valid.");
 	}
 
-	$cipher_validation_list = array_keys(openvpn_get_cipherlist());
+	$cipher_validation_list = array_keys($openvpn_all_data_ciphers);
 	if (!in_array($pconfig['data_ciphers_fallback'], $cipher_validation_list)) {
 		$input_errors[] = gettext("The selected Fallback Data Encryption Algorithm is not valid.");
 	}
@@ -595,8 +598,10 @@ if ($_POST['save']) {
 		$reqdfieldsn = array(gettext('Shared key'));
 	}
 
-	if (($pconfig['mode'] == "p2p_shared_key") && strstr($pconfig['data_ciphers_fallback'], "GCM")) {
-		$input_errors[] = gettext("GCM Encryption Algorithms cannot be used with Shared Key mode.");
+	if (($pconfig['mode'] == "p2p_shared_key") &&
+	    (strstr($pconfig['data_ciphers_fallback'], "GCM") ||
+	    strstr($pconfig['data_ciphers_fallback'], "CHACHA"))) {
+		$input_errors[] = gettext("AEAD Encryption Algorithms (GCM, CHACHA) cannot be used with Shared Key mode.");
 	}
 
 	if ($pconfig['dev_mode'] == "tap") {
@@ -686,7 +691,8 @@ if ($_POST['save']) {
 
 		$server = array();
 
-		if ($this_server_config && $pconfig['dev_mode'] <> $this_server_config['dev_mode']) {
+		if ($this_server_config &&
+		    ($pconfig['dev_mode'] != $this_server_config['dev_mode'])) {
 			/*
 			 * delete old interface so a new TUN or TAP interface
 			 * can be created.
@@ -743,7 +749,6 @@ if ($_POST['save']) {
 			$server['shared_key'] = base64_encode($pconfig['shared_key']);
 		}
 
-		$server['data_ciphers_fallback'] = $pconfig['data_ciphers_fallback'];
 		$server['digest'] = $pconfig['digest'];
 
 		foreach (array('', 'v6') as $ntype) {
@@ -831,6 +836,7 @@ if ($_POST['save']) {
 		if (!empty($pconfig['data_ciphers'])) {
 			$server['data_ciphers'] = implode(",", $pconfig['data_ciphers']);
 		}
+		$server['data_ciphers_fallback'] = $pconfig['data_ciphers_fallback'];
 
 		$server['ping_method'] = $pconfig['ping_method'];
 		$server['keepalive_interval'] = $pconfig['keepalive_interval'];
@@ -1174,12 +1180,13 @@ if ($act=="new" || $act=="edit"):
 	))->setHelp('Paste the shared key here');
 
 	$group = new Form_Group('Data Encryption Algorithms');
+	$group->addClass("datacipherlist");
 
 	$group->add(new Form_Select(
 		'availciphers',
 		null,
 		array(),
-		openvpn_get_cipherlist(),
+		$openvpn_all_data_ciphers,
 		true
 	))->setAttribute('size', '10')
 	  ->setHelp('Available Data Encryption Algorithms%1$sClick to add or remove an algorithm from the list', '<br />');
@@ -1208,7 +1215,7 @@ if ($act=="new" || $act=="edit"):
 		'data_ciphers_fallback',
 		'Fallback Data Encryption Algorithm',
 		$pconfig['data_ciphers_fallback'],
-		openvpn_get_cipherlist()
+		$openvpn_all_data_ciphers
 		))->setHelp('The Fallback Data Encryption Algorithm used for data channel packets when communicating with ' .
 				'clients that do not support data encryption algorithm negotiation (e.g. Shared Key). ' .
 				'This algorithm is automatically included in the Data Encryption Algorithms list.');
@@ -2400,6 +2407,7 @@ events.push(function() {
 
 	function updateCipher(mem) {
 		var found = false;
+		var ciphers_all = <?= json_encode($openvpn_all_data_ciphers) ?>;
 
 		// If the cipher exists, remove it
 		$('[id="data_ciphers[]"] option').each(function() {
@@ -2411,7 +2419,7 @@ events.push(function() {
 
 		// If not, add it
 		if (!found) {
-			$('[id="data_ciphers[]"]').append(new Option(mem , mem));
+			$('[id="data_ciphers[]"]').append(new Option(ciphers_all[mem], mem));
 		}
 	}
 
diff --git a/src/usr/local/www/widgets/widgets/interfaces.widget.php b/src/usr/local/www/widgets/widgets/interfaces.widget.php
index 0f629eee2c..d992ac37de 100644
--- a/src/usr/local/www/widgets/widgets/interfaces.widget.php
+++ b/src/usr/local/www/widgets/widgets/interfaces.widget.php
@@ -91,7 +91,8 @@ foreach ($ifdescrs as $ifdescr => $ifname):
 	$known_status = true;
 
 	// Choose an icon by interface status
-	if ($ifinfo['status'] == "up" || $ifinfo['status'] == "associated") {
+	if ($ifinfo['status'] == "up" ||
+	    $ifinfo['status'] == "associated") {
 		$icon = 'fa-solid fa-arrow-up text-success';
 	} elseif ($ifinfo['status'] == "no carrier") {
 		$icon = 'fa-solid fa-times-circle text-danger';
diff --git a/src/usr/local/www/widgets/widgets/system_information.widget.php b/src/usr/local/www/widgets/widgets/system_information.widget.php
index dd33d4dcd4..e72dd9c502 100644
--- a/src/usr/local/www/widgets/widgets/system_information.widget.php
+++ b/src/usr/local/www/widgets/widgets/system_information.widget.php
@@ -56,7 +56,7 @@ $sysinfo_items = array(
 	);
 
 // Declared here so that JavaScript can access it
-$updtext = sprintf(gettext("Obtaining update status %s"), "<i class='fa-solid fa-cog fa-spin'></i>");
+$updtext = sprintf(gettext("Obtaining update status %s"), "<i class='fa-solid fa-rotate fa-spin'></i>");
 $state_tt = gettext("Adaptive state handling is enabled, state timeouts are reduced by ");
 
 if ($_REQUEST['getupdatestatus']) {
@@ -126,7 +126,7 @@ if ($_REQUEST['getupdatestatus']) {
 		<?printf("%s %s", gettext("Version information updated at"),
 		    date("D M j G:i:s T Y", filemtime($cache_file)));?>
 		    &nbsp;
-		    <a id="updver" href="#" class="fa-solid fa-arrows-rotate"></a>
+		    <a id="updver" href="#" class="fa-solid fa-rotate"></a>
 	</div>
 <?php
 	endif;
@@ -300,7 +300,13 @@ $temp_use_f = (isset($user_settings['widgets']['thermal_sensors-0']) && !empty($
 			$cpucount = get_cpu_count();
 			if ($cpucount > 1): ?>
 				<div id="cpucount">
-					<?= htmlspecialchars($cpucount) ?> <?=gettext('CPUs')?>: <?= htmlspecialchars(get_cpu_count(true)); ?>
+					<?= htmlspecialchars($cpucount) ?> <?=gettext('CPUs')?>
+<?php
+				$cpudetail = get_cpu_count(true);
+				if ($cpudetail != $cpucount): ?>
+					: <?= htmlspecialchars($cpudetail); ?>
+<?php
+				endif; ?>
 				</div>
 		<?php endif; ?>
 				<div id="cpucrypto">
diff --git a/src/usr/local/www/wizard.php b/src/usr/local/www/wizard.php
index adcffa9320..8528ebcff6 100644
--- a/src/usr/local/www/wizard.php
+++ b/src/usr/local/www/wizard.php
@@ -871,6 +871,30 @@ if ($pkg['step'][$stepid]['fields']['field'] != "") {
 				  ->setAttribute('rows', $field['rows'])
 				  ->setOnchange(($field['validate']) ? "FieldValidate(this.value, \"" . $field['validate'] . "\", \"" . $field['message'] . "\")":"");
 
+				break;
+			case "textarea_source":
+				if ($field['displayname']) {
+					$etitle = $field['displayname'];
+				} else if (!$field['dontdisplayname']) {
+					$etitle =  fixup_string($field['name']);
+				}
+
+				$source = $field['source'];
+				try{
+					@eval("\$value = &$source;");
+				} catch (\Throwable | \Error | \Exception $e) {
+					log_error($e);
+				}
+				$input = $section->addInput(new Form_Textarea(
+					$name,
+					$etitle,
+					$value
+				))->setHelp($field['description'])
+				  ->setAttribute('rows', $field['rows'])
+				  ->setOnchange(($field['validate']) ? "FieldValidate(this.value, \"" . $field['validate'] . "\", \"" . $field['message'] . "\")":"");
+				if ($field['readonly']) {
+					$input->setReadonly();
+				}
 				break;
 			case "submit":
 				$form->addGlobal(new Form_Button(
