summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/Makefile1
-rw-r--r--net/net.c19
-rw-r--r--net/wol.c96
-rw-r--r--net/wol.h65
4 files changed, 181 insertions, 0 deletions
diff --git a/net/Makefile b/net/Makefile
index 07466879f5..ce36362168 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -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)
diff --git a/net/net.c b/net/net.c
index b4563a4cab..084269e31e 100644
--- a/net/net.c
+++ b/net/net.c
@@ -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
*/
@@ -108,6 +114,9 @@
#if defined(CONFIG_CMD_SNTP)
#include "sntp.h"
#endif
+#if defined(CONFIG_CMD_WOL)
+#include "wol.h"
+#endif
/** BOOTP EXTENTIONS **/
@@ -515,6 +524,11 @@ restart:
link_local_start();
break;
#endif
+#if defined(CONFIG_CMD_WOL)
+ case WOL:
+ wol_start();
+ break;
+#endif
default:
break;
}
@@ -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
}
}
diff --git a/net/wol.c b/net/wol.c
new file mode 100644
index 0000000000..946bd91b47
--- /dev/null
+++ b/net/wol.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Lothar Felten, lothar.felten@gmail.com
+ */
+
+#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);
+}
diff --git a/net/wol.h b/net/wol.h
new file mode 100644
index 0000000000..ebc81f24b6
--- /dev/null
+++ b/net/wol.h
@@ -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, lothar.felten@gmail.com
+ */
+
+#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