| /* |
| * Copyright 2011, Christian Lamparter <chunkeey@googlemail.com> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation version 2 of the License. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <stdbool.h> |
| |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| |
| #include <linux/types.h> |
| #include <linux/if_ether.h> /* ETH_P_ALL */ |
| #include <linux/if_packet.h> /* sockaddr_ll */ |
| #include <linux/if.h> /* IFNAMSIZ */ |
| |
| static int monitor_init(const char *ifname) |
| { |
| struct sockaddr_ll ll; |
| int monitor_sock; |
| |
| memset(&ll, 0, sizeof(ll)); |
| ll.sll_family = AF_PACKET; |
| ll.sll_ifindex = if_nametoindex(ifname); |
| if (ll.sll_ifindex == 0) { |
| fprintf(stderr, "Monitor interface '%s' does not exist\n", ifname); |
| return -1; |
| } |
| |
| monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); |
| if (monitor_sock < 0) { |
| fprintf(stderr, "socket(PF_PACKET,SOCK_RAW): %s\n", strerror(errno)); |
| return -1; |
| } |
| |
| if (bind(monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) { |
| fprintf(stderr, "bind(PACKET): %s\n", strerror(errno)); |
| close(monitor_sock); |
| return -1; |
| } |
| |
| return monitor_sock; |
| } |
| |
| static int inject_frame(int s, const void *data, size_t len) |
| { |
| #define IEEE80211_RADIOTAP_F_FRAG 0x08 |
| unsigned char rtap_hdr[] = { |
| 0x00, 0x00, /* radiotap version */ |
| 0x0e, 0x00, /* radiotap length */ |
| 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ |
| IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */ |
| 0x00, /* padding */ |
| 0x00, 0x00, /* RX and TX flags to indicate that */ |
| 0x00, 0x00, /* this is the injected frame directly */ |
| }; |
| struct iovec iov[2] = { |
| { |
| .iov_base = &rtap_hdr, |
| .iov_len = sizeof(rtap_hdr), |
| }, |
| { |
| .iov_base = (void *) data, |
| .iov_len = len, |
| } |
| }; |
| struct msghdr msg = { |
| .msg_name = NULL, |
| .msg_namelen = 0, |
| .msg_iov = iov, |
| .msg_iovlen = 2, |
| .msg_control = NULL, |
| .msg_controllen = 0, |
| .msg_flags = 0, |
| }; |
| int ret; |
| |
| ret = sendmsg(s, &msg, 0); |
| if (ret < 0) |
| perror("sendmsg"); |
| return ret; |
| } |
| |
| static unsigned char wol_magic_tmpl[30 + 6 + 16 * 6] = { |
| 0x08, 0x00, 0x00, 0x00, |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* RA */ |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* TA */ |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* SA */ |
| 0x00, 0x00, |
| |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
| }; |
| |
| static void prepare_wol(unsigned char *wol_magic, unsigned char *mac) |
| { |
| int i; |
| |
| for (i = 0; i < 16; i++) |
| memcpy(&wol_magic[30 + i * 6], mac, 6); |
| } |
| |
| void usage(void) |
| { |
| fprintf(stderr, "Usage:\n"); |
| fprintf(stderr, "\twol -i monitor_dev -m DE:VI:CE:MA:CW:OL -n #num -v\n"); |
| |
| fprintf(stderr, "\nDescription:\n"); |
| fprintf(stderr, "\tThis utility generates a WOL packet for the" |
| "given [MAC] address and tries to injects" |
| "it into [monitor_dev]\n"); |
| |
| exit(EXIT_FAILURE); |
| } |
| |
| #define MAC_STR "%2X:%2X:%2X:%2X:%2X:%2X" |
| |
| #define M(a, i) ((unsigned int *)&a[i]) |
| #define MAC_ARG(a) M(a, 0), M(a, 1), M(a, 2), M(a, 3), M(a, 4), M(a, 5) |
| |
| #define M2(a, i) (a[i]) |
| #define MAC_ARG2(a) M2(a, 0), M2(a, 1), M2(a, 2), M2(a, 3), M2(a, 4), M2(a, 5) |
| |
| int main(int argc, char **args) |
| { |
| int sock, err = 0, opt, num = 10; |
| unsigned char mac[ETH_ALEN]; |
| char dev_name[IFNAMSIZ + 1] = { 0 }; |
| bool has_mac = false, has_dev = false, verbose = false; |
| |
| while ((opt = getopt(argc, args, "m:i:n:v")) != -EXIT_FAILURE) { |
| switch (opt) { |
| case 'i': |
| has_dev = true; |
| strncpy(dev_name, optarg, IFNAMSIZ); |
| break; |
| case 'm': |
| has_mac = true; |
| err = sscanf(optarg, MAC_STR, MAC_ARG(mac)) != 6; |
| if (err) |
| fprintf(stderr, "invalid MAC: \"%s\"\n", optarg); |
| break; |
| |
| case 'n': |
| err = sscanf(optarg, "%d", &num) != 1; |
| err |= num < 1 | num > 1000; |
| if (err) |
| fprintf(stderr, "invalid tries: \"%s\"\n", optarg); |
| break; |
| |
| case 'v': |
| verbose = true; |
| break; |
| |
| default: |
| err = -EINVAL; |
| break; |
| } |
| |
| if (err) |
| break; |
| } |
| |
| if (!has_mac || !has_dev || err) |
| usage(); |
| |
| if (verbose) |
| fprintf(stdout, "Opening monitor injection interface [%s].\n", dev_name); |
| |
| sock = monitor_init(dev_name); |
| if (sock < 0) |
| return EXIT_FAILURE; |
| |
| if (verbose) |
| fprintf(stdout, "Generating %d WOL packet for ["MAC_STR"].\n", num, MAC_ARG2(mac)); |
| |
| prepare_wol(wol_magic_tmpl, mac); |
| |
| while (num--) { |
| err = inject_frame(sock, wol_magic_tmpl, sizeof(wol_magic_tmpl)); |
| if (err < 0) { |
| fprintf(stderr, "failed to send WOL packet.\n"); |
| break; |
| } else if (verbose) { |
| fprintf(stdout, "WOL packet sent.\n"); |
| } |
| } |
| |
| close(sock); |
| if (err < 0) |
| return EXIT_FAILURE; |
| |
| return 0; |
| } |