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 */