Skip to content

Commit

Permalink
net: Add new wol command - Wake on LAN
Browse files Browse the repository at this point in the history
Add a new command 'wol': Wait for an incoming Wake-on-LAN packet or
time out if no WoL packed is received.
If the WoL packet contains a password, it is saved in the environment
variable 'wolpassword' using the etherwake format (dot or colon
separated decimals).

Intended use case: a networked device should boot an alternate image.
It's attached to a network on a client site, modifying the DHCP server
configuration or setup of a tftp server is not allowed.
After power on the device waits a few seconds for a WoL packet. If a
packet is received, the device boots the alternate image. Otherwise
it boots the default image.

This method is a simple way to interact with a system via network even
if only the MAC address is known. Tools to send WoL packets are
available on all common platforms.

Some Ethernet drivers seem to pad the incoming packet. The additional
padding bytes might be recognized as Wake-on-LAN password bytes.

By default enabled in pengwyn_defconfig.

Signed-off-by: Lothar Felten <[email protected]>
Acked-by: Joe Hershberger <[email protected]>
  • Loading branch information
lfelten authored and jhershbe committed Jul 2, 2018
1 parent 318b5d7 commit d8970da
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 1 deletion.
5 changes: 5 additions & 0 deletions cmd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1239,6 +1239,11 @@ config CMD_PXE
help
Boot image via network using PXE protocol

config CMD_WOL
bool "wol"
help
Wait for wake-on-lan Magic Packet

endif

menu "Misc commands"
Expand Down
1 change: 1 addition & 0 deletions cmd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ obj-$(CONFIG_CMD_PCI) += pci.o
endif
obj-y += pcmcia.o
obj-$(CONFIG_CMD_PXE) += pxe.o
obj-$(CONFIG_CMD_WOL) += wol.o
obj-$(CONFIG_CMD_QFW) += qfw.o
obj-$(CONFIG_CMD_READ) += read.o
obj-$(CONFIG_CMD_REGINFO) += reginfo.o
Expand Down
33 changes: 33 additions & 0 deletions cmd/wol.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2018
* Lothar Felte, [email protected]
*/

/*
* Wake-on-LAN support
*/
#include <common.h>
#include <command.h>
#include <net.h>

#if defined(CONFIG_CMD_WOL)
void wol_set_timeout(ulong);

int do_wol(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
/* Validate arguments */
if (argc < 2)
return CMD_RET_USAGE;
wol_set_timeout(simple_strtol(argv[1], NULL, 10) * 1000);
if (net_loop(WOL) < 0)
return CMD_RET_FAILURE;
return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
wol, 2, 1, do_wol,
"wait for an incoming wake-on-lan packet",
"Timeout"
);
#endif
1 change: 1 addition & 0 deletions configs/pengwyn_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ CONFIG_CMD_MMC=y
CONFIG_CMD_NAND=y
CONFIG_CMD_SPI=y
CONFIG_CMD_USB=y
CONFIG_CMD_WOL=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_MTDPARTS=y
Expand Down
3 changes: 2 additions & 1 deletion include/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ struct vlan_ethernet_hdr {

#define PROT_IP 0x0800 /* IP protocol */
#define PROT_ARP 0x0806 /* IP ARP protocol */
#define PROT_WOL 0x0842 /* ether-wake WoL protocol */
#define PROT_RARP 0x8035 /* IP ARP protocol */
#define PROT_VLAN 0x8100 /* IEEE 802.1q protocol */
#define PROT_IPV6 0x86dd /* IPv6 over bluebook */
Expand Down Expand Up @@ -535,7 +536,7 @@ extern int net_restart_wrap; /* Tried all network devices */

enum proto_t {
BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT
TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL
};

extern char net_boot_file_name[1024];/* Boot File name */
Expand Down
1 change: 1 addition & 0 deletions net/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ obj-$(CONFIG_CMD_RARP) += rarp.o
obj-$(CONFIG_CMD_SNTP) += sntp.o
obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fastboot.o
obj-$(CONFIG_CMD_WOL) += wol.o

# Disable this warning as it is triggered by:
# sprintf(buf, index ? "foo%d" : "foo", index)
Expand Down
19 changes: 19 additions & 0 deletions net/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@
* - own IP address
* We want: - network time
* Next step: none
*
* WOL:
*
* Prerequisites: - own ethernet address
* We want: - magic packet or timeout
* Next step: none
*/


Expand Down Expand Up @@ -108,6 +114,9 @@
#if defined(CONFIG_CMD_SNTP)
#include "sntp.h"
#endif
#if defined(CONFIG_CMD_WOL)
#include "wol.h"
#endif

/** BOOTP EXTENTIONS **/

Expand Down Expand Up @@ -514,6 +523,11 @@ int net_loop(enum proto_t protocol)
case LINKLOCAL:
link_local_start();
break;
#endif
#if defined(CONFIG_CMD_WOL)
case WOL:
wol_start();
break;
#endif
default:
break;
Expand Down Expand Up @@ -1281,6 +1295,11 @@ void net_process_received_packet(uchar *in_packet, int len)
ntohs(ip->udp_src),
ntohs(ip->udp_len) - UDP_HDR_SIZE);
break;
#ifdef CONFIG_CMD_WOL
case PROT_WOL:
wol_receive(ip, len);
break;
#endif
}
}

Expand Down
96 changes: 96 additions & 0 deletions net/wol.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2018 Lothar Felten, [email protected]
*/

#include <common.h>
#include <command.h>
#include <net.h>
#include <environment.h>
#include "wol.h"

static ulong wol_timeout = WOL_DEFAULT_TIMEOUT;

/*
* Check incoming Wake-on-LAN packet for:
* - sync bytes
* - sixteen copies of the target MAC address
*
* @param wol Wake-on-LAN packet
* @param len Packet length
*/
static int wol_check_magic(struct wol_hdr *wol, unsigned int len)
{
int i;

if (len < sizeof(struct wol_hdr))
return 0;

for (i = 0; i < WOL_SYNC_COUNT; i++)
if (wol->wol_sync[i] != WOL_SYNC_BYTE)
return 0;

for (i = 0; i < WOL_MAC_REPETITIONS; i++)
if (memcmp(&wol->wol_dest[i * ARP_HLEN],
net_ethaddr, ARP_HLEN) != 0)
return 0;

return 1;
}

void wol_receive(struct ip_udp_hdr *ip, unsigned int len)
{
struct wol_hdr *wol;

wol = (struct wol_hdr *)ip;

if (!wol_check_magic(wol, len))
return;

/* save the optional password using the ether-wake formats */
/* don't check for exact length, the packet might have padding */
if (len >= (sizeof(struct wol_hdr) + WOL_PASSWORD_6B)) {
eth_env_set_enetaddr("wolpassword", wol->wol_passwd);
} else if (len >= (sizeof(struct wol_hdr) + WOL_PASSWORD_4B)) {
char buffer[16];
struct in_addr *ip = (struct in_addr *)(wol->wol_passwd);

ip_to_string(*ip, buffer);
env_set("wolpassword", buffer);
}
net_set_state(NETLOOP_SUCCESS);
}

static void wol_udp_handler(uchar *pkt, unsigned int dest, struct in_addr sip,
unsigned int src, unsigned int len)
{
struct wol_hdr *wol;

wol = (struct wol_hdr *)pkt;

/* UDP destination port must be 0, 7 or 9 */
if (dest != 0 && dest != 7 && dest != 9)
return;

if (!wol_check_magic(wol, len))
return;

net_set_state(NETLOOP_SUCCESS);
}

void wol_set_timeout(ulong timeout)
{
wol_timeout = timeout;
}

static void wol_timeout_handler(void)
{
eth_halt();
net_set_state(NETLOOP_FAIL);
}

void wol_start(void)
{
net_set_timeout_handler(wol_timeout, wol_timeout_handler);
net_set_udp_handler(wol_udp_handler);
}
65 changes: 65 additions & 0 deletions net/wol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* wol - Wake-on-LAN
*
* Supports both Wake-on-LAN packet types:
* - EtherType 0x0842 packets
* - UDP packets on ports 0, 7 and 9.
*
* Copyright 2018 Lothar Felten, [email protected]
*/

#if defined(CONFIG_CMD_WOL)

#ifndef __WOL_H__
#define __WOL_H__

#include <net.h>

/**********************************************************************/

#define WOL_SYNC_BYTE 0xFF
#define WOL_SYNC_COUNT 6
#define WOL_MAC_REPETITIONS 16
#define WOL_DEFAULT_TIMEOUT 5000
#define WOL_PASSWORD_4B 4
#define WOL_PASSWORD_6B 6

/*
* Wake-on-LAN header
*/
struct wol_hdr {
u8 wol_sync[WOL_SYNC_COUNT]; /* sync bytes */
u8 wol_dest[WOL_MAC_REPETITIONS * ARP_HLEN]; /* 16x MAC */
u8 wol_passwd[0]; /* optional */
};

/*
* Initialize wol (beginning of netloop)
*/
void wol_start(void);

/*
* Check incoming Wake-on-LAN packet for:
* - sync bytes
* - sixteen copies of the target MAC address
*
* Optionally store the four or six byte password in the environment
* variable "wolpassword"
*
* @param ip IP header in the packet
* @param len Packet length
*/
void wol_receive(struct ip_udp_hdr *ip, unsigned int len);

/*
* Set the timeout for the reception of a Wake-on-LAN packet
*
* @param timeout in milliseconds
*/
void wol_set_timeout(ulong timeout);

/**********************************************************************/

#endif /* __WOL_H__ */
#endif

0 comments on commit d8970da

Please sign in to comment.