-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwol.c
158 lines (125 loc) · 2.88 KB
/
wol.c
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <arpa/inet.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#define print(str) write(STDERR_FILENO, str, sizeof(str) - 1)
static uint32_t ip_addr = 0xFFFFFFFF; /* 255.255.255.255 by default */
static uint16_t port = 9; /* discard port by default */
/* 48 bit media access control address stored in network order */
typedef struct {
uint8_t octets[6];
} MacAddress;
typedef struct {
uint8_t magic[6];
MacAddress data[16];
} WolPackage;
static const char str_help_msg[] = "======================================\n"
"USAGE:\n"
" wol [mac]\n"
"\n"
" wol A3:43:F5:87:01:3B\n"
"======================================\n";
static const char str_wake_up[] = "WAKE UP!\n";
void
print_help(void)
{
/* size of str_help_msg is known at compile time so no need to calculate
* this shit again */
print(str_help_msg);
}
uint8_t
is_hexdigit(const char s)
{
return ((s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') ||
(s >= 'a' && s <= 'f'));
}
/* only use this function after checking with is_hexdigit */
uint8_t
hexchar_to_bin(const char d)
{
return (uint8_t)((d >= 'a') ? (d - 0x57)
: (d - ((d >= 'A') ? 0x37 : 0x30)));
}
/* convert a 48 bit mac address string with ':' notation to binary data. returns
* 1 if successfull, otherwise 0 */
uint8_t
str_to_mac(char *str_mac, MacAddress *buffer_addr)
{
uint8_t i;
char d0, d1, sep;
if (!str_mac) {
return 0;
}
for (i = 0; i < 6; i++) {
d1 = *str_mac;
if (!is_hexdigit(d1)) {
return 0;
}
str_mac++;
d0 = *str_mac;
if (!is_hexdigit(d0)) {
return 0;
}
str_mac++;
sep = *str_mac;
if ((sep != ':') && (sep != 0)) {
return 0;
}
str_mac++;
buffer_addr->octets[i] = hexchar_to_bin(d0);
buffer_addr->octets[i] |= (hexchar_to_bin(d1) << 4);
}
return 1;
}
uint8_t
wol_send(struct in_addr *ip, uint16_t port, MacAddress addr)
{
struct sockaddr_in sock_addr;
WolPackage wol_package;
int i, sd, broadcast_enable;
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd == -1) {
perror("socket");
return 1;
}
broadcast_enable = 1;
if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &broadcast_enable,
sizeof(broadcast_enable)) != 0) {
perror("setsockopt");
return 1;
}
for (i = 0; i < 6; i++) {
wol_package.magic[i] = 0xFF;
}
for (i = 0; i < 16; i++) {
wol_package.data[i] = addr;
}
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = htons(port);
sock_addr.sin_addr = *ip;
if (sendto(sd, &wol_package, sizeof(wol_package), 0,
(const struct sockaddr *)&sock_addr,
sizeof(sock_addr)) == -1) {
perror("sendto");
return 1;
}
print(str_wake_up);
close(sd);
return 0;
}
int
main(int argc, char **argv)
{
struct in_addr ip;
MacAddress mac;
if (argc != 2) {
print_help();
return 1;
}
if (!str_to_mac(argv[1], &mac)) {
print_help();
return 1;
}
ip.s_addr = ip_addr;
return (int)wol_send(&ip, port, mac);
}