carl9170 firmware: add get_random_u16 helper
[carl9170fw.git] / tools / src / wol.c
1 /*
2  * Copyright 2011, Christian Lamparter <chunkeey@googlemail.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <unistd.h>
23 #include <stdbool.h>
24
25 #include <sys/types.h>
26 #include <sys/socket.h>
27
28 #include <arpa/inet.h>
29 #include <net/if.h>
30
31 #include <linux/types.h>
32 #include <linux/if_ether.h>     /* ETH_P_ALL */
33 #include <linux/if_packet.h>    /* sockaddr_ll */
34
35 static int monitor_init(const char *ifname)
36 {
37         struct sockaddr_ll ll;
38         int monitor_sock;
39
40         memset(&ll, 0, sizeof(ll));
41         ll.sll_family = AF_PACKET;
42         ll.sll_ifindex = if_nametoindex(ifname);
43         if (ll.sll_ifindex == 0) {
44                 fprintf(stderr, "Monitor interface '%s' does not exist\n", ifname);
45                 return -1;
46         }
47
48         monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
49         if (monitor_sock < 0) {
50                 fprintf(stderr, "socket(PF_PACKET,SOCK_RAW): %s\n", strerror(errno));
51                 return -1;
52         }
53
54         if (bind(monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
55                 fprintf(stderr, "bind(PACKET): %s\n", strerror(errno));
56                 close(monitor_sock);
57                 return -1;
58         }
59
60         return monitor_sock;
61 }
62
63 static int inject_frame(int s, const void *data, size_t len)
64 {
65 #define IEEE80211_RADIOTAP_F_FRAG       0x08
66         unsigned char rtap_hdr[] = {
67                 0x00, 0x00, /* radiotap version */
68                 0x0e, 0x00, /* radiotap length */
69                 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
70                 IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
71                 0x00,       /* padding */
72                 0x00, 0x00, /* RX and TX flags to indicate that */
73                 0x00, 0x00, /* this is the injected frame directly */
74         };
75         struct iovec iov[2] = {
76                 {
77                         .iov_base = &rtap_hdr,
78                         .iov_len = sizeof(rtap_hdr),
79                 },
80                 {
81                         .iov_base = (void *) data,
82                         .iov_len = len,
83                 }
84         };
85         struct msghdr msg = {
86                 .msg_name = NULL,
87                 .msg_namelen = 0,
88                 .msg_iov = iov,
89                 .msg_iovlen = 2,
90                 .msg_control = NULL,
91                 .msg_controllen = 0,
92                 .msg_flags = 0,
93         };
94         int ret;
95
96         ret = sendmsg(s, &msg, 0);
97         if (ret < 0)
98                 perror("sendmsg");
99         return ret;
100 }
101
102 static unsigned char wol_magic_tmpl[30 + 6 + 16 * 6] = {
103         0x08, 0x00, 0x00, 0x00,
104         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,     /* RA */
105         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,     /* TA */
106         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,     /* SA */
107         0x00, 0x00,
108
109         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
110 };
111
112 static void prepare_wol(unsigned char *wol_magic, unsigned char *mac)
113 {
114         int i;
115
116         for (i = 0; i < 16; i++)
117                 memcpy(&wol_magic[30 + i * 6], mac, 6);
118 }
119
120 void usage(void)
121 {
122         fprintf(stderr, "Usage:\n");
123         fprintf(stderr, "\twol -i monitor_dev -m DE:VI:CE:MA:CW:OL -n #num -v\n");
124
125         fprintf(stderr, "\nDescription:\n");
126         fprintf(stderr, "\tThis utility generates a WOL packet for the"
127                         "given [MAC] address and tries to injects"
128                         "it into [monitor_dev]\n");
129
130         exit(EXIT_FAILURE);
131 }
132
133 #define MAC_STR "%2X:%2X:%2X:%2X:%2X:%2X"
134
135 #define M(a, i) ((unsigned int *)&a[i])
136 #define MAC_ARG(a) M(a, 0), M(a, 1), M(a, 2), M(a, 3), M(a, 4), M(a, 5)
137
138 #define M2(a, i) (a[i])
139 #define MAC_ARG2(a) M2(a, 0), M2(a, 1), M2(a, 2), M2(a, 3), M2(a, 4), M2(a, 5)
140
141 int main(int argc, char **args)
142 {
143         int sock, err = 0, opt, num = 10;
144         unsigned char mac[ETH_ALEN];
145         char dev_name[IFNAMSIZ + 1] = { 0 };
146         bool has_mac = false, has_dev = false, verbose = false;
147
148         while ((opt = getopt(argc, args, "m:i:n:v")) != -EXIT_FAILURE) {
149                 switch (opt) {
150                 case 'i':
151                         has_dev = true;
152                         strncpy(dev_name, optarg, IFNAMSIZ);
153                         break;
154                 case 'm':
155                         has_mac = true;
156                         err = sscanf(optarg, MAC_STR, MAC_ARG(mac)) != 6;
157                         if (err)
158                                 fprintf(stderr, "invalid MAC: \"%s\"\n", optarg);
159                         break;
160
161                 case 'n':
162                         err = sscanf(optarg, "%d", &num) != 1;
163                         err |= num < 1 | num > 1000;
164                         if (err)
165                                 fprintf(stderr, "invalid tries: \"%s\"\n", optarg);
166                         break;
167
168                 case 'v':
169                         verbose = true;
170                         break;
171
172                 default:
173                         err = -EINVAL;
174                         break;
175                 }
176
177                 if (err)
178                         break;
179         }
180
181         if (!has_mac || !has_dev || err)
182                 usage();
183
184         if (verbose)
185                 fprintf(stdout, "Opening monitor injection interface [%s].\n", dev_name);
186
187         sock = monitor_init(dev_name);
188         if (sock < 0)
189                 return EXIT_FAILURE;
190
191         if (verbose)
192                 fprintf(stdout, "Generating %d WOL packet for ["MAC_STR"].\n", num, MAC_ARG2(mac));
193
194         prepare_wol(wol_magic_tmpl, mac);
195
196         while (num--) {
197                 err = inject_frame(sock, wol_magic_tmpl, sizeof(wol_magic_tmpl));
198                 if (err < 0) {
199                         fprintf(stderr, "failed to send WOL packet.\n");
200                         break;
201                 } else if (verbose) {
202                         fprintf(stdout, "WOL packet sent.\n");
203                 }
204         }
205
206         close(sock);
207         if (err < 0)
208                 return EXIT_FAILURE;
209
210         return 0;
211 }