david/ipxe
david
/
ipxe
Archived
1
0
Fork 0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/contrib/wakeonlan/wol.c

375 lines
11 KiB
C

/*****************************************************************************
*
* wol.c - Wake-On-LAN utility to wake a networked PC
*
* by R. Edwards (bob@cs.anu.edu.au), January 2000
* (in_ether routine adapted from net-tools-1.51/lib/ether.c by
* Fred N. van Kempen)
* added file input, some minor changes for compiling for NetWare
* added switches -q and -d=<ms>, added Win32 target support
* by G. Knauf (gk@gknw.de), 30-Jan-2001
* added switches -b=<bcast> and -p=<port>
* by G. Knauf (gk@gknw.de), 10-Okt-2001
* added OS/2 target support
* by G. Knauf (gk@gknw.de), 24-May-2002
*
* This utility allows a PC with WOL configured to be powered on by
* sending a "Magic Packet" to it's network adaptor (see:
* http://www.amd.com/products/npd/overview/20212.html).
* Only the ethernet dest address needs to be given to make this work.
* Current version uses a UDP broadcast to send out the Magic Packet.
*
* compile with: gcc -Wall -o wol wol.c
* with Solaris: (g)cc -o wol wol.c -lsocket -lnsl
* with MingW32: gcc -Wall -o wol wol.c -lwsock32
*
* usage: wol <dest address>
* where <dest address> is in [ddd.ddd.ddd.ddd-]xx:xx:xx:xx:xx:xx format.
* or: wol [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<File name>
* where <File name> is a file containing one dest address per line,
* optional followed by a hostname or ip separated by a blank.
* -b sets optional broadcast address, -p sets optional port,
* -q supresses output, -d=<ms> delays ms milliseconds between sending.
*
* Released under GNU Public License January, 2000.
*/
#define VERSION "1.12.2 (c) G.Knauf http://www.gknw.de/"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WATTCP
#define strncasecmp strnicmp
#include <ctype.h>
#include <dos.h>
#include <tcp.h>
#else
#ifdef WIN32 /* Win32 platform */
#define USE_WINSOCKAPI
#define delay Sleep
#if (defined(__LCC__) || defined(__BORLANDC__))
#define strncasecmp strnicmp
#else
#define strncasecmp _strnicmp
#endif
#elif defined(N_PLAT_NLM) /* NetWare platform */
#ifdef __NOVELL_LIBC__
#include <ctype.h>
#else
extern int isdigit(int c); /* no ctype.h for NW3.x */
#include <nwthread.h>
#define strncasecmp strnicmp
#endif
#elif defined(__OS2__) /* OS/2 platform */
#ifdef __EMX__
#define strncasecmp strnicmp
#endif
extern int DosSleep(long t);
#define delay DosSleep
#else /* all other platforms */
#define delay(t) usleep(t*1000)
#endif
#ifndef N_PLAT_NLM /* ! NetWare platform */
#include <ctype.h>
#endif
#ifndef WIN32 /* ! Win32 platform */
#include <unistd.h>
#endif
#ifdef USE_WINSOCKAPI /* Winsock2 platforms */
#ifdef N_PLAT_NLM /* NetWare platform */
#include <ws2nlm.h>
#else
#include <winsock.h>
#endif
#define close(s) { \
closesocket(s); \
WSACleanup(); \
}
#else /* Socket platforms */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#if defined(__OS2__) && !defined(__EMX__)
#include <utils.h>
#else
#include <arpa/inet.h>
#endif
#endif
#endif
static int read_file (char *destfile);
static int in_ether (char *bufp, unsigned char *addr);
static int send_wol (char *dest, char *host);
char *progname;
int quiet = 0;
int twait = 0;
unsigned int port = 60000;
unsigned long bcast = 0xffffffff;
int main (int argc, char *argv[]) {
int cmdindx = 0;
progname = argv[0];
if (argc > 1) {
/* parse input parameters */
for (argc--, argv++; *argv; argc--, argv++) {
char *bp;
char *ep;
if (strncasecmp (*argv, "-", 1) == 0) {
if (strncasecmp (*argv, "-F=", 3) == 0) {
bp = *argv + 3;
read_file (bp);
} else if (strncasecmp (*argv, "-B=", 3) == 0) {
bp = *argv + 3;
bcast = inet_addr(bp);
if (bcast == -1) {
fprintf (stderr, "%s: expected address argument at %s\n", progname, *argv);
exit (1);
}
} else if (strncasecmp (*argv, "-D=", 3) == 0) {
bp = *argv + 3;
twait = strtol (bp, &ep, 0);
if (ep == bp || *ep != '\0') {
fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv);
exit (1);
}
} else if (strncasecmp (*argv, "-P=", 3) == 0) {
bp = *argv + 3;
port = strtol (bp, &ep, 0);
if (ep == bp || *ep != '\0') {
fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv);
exit (1);
}
} else if (strncasecmp (*argv, "-Q", 2) == 0) {
quiet = 1;
} else if (strncasecmp (*argv, "-V", 2) == 0) {
fprintf (stderr, "\r%s Version %s\n", progname, VERSION);
exit (0);
} else {
fprintf (stderr, "\r%s: invalid or unknown option %s\n", progname, *argv);
exit (1);
}
} else {
send_wol (*argv, "");
}
cmdindx++;
}
return (0);
} else {
/* No arguments given -> usage message */
fprintf (stderr, "\rUsage: %s [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<file> | <dest>\n", progname);
fprintf (stderr, " need at least hardware address or file option\n");
return (-1);
}
}
static int in_ether (char *bufp, unsigned char *addr) {
char c, *orig;
int i;
unsigned char *ptr = addr;
unsigned val;
i = 0;
orig = bufp;
while ((*bufp != '\0') && (i < 6)) {
val = 0;
c = *bufp++;
if (isdigit(c))
val = c - '0';
else if (c >= 'a' && c <= 'f')
val = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
val = c - 'A' + 10;
else {
#ifdef DEBUG
fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig);
#endif
errno = EINVAL;
return (-1);
}
val <<= 4;
c = *bufp;
if (isdigit(c))
val |= c - '0';
else if (c >= 'a' && c <= 'f')
val |= c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
val |= c - 'A' + 10;
else if (c == ':' || c == 0)
val >>= 4;
else {
#ifdef DEBUG
fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig);
#endif
errno = EINVAL;
return (-1);
}
if (c != 0)
bufp++;
*ptr++ = (unsigned char) (val & 0377);
i++;
/* We might get a semicolon here - not required. */
if (*bufp == ':') {
if (i == 6) {
; /* nothing */
}
bufp++;
}
}
if (bufp - orig != 17) {
return (-1);
} else {
return (0);
}
} /* in_ether */
static int read_file (char *destfile) {
FILE *pfile = NULL;
char dest[64];
char host[32];
char buffer[512];
pfile = fopen (destfile, "r+");
if (pfile) {
while (fgets (buffer, 511, pfile) != NULL) {
if (buffer[0] != '#' && buffer[0] != ';') {
dest[0] = host[0] = '\0';
sscanf (buffer, "%s %s", dest, host);
send_wol (dest, host);
}
}
fclose (pfile);
return (0);
} else {
fprintf (stderr, "\r%s: destfile '%s' not found\n", progname, destfile);
return (-1);
}
}
static int send_wol (char *dest, char *host) {
int i, j;
int packet;
struct sockaddr_in sap;
unsigned char ethaddr[8];
unsigned char *ptr;
unsigned char buf [128];
unsigned long bc;
char mask[32];
char *tmp;
#ifdef USE_WINSOCKAPI
WORD wVersionRequested;
WSADATA wsaData;
int err;
#endif
#ifdef WATTCP
static udp_Socket sock;
udp_Socket *s;
#else
int optval = 1;
#endif
/* Fetch the broascast address if present. */
if ((tmp = strstr(dest,"-"))) {
printf("found: %s\n", tmp);
tmp[0] = 32;
sscanf (dest, "%s %s", mask, dest);
bc = inet_addr(mask);
printf("bc: string %s address %08lX\n", mask, bc);
if (bc == -1) {
fprintf (stderr, "\r%s: expected address argument at %s\n", progname, mask);
return (-1);
}
} else
bc = bcast;
/* Fetch the hardware address. */
if (in_ether (dest, ethaddr) < 0) {
fprintf (stderr, "\r%s: invalid hardware address\n", progname);
return (-1);
}
#ifdef USE_WINSOCKAPI
/* I would like to have Socket Vers. 1.1 */
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup (wVersionRequested, &wsaData);
if (err != 0) {
fprintf (stderr, "\r%s: couldn't init Winsock Version 1.1\n", progname);
WSACleanup ();
return (-1);
}
#endif
/* setup the packet socket */
#ifdef WATTCP
sock_init();
s = &sock;
if (!udp_open( s, 0, bc, port, NULL )) {
#else
if ((packet = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
#endif
fprintf (stderr, "\r%s: socket failed\n", progname);
#ifdef USE_WINSOCKAPI
WSACleanup ();
#endif
return (-1);
}
#ifndef WATTCP
/* Set socket options */
if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof (optval)) < 0) {
fprintf (stderr, "\r%s: setsocket failed %s\n", progname, strerror (errno));
close (packet);
return (-1);
}
/* Set up broadcast address */
sap.sin_family = AF_INET;
sap.sin_addr.s_addr = bc; /* broadcast address */
sap.sin_port = htons(port);
#endif
/* Build the message to send - 6 x 0xff then 16 x dest address */
ptr = buf;
for (i = 0; i < 6; i++)
*ptr++ = 0xff;
for (j = 0; j < 16; j++)
for (i = 0; i < 6; i++)
*ptr++ = ethaddr [i];
/* Send the packet out */
#ifdef WATTCP
sock_write( s, buf, 102 );
sock_close( s );
#else
if (sendto (packet, (char *)buf, 102, 0, (struct sockaddr *)&sap, sizeof (sap)) < 0) {
fprintf (stderr, "\r%s: sendto failed, %s\n", progname, strerror(errno));
close (packet);
return (-1);
}
close (packet);
#endif
if (!quiet) fprintf (stderr, "\r%s: packet sent to %04X:%08lX-%s %s\n",
progname, port, (unsigned long)htonl(bc), dest, host);
if (twait > 0 ) {
delay (twait);
}
return (0);
}