c++linuxwindowswake-on-lan

Why WOL(WakeOnLan) Is Releated To Operating System?


Wikipedia says:

Wake-on-LAN (WoL) is an Ethernet or Token Ring computer networking standard that allows a computer to be turned on or awakened by a network message.

But, in another section:

Responding to the magic packet ... Most WoL hardware functionally is typically blocked by default and needs to be enabled in using the system BIOS. Further configuration from the OS is required in some cases, for example via the Device Manager network card properties on Windows operating systems.

Why? why do we need to also enable WOL in OS?

The Problem:

My actual problem rise when I implement a WOL program to turn on other PCs in a network(connected by LAN) from a local server. But failed, because it needs some extra configurations in the PCs:

  1. The configurations are different from OS to OS (and from version to version).
  2. Some of the configurations are not permanent and need to be done in every OS startup. (for example: in Ubuntu 16.04 I had to run ethtool -s eno1 wol g).

Is there any way to bypass the OS configurations and only enable WOL from BIOS settings? Or it's the code problem?

WOL Example:

#include <QByteArray>
#include <QDebug>
#include <QUdpSocket>

#include <thread>

auto sendMagicPacket(QString const& ip, QString const& mac)
{
  std::pair<bool, QString> result = {true, ""};
  ///
  /// \note Constants are from
  /// https://en.wikipedia.org/wiki/Wake-on-LAN#Magic_packet
  ///
  constexpr auto magicPacketLength = 102;
  constexpr auto payloadLength = 6;
  constexpr auto payloadValue = static_cast<char>(0xFF);
  constexpr auto defaultPort = 9; // Could be 0, 7, 9
  char toSend[magicPacketLength];

  for (int i = 0; i < payloadLength; ++i)
  {
    toSend[i] = payloadValue;
  }

  auto const macSplited = mac.split(':');
  auto const macLength = macSplited.size();

  for (int j = payloadLength; j < magicPacketLength; j += macLength)
  {
    for (int i = 0; i < macLength; ++i)
    {
      toSend[i + j] = static_cast<char>(macSplited[i].toUInt(nullptr, 16));
    }
  }

  QUdpSocket socket;
  auto const writtenSize =
          socket.writeDatagram(toSend, magicPacketLength, QHostAddress(ip), defaultPort);

  if (writtenSize != magicPacketLength)
  {
    result = {false, "writtenSize(" + QString::number(writtenSize) +
              ") != magicPacketLength(" +
              QString::number(magicPacketLength) +
              "): " + socket.errorString()
             };
  }

  return result;
}

int main()
{
  for (int i = 0; i < 5; ++i)
  {
    auto const result = sendMagicPacket("192.168.11.31", "1c:1c:1e:1f:19:15");

    if (not result.first)
    {
      qDebug() << result.second;
    }

    std::this_thread::sleep_for(std::chrono::seconds(1));
  }
}

Solution

  • The OS is involved only to the extent that there's not a standardized way to enable WoL for all hardware. Therefore, you typically need a device driver for the specific hardware to be able to enable the hardware's capability. Loading the OS usually gives you such a device driver.

    Running ethtool every startup should be fairly trivial, especially since (at last if memory serves) running it twice (or more) should be harmless, so you can add it to (for one example) your .bashrc. If you need to ensure it really only happens once when you start up, instead of every time you login, you can add an init script to do that. man init-d-script should get you going pretty easily.

    You have to enable it because most BIOSes leave it disabled by default, so unless you enable it, it won't work.

    As to why the disable it by default: less certain, but my guess is that it's simply because most people don't use it.