diff options
Diffstat (limited to 'contrib/wakeonlan/wol.c')
-rw-r--r-- | contrib/wakeonlan/wol.c | 452 |
1 files changed, 93 insertions, 359 deletions
diff --git a/contrib/wakeonlan/wol.c b/contrib/wakeonlan/wol.c index 07b7e4fc3..40a8415a0 100644 --- a/contrib/wakeonlan/wol.c +++ b/contrib/wakeonlan/wol.c @@ -1,374 +1,108 @@ -/***************************************************************************** +/* + * Copyright (C) 2008 William Stewart. * - * wol.c - Wake-On-LAN utility to wake a networked PC + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. * - * 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 program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. * - * 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#define VERSION "1.12.2 (c) G.Knauf http://www.gknw.de/" - -#include <errno.h> #include <stdio.h> +#include <stdint.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+"); +#include <errno.h> +#include <byteswap.h> +#include <gpxe/features.h> +#include <gpxe/netdevice.h> +#include <gpxe/if_ether.h> +#include <gpxe/iobuf.h> +#include <usr/ifmgmt.h> +#include <usr/wol.h> +#include <timer.h> + +/** @file + * + * Wake on lan + * + */ - 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); - } +/** + * Boot from a network device + * + * @v netdev Network device + * @ret rc Return status code + */ +#define WOL_MSG_LEN (6 + 16*6) + +void wakeup_server(char *server_adr) +{ + int rc, i,j; + unsigned char *buf; + uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + unsigned int len; + struct io_buffer *iobuf; + struct ethhdr *ethhdr; + struct net_device *netdev; + + for_each_netdev ( netdev ) { + break; + } + + if (netdev == NULL) + { + printf("Could not find netdev\n"); + return; } - 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); - } + + /* Open device and display device status */ + if ( (ifopen ( netdev ) ) != 0 ) + { + printf("Could not open netdev\n"); + return; + } + + /* Create outgoing I/O buffer */ + iobuf = alloc_iob ((ETH_HLEN + WOL_MSG_LEN)*2); + if (!iobuf) + { + printf("Could not allocate iob\n"); + return; + } + + ethhdr = iob_put(iobuf, sizeof(*ethhdr)); + + /* Build Ethernet header */ + memcpy (ethhdr->h_dest, eth_broadcast, ETH_ALEN ); + memcpy (ethhdr->h_source, netdev->ll_addr, ETH_ALEN ); + ethhdr->h_protocol = htons (0x0842); + + buf = iob_put (iobuf, WOL_MSG_LEN); + + /* Build the message to send - 6 x 0xff then 16 x dest address */ + len =0; + for (i = 0; i < 6; i++) + buf[len++] = 0xff; + for (j = 0; j < 16; j++) + for (i = 0; i < 6; i++) + buf[len++] = server_adr[i]; -#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); - } + rc = netdev_tx (netdev, iobuf); - /* Set up broadcast address */ - sap.sin_family = AF_INET; - sap.sin_addr.s_addr = bc; /* broadcast address */ - sap.sin_port = htons(port); -#endif + if (rc !=0) + printf("Failed to transmit WOL packet\n"); - /* 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]; + /* Give the controller a chance to send it before checking */ + mdelay(100); - /* 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); + netdev_poll(netdev); } |