/* * Copyright 2011, Christian Lamparter * * 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 #include #include #include #include #include #include #include #include #include /* ETH_P_ALL */ #include /* sockaddr_ll */ #include /* 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; }