/***************************************************************************** * * 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=, added Win32 target support * by G. Knauf (gk@gknw.de), 30-Jan-2001 * added switches -b= and -p= * 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 * where is in [ddd.ddd.ddd.ddd-]xx:xx:xx:xx:xx:xx format. * or: wol [-q] [-b=] [-p=] [-d=] -f= * where 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= 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 #include #include #include #ifdef WATTCP #define strncasecmp strnicmp #include #include #include #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 #else extern int isdigit(int c); /* no ctype.h for NW3.x */ #include #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 #endif #ifndef WIN32 /* ! Win32 platform */ #include #endif #ifdef USE_WINSOCKAPI /* Winsock2 platforms */ #ifdef N_PLAT_NLM /* NetWare platform */ #include #else #include #endif #define close(s) { \ closesocket(s); \ WSACleanup(); \ } #else /* Socket platforms */ #include #include #include #if defined(__OS2__) && !defined(__EMX__) #include #else #include #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=] [-p=] [-d=] -f= | \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); }