/******************************************************* * $Header: /afs/cs.cmu.edu/user/yke/cvsroot/MyDocuments/WebSites/Andrew/magic.c,v 1.1 2004/12/09 02:57:21 yke Exp $ * $Date: 2004/12/09 02:57:21 $ * * magic.c * * Magic Packet (TM) generator program for HP OpenView NNM * Copyright (C) 1997 Katsuyuki Yumoto * * Magic Packet is trademark of Advanced Micro Devices, Inc. * * This program can be executed stand-alone, but usually it * should be called by another program such as "sndmagic.exe" * * This program needs three arguments. First one is IP address * IP address of a destination host. Second one is the number of * subnet mask bits. Third one is physical address of the * destination host. * * Why this program needs them? Because "Remote power on" * is executed while the destination node is powered off. * Therefore we cannot use address resolution using ARP. * i.e. We cannot assume that the ARP cache of the sender host * has the physical address of the destination host. So long * as we use (win)sock library, we need to use broadcast * mechanism in order to make the Magic Packet reach the * destination host certainly. * * The first and second arguments are used for caluculating * the broadcast address corresponds to the subnet to which * the destination host belongs. * * The third argument is used for generating packet data. * The Magic Packet *always* contains single physical address * of the destination host. * * Technical document about Magic Packet is available on * the web page pointed by following URL: * http://www.amd.com/products/npd/overview/20212d.html * * regards, Yumo// * ))) Katsuyuki Yumoto * ((( yumo@st.rim.or.jp * ~~~~ * ********************************************************/ #include #include #include #include #ifdef WIN32 #include #else #include #include #endif #ifdef WIN32 #define PTYPE PF_INET #else #define PTYPE AF_INET #define SOCKET_ERROR -1 #define LPSOCKADDR struct sockaddr * #endif #define REFRAIN 20 /* Refraining MAC Address this times in the Magic Packet */ #define SIZEOF_MAC_ADDRESS 6 #define SIZEOF_SYNC 6 typedef unsigned char OCTET; int qflag = 0; /* keep whether q option is specified or not */ OCTET atox(char s) { if (s >= 'a'){ s -= 0x20; } if (s >= 'A'){ s -= 'A'; s += 10; } else if ('1' <= s && s <= '9') { s -= '1'; s += 1; } else { s = 0; } return((OCTET)s); } void usage() { #ifdef WIN32 fprintf(stderr, "Magic Packet(TM) generator for Win32\n"); #else fprintf(stderr, "Magic Packet(TM) generator\n"); #endif fprintf(stderr, "Copyright (c) 1997 K.Yumoto \n"); fprintf(stderr, "\n"); fprintf(stderr, "Usage: magic [-q] <# of SubnetMask bits> \n"); fprintf(stderr, " : xx.xx.xx.xx xx is decimal(8bit range)\n"); fprintf(stderr, " <# of SubnetMask bits> : 1 - 32 \n"); fprintf(stderr, " (When this value is 32, first argument is single host)\n"); fprintf(stderr, " : 12 digits hexadecimal code\n"); fprintf(stderr, "\n"); fprintf(stderr, "Magic Packet is trademark of Advanced Micro Devices, Inc.\n"); } unsigned long get_mask(int mask) { unsigned long x = 0; int i = mask; i = 32-i; for (; i > 0; i--){ x <<= 1; x |= 1; } x = ~x; return(x); } int get_broadcast_addr(char *broadcast, char *subnet, int mask) { long sn, ba, ma; struct in_addr ia; sn = ntohl(inet_addr(subnet)); ma = get_mask(mask); ba = sn & ma; ba |= ~ma; ia.s_addr = htonl(ba); strcpy(broadcast, (char *)inet_ntoa(ia)); return(0); } int main(int argc, char *argv[]) { int sd; /* Socket descriptor */ #ifdef WIN32 BOOL t = TRUE; /* socket option value (always TRUE in this program) */ #else int t = 1; /* socket option value (always 1 in this program) */ #endif OCTET dest_mac_address[10]; OCTET sync[10] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; OCTET buf[200]; int n; /* The number of octet sent to destination */ struct in_addr n_dest; struct sockaddr_in hostaddr; /* holds socket address */ char destaddr[30]; /* Destination IP address */ char * destport; /* holds destination (UDP) port */ char mask[50]; char subnet[50]; char broadcastaddr[50]; char av[3][50]; /* holds three arguments. */ #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; int err, bSockOpen; #endif if (argc < 5){ usage(); return(0); } if (argv[1][0] == '-'){ strcpy(av[0], argv[2]); strcpy(av[1], argv[3]); strcpy(av[2], argv[4]); destport = argv[5]; if (argv[1][1] == 'q'){ qflag = 1; } else { fprintf(stderr, "magic: Invalid option. Ignored\n"); } } else { strcpy(av[0], argv[1]); strcpy(av[1], argv[2]); strcpy(av[2], argv[3]); destport = argv[4]; } strcpy(subnet, av[0]); strcpy(mask, av[1]); switch (get_broadcast_addr(broadcastaddr, subnet, atoi(mask))){ case 1: if (!qflag){ fprintf (stderr, "magic: Subnet ID or IP Address is not recognized\n"); usage(); } break; case 2: if (!qflag){ fprintf (stderr, "magic: Number of SubnetMask bits is too long or too short\n"); usage(); } break; default: break; } dest_mac_address[0] = atox(av[2][0])*0x10 + atox(av[2][1]); dest_mac_address[1] = atox(av[2][2])*0x10 + atox(av[2][3]); dest_mac_address[2] = atox(av[2][4])*0x10 + atox(av[2][5]); dest_mac_address[3] = atox(av[2][6])*0x10 + atox(av[2][7]); dest_mac_address[4] = atox(av[2][8])*0x10 + atox(av[2][9]); dest_mac_address[5] = atox(av[2][10])*0x10 + atox(av[2][11]); if (!qflag){ printf("Destination MAC address is %02x-%02x-%02x-%02x-%02x-%02x\n", dest_mac_address[0], dest_mac_address[1], dest_mac_address[2], dest_mac_address[3], dest_mac_address[4], dest_mac_address[5]); } memcpy(buf, sync, SIZEOF_SYNC); for (n = 0; n < REFRAIN; n++){ memcpy(buf+SIZEOF_SYNC+n*SIZEOF_MAC_ADDRESS, dest_mac_address, SIZEOF_MAC_ADDRESS); } /* Set Destination Address */ hostaddr.sin_family = AF_INET; hostaddr.sin_addr.s_addr = inet_addr(broadcastaddr); /* Set Destination Port */ hostaddr.sin_port = htons((u_short)atoi(destport)); #ifdef WIN32 wVersionRequested = MAKEWORD(1, 1); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { /* Tell the user that we couldn't find a useable */ /* winsock.dll. */ if (!qflag){ printf ("A useable winsock.dll not found.\n"); } return(5); } /* Confirm that the Windows Sockets DLL supports 1.1.*/ /* Note that if the DLL supports versions greater */ /* than 1.1 in addition to 1.1, it will still return */ /* 1.1 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { /* Tell the user that we couldn't find a useable */ /* winsock.dll. */ if (!qflag){ printf ("A useable winsock.dll not found.\n"); } WSACleanup(); return(5); } #endif /* Open an UDP socket */ if ((sd = socket(PTYPE, SOCK_DGRAM, 0)) == -1){ if (!qflag){ fprintf(stderr, "Cannot open socket\n"); } return(1); } /* Enable to broadcast */ if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, (char *)&t, sizeof(t)) == SOCKET_ERROR){ if (!qflag){ fprintf(stderr, "Cannot enable to broadcast\n"); } } /* Send *Magic data* to destination node */ if ((n = sendto(sd, buf, REFRAIN*SIZEOF_MAC_ADDRESS+SIZEOF_SYNC, 0, (LPSOCKADDR)&hostaddr, sizeof(hostaddr))) == SOCKET_ERROR){ if (!qflag){ fprintf(stderr, "Cannot send data\n"); } return(1); } if (!qflag){ printf ("%d[octet] sent\n", n); } /* Close the UDP socket */ if (sd >= 0){ #ifdef WIN32 closesocket(sd); #else close(sd); #endif } if (!qflag){ printf("Socket closed\n"); } return(0); }