
/*
 * dhcp_server_check_reconfig()
 *	Fixup the dhcp server settings based upon new lan ip addressing.
 * Only invoke this function is DHCP server is enabled.
 */
function dhcp_server_check_reconfig(original_lan_network_address, original_lan_subnet_mask, data_copy)
{
	/*
	 * If the LAN IP or subnet has changed we may need to reconfigure other parts of the system.
	 */
	if ((original_lan_network_address == data_copy.lan_network_address) && (original_lan_subnet_mask == data_copy.lan_subnet_mask)) {
		return 1;
	}

	/*
	 * Ensure that the LAN IP address does not conflict with any existing reservation
	 */
	for (i = 0; i < data_copy.dhcp_addr_resv_table.length; i++) {
		if (data_copy.dhcp_addr_resv_table[i].used
				&& (data_copy.dhcp_addr_resv_table[i].mac_ip == data_copy.lan_network_address)) {
			alert("New LAN IP address conflicts with a DHCP Server reservation");
			return 0;
		}
	}

	/*
	 * Get numeric formats of the original details.
	 */
	var lan_subnet_mask_original = IPAddressToInteger(original_lan_subnet_mask);
	var lan_host_mask_original = ~lan_subnet_mask_original;

	/*
	 * Get details about new LAN IP addressing.
	 */
	var lan_network_address = IPAddressToInteger(data_copy.lan_network_address);
	var lan_subnet_mask = IPAddressToInteger(data_copy.lan_subnet_mask);
	var lan_host_mask = ~lan_subnet_mask;
	if (lan_host_mask < 3) {
		/*
		 * Mask but have bit 0 and 1 set for there to be a bare minimum of IP's
		 */
		alert("LAN subnet mask does not allow sufficient number of host IP addresses");
		return 0;
	}
	var lan_network = lan_network_address & lan_subnet_mask;
	var lan_num_ips = lan_host_mask - 1;		/* Take off all 0's and 1's, e.g. for a mask of '3' there are 4 addresses (0, 1, 2, 3).  Taking 1 off this mask yeilds '2' - i.e. .1 and .2  - one of which is the LAN address */

	/*
	 * Limit the potential range to MAX 256
	 */
	if (lan_num_ips > 256) {
		lan_num_ips = 256;
	}

	/*
	 * Identify if the existing DHCP server range is compatible with the new subnet.
	 */
	var lan_dhcp_range_from = IPAddressToInteger(data_copy.lan_dhcp_range_ip_start);
	var lan_dhcp_range_to = IPAddressToInteger(data_copy.lan_dhcp_range_ip_end);
	var compatible = true;
	if (lan_network != (lan_dhcp_range_from & lan_subnet_mask)) {
		compatible = false;
	}
	if (lan_network != (lan_dhcp_range_to & lan_subnet_mask)) {
		compatible = false;
	}

	/*
	 * If the DHCP server addressing range is still compatible then we don't have to reconfigure
	 */
	if (compatible) {
		return 1;
	}

	/*
	 * Discover a new DHCP Server range of IP addresses, using one of two strategies:
	 * 1. If the original subnet mask was larger (i.e. less hosts) than the new, we should be able to keep the existing host range.
	 * 2. If the orihinal subnet mask was smaller (i.e. more hosts) than the new mask, we need to select a new range.
	 */
	var lan_dhcp_new_range_from = lan_network + 1;
	var lan_dhcp_new_range_to = (lan_dhcp_new_range_from + lan_num_ips) - 1;
	if (lan_subnet_mask_original >= lan_subnet_mask) {
		lan_dhcp_new_range_from = lan_dhcp_range_from & lan_host_mask_original;
		lan_dhcp_new_range_from += lan_network;
		lan_dhcp_new_range_to = lan_dhcp_range_to & lan_host_mask_original;
		lan_dhcp_new_range_to += lan_network;
	}

	/*
	 * Identify how many reservations there are and if we can make them fit.
	 */
	var lan_dhcp_num_resvs = 0;
	for (i = 0; i < data_copy.dhcp_addr_resv_table.length; i++) {
		if (data_copy.dhcp_addr_resv_table[i].used) {
			lan_dhcp_num_resvs++;
		}
	}

	/*
	 * Ensure there are enough IP's to satisfy the reservations.
	 * Take into consideration that lan_num_ip's includes the LAN network address.
	 */
	if (lan_dhcp_num_resvs > (lan_num_ips - 1)) {
		alert("The number of DHCP reservations exceeds the available dhcp server range.");
		return 0;
	}

	/*
	 * Reconfigure the reservations.
	 * Ensure that, once moved, they do not conflict with the LAN IP address.
	 */
	var lan_dhcp_next_resv_ip = lan_dhcp_new_range_from;
	for (i = 0; i < data_copy.dhcp_addr_resv_table.length; i++) {
		if (data_copy.dhcp_addr_resv_table[i].used) {
			/*
			 * If the reservation IP still fits in the range and does not
			 * conflict with the LAN Network Address then keep it.
			 */
			var lan_resv_ip = IPAddressToInteger(data_copy.dhcp_addr_resv_table[i].mac_ip);
			if ((lan_resv_ip >= lan_dhcp_new_range_from) && (lan_resv_ip <= lan_dhcp_new_range_to)) {
				continue;
			}

			/*
			 * Need to move the reservation to an available IP
			 * We have two strategies for doing this:
			 * 1. If the previous subnet mask is >= the new lan subnet mask then we should be able to
			 * simply use the same HOST PART with the new SUBNET PART.
			 * 2. If the previous subnet mask is < the new lan subnet then we have to select a brand new IP
			 * by using 'lan_dhcp_next_resv_ip'.
			 */
			if (lan_subnet_mask_original >= lan_subnet_mask) {
				lan_resv_ip = lan_resv_ip & lan_host_mask_original;
				lan_resv_ip += lan_network;
			} else {
				lan_resv_ip = lan_dhcp_next_resv_ip; 
			}

			/* 
			 * Does the IP Conflict with the lan IP address or a different reservation
			 */
			var conflicts = false;
			if (lan_resv_ip == lan_network_address) {
				conflicts = true;
			}
			var ri;
			for (ri = 0; ri < data_copy.dhcp_addr_resv_table.length; ri++) {
				var test_lan_resv_ip = IPAddressToInteger(data_copy.dhcp_addr_resv_table[ri].mac_ip);
				if (test_lan_resv_ip == lan_resv_ip) {
					conflicts = true;
					break;
				}
			}

			/*
			 * If it conflicts we need to select a different IP
			 */
			if (!conflicts) {
				/*
				 * Convert the selected IP back to a string and assign it to the reservation
				 */
				var ip_array = intToByteArray(lan_resv_ip, 4);
				data_copy.dhcp_addr_resv_table[i].mac_ip = byteArrayToIPAddress(ip_array, 0);				
				continue;
			}

			/*
			 * Select a new IP
			 */
			for (ri = 0; ri < data_copy.dhcp_addr_resv_table.length; ri++) {
				var test_lan_resv_ip = IPAddressToInteger(data_copy.dhcp_addr_resv_table[ri].mac_ip);
				if ((test_lan_resv_ip == lan_dhcp_next_resv_ip) || (lan_dhcp_next_resv_ip == lan_network_address)) {
					lan_dhcp_next_resv_ip++;
					ri = 0;		/* Rescan to examine the new 'lan_dhcp_next_resv_ip' */
				}
			}

			/*
			 * Convert the selected IP back to a string and assign it to the reservation
			 */
			var ip_array = intToByteArray(lan_dhcp_next_resv_ip, 4);
			data_copy.dhcp_addr_resv_table[i].mac_ip = byteArrayToIPAddress(ip_array, 0);
			lan_dhcp_next_resv_ip++;
		}
	}

	/*
	 * Convert the selected IPs back to a string and assign them
	 */
	var ip_array = intToByteArray(lan_dhcp_new_range_from, 4);
	var lan_dhcp_new_range_from_str = byteArrayToIPAddress(ip_array, 0);
	ip_array = intToByteArray(lan_dhcp_new_range_to, 4);
	var lan_dhcp_new_range_to_str = byteArrayToIPAddress(ip_array, 0);

	data_copy.lan_dhcp_range_ip_start = lan_dhcp_new_range_from_str;
	data_copy.lan_dhcp_range_ip_end = lan_dhcp_new_range_to_str;
	return 1;
}

function fixup_dhcp_server_config_js_loaded() { return true; }
