xref: /openbmc/u-boot/net/wol.c (revision d4c7a9348f27c8e3fdb1b754d8f0d1fa27375d1c)
1*d8970daeSLothar Felten // SPDX-License-Identifier: GPL-2.0+
2*d8970daeSLothar Felten /*
3*d8970daeSLothar Felten  * Copyright 2018 Lothar Felten, lothar.felten@gmail.com
4*d8970daeSLothar Felten  */
5*d8970daeSLothar Felten 
6*d8970daeSLothar Felten #include <common.h>
7*d8970daeSLothar Felten #include <command.h>
8*d8970daeSLothar Felten #include <net.h>
9*d8970daeSLothar Felten #include <environment.h>
10*d8970daeSLothar Felten #include "wol.h"
11*d8970daeSLothar Felten 
12*d8970daeSLothar Felten static ulong wol_timeout = WOL_DEFAULT_TIMEOUT;
13*d8970daeSLothar Felten 
14*d8970daeSLothar Felten /*
15*d8970daeSLothar Felten  * Check incoming Wake-on-LAN packet for:
16*d8970daeSLothar Felten  * - sync bytes
17*d8970daeSLothar Felten  * - sixteen copies of the target MAC address
18*d8970daeSLothar Felten  *
19*d8970daeSLothar Felten  * @param wol Wake-on-LAN packet
20*d8970daeSLothar Felten  * @param len Packet length
21*d8970daeSLothar Felten  */
wol_check_magic(struct wol_hdr * wol,unsigned int len)22*d8970daeSLothar Felten static int wol_check_magic(struct wol_hdr *wol, unsigned int len)
23*d8970daeSLothar Felten {
24*d8970daeSLothar Felten 	int i;
25*d8970daeSLothar Felten 
26*d8970daeSLothar Felten 	if (len < sizeof(struct wol_hdr))
27*d8970daeSLothar Felten 		return 0;
28*d8970daeSLothar Felten 
29*d8970daeSLothar Felten 	for (i = 0; i < WOL_SYNC_COUNT; i++)
30*d8970daeSLothar Felten 		if (wol->wol_sync[i] != WOL_SYNC_BYTE)
31*d8970daeSLothar Felten 			return 0;
32*d8970daeSLothar Felten 
33*d8970daeSLothar Felten 	for (i = 0; i < WOL_MAC_REPETITIONS; i++)
34*d8970daeSLothar Felten 		if (memcmp(&wol->wol_dest[i * ARP_HLEN],
35*d8970daeSLothar Felten 			   net_ethaddr, ARP_HLEN) != 0)
36*d8970daeSLothar Felten 			return 0;
37*d8970daeSLothar Felten 
38*d8970daeSLothar Felten 	return 1;
39*d8970daeSLothar Felten }
40*d8970daeSLothar Felten 
wol_receive(struct ip_udp_hdr * ip,unsigned int len)41*d8970daeSLothar Felten void wol_receive(struct ip_udp_hdr *ip, unsigned int len)
42*d8970daeSLothar Felten {
43*d8970daeSLothar Felten 	struct wol_hdr *wol;
44*d8970daeSLothar Felten 
45*d8970daeSLothar Felten 	wol = (struct wol_hdr *)ip;
46*d8970daeSLothar Felten 
47*d8970daeSLothar Felten 	if (!wol_check_magic(wol, len))
48*d8970daeSLothar Felten 		return;
49*d8970daeSLothar Felten 
50*d8970daeSLothar Felten 	/* save the optional password using the ether-wake formats */
51*d8970daeSLothar Felten 	/* don't check for exact length, the packet might have padding */
52*d8970daeSLothar Felten 	if (len >= (sizeof(struct wol_hdr) + WOL_PASSWORD_6B)) {
53*d8970daeSLothar Felten 		eth_env_set_enetaddr("wolpassword", wol->wol_passwd);
54*d8970daeSLothar Felten 	} else if (len >= (sizeof(struct wol_hdr) + WOL_PASSWORD_4B)) {
55*d8970daeSLothar Felten 		char buffer[16];
56*d8970daeSLothar Felten 		struct in_addr *ip = (struct in_addr *)(wol->wol_passwd);
57*d8970daeSLothar Felten 
58*d8970daeSLothar Felten 		ip_to_string(*ip, buffer);
59*d8970daeSLothar Felten 		env_set("wolpassword", buffer);
60*d8970daeSLothar Felten 	}
61*d8970daeSLothar Felten 	net_set_state(NETLOOP_SUCCESS);
62*d8970daeSLothar Felten }
63*d8970daeSLothar Felten 
wol_udp_handler(uchar * pkt,unsigned int dest,struct in_addr sip,unsigned int src,unsigned int len)64*d8970daeSLothar Felten static void wol_udp_handler(uchar *pkt, unsigned int dest, struct in_addr sip,
65*d8970daeSLothar Felten 			    unsigned int src, unsigned int len)
66*d8970daeSLothar Felten {
67*d8970daeSLothar Felten 	struct wol_hdr *wol;
68*d8970daeSLothar Felten 
69*d8970daeSLothar Felten 	wol = (struct wol_hdr *)pkt;
70*d8970daeSLothar Felten 
71*d8970daeSLothar Felten 	/* UDP destination port must be 0, 7 or 9 */
72*d8970daeSLothar Felten 	if (dest != 0 && dest != 7 && dest != 9)
73*d8970daeSLothar Felten 		return;
74*d8970daeSLothar Felten 
75*d8970daeSLothar Felten 	if (!wol_check_magic(wol, len))
76*d8970daeSLothar Felten 		return;
77*d8970daeSLothar Felten 
78*d8970daeSLothar Felten 	net_set_state(NETLOOP_SUCCESS);
79*d8970daeSLothar Felten }
80*d8970daeSLothar Felten 
wol_set_timeout(ulong timeout)81*d8970daeSLothar Felten void wol_set_timeout(ulong timeout)
82*d8970daeSLothar Felten {
83*d8970daeSLothar Felten 	wol_timeout = timeout;
84*d8970daeSLothar Felten }
85*d8970daeSLothar Felten 
wol_timeout_handler(void)86*d8970daeSLothar Felten static void wol_timeout_handler(void)
87*d8970daeSLothar Felten {
88*d8970daeSLothar Felten 	eth_halt();
89*d8970daeSLothar Felten 	net_set_state(NETLOOP_FAIL);
90*d8970daeSLothar Felten }
91*d8970daeSLothar Felten 
wol_start(void)92*d8970daeSLothar Felten void wol_start(void)
93*d8970daeSLothar Felten {
94*d8970daeSLothar Felten 	net_set_timeout_handler(wol_timeout, wol_timeout_handler);
95*d8970daeSLothar Felten 	net_set_udp_handler(wol_udp_handler);
96*d8970daeSLothar Felten }
97