1195200Smbr/* 2203686Smbr * Copyright (C) 2006, 2007, 2008, 2009, 2010 Marc Balmer <marc@msys.ch> 3195200Smbr * Copyright (C) 2000 Eugene M. Kim. All rights reserved. 4195200Smbr * 5195200Smbr * Redistribution and use in source and binary forms, with or without 6195200Smbr * modification, are permitted provided that the following conditions 7195200Smbr * are met: 8195200Smbr * 9195200Smbr * 1. Redistributions of source code must retain the above copyright 10195200Smbr * notice, this list of conditions and the following disclaimer. 11195200Smbr * 2. Author's name may not be used endorse or promote products derived 12195200Smbr * from this software without specific prior written permission. 13195200Smbr * 14195200Smbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15195200Smbr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16195200Smbr * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17195200Smbr * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 18195200Smbr * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19195200Smbr * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20195200Smbr * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21195200Smbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22195200Smbr * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23195200Smbr * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24195200Smbr * POSSIBILITY OF SUCH DAMAGE. 25195200Smbr */ 26195200Smbr 27195200Smbr#include <sys/cdefs.h> 28195200Smbr__FBSDID("$FreeBSD: releng/10.3/usr.sbin/wake/wake.c 232102 2012-02-24 07:54:08Z jh $"); 29195200Smbr 30195200Smbr#include <sys/ioctl.h> 31195200Smbr#include <sys/socket.h> 32195200Smbr#include <sys/time.h> 33195200Smbr#include <net/bpf.h> 34195200Smbr#include <net/if.h> 35203686Smbr#include <net/if_dl.h> 36203686Smbr#include <net/if_types.h> 37195200Smbr#include <netinet/in.h> 38195200Smbr#include <netinet/if_ether.h> 39195200Smbr 40195264Sstas#include <err.h> 41195264Sstas#include <fcntl.h> 42203686Smbr#include <ifaddrs.h> 43195264Sstas#include <stdio.h> 44195264Sstas#include <stdlib.h> 45195264Sstas#include <string.h> 46195264Sstas#include <unistd.h> 47195264Sstas 48195237Sstas#define _PATH_BPF "/dev/bpf" 49195200Smbr 50195200Smbr#ifndef SYNC_LEN 51195237Sstas#define SYNC_LEN 6 52195200Smbr#endif 53195200Smbr 54195200Smbr#ifndef DESTADDR_COUNT 55195237Sstas#define DESTADDR_COUNT 16 56195200Smbr#endif 57195200Smbr 58195237Sstasstatic int bind_if_to_bpf(char const *ifname, int bpf); 59203686Smbrstatic int find_ether(char *dst, size_t len); 60195237Sstasstatic int get_ether(char const *text, struct ether_addr *addr); 61195237Sstasstatic int send_wakeup(int bpf, struct ether_addr const *addr); 62195264Sstasstatic void usage(void); 63203686Smbrstatic int wake(int bpf, const char *host); 64195200Smbr 65195237Sstasstatic void 66195200Smbrusage(void) 67195200Smbr{ 68195237Sstas 69203686Smbr (void)fprintf(stderr, "usage: wake [interface] lladdr [lladdr ...]\n"); 70195264Sstas exit(1); 71195200Smbr} 72195200Smbr 73195237Sstasstatic int 74203686Smbrwake(int bpf, const char *host) 75195200Smbr{ 76195200Smbr struct ether_addr macaddr; 77195200Smbr 78203686Smbr if (get_ether(host, &macaddr) == -1) 79195237Sstas return (-1); 80203686Smbr 81232101Sjh return (send_wakeup(bpf, &macaddr)); 82195200Smbr} 83195200Smbr 84195237Sstasstatic int 85195200Smbrbind_if_to_bpf(char const *ifname, int bpf) 86195200Smbr{ 87195200Smbr struct ifreq ifr; 88195200Smbr u_int dlt; 89195200Smbr 90195200Smbr if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= 91203686Smbr sizeof(ifr.ifr_name)) 92195237Sstas return (-1); 93203686Smbr 94203686Smbr if (ioctl(bpf, BIOCSETIF, &ifr) == -1) 95195237Sstas return (-1); 96203686Smbr 97203686Smbr if (ioctl(bpf, BIOCGDLT, &dlt) == -1) 98195237Sstas return (-1); 99203686Smbr 100203686Smbr if (dlt != DLT_EN10MB) 101195237Sstas return (-1); 102203686Smbr 103195237Sstas return (0); 104195200Smbr} 105195200Smbr 106195237Sstasstatic int 107203686Smbrfind_ether(char *dst, size_t len) 108203686Smbr{ 109203686Smbr struct ifaddrs *ifap, *ifa; 110203686Smbr struct sockaddr_dl *sdl = NULL; 111203686Smbr int nifs; 112203686Smbr 113203686Smbr if (dst == NULL || len == 0) 114232101Sjh return (0); 115203686Smbr 116203686Smbr if (getifaddrs(&ifap) != 0) 117232101Sjh return (-1); 118203686Smbr 119203686Smbr /* XXX also check the link state */ 120203686Smbr for (nifs = 0, ifa = ifap; ifa; ifa = ifa->ifa_next) 121203686Smbr if (ifa->ifa_addr->sa_family == AF_LINK && 122203686Smbr ifa->ifa_flags & IFF_UP && ifa->ifa_flags & IFF_RUNNING) { 123203686Smbr sdl = (struct sockaddr_dl *)ifa->ifa_addr; 124203686Smbr if (sdl->sdl_type == IFT_ETHER) { 125203686Smbr strlcpy(dst, ifa->ifa_name, len); 126203686Smbr nifs++; 127203686Smbr } 128203686Smbr } 129203686Smbr 130203686Smbr freeifaddrs(ifap); 131232101Sjh return (nifs == 1 ? 0 : -1); 132203686Smbr} 133203686Smbr 134203686Smbrstatic int 135195200Smbrget_ether(char const *text, struct ether_addr *addr) 136195200Smbr{ 137195200Smbr struct ether_addr *paddr; 138195200Smbr 139195200Smbr paddr = ether_aton(text); 140195200Smbr if (paddr != NULL) { 141195200Smbr *addr = *paddr; 142195237Sstas return (0); 143195200Smbr } 144195237Sstas if (ether_hostton(text, addr)) { 145195237Sstas warnx("no match for host %s found", text); 146195237Sstas return (-1); 147195237Sstas } 148195237Sstas return (0); 149195200Smbr} 150195200Smbr 151195237Sstasstatic int 152195200Smbrsend_wakeup(int bpf, struct ether_addr const *addr) 153195200Smbr{ 154195200Smbr struct { 155195200Smbr struct ether_header hdr; 156195200Smbr u_char data[SYNC_LEN + ETHER_ADDR_LEN * DESTADDR_COUNT]; 157195237Sstas } __packed pkt; 158195264Sstas u_char *p; 159195200Smbr ssize_t bw; 160195200Smbr ssize_t len; 161195237Sstas int i; 162195200Smbr 163195200Smbr (void)memset(pkt.hdr.ether_dhost, 0xff, sizeof(pkt.hdr.ether_dhost)); 164195200Smbr pkt.hdr.ether_type = htons(0); 165195200Smbr (void)memset(pkt.data, 0xff, SYNC_LEN); 166195200Smbr for (p = pkt.data + SYNC_LEN, i = 0; i < DESTADDR_COUNT; 167195200Smbr p += ETHER_ADDR_LEN, i++) 168195200Smbr bcopy(addr->octet, p, ETHER_ADDR_LEN); 169195200Smbr p = (u_char *)&pkt; 170195200Smbr len = sizeof(pkt); 171195200Smbr bw = 0; 172195200Smbr while (len) { 173195237Sstas if ((bw = write(bpf, p, len)) == -1) { 174195237Sstas warn("write()"); 175195237Sstas return (-1); 176195237Sstas } 177195200Smbr len -= bw; 178195200Smbr p += bw; 179195200Smbr } 180195237Sstas return (0); 181195200Smbr} 182195200Smbr 183195200Smbrint 184195200Smbrmain(int argc, char *argv[]) 185195200Smbr{ 186232102Sjh int bpf, n, rval; 187203686Smbr char ifname[IF_NAMESIZE]; 188195200Smbr 189203686Smbr if (argc < 2) 190195200Smbr usage(); 191195200Smbr 192203686Smbr if ((bpf = open(_PATH_BPF, O_RDWR)) == -1) 193203686Smbr err(1, "Cannot open bpf interface"); 194203686Smbr 195203686Smbr n = 2; 196203686Smbr if (bind_if_to_bpf(argv[1], bpf) == -1) { 197203686Smbr if (find_ether(ifname, sizeof(ifname))) 198203686Smbr err(1, "Failed to determine ethernet interface"); 199203686Smbr if (bind_if_to_bpf(ifname, bpf) == -1) 200203686Smbr err(1, "Cannot bind to interface `%s'", ifname); 201203686Smbr --n; 202203686Smbr } else 203203686Smbr strlcpy(ifname, argv[1], sizeof(ifname)); 204203686Smbr 205203686Smbr if (n >= argc) 206203686Smbr usage(); 207232102Sjh rval = 0; 208232102Sjh for (; n < argc; n++) { 209232102Sjh if (wake(bpf, argv[n]) != 0) { 210232102Sjh rval = 1; 211203686Smbr warn("Cannot send Wake on LAN frame over `%s' to `%s'", 212203686Smbr ifname, argv[n]); 213232102Sjh } 214232102Sjh } 215232102Sjh exit(rval); 216195200Smbr} 217