I totally forgot about demime, shame on me.. :-) Index: ifconfig.8 =================================================================== RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v retrieving revision 1.173 diff -u -r1.173 ifconfig.8 --- ifconfig.8 12 Dec 2008 22:09:26 -0000 1.173 +++ ifconfig.8 10 Feb 2009 22:50:27 -0000 @@ -412,6 +412,15 @@ It happens automatically when setting the first address on an interface. If the interface was reset when previously marked down, the hardware will be re-initialized. +.It Cm wake Ar etheraddr +Sends a Wake on LAN (WoL) frame over a local Ethernet network using a +link-layer (hardware) address. +.Ar etheraddr +is the link layer address of the remote machine +and can be specified as an actual hardware address +(six hexadecimal numbers separated by colons) +or as a hostname entry in +.Pa /etc/ethers . .El .Pp .Nm @@ -1237,6 +1246,7 @@ .Xr hostname.if 5 , .Xr hosts 5 , .Xr networks 5 , +.Xr ethers 5 , .Xr rc 8 , .Xr tcpdump 8 .Sh HISTORY Index: ifconfig.c =================================================================== RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v retrieving revision 1.211 diff -u -r1.211 ifconfig.c --- ifconfig.c 6 Feb 2009 22:07:04 -0000 1.211 +++ ifconfig.c 10 Feb 2009 22:50:28 -0000 @@ -64,6 +64,9 @@ #include <sys/socket.h> #include <sys/ioctl.h>
+#ifndef SMALL +#include <net/bpf.h> +#endif /* SMALL */ #include <net/if.h> #include <net/if_dl.h> #include <net/if_media.h> @@ -98,6 +101,9 @@ #include <ctype.h> #include <err.h> #include <errno.h> +#ifndef SMALL +#include <fcntl.h> +#endif /* SMALL */ #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -240,7 +246,22 @@ void unsetpflow_sender(const char *, int); void setpflow_receiver(const char *, int); void unsetpflow_receiver(const char *, int); + +#ifndef BPF_PATH_FORMAT +#define BPF_PATH_FORMAT "/dev/bpf%u" +#endif +#ifndef SYNC_LEN +#define SYNC_LEN 6 #endif +#ifndef DESTADDR_COUNT +#define DESTADDR_COUNT 16 +#endif +void wolhandler(const char *, int); +int get_bpf(void); +int bind_if_to_bpf(char const *, int); +int get_ether(char const *, struct ether_addr *); +int send_wakeup(int, struct ether_addr const *); +#endif /* SMALL */ /* * Media stuff. Whenever a media command is first performed, the @@ -409,7 +430,8 @@ { "-flowsrc", 1, 0, unsetpflow_sender }, { "flowdst", NEXTARG, 0, setpflow_receiver }, { "-flowdst", 1, 0, unsetpflow_receiver }, -#endif + { "wake", NEXTARG, 0, wolhandler }, +#endif /* SMALL */ { NULL, /*src*/ 0, 0, setifaddr }, { NULL, /*dst*/ 0, 0, setifdstaddr }, { NULL, /*illegal*/0, 0, NULL }, @@ -4572,3 +4594,104 @@ warn("SIOCSIFLLADDR"); } +#ifndef SMALL +void +wolhandler(const char *addr, int param) +{ + int bpf; + struct ether_addr macaddr; + + bpf = get_bpf(); + if (bpf == -1 || + bind_if_to_bpf(name, bpf) == -1 || + get_ether(addr, &macaddr) == -1 || + send_wakeup(bpf, &macaddr) == -1) { + warn("error sending Wake on LAN frame over %s to %s", + name, addr); + } + (void)close(bpf); + return; +} + +int +get_bpf(void) +{ + int i, fd; + char path[MAXPATHLEN]; + + for (i = 0;; i++) { + if (snprintf(path, sizeof(path), BPF_PATH_FORMAT, i) == -1) + return -1; + + fd = open(path, O_RDWR); + if (fd != -1) + return fd; + if (errno == EBUSY) + continue; + break; + } + return -1; +} + +int +bind_if_to_bpf(char const *ifname, int bpf) +{ + struct ifreq ifr; + u_int dlt; + + if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= + sizeof(ifr.ifr_name)) + return -1; + if (ioctl(bpf, BIOCSETIF, &ifr) == -1) + return -1; + if (ioctl(bpf, BIOCGDLT, &dlt) == -1) + return -1; + if (dlt != DLT_EN10MB) + return -1; + return 0; +} + +int +get_ether(char const *text, struct ether_addr *addr) +{ + struct ether_addr *paddr; + paddr = ether_aton(text); + if (paddr != NULL) { + *addr = *paddr; + return 0; + } + if (ether_hostton(text, addr)) + return -1; + return 0; +} + +int +send_wakeup(int bpf, struct ether_addr const *addr) +{ + struct { + struct ether_header hdr; + u_char data[SYNC_LEN + ETHER_ADDR_LEN * DESTADDR_COUNT]; + } pkt; + u_char *p; + int i; + ssize_t bw; + ssize_t len; + + (void)memset(pkt.hdr.ether_dhost, 0xff, sizeof(pkt.hdr.ether_dhost)); + pkt.hdr.ether_type = htons(0); + (void)memset(pkt.data, 0xff, SYNC_LEN); + for (p = pkt.data + SYNC_LEN, i = 0; i < DESTADDR_COUNT; + p += ETHER_ADDR_LEN, i++) + bcopy(addr->ether_addr_octet, p, ETHER_ADDR_LEN); + p = (u_char *)&pkt; + len = sizeof(pkt); + bw = 0; + while (len) { + if ((bw = write(bpf, &pkt, sizeof(pkt))) == -1) + return -1; + len -= bw; + p += bw; + } + return 0; +} +#endif /* SMALL */