1 /* ether-wake.c: Send a magic packet to wake up sleeping machines. */
3 static char version_msg
[] =
4 "ether-wake.c: v1.09 11/12/2003 Donald Becker, http://www.scyld.com/";
5 static char brief_usage_msg
[] =
6 "usage: ether-wake [-i <ifname>] [-p aa:bb:cc:dd[:ee:ff]] 00:11:22:33:44:55\n"
7 " Use '-u' to see the complete set of options.\n";
8 static char usage_msg
[] =
9 "usage: ether-wake [-i <ifname>] [-p aa:bb:cc:dd[:ee:ff]] 00:11:22:33:44:55\n"
11 " This program generates and transmits a Wake-On-LAN (WOL)\n"
12 " \"Magic Packet\", used for restarting machines that have been\n"
13 " soft-powered-down (ACPI D3-warm state).\n"
14 " It currently generates the standard AMD Magic Packet format, with\n"
15 " an optional password appended.\n"
17 " The single required parameter is the Ethernet MAC (station) address\n"
18 " of the machine to wake or a host ID with known NSS 'ethers' entry.\n"
19 " The MAC address may be found with the 'arp' program while the target\n"
20 " machine is awake.\n"
23 " -b Send wake-up packet to the broadcast address.\n"
24 " -D Increase the debug level.\n"
25 " -i ifname Use interface IFNAME instead of the default 'eth0'.\n"
26 " -p <pw> Append the four or six byte password PW to the packet.\n"
27 " A password is only required for a few adapter types.\n"
28 " The password may be specified in ethernet hex format\n"
29 " or dotted decimal (Internet address)\n"
30 " -p 00:22:44:66:88:aa\n"
34 This program generates and transmits a Wake-On-LAN (WOL) "Magic Packet",
35 used for restarting machines that have been soft-powered-down
36 (ACPI D3-warm state). It currently generates the standard AMD Magic Packet
37 format, with an optional password appended.
39 This software may be used and distributed according to the terms
40 of the GNU Public License, incorporated herein by reference.
41 Contact the author for use under other terms.
43 This source file was originally part of the network tricks package, and
44 is now distributed to support the Scyld Beowulf system.
45 Copyright 1999-2003 Donald Becker and Scyld Computing Corporation.
47 The author may be reached as becker@scyld, or C/O
48 Scyld Computing Corporation
49 914 Bay Ridge Road, Suite 220
53 On some systems dropping root capability allows the process to be
54 dumped, traced or debugged.
55 If someone traces this program, they get control of a raw socket.
56 Linux handles this safely, but beware when porting this program.
58 An alternative to needing 'root' is using a UDP broadcast socket, however
59 doing so only works with adapters configured for unicast+broadcast Rx
60 filter. That configuration consumes more power.
70 #if 0 /* Only exists on some versions. */
74 #include <sys/socket.h>
76 #include <sys/types.h>
77 #include <sys/ioctl.h>
81 #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
82 #include <netpacket/packet.h>
83 #include <net/ethernet.h>
85 #include <asm/types.h>
86 #include <linux/if_packet.h>
87 #include <linux/if_ether.h>
90 #include <netinet/ether.h>
92 /* Grrr, no consistency between include versions.
93 Enable this if setsockopt() isn't declared with your library. */
95 extern int setsockopt
__P ((int __fd
, int __level
, int __optname
,
96 __ptr_t __optval
, int __optlen
));
97 #else /* New, correct head files. */
98 #include <sys/socket.h>
101 u_char outpack
[1000];
104 u_char wol_passwd
[6];
105 int wol_passwd_sz
= 0;
107 static int opt_no_src_addr
= 0, opt_broadcast
= 0;
109 static int get_dest_addr(const char *arg
, struct ether_addr
*eaddr
);
110 static int get_fill(unsigned char *pkt
, struct ether_addr
*eaddr
);
111 static int get_wol_pw(const char *optarg
);
113 int main(int argc
, char *argv
[])
115 char *ifname
= "eth0";
116 int one
= 1; /* True, for socket options. */
117 int s
; /* Raw socket */
118 int errflag
= 0, verbose
= 0, do_version
= 0;
119 int perm_failure
= 0;
121 #if defined(PF_PACKET)
122 struct sockaddr_ll whereto
;
124 struct sockaddr whereto
; /* who to wake up */
126 struct ether_addr eaddr
;
128 while ((c
= getopt(argc
, argv
, "bDi:p:uvV")) != -1)
130 case 'b': opt_broadcast
++; break;
131 case 'D': debug
++; break;
132 case 'i': ifname
= optarg
; break;
133 case 'p': get_wol_pw(optarg
); break;
134 case 'u': printf(usage_msg
); return 0;
135 case 'v': verbose
++; break;
136 case 'V': do_version
++; break;
140 if (verbose
|| do_version
)
141 printf("%s\n", version_msg
);
143 fprintf(stderr
, brief_usage_msg
);
147 if (optind
== argc
) {
148 fprintf(stderr
, "Specify the Ethernet address as 00:11:22:33:44:55.\n");
152 /* Note: PF_INET, SOCK_DGRAM, IPPROTO_UDP would allow SIOCGIFHWADDR to
153 work as non-root, but we need SOCK_PACKET to specify the Ethernet
154 destination address. */
155 #if defined(PF_PACKET)
156 s
= socket(PF_PACKET
, SOCK_RAW
, 0);
158 s
= socket(AF_INET
, SOCK_PACKET
, SOCK_PACKET
);
162 fprintf(stderr
, "ether-wake: This program must be run as root.\n");
164 perror("ether-wake: socket");
167 /* Don't revert if debugging allows a normal user to get the raw socket. */
170 /* We look up the station address before reporting failure so that
171 errors may be reported even when run as a normal user.
173 if (get_dest_addr(argv
[optind
], &eaddr
) != 0)
175 if (perm_failure
&& ! debug
)
178 pktsize
= get_fill(outpack
, &eaddr
);
180 /* Fill in the source address, if possible.
181 The code to retrieve the local station address is Linux specific. */
182 if (! opt_no_src_addr
) {
183 struct ifreq if_hwaddr
;
184 unsigned char *hwaddr
= if_hwaddr
.ifr_hwaddr
.sa_data
;
186 strcpy(if_hwaddr
.ifr_name
, ifname
);
187 if (ioctl(s
, SIOCGIFHWADDR
, &if_hwaddr
) < 0) {
188 fprintf(stderr
, "SIOCGIFHWADDR on %s failed: %s\n", ifname
,
190 /* Magic packets still work if our source address is bogus, but
191 we fail just to be anal. */
194 memcpy(outpack
+6, if_hwaddr
.ifr_hwaddr
.sa_data
, 6);
197 printf("The hardware address (SIOCGIFHWADDR) of %s is type %d "
198 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ifname
,
199 if_hwaddr
.ifr_hwaddr
.sa_family
, hwaddr
[0], hwaddr
[1],
200 hwaddr
[2], hwaddr
[3], hwaddr
[4], hwaddr
[5]);
204 if (wol_passwd_sz
> 0) {
205 memcpy(outpack
+pktsize
, wol_passwd
, wol_passwd_sz
);
206 pktsize
+= wol_passwd_sz
;
210 printf("The final packet is: ");
211 for (i
= 0; i
< pktsize
; i
++)
212 printf(" %2.2x", outpack
[i
]);
216 /* This is necessary for broadcasts to work */
217 if (setsockopt(s
, SOL_SOCKET
, SO_BROADCAST
, (char *)&one
, sizeof(one
)) < 0)
218 perror("setsockopt: SO_BROADCAST");
220 #if defined(PF_PACKET)
223 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
224 if (ioctl(s
, SIOCGIFINDEX
, &ifr
) == -1) {
225 fprintf(stderr
, "SIOCGIFINDEX on %s failed: %s\n", ifname
,
229 memset(&whereto
, 0, sizeof(whereto
));
230 whereto
.sll_family
= AF_PACKET
;
231 whereto
.sll_ifindex
= ifr
.ifr_ifindex
;
232 /* The manual page incorrectly claims the address must be filled.
233 We do so because the code may change to match the docs. */
234 whereto
.sll_halen
= ETH_ALEN
;
235 memcpy(whereto
.sll_addr
, outpack
, ETH_ALEN
);
239 whereto
.sa_family
= 0;
240 strcpy(whereto
.sa_data
, ifname
);
243 if ((i
= sendto(s
, outpack
, pktsize
, 0, (struct sockaddr
*)&whereto
,
244 sizeof(whereto
))) < 0)
247 printf("Sendto worked ! %d.\n", i
);
250 if (bind(s
, (struct sockaddr
*)&whereto
, sizeof(whereto
)) < 0)
252 else if (send(s
, outpack
, 100, 0) < 0)
257 struct msghdr msghdr
= { 0,};
258 struct iovec iovector
[1];
259 msghdr
.msg_name
= &whereto
;
260 msghdr
.msg_namelen
= sizeof(whereto
);
261 msghdr
.msg_iov
= iovector
;
262 msghdr
.msg_iovlen
= 1;
263 iovector
[0].iov_base
= outpack
;
264 iovector
[0].iov_len
= pktsize
;
265 if ((i
= sendmsg(s
, &msghdr
, 0)) < 0)
268 printf("sendmsg worked, %d (%d).\n", i
, errno
);
275 /* Convert the host ID string to a MAC address.
282 static int get_dest_addr(const char *hostid
, struct ether_addr
*eaddr
)
284 struct ether_addr
*eap
;
286 eap
= ether_aton(hostid
);
290 fprintf(stderr
, "The target station address is %s.\n",
292 } else if (ether_hostton(hostid
, eaddr
) == 0) {
294 fprintf(stderr
, "Station address for hostname %s is %s.\n",
295 hostid
, ether_ntoa(eaddr
));
297 (void)fprintf(stderr
,
298 "ether-wake: The Magic Packet host address must be "
300 " - a station address, 00:11:22:33:44:55, or\n"
301 " - a hostname with a known 'ethers' entry.\n");
308 static int get_fill(unsigned char *pkt
, struct ether_addr
*eaddr
)
311 unsigned char *station_addr
= eaddr
->ether_addr_octet
;
314 memset(pkt
+0, 0xff, 6);
316 memcpy(pkt
, station_addr
, 6);
317 memcpy(pkt
+6, station_addr
, 6);
318 pkt
[12] = 0x08; /* Or 0x0806 for ARP, 0x8035 for RARP */
322 memset(pkt
+offset
, 0xff, 6);
325 for (i
= 0; i
< 16; i
++) {
326 memcpy(pkt
+offset
, station_addr
, 6);
330 fprintf(stderr
, "Packet is ");
331 for (i
= 0; i
< offset
; i
++)
332 fprintf(stderr
, " %2.2x", pkt
[i
]);
333 fprintf(stderr
, ".\n");
338 static int get_wol_pw(const char *optarg
)
344 byte_cnt
= sscanf(optarg
, "%2x:%2x:%2x:%2x:%2x:%2x",
345 &passwd
[0], &passwd
[1], &passwd
[2],
346 &passwd
[3], &passwd
[4], &passwd
[5]);
348 byte_cnt
= sscanf(optarg
, "%d.%d.%d.%d",
349 &passwd
[0], &passwd
[1], &passwd
[2], &passwd
[3]);
351 fprintf(stderr
, "Unable to read the Wake-On-LAN password.\n");
354 printf(" The Magic packet password is %2.2x %2.2x %2.2x %2.2x (%d).\n",
355 passwd
[0], passwd
[1], passwd
[2], passwd
[3], byte_cnt
);
356 for (i
= 0; i
< byte_cnt
; i
++)
357 wol_passwd
[i
] = passwd
[i
];
358 return wol_passwd_sz
= byte_cnt
;
363 to
= (struct sockaddr_in
*)&whereto
;
364 to
->sin_family
= AF_INET
;
365 if (inet_aton(target
, &to
->sin_addr
)) {
368 memset (&sa
, 0, sizeof sa
);
369 sa
.sa_family
= AF_INET
;
370 strncpy (sa
.sa_data
, interface
, sizeof sa
.sa_data
);
371 sendto (sock
, buf
, bufix
+ len
, 0, &sa
, sizeof sa
);
372 strncpy (sa
.sa_data
, interface
, sizeof sa
.sa_data
);
374 sendto (sock
, buf
, bufix
+ len
, 0, &sa
, sizeof sa
);
376 bind (sock
, &sa
, sizeof sa
);
378 send (sock
, buf
, bufix
+ len
, 0);
386 * compile-command: "gcc -O -Wall -o ether-wake ether-wake.c"
This page took 0.096652 seconds and 5 git commands to generate.