1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86#include "libbb.h"
87#include <netpacket/packet.h>
88#include <netinet/ether.h>
89#include <linux/if.h>
90
91
92
93
94
95#ifdef PF_PACKET
96# define whereto_t sockaddr_ll
97# define make_socket() xsocket(PF_PACKET, SOCK_RAW, 0)
98#else
99# define whereto_t sockaddr
100# define make_socket() xsocket(AF_INET, SOCK_PACKET, SOCK_PACKET)
101#endif
102
103#ifdef DEBUG
104# define bb_debug_msg(fmt, args...) fprintf(stderr, fmt, ## args)
105void bb_debug_dump_packet(unsigned char *outpack, int pktsize)
106{
107 int i;
108 printf("packet dump:\n");
109 for (i = 0; i < pktsize; ++i) {
110 printf("%2.2x ", outpack[i]);
111 if (i % 20 == 19) bb_putchar('\n');
112 }
113 printf("\n\n");
114}
115#else
116# define bb_debug_msg(fmt, args...) ((void)0)
117# define bb_debug_dump_packet(outpack, pktsize) ((void)0)
118#endif
119
120
121
122
123
124
125
126static void get_dest_addr(const char *hostid, struct ether_addr *eaddr)
127{
128 struct ether_addr *eap;
129
130 eap = ether_aton_r(hostid, eaddr);
131 if (eap) {
132 bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eap));
133#if !defined(__UCLIBC__) || UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 30)
134 } else if (ether_hostton(hostid, eaddr) == 0) {
135 bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr));
136#endif
137 } else {
138 bb_show_usage();
139 }
140}
141
142#define PKT_HEADER_SIZE (20 + 16*6)
143static int fill_pkt_header(unsigned char *pkt, struct ether_addr *eaddr, int broadcast)
144{
145 int i;
146 unsigned char *station_addr = eaddr->ether_addr_octet;
147
148 memset(pkt, 0xff, 6);
149 if (!broadcast)
150 memcpy(pkt, station_addr, 6);
151 pkt += 6;
152
153 memcpy(pkt, station_addr, 6);
154 pkt += 6;
155
156 *pkt++ = 0x08;
157 *pkt++ = 0x42;
158
159 memset(pkt, 0xff, 6);
160
161 for (i = 0; i < 16; ++i) {
162 pkt += 6;
163 memcpy(pkt, station_addr, 6);
164 }
165
166 return PKT_HEADER_SIZE;
167}
168
169static int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd)
170{
171 unsigned passwd[6];
172 int byte_cnt, i;
173
174
175 byte_cnt = sscanf(ethoptarg, "%2x:%2x:%2x:%2x:%2x:%2x",
176 &passwd[0], &passwd[1], &passwd[2],
177 &passwd[3], &passwd[4], &passwd[5]);
178
179
180 if (byte_cnt < 4)
181 byte_cnt = sscanf(ethoptarg, "%u.%u.%u.%u",
182 &passwd[0], &passwd[1], &passwd[2], &passwd[3]);
183 if (byte_cnt < 4) {
184 bb_simple_error_msg("can't read Wake-On-LAN pass");
185 return 0;
186 }
187
188 for (i = 0; i < byte_cnt; ++i)
189 wol_passwd[i] = passwd[i];
190
191 bb_debug_msg("password: %2.2x %2.2x %2.2x %2.2x (%d)\n\n",
192 wol_passwd[0], wol_passwd[1], wol_passwd[2], wol_passwd[3],
193 byte_cnt);
194
195 return byte_cnt;
196}
197
198int ether_wake_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
199int ether_wake_main(int argc UNUSED_PARAM, char **argv)
200{
201 const char *ifname = "eth0";
202 char *pass;
203 unsigned flags;
204 unsigned char wol_passwd[6];
205 int wol_passwd_sz = 0;
206 int s;
207 int pktsize;
208 unsigned char outpack[PKT_HEADER_SIZE + 6 + 16 ];
209
210 struct ether_addr eaddr;
211 struct whereto_t whereto;
212
213
214 flags = getopt32(argv, "^" "bi:p:" "\0" "=1", &ifname, &pass);
215 if (flags & 4)
216 wol_passwd_sz = get_wol_pw(pass, wol_passwd);
217 flags &= 1;
218
219
220 s = make_socket();
221
222
223
224
225
226 get_dest_addr(argv[optind], &eaddr);
227
228
229 pktsize = fill_pkt_header(outpack, &eaddr, flags );
230
231 bb_debug_dump_packet(outpack, pktsize);
232
233
234#ifdef __linux__
235 {
236 struct ifreq if_hwaddr;
237
238 strncpy_IFNAMSIZ(if_hwaddr.ifr_name, ifname);
239 ioctl_or_perror_and_die(s, SIOCGIFHWADDR, &if_hwaddr, "SIOCGIFHWADDR on %s failed", ifname);
240
241 memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6);
242
243# ifdef DEBUG
244 {
245 unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data;
246 printf("The hardware address (SIOCGIFHWADDR) of %s is type %d "
247 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n", ifname,
248 if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1],
249 hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
250 }
251# endif
252 }
253#endif
254
255 bb_debug_dump_packet(outpack, pktsize);
256
257
258 if (wol_passwd_sz > 0) {
259 memcpy(outpack+pktsize, wol_passwd, wol_passwd_sz);
260 pktsize += wol_passwd_sz;
261 }
262
263 bb_debug_dump_packet(outpack, pktsize);
264
265
266 if (flags ) {
267 if (setsockopt_broadcast(s) != 0)
268 bb_simple_perror_msg("SO_BROADCAST");
269 }
270
271#if defined(PF_PACKET)
272 {
273 struct ifreq ifr;
274 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
275 xioctl(s, SIOCGIFINDEX, &ifr);
276 memset(&whereto, 0, sizeof(whereto));
277 whereto.sll_family = AF_PACKET;
278 whereto.sll_ifindex = ifr.ifr_ifindex;
279
280
281 whereto.sll_halen = ETH_ALEN;
282 memcpy(whereto.sll_addr, outpack, ETH_ALEN);
283 }
284#else
285 whereto.sa_family = 0;
286 strcpy(whereto.sa_data, ifname);
287#endif
288 xsendto(s, outpack, pktsize, (struct sockaddr *)&whereto, sizeof(whereto));
289 if (ENABLE_FEATURE_CLEAN_UP)
290 close(s);
291 return EXIT_SUCCESS;
292}
293