summaryrefslogtreecommitdiffstats
path: root/contrib/wakeonlan/wol.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wakeonlan/wol.c')
-rw-r--r--contrib/wakeonlan/wol.c374
1 files changed, 374 insertions, 0 deletions
diff --git a/contrib/wakeonlan/wol.c b/contrib/wakeonlan/wol.c
new file mode 100644
index 00000000..07b7e4fc
--- /dev/null
+++ b/contrib/wakeonlan/wol.c
@@ -0,0 +1,374 @@
+/*****************************************************************************
+ *
+ * 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);
+}
+