]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/wake/wake.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / usr.sbin / wake / wake.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Marc Balmer <marc@msys.ch>
5  * Copyright (C) 2000 Eugene M. Kim.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Author's name may not be used endorse or promote products derived
14  *    from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/ioctl.h>
33 #include <sys/socket.h>
34 #include <sys/time.h>
35 #include <net/bpf.h>
36 #include <net/if.h>
37 #include <net/if_dl.h>
38 #include <net/if_types.h>
39 #include <netinet/in.h>
40 #include <netinet/if_ether.h>
41
42 #include <err.h>
43 #include <fcntl.h>
44 #include <ifaddrs.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 #define _PATH_BPF       "/dev/bpf"
51
52 #ifndef SYNC_LEN
53 #define SYNC_LEN        6
54 #endif
55
56 #ifndef DESTADDR_COUNT
57 #define DESTADDR_COUNT  16
58 #endif
59
60 static int      bind_if_to_bpf(char const *ifname, int bpf);
61 static int      find_ether(char *dst, size_t len);
62 static int      get_ether(char const *text, struct ether_addr *addr);
63 static int      send_wakeup(int bpf, struct ether_addr const *addr);
64 static void     usage(void);
65 static int      wake(int bpf, const char *host);
66
67 static void
68 usage(void)
69 {
70
71         (void)fprintf(stderr, "usage: wake [interface] lladdr [lladdr ...]\n");
72         exit(1);
73 }
74
75 static int
76 wake(int bpf, const char *host)
77 {
78         struct ether_addr macaddr;
79
80         if (get_ether(host, &macaddr) == -1)
81                 return (-1);
82
83         return (send_wakeup(bpf, &macaddr));
84 }
85
86 static int
87 bind_if_to_bpf(char const *ifname, int bpf)
88 {
89         struct ifreq ifr;
90         u_int dlt;
91
92         if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
93             sizeof(ifr.ifr_name))
94                 return (-1);
95
96         if (ioctl(bpf, BIOCSETIF, &ifr) == -1)
97                 return (-1);
98
99         if (ioctl(bpf, BIOCGDLT, &dlt) == -1)
100                 return (-1);
101
102         if (dlt != DLT_EN10MB)
103                 return (-1);
104
105         return (0);
106 }
107
108 static int
109 find_ether(char *dst, size_t len)
110 {
111         struct ifaddrs *ifap, *ifa;
112         struct sockaddr_dl *sdl = NULL;
113         int nifs;
114
115         if (dst == NULL || len == 0)
116                 return (0);
117
118         if (getifaddrs(&ifap) != 0)
119                 return (-1);
120
121         /* XXX also check the link state */
122         for (nifs = 0, ifa = ifap; ifa; ifa = ifa->ifa_next)
123                 if (ifa->ifa_addr->sa_family == AF_LINK &&
124                     ifa->ifa_flags & IFF_UP && ifa->ifa_flags & IFF_RUNNING) {
125                         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
126                         if (sdl->sdl_type == IFT_ETHER) {
127                                 strlcpy(dst, ifa->ifa_name, len);
128                                 nifs++;
129                         }
130                 }
131
132         freeifaddrs(ifap);
133         return (nifs == 1 ? 0 : -1);
134 }
135
136 static int
137 get_ether(char const *text, struct ether_addr *addr)
138 {
139         struct ether_addr *paddr;
140
141         paddr = ether_aton(text);
142         if (paddr != NULL) {
143                 *addr = *paddr;
144                 return (0);
145         }
146         if (ether_hostton(text, addr)) {
147                 warnx("no match for host %s found", text);
148                 return (-1);
149         }
150         return (0);
151 }
152
153 static int
154 send_wakeup(int bpf, struct ether_addr const *addr)
155 {
156         struct {
157                 struct ether_header hdr;
158                 u_char data[SYNC_LEN + ETHER_ADDR_LEN * DESTADDR_COUNT];
159         } __packed pkt;
160         u_char *p;
161         ssize_t bw;
162         ssize_t len;
163         int i;
164
165         (void)memset(pkt.hdr.ether_dhost, 0xff, sizeof(pkt.hdr.ether_dhost));
166         pkt.hdr.ether_type = htons(0);
167         (void)memset(pkt.data, 0xff, SYNC_LEN);
168         for (p = pkt.data + SYNC_LEN, i = 0; i < DESTADDR_COUNT;
169             p += ETHER_ADDR_LEN, i++)
170                 bcopy(addr->octet, p, ETHER_ADDR_LEN);
171         p = (u_char *)&pkt;
172         len = sizeof(pkt);
173         bw = 0;
174         while (len) {
175                 if ((bw = write(bpf, p, len)) == -1) {
176                         warn("write()");
177                         return (-1);
178                 }
179                 len -= bw;
180                 p += bw;
181         }
182         return (0);
183 }
184
185 int
186 main(int argc, char *argv[])
187 {
188         int bpf, n, rval;
189         char ifname[IF_NAMESIZE];
190
191         if (argc < 2)
192                 usage();
193
194         if ((bpf = open(_PATH_BPF, O_RDWR)) == -1)
195                 err(1, "Cannot open bpf interface");
196
197         n = 2;
198         if (bind_if_to_bpf(argv[1], bpf) == -1) {
199                 if (find_ether(ifname, sizeof(ifname)))
200                         err(1, "Failed to determine ethernet interface");
201                 if (bind_if_to_bpf(ifname, bpf) == -1)
202                         err(1, "Cannot bind to interface `%s'", ifname);
203                 --n;
204         } else
205                 strlcpy(ifname, argv[1], sizeof(ifname));
206
207         if (n >= argc)
208                 usage();
209         rval = 0;
210         for (; n < argc; n++) {
211                 if (wake(bpf, argv[n]) != 0) {
212                         rval = 1;
213                         warn("Cannot send Wake on LAN frame over `%s' to `%s'",
214                             ifname, argv[n]);
215                 }
216         }
217         exit(rval);
218 }