From 77a46f04ffbab86fd926836ec7509f9df6bb1812 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Fri, 23 Apr 2021 17:28:25 -0700 Subject: [PATCH] Fixed server wake-on-lan. --- amt/amt.js | 7 +++++++ amtmanager.js | 13 ++++++++++++- meshscanner.js | 33 +++++++++++++++++++-------------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/amt/amt.js b/amt/amt.js index fdc3af4f..90e86688 100644 --- a/amt/amt.js +++ b/amt/amt.js @@ -194,6 +194,10 @@ function AmtStackCreateService(wsmanStack) { obj.CIM_PowerManagementService_RequestPowerStateChange(PowerState, "
http://schemas.xmlsoap.org/ws/2004/08/addressing
http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystemCIM_ComputerSystemManagedSystem", null, null, callback_func); } + obj.RequestOSPowerStateChange = function (PowerState, callback_func) { + obj.IPS_PowerManagementService_RequestOSPowerSavingStateChange(PowerState, '
http://schemas.xmlsoap.org/ws/2004/08/addressing
http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystemCIM_ComputerSystemManagedSystem', null, null, callback_func); + } + obj.SetBootConfigRole = function (Role, callback_func) { obj.CIM_BootService_SetBootConfigRole("
http://schemas.xmlsoap.org/ws/2004/08/addressing
http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootConfigSettingIntel(r) AMT: Boot Configuration 0", Role, callback_func); } @@ -384,9 +388,12 @@ function AmtStackCreateService(wsmanStack) { obj.IPS_OptInService_StartService = function (callback_func) { obj.Exec("IPS_OptInService", "StartService", {}, callback_func); } obj.IPS_OptInService_StopService = function (callback_func) { obj.Exec("IPS_OptInService", "StopService", {}, callback_func); } obj.IPS_OptInService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("IPS_OptInService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); } + obj.IPS_PowerManagementService_RequestOSPowerSavingStateChange = function (PowerState, ManagedElement, Time, TimeoutPeriod, callback_func) { obj.Exec('IPS_PowerManagementService', 'RequestOSPowerSavingStateChange', { 'OSPowerSavingState': PowerState, 'ManagedElement': ManagedElement, 'Time': Time, 'TimeoutPeriod': TimeoutPeriod }, callback_func, 0, 1); } obj.IPS_ProvisioningRecordLog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("IPS_ProvisioningRecordLog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); } obj.IPS_ProvisioningRecordLog_ClearLog = function (_method_dummy, callback_func) { obj.Exec("IPS_ProvisioningRecordLog", "ClearLog", { "_method_dummy": _method_dummy }, callback_func); } + obj.IPS_ScreenConfigurationService_SetSessionState = function (SessionState, ConsecutiveRebootsNum, callback_func) { obj.Exec('IPS_ScreenConfigurationService', 'SetSessionState', { 'SessionState': SessionState, 'ConsecutiveRebootsNum': ConsecutiveRebootsNum }, callback_func); } obj.IPS_SecIOService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("IPS_SecIOService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); } + obj.IPS_HTTPProxyService_AddProxyAccessPoint = function (AccessInfo, InfoFormat, Port, NetworkDnsSuffix, callback_func) { obj.Exec('IPS_HTTPProxyService', 'AddProxyAccessPoint', { 'AccessInfo': AccessInfo, 'InfoFormat': InfoFormat, 'Port': Port, 'NetworkDnsSuffix': NetworkDnsSuffix }, callback_func); } obj.AmtStatusToStr = function (code) { if (obj.AmtStatusCodes[code]) return obj.AmtStatusCodes[code]; else return "UNKNOWN_ERROR" } obj.AmtStatusCodes = { diff --git a/amtmanager.js b/amtmanager.js index f5ef3486..38d08d0a 100644 --- a/amtmanager.js +++ b/amtmanager.js @@ -838,6 +838,7 @@ module.exports.CreateAmtManager = function (parent) { // If not LMS, has a AMT stack present and is in connected state, perform power operation. if ((dev.connType != 2) && (dev.state == 1) && (dev.amtstack != null)) { // Action: 2 = Power on, 8 = Power down, 10 = reset + dev.powerAction = action; try { dev.amtstack.RequestPowerStateChange(action, performPowerActionResponse); } catch (ex) { } } } @@ -845,7 +846,17 @@ module.exports.CreateAmtManager = function (parent) { // Response to Intel AMT power action function performPowerActionResponse(stack, name, responses, status) { - //console.log('performPowerActionResponse', status); + const dev = stack.dev; + const action = dev.powerAction; + delete dev.powerAction; + if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response. + if (status != 200) return; + + // If this is Intel AMT 10 or higher and we are trying to wake the device, send an OS wake. + // This will wake the device from "Modern Standby". + if ((action == 2) && (dev.aquired.majorver > 9)) { + try { dev.amtstack.RequestOSPowerStateChange(2, function (stack, name, response, status) { }); } catch (ex) { } + } } diff --git a/meshscanner.js b/meshscanner.js index 9cc465da..64b32e54 100644 --- a/meshscanner.js +++ b/meshscanner.js @@ -28,6 +28,8 @@ module.exports.CreateMeshScanner = function (parent) { const membershipIPv6 = 'FF02:0:0:0:0:0:0:FE'; obj.agentCertificateHashHex = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(parent.certificates.agent.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'hex' }).toUpperCase(); obj.error = 0; + obj.pendingOutboundPackets = []; + obj.pendingOutboundTimer = null; // Setup the multicast key if present if ((typeof obj.parent.args.localdiscovery == 'object') && (typeof obj.parent.args.localdiscovery.key == 'string') && (obj.parent.args.localdiscovery.key.length > 0)) { @@ -227,34 +229,37 @@ module.exports.CreateMeshScanner = function (parent) { } } + // Send the next packet in the pending list, stop the timer if we are done. + function sendPendingPacket() { + if (obj.pendingOutboundPackets.length == 0) { if (obj.pendingOutboundTimer != null) { clearInterval(obj.pendingOutboundTimer); obj.pendingOutboundTimer = null; } return; } + var packet = obj.pendingOutboundPackets.shift(); + if (packet != null) { packet[0].send(packet[1], 0, packet[1].length, packet[2], packet[3]); } + } + // As a side job, we also send server wake-on-lan packets obj.wakeOnLan = function (macs, host) { - var i, j; + var i, j, futureTime = 0; for (i in macs) { var mac = macs[i].split(':').join(''); var hexpacket = 'FFFFFFFFFFFF'; for (j = 0; j < 16; j++) { hexpacket += mac; } var wakepacket = Buffer.from(hexpacket, 'hex'); - //console.log(wakepacket.toString('hex')); - // Setup the wake function - const func = function wakeFunc() { + // Add all wake packets to the pending list + for (var k = 0; k < 2; k++) { for (j in obj.servers4) { - obj.servers4[j].send(wakeFunc.wakepacket, 0, wakeFunc.wakepacket.length, 7, '255.255.255.255'); - obj.servers4[j].send(wakeFunc.wakepacket, 0, wakeFunc.wakepacket.length, 16990, membershipIPv4); - if (wakeFunc.host != null) { obj.servers4[j].send(wakeFunc.wakepacket, 0, wakeFunc.wakepacket.length, 7, wakeFunc.host); } + obj.pendingOutboundPackets.push([obj.servers4[j], wakepacket, 7, '255.255.255.255']); // IPv4 Broadcast + obj.pendingOutboundPackets.push([obj.servers4[j], wakepacket, 16990, membershipIPv4]); // IPv4 Multicast + if (host != null) { obj.pendingOutboundPackets.push([obj.servers4[j], wakepacket, 7, host]); } // IPv4 Directed } for (j in obj.servers6) { - obj.servers6[j].send(wakeFunc.wakepacket, 0, wakeFunc.wakepacket.length, 16990, membershipIPv6); + obj.pendingOutboundPackets.push([obj.servers6[j], wakepacket, 16990, membershipIPv6]); // IPv6 Multicast } } - func.wakepacket = wakepacket; - func.host = host; - // Call the wake function 3 times with small time intervals - func(); - setTimeout(func, 200); - setTimeout(func, 500); + // Send each packet at 10ms interval + // This packet spacing is absolutly required, otherwise the outbound buffer gets filled up and packets get lost which often causes the machine not to wake. + if (obj.pendingOutboundTimer == null) { obj.pendingOutboundTimer = setInterval(sendPendingPacket, 10); } } };