1/* 2 * 3 * Copyright (C) 1998 by Christopher Chan-Nui 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 */ 20#include <ctype.h> 21#include <unistd.h> 22#include <stdio.h> 23#include <netdb.h> 24#include <netinet/in.h> 25#include <sys/socket.h> 26#ifdef HAVE_GETOPT_H 27#include <getopt.h> 28#endif 29#include <errno.h> 30 31#include <arpa/inet.h> 32#include <net/if.h> 33#include <net/if_arp.h> 34#include <netinet/ether.h> 35#include <netpacket/packet.h> 36#include <string.h> 37#include <stdlib.h> 38#include <sys/ioctl.h> 39 40#define _PATH_PROCNET_ARP "/proc/net/arp" 41 42#define ARP_OPT_A (0x1) 43#define ARP_OPT_p (0x2) 44#define ARP_OPT_H (0x4) 45#define ARP_OPT_t (0x8) 46#define ARP_OPT_i (0x10) 47#define ARP_OPT_a (0x20) 48#define ARP_OPT_d (0x40) 49#define ARP_OPT_n (0x80) /* do not resolve addresses */ 50#define ARP_OPT_D (0x100) /* HW-address is devicename */ 51#define ARP_OPT_s (0x200) 52#define ARP_OPT_v (0x400 * DEBUG) /* debugging output flag */ 53 54#define DEV_NAME "br0" 55 56#if 0 57#ifndef DEFAULTMAC 58#define DEFAULTMAC "00a0c9852a5f" 59#endif 60#ifndef DEFAULTTARGET 61#define DEFAULTTARGET "255.255.255.255" 62#endif 63 64static char *rcsid="@(#) $Id: wakelan.c,v 1.8 1998/08/30 05:04:28 channui Exp $"; 65static void *use_rcsid = (void *)((char *)&use_rcsid || (void *)&rcsid); 66char *versionid = "1.0"; 67 68void usage(char *name) { 69 printf ("Usage: %s [options] [mac] [broadcast] [port]\n" 70 " -b addr broadcast address\n" 71 " -m mac mac address of host\n" 72 " -p port UDP port to broadcast to\n" 73 " -v[v] version\n" 74 , name); 75 exit (0); 76} 77#endif 78 79int parse_mac(unsigned char *mac, char *str) { 80 int i; 81 int count; 82 char c; 83 unsigned char val; 84 int colon_ok = 1; 85 for (i = 0; i < 6; i++) { 86 mac[i] = 0; 87 } 88 for (i = 0; i < 6; i++) { 89 count = 0; 90 val = 0; 91 do { 92 c = toupper(*str++); 93 if (c >= '0' && c <= '9') { 94 val = (val * 16) + (c - '0'); 95 } else if (c >= 'A' && c <= 'F') { 96 val = (val * 16) + (c - 'A') + 10; 97 } else if (c == ':') { 98 if (colon_ok || count-- != 0) 99 break; 100 } else if (c == '\0') { 101 str--; 102 break; 103 } else { 104 return 0; 105 } 106 colon_ok=1; 107 } while (++count < 2); 108 colon_ok=(count<2); 109 *mac++ = val; 110 } 111 if (*str) 112 return 0; 113 return 1; 114} 115 116#if 0 117int main (int argc, char *argv[]) { 118 int sock; 119 int optval = 1; 120 int version =0; 121 int i, j, c, rc; 122 char msg[1024]; 123 int msglen = 0; 124 struct sockaddr_in bcast; 125 struct hostent *he; 126 struct in_addr inaddr; 127 unsigned char macaddr[6]; 128 char *mac = DEFAULTMAC; 129 char *target = DEFAULTTARGET; 130 short bport = htons(32767); 131 132 while ((c = getopt(argc, argv, "hvp:m:b:")) != EOF) { 133 switch (c) { 134 case 'b': target = optarg; break; 135 case 'm': mac = optarg; break; 136 case 'p': bport = htons(atoi(optarg)); break; 137 case 'v': version++; break; 138 case 'h': 139 case '?': 140 usage(argv[0]); 141 } 142 } 143 144 if (version) { 145 printf ("Version: %s\n", versionid); 146 if (version > 1) { 147 printf (" RCSID: %s\n", rcsid); 148 } 149 exit (0); 150 } 151 152 if (argv[optind] != NULL) { 153 mac = argv[optind++]; 154 } 155 if (argv[optind] != NULL) { 156 target = argv[optind++]; 157 } 158 if (argv[optind] != NULL) { 159 bport = htons(atoi(argv[optind++])); 160 } 161 if (argv[optind] != NULL) { 162 usage(argv[0]); 163 } 164 165 if (!parse_mac(macaddr, mac)) { 166 printf ("Illegal MAC address '%s'\n", mac); 167 exit (1); 168 } 169 170 if (!inet_aton(target, &inaddr)) { 171 he = gethostbyname(target); 172 inaddr = *(struct in_addr *)he->h_addr_list[0]; 173 } 174 175 for (i = 0; i < 6; i++) { 176 msg[msglen++] = 0xff; 177 } 178 for (i = 0; i < 16; i++) { 179 for (j = 0; j < sizeof(macaddr); j++) { 180 msg[msglen++] = macaddr[j]; 181 } 182 } 183 184 memset(&bcast, 0, sizeof(bcast)); 185 bcast.sin_family = AF_INET; 186 bcast.sin_addr.s_addr = inaddr.s_addr; 187 bcast.sin_port = bport; 188 189 sock = socket(AF_INET, SOCK_DGRAM, 0); 190 if (sock < 0) { 191 printf ("Can't allocate socket\n"); 192 exit (1); 193 } 194 if ((rc=setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval))) < 0) { 195 printf ("Can't socket option SO_BROADCAST: rc = %d, errno=%s(%d)\n", 196 rc, strerror(errno), errno); 197 exit (1); 198 } 199 sendto(sock, &msg, msglen, 0, (struct sockaddr *)&bcast, sizeof(bcast)); 200 return 0; 201} 202#else 203int send_wol (char *target, char *mac) 204{ 205 int sock; 206 int optval = 1; 207 int i, j, rc; 208 char msg[1024]; 209 int msglen = 0; 210 struct sockaddr_in bcast; 211 struct hostent *he; 212 struct in_addr inaddr; 213 unsigned char macaddr[6]; 214 short bport = htons(32767); 215 216 if (!parse_mac(macaddr, mac)) { 217 printf ("Illegal MAC address '%s'\n", mac); 218 exit (1); 219 } 220 221 if (!inet_aton(target, &inaddr)) { 222 he = gethostbyname(target); 223 inaddr = *(struct in_addr *)he->h_addr_list[0]; 224 } 225 226 for (i = 0; i < 6; i++) { 227 msg[msglen++] = 0xff; 228 } 229 for (i = 0; i < 16; i++) { 230 for (j = 0; j < sizeof(macaddr); j++) { 231 msg[msglen++] = macaddr[j]; 232 } 233 } 234 235 memset(&bcast, 0, sizeof(bcast)); 236 bcast.sin_family = AF_INET; 237 bcast.sin_addr.s_addr = inaddr.s_addr; 238 bcast.sin_port = bport; 239 240 sock = socket(AF_INET, SOCK_DGRAM, 0); 241 if (sock < 0) { 242 printf ("Can't allocate socket\n"); 243 return -1; 244 } 245 if ((rc=setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval))) < 0) { 246 printf ("Can't socket option SO_BROADCAST: rc = %d, errno=%s(%d)\n", 247 rc, strerror(errno), errno); 248 return -1; 249 } 250 sendto(sock, &msg, msglen, 0, (struct sockaddr *)&bcast, sizeof(bcast)); 251 return 0; 252} 253#endif 254 255int get_bcast_addr(char *ifname, char *bcast_addr) 256{ 257 struct ifreq ifr; 258 int fd; 259 260 fd = socket(AF_INET, SOCK_DGRAM, 0); 261 if (fd < 0) { 262 printf("Unable to open the socket\n"); 263 return -1; 264 } 265 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 266 memset(bcast_addr, 0, 16); 267 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) >= 0) 268 sprintf(bcast_addr, "%s", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_broadaddr)->sin_addr)); 269 270 close(fd); 271 272 return 0; 273} 274 275int main() 276{ 277 char host[100]; 278 char ip[100]; 279 char hwa[100]; 280 char mask[100]; 281 char line[200]; 282 char dev[100]; 283 int type, flags; 284 FILE *fp; 285 int num; 286 char mac[16]; 287 char bcast_addr[16]; 288 int hwa_idx; 289 int mac_idx; 290 291 host[0] = '\0'; 292 293 /* Open the PROCps kernel table. */ 294 fp = fopen(_PATH_PROCNET_ARP, "r"); 295 if (fp == NULL) { 296 printf("Unable to open the file\n"); 297 return 0; 298 } 299 300 /* get Bcast addr for 'br0' */ 301 get_bcast_addr(DEV_NAME, (char *)bcast_addr); 302 303 /* Bypass header -- read until newline */ 304 if (fgets(line, sizeof(line), fp) != (char *) NULL) { 305 mask[0] = '-'; mask[1] = '\0'; 306 dev[0] = '-'; dev[1] = '\0'; 307 308 /* Read the ARP cache entries. */ 309 for (; fgets(line, sizeof(line), fp);) { 310 num = sscanf(line, "%s 0x%x 0x%x %100s %100s %100s\n", 311 ip, &type, &flags, hwa, mask, dev); 312 if (num < 4) 313 break; 314 315// printf("ip: %s, hwa: %s, dev: %s\n", ip, hwa, dev); 316 317 if (!strcmp(dev, DEV_NAME)) { 318 memset(mac, 0, 16); 319 mac_idx = 0; 320 /* exclude ':' from the 'hwa' */ 321 for (hwa_idx = 0; hwa_idx <= 17; hwa_idx += 3, mac_idx += 2) { 322 memcpy(mac + mac_idx, hwa + hwa_idx, 2); 323 } 324// printf("mac: %s\n", mac); 325 /* Trigger WOL for the mac */ 326 send_wol(bcast_addr, mac); 327// sprintf(cmd, "/usr/sbin/wol -b %s -m %s", bcast_addr, mac); 328// printf("cmd: %s\n", cmd); 329// system(cmd); 330 } 331 } 332 } 333 334 fclose(fp); 335 336 return 0; 337} 338