<?php

function perform_ipmitool_cmd($con, $conf, $machine_id, $ipmi_username, $ipmi_password, $ipmi_addr, $ipmi_default_gw, $ipmi_netmask){
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";

    $q = "SELECT * FROM machines WHERE id='$machine_id'";
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }
    $n = mysqli_num_rows($r);
    if($n != 1){
        $json["status"] = "error";
        $json["message"] = "No machine with serial id $machine_id in database.";
        return $json;
    }
    $machine = mysqli_fetch_array($r);

    # Call oci-lenovo-set-default-onecli-config. It will itself know if
    # it runs on a Lenovo machine and if /usr/bin/onecli is present, and
    # skip running if conditions aren't met.
    # Note that it is mandatory to run it, otherwise setting-up the IPMI
    # password will not work.
    $cmd = "/usr/bin/oci-lenovo-set-default-onecli-config";
    $json["message"] .= "\n$cmd";
    send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

    # This is for HP cloud line
    if($machine["product_name"] == "CL2600 Gen10" || $machine["product_name"] == "CL2800 Gen10"){
        // What's below is proven to work with HP Cloud Line CL2600 and CL2800 machines
        // Set the username
        $cmd = "ipmitool user set name 3 " . escapeshellarg($ipmi_username);
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set the password
        $cmd = "ipmitool user set password 3 " . escapeshellarg($ipmi_password);
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Enable the user
        $cmd = "ipmitool user enable 3";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set user privileges for channel 1
        $cmd = "ipmitool user priv 3 4 1";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set user privileges for channel 8
        $cmd = "ipmitool user priv 3 4 8";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set user channel access for channel 1
        $cmd = "ipmitool channel setaccess 1 3 link=on ipmi=on callin=on privilege=4";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set user channel access for channel 8
        $cmd = "ipmitool channel setaccess 8 3 link=on ipmi=on callin=on privilege=4";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Enable Serial On LAN
        $cmd = "ipmitool sol payload enable 1 3";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        $cmd = "ipmitool sol payload enable 8 3";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

// This may eventually be needed if we also want to change the default Administrator password
// ipmitool user set name 4 Administrator
// ipmitool user set password 4 XXXXXX
// ipmitool user enable 4
// ipmitool user priv 4 4 1
// ipmitool user priv 4 4 8
// ipmitool channel setaccess 1 4 link=on ipmi=on callin=on privilege=4
// ipmitool channel setaccess 8 4 link=on ipmi=on callin=on privilege=4

        // Set DHCP Off
        $cmd = "ipmitool lan set 1 ipsrc static";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set the IP address
        $cmd = "ipmitool lan set 1 ipaddr " . $ipmi_addr;
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set the default GW
        if( isset($ipmi_default_gw)){
            $cmd = "ipmitool lan set 1 defgw ipaddr " . $ipmi_default_gw;
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        }

        // Set the netmask
        if( isset($ipmi_netmask)){
            $cmd = "ipmitool lan set 1 netmask " . $ipmi_netmask;
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        }

        // Set DHCP Off
        $cmd = "ipmitool lan set 8 ipsrc static";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set the IP address
        $cmd = "ipmitool lan set 8 ipaddr " . $ipmi_addr;
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set the default GW
        if( isset($ipmi_default_gw)){
            $cmd = "ipmitool lan set 8 defgw ipaddr " . $ipmi_default_gw;
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        }

        // Set the netmask
        if( isset($ipmi_netmask)){
            $cmd = "ipmitool lan set 8 netmask " . $ipmi_netmask;
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        }

//
// ipmitool lan set 1 ipsrc static
// ipmitool lan set 1 ipaddr <IP-IPMI>
// ipmitool lan set 1 defgw ipaddr <IPMI-GW>
// ipmitool lan set 1 netmask 255.255.255.0
//
// ipmitool lan set 8 ipsrc static
// ipmitool lan set 8 ipaddr <IP-IPMI>
// ipmitool lan set 8 defgw ipaddr <IPMI-GW>
// ipmitool lan set 8 netmask 255.255.255.0
    }else{
        // What's below is proven to work with Dell r440 and r640 machines
        // Set the username
        $cmd = "ipmitool user set name 2 " . escapeshellarg($ipmi_username);
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set the password
        $cmd = "ipmitool user set password 2 " . escapeshellarg($ipmi_password);
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set DHCP off
        $cmd = "ipmitool lan set 1 ipsrc static";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set the IP address
        $cmd = "ipmitool lan set 1 ipaddr " . $ipmi_addr;
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set the default GW
        $cmd = "ipmitool lan set 1 defgw ipaddr " . $ipmi_default_gw;
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set the default GW
        $cmd = "ipmitool lan set 1 netmask " . $ipmi_netmask;
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        // Set some credentials
        $cmd = "ipmitool channel setaccess 1 2 link=on ipmi=on callin=on privilege=4";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        $cmd = "ipmitool sol payload enable 1 2";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        $cmd = "ipmitool user priv 2 4 1";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

        $cmd = "/usr/bin/oci-dell-set-default-racadm-config";
        $json["message"] .= "\n$cmd";
        send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
    }
    if($conf["dellipmi"]["live_image_install_dell_ipmi"] == "1"){
        if($machine["product_name"] == "PowerEdge R640" || $machine["product_name"] == "PowerEdge R440" || $machine["product_name"] == "PowerEdge R6525" || $machine["product_name"] == "DSS 1510"){
            $cmd = "racadm set BIOS.SysSecurity.AcPwrRcvry On";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set BIOS.SerialCommSettings.RedirAfterBoot Enabled";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set BIOS.SerialCommSettings.ExtSerialConnector Serial1";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set BIOS.SerialCommSettings.ConTermType Vt100Vt220";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set iDRAC.IPMISerial.BaudRate 115200";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set iDRAC.IPMISerial.FlowControl RTS/CTS";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set iDRAC.IPMISerial.HandshakeControl Enabled";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set iDRAC.IPMISOL.BaudRate 115200";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set iDRAC.IPMISOL.Enable Enabled";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set iDRAC.Serial.BaudRate 115200";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set iDRAC.Serial.Enable Enabled";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set iDRAC.SerialRedirection.Enable Enabled";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set iDRAC.WebServer.Enable Enabled";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set BIOS.ProcSettings.ProcVirtualization Enabled";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

            $cmd = "racadm set BIOS.ProcSettings.ProcAdjCacheLine Enabled";
            $json["message"] .= "\n$cmd";
            send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        }
    }

    // This sometimes help
    $cmd = "ipmitool lan set 1 arp generate on";
    $json["message"] .= "\n$cmd";
    send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

    $cmd = "ipmitool lan set 1 arp interval 5";
    $json["message"] .= "\n$cmd";
    send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

    // Set the VLAN
    $cmd = "ipmitool lan set 1 vlan id " . $machine["ipmi_vlan"];
    $json["message"] .= "\n$cmd";
    send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

    // Set access on, so we have remote IPMI access
    $cmd = "ipmitool lan set 1 access on";
    $json["message"] .= "\n$cmd";
    send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

    // Print the lan config
    $cmd = "ipmitool lan print 1";
    $json["message"] .= "\n$cmd";
    $out = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
    $json["message"] .= "\n$out";

    if($machine["ipmi_addr"] != $ipmi_addr && ($machine["product_name"] == "ProLiant DL385 Gen10" || $machine["product_name"] == "ProLiant DL385 Gen10 Plus" || $machine["product_name"] == "ProLiant DL345 Gen11" || $machine["product_name"] == "ProLiant DL385 Gen11")){
        # Enable the IPMI over LAN, which is off by default on these machines
        $cmd = "echo '<RIBCL VERSION=\\\"2.0\\\"><LOGIN USER_LOGIN=\\\"admin\\\" PASSWORD=\\\"password\\\"><RIB_INFO mode=\\\"write\\\"><MOD_GLOBAL_SETTINGS><IPMI_DCMI_OVER_LAN_ENABLED VALUE=\\\"Y\\\"/></MOD_GLOBAL_SETTINGS></RIB_INFO></LOGIN></RIBCL>' >set-ipmi-on.xml ; hponcfg -f set-ipmi-on.xml ; rm set-ipmi-on.xml";
        $json["message"] .= "\n$cmd";
        $out = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        $json["message"] .= "\n$out";

        # Also activate IPMI over LAN using ilorest, if the above didn't work.
        $cmd = "oci-ilorest" . $machine["serial"] . "set --selector NetworkProtocol IPMI/ProtocolEnabled=True --commit";
        $output = array();
        $return_var = 0;
        exec($cmd, $output, $return_var);

        # Add the ILO license if we have the /root/License.xml file (should be present in the Live OS only).
        # Users of OCI should install the file under:
        # /etc/openstack-cluster-installer/live-image-additions/root/License.xml
        $cmd = "if [ -e /root/License.xml ] ; then hponcfg -f /root/License.xml ; fi";
        $json["message"] .= "\n$cmd";
        $out = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        $json["message"] .= "\n$out";

        if($machine["product_name"] == "ProLiant DL345 Gen11" || $machine["product_name"] == "ProLiant DL385 Gen10 Plus" || $machine["product_name"] == "ProLiant DL385 Gen11"){
            # Add an SMP community so that we can monitor the system NVMe RAID of these machines
            $cmd = "oci-ilorest " . $machine["serial"] . 'set ReadCommunities=["snmp_read_string","",""] --selector=HpeiLOSnmpService.v2_3_0 --commit';
            $output = array();
            $return_var = 0;
            exec($cmd, $output, $return_var);
        }

        // Since we changed IP address, the ILO needs a reset (thank you HP !)
        $cmd = "ipmitool mc reset cold";
        $json["message"] .= "\n$cmd";
        $out = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        $json["message"] .= "\n$out";
    }
    return $json;
}

function machine_activate_ipmi_over_lan($con, $conf, $machine){
    switch($machine["system_manufacturer"]){
    case "Dell Inc.":
    case "Dell":
        send_ssh_cmd($conf, $con, $machine["ipaddr"], "racadm set iDRAC.IPMILan.Enable Enabled");
        break;
    case "HPE":
        $cmd = "oci-ilorest" . $machine["serial"] . "set --selector NetworkProtocol IPMI/ProtocolEnabled=True";
        $output = array();
        $return_var = 0;
        exec($cmd, $output, $return_var);
        break;
    default:
        break;
    }
}

# Adopting an IPMI means using its IPMI username,
# but set a random password, and leave it run over DHCP,
# then save its IPMI password to a password vault if
# the plugin is activated.
function machine_ipmi_adopt($con, $conf, $machine){
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";
    if($machine["product_name"] == "Lenovo" || $machine["product_name"] == "LENOVO"){
        # This produces a 16 char long pass
        $num_bytes = 12;
    }else{
        # This produces a 12 char long pass
        $num_bytes = 9;
    }
    # Get the current IPMI username for user 2.
    $ipmi_username = send_ssh_cmd($conf, $con, $machine["ipaddr"], "ipmitool user list 1 2>/dev/null | grep ^2 | awk '{print \\$2}'");
    # Generate a new IPMI password...
    $ipmi_password = base64_encode(openssl_random_pseudo_bytes($num_bytes, $crypto_strong));
    # and imediatelly set it with ipmitool.
    send_ssh_cmd($conf, $con, $machine["ipaddr"], "ipmitool user set password 2 $ipmi_password");

    machine_activate_ipmi_over_lan($con, $conf, $machine);

    # Update the db with the new info...
    $q = "UPDATE machines SET ipmi_username='$ipmi_username', ipmi_password='$ipmi_password', ipmi_addr='". $machine["ipmi_detected_ip"] ."', ipmi_use='yes', ipmi_call_chassis_bootdev='yes' WHERE id='" . $machine["id"] . "'";
    $r = mysqli_query($con, $q);
    # ... as well as the password vault.
    machine_save_ipmi_pass($con, $conf, $machine);
}

function automatic_ipmi_assign($con, $conf, $machine_id){
    $q = "SELECT * FROM machines WHERE id='$machine_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n == 1){
        $machine = mysqli_fetch_array($r);
        $machine_dhcp_ip = $machine["dhcp_ip"];
        $machine_dhcp_ip_long = ip2long($machine_dhcp_ip);
        $machine_ipmi_detected_ip = $machine["ipmi_detected_ip"];
        $machine_ipmi_detected_ip_long = ip2long($machine_ipmi_detected_ip);

        # Check if the machine already has its IPMI set on one of the IPMI networks
        $qn = "SELECT * FROM networks WHERE role='ipmi'";
        $rn = mysqli_query($con, $qn);
        $nn = mysqli_num_rows($rn);
        $ipmi_addr_is_ok = "no";
        for($i=0;$i<$nn;$i++){
            $network = mysqli_fetch_array($rn);
            $network_start = ip2long($network["ip"]) + 2;
            $network_end = (pow(2, 32 - $network["cidr"]) - 4) + $network_start;
            if($machine_ipmi_detected_ip_long >= $network_start && $machine_ipmi_detected_ip_long <= $network_end){
                $ipmi_addr_is_ok = "yes";
            }
        }

# We can't just exit at this point, because maybe the machine
# set set with an IPMI IP address on a wrong network, and may
# need to change. See below for that.
#        if($ipmi_addr_is_ok == "yes"){
#            return;
#        }

        # See if we're currently updating the ipmi config of the machine,
        # if so, do nothing...
        # Note this is a loosy lock, but that's fine as the report script isn't running so often
        if($machine["ipmi_set_in_progress"] == "no"){
            # Set the ipmi_set_in_progress lock
            $qlock = "UPDATE machines SET ipmi_set_in_progress='yes' WHERE id='$machine_id'";
            mysqli_query($con, $qlock);

            # Attempt to match one of the IPMI networks in the OCI's DB with the machine's DHCP address
            $qn = "SELECT * FROM networks WHERE role='ipmi'";
            $rn = mysqli_query($con, $qn);
            $nn = mysqli_num_rows($rn);
            $ipmi_addr_is_ok = "no";
            $matched_network = "no";
            for($i=0;$i<$nn;$i++){
                $network = mysqli_fetch_array($rn);
                $network_dhcp_start = ip2long($network["ipmi_match_addr"]) + 2;
                $network_dhcp_end = (pow(2, 32 - $network["ipmi_match_cidr"]) - 4) + $network_dhcp_start;
                if($machine_dhcp_ip_long >= $network_dhcp_start && $machine_dhcp_ip_long <= $network_dhcp_end){
                    $matched_network = $network;
                }
            }


            if($matched_network != "no"){
                # At this point, we know the machine should be having its IPMI
                # address on $matched_network. Let's get some properties of it.
                $net_id = $matched_network["id"];
                if(is_null($matched_network["vlan"])){
                    $net_vlan = "off";
                }else{
                    $net_vlan = $matched_network["vlan"];
                }
                $net_iplong = ip2long($matched_network["ip"]);
                $ipmi_net_def_gateway = long2ip($net_iplong+1);
                switch($matched_network["cidr"]){
                case "32":
                    $ipmi_netmask = "255.255.255.255";
                    break;
                case "31":
                    $ipmi_netmask = "255.255.255.254";
                    break;
                case "30":
                    $ipmi_netmask = "255.255.255.252";
                    break;
                case "29":
                    $ipmi_netmask = "255.255.255.248";
                    break;
                case "28":
                    $ipmi_netmask = "255.255.255.240";
                    break;
                case "27":
                    $ipmi_netmask = "255.255.255.224";
                    break;
                case "26":
                    $ipmi_netmask = "255.255.255.192";
                    break;
                case "25":
                    $ipmi_netmask = "255.255.255.128";
                    break;
                case "24":
                    $ipmi_netmask = "255.255.255.0";
                    break;
                case "23":
                    $ipmi_netmask = "255.255.254.0";
                    break;
                case "22":
                    $ipmi_netmask = "255.255.252.0";
                    break;
               case "21":
                    $ipmi_netmask = "255.255.248.0";
                    break;
               case "20":
                    $ipmi_netmask = "255.255.240.0";
                    break;
               case "19":
                    $ipmi_netmask = "255.255.224.0";
                    break;
               case "18":
                    $ipmi_netmask = "255.255.192.0";
                    break;
               case "17":
                    $ipmi_netmask = "255.255.128.0";
                    break;
                case "16":
                    $ipmi_netmask = "255.255.0.0";
                    break;
                case "15":
                    $ipmi_netmask = "255.254.0.0";
                    break;
                case "14":
                    $ipmi_netmask = "255.252.0.0";
                    break;
                case "13":
                    $ipmi_netmask = "255.248.0.0";
                    break;
                case "12":
                    $ipmi_netmask = "255.240.0.0";
                    break;
                case "11":
                    $ipmi_netmask = "255.224.0.0";
                    break;
                case "10":
                    $ipmi_netmask = "255.192.0.0";
                    break;
                case "9":
                    $ipmi_netmask = "255.128.0.0";
                    break;
                case "8":
                    $ipmi_netmask = "255.0.0.0";
                    break;
                case "7":
                    $ipmi_netmask = "254.0.0.0";
                    break;
                case "6":
                    $ipmi_netmask = "252.0.0.0";
                    break;
                case "5":
                    $ipmi_netmask = "248.0.0.0";
                    break;
                case "4":
                    $ipmi_netmask = "240.0.0.0";
                    break;
                case "3":
                    $ipmi_netmask = "224.0.0.0";
                    break;
                case "2":
                    $ipmi_netmask = "192.0.0.0";
                    break;
                case "1":
                    $ipmi_netmask = "128.0.0.0";
                    break;
                case "0":
                    $ipmi_netmask = "0.0.0.0";
                    break;
                }
                if($network["ipmi_mode"] == "externaldhcp"){
                    # If we have this, then the server should have been already set.
                    if($machine["ipmi_addr"] == $machine["ipmi_detected_ip"]){
                        return;
                    }
                    $ret = machine_ipmi_adopt($con, $conf, $machine);
                }else{
                    $ret = get_ip_of_machine_on_network($con, $conf, $matched_network["id"], $machine_id);
                    if($ret["status"] != "success"){
                        # If we don't have an IP on this network, there's 2 cases:
                        # 1/ the machine never had its IPMI set and recorded in the DB.
                        # 2/ the machine already was in an IPMI network, but that's the wrong one.
                        # We simply get rid of all IPMI IPs for that machine, so we get back on case 1/.
                        $qcheckwrong = "SELECT * FROM ips WHERE machine='".$machine["id"]."' AND usefor='ipmi'";
                        $rcheckwrong = mysqli_query($con, $qcheckwrong);
                        $ncheckwrong = mysqli_num_rows($rcheckwrong);
                        if($ncheckwrong >= 0){
                            $q_remove_ip = "DELETE FROM ips WHERE machine='".$machine["id"]."' AND usefor='ipmi'";
                            $r_remove_ip = mysqli_query($con, $q_remove_ip);
                        }

                        $ret = reserve_ip_address($con, $conf, $net_id, $machine["id"], "ipmi");
                        if($ret["status"] != "success"){
                            print($ret["message"]);
                        }
                        $ret = get_ip_of_machine_on_network($con, $conf, $matched_network["id"], $machine_id);
                        # Since we had to reserve a new IP, this means we got to do the IPMI setup.
                        $do_update = "yes";
                    }else{
                        # As an IP address was already reserved, it means we don't need to do the setup.
                        $do_update = "no";
                    }
                    if($ret["status"] == "success"){
                        $ipmi_addr = $ret["data"];
                        if($do_update == "yes"){
                            if($machine["product_name"] == "Lenovo" || $machine["product_name"] == "LENOVO"){
                                # This produces a 16 char long pass
                                $num_bytes = 12;
                            }else{
                                # This produces a 12 char long pass
                                $num_bytes = 9;
                            }
                            $hex = base64_encode(openssl_random_pseudo_bytes($num_bytes, $crypto_strong));
                            $json = perform_ipmitool_cmd($con, $conf, $machine_id, $conf["ipmi"]["automatic_ipmi_username"], $hex, $ipmi_addr, $ipmi_net_def_gateway, $ipmi_netmask);
                            $qmachine = "UPDATE machines SET ipmi_use='yes', ipmi_call_chassis_bootdev='yes', ipmi_addr='$ipmi_addr', ipmi_netmask='$ipmi_netmask', ipmi_default_gw='$ipmi_net_def_gateway', ipmi_vlan='$net_vlan', ipmi_username='". $conf["ipmi"]["automatic_ipmi_username"] ."', ipmi_password='$hex' WHERE id='$machine_id'";
                            mysqli_query($con, $qmachine);
                        }
                    }
                }
            }

            # Release the ipmi_set_in_progress lock
            $qlock = "UPDATE machines SET ipmi_set_in_progress='no' WHERE id='$machine_id'";
            mysqli_query($con, $qlock);
        }
    }
}

function check_if_machines_on_ipmi_network($con, $conf){
    $json["status"] = "success";

    $q = "SELECT serial, id, ipmi_addr, ipmi_detected_ip FROM machines WHERE ipmi_set_in_progress='no'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    # For each machine
    $msg = "";
    for($i=0;$i<$n;$i++){
        $machine = mysqli_fetch_array($r);
        $machine_id = $machine["id"];
        $machine_ipmi_addr = $machine["ipmi_addr"];
        $machine_ipmi_detected_ip = $machine["ipmi_detected_ip"];
        $machine_serial = $machine["serial"];

        if($machine_ipmi_addr == $machine_ipmi_detected_ip){
            $machine_ipmi_addr_long = ip2long($machine_ipmi_addr);

            # Check if it's IPMI ip matches one of the IPMI networks
            $qn = "SELECT * FROM networks WHERE role='ipmi'";
            $rn = mysqli_query($con, $qn);
            $nn = mysqli_num_rows($rn);
            $ipmi_addr_is_ok = "no";
            $matched_network = "no";
            for($j=0;$j<$nn;$j++){
                $network = mysqli_fetch_array($rn);
                $network_id = $network["id"];
                $network_start_long = ip2long($network["ip"]) + 2;
                $network_end_long = (pow(2, 32 - $network["cidr"]) - 4) + $network_start_long;
                if($machine_ipmi_addr_long >= $network_start_long && $machine_ipmi_addr_long <= $network_end_long){
                    # We have a match, check if the IPMI IP addr is in the db.
                    $qip = "SELECT * FROM ips WHERE network='$network_id' AND machine='$machine_id' AND usefor='ipmi'";
                    $rip = mysqli_query($con, $qip);
                    $nip = mysqli_num_rows($rip);
                    # If we don't find the IPMI IP in the db, then we are in the
                    # case were we must fix that: record that IP!
                    if($nip == 0){
                        # We first check if this IP exist already in the DB (maybe we have some
                        # IPs that are conflicting?)
                        $qipcheck = "SELECT * FROM ips WHERE ip='$machine_ipmi_addr_long'";
                        $ripcheck = mysqli_query($con, $qipcheck);
                        $nipcheck = mysqli_num_rows($ripcheck);
                        if($nipcheck == 0){
                            # It's now safe to record the IP in the db.
                            $qnip = "INSERT INTO ips (network, ip, type, machine, usefor) VALUES ('$network_id', '$machine_ipmi_addr_long', '4', '$machine_id', 'ipmi')";
                            $rnip = mysqli_query($con, $qnip);
                            $msg .= "Recorded IPMI addr $machine_ipmi_addr for machine with serial $machine_serial.\n";
                        }
                    }
                }
            }
        }
        print("\n\n");
    }
    if($msg == ""){
        $json["message"] = "All checked: done nothing.";
    }else{
        $json["message"] = $msg;
    }
    return $json;
}

?>
