/****************************************************************************** (c) 2001-2004 patrick Caulfield patrick@debian.org 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; either version 2 of the License, or any later version. 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. ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_NET_IF_ETHER_H #include #include #endif #ifdef HAVE_NET_ETHERNET_H #include #endif #ifdef HAVE_NETINET_ETHER_H #include #endif #include #include "interfaces.h" #include "moprc.h" #ifdef __FreeBSD__ #define ether_addr_octet octet #endif static int mop_socket; static unsigned char last_message[1500]; static int last_message_len; static int show_info = 0; static int do_moprc(u_int8_t *, int, int, int); static int send_boot(u_int8_t *macaddr, int interface); static LATinterfaces *iface; static int usage(FILE *f, char *cmd) { fprintf(f, "\nUsage: %s [?hVv] [-i ] |\n", cmd); fprintf(f, " -? Show this usage message\n"); fprintf(f, " -h Show this usage message\n"); fprintf(f, " -V Show the version of moprc\n"); fprintf(f, " -i Ethernet interface to use (default to first found)\n"); fprintf(f, " -t Trigger (reboot) the server\n"); fprintf(f, " -b Make ^H send DEL\n"); fprintf(f, " -v Show target information\n"); fprintf(f, " -p Set poll interval (default 200)\n"); fprintf(f, "\n"); fprintf(f, "Node names are read from /etc/ethers\n"); fprintf(f, "MAC addresses in colon-seperated form. eg:\n"); fprintf(f, "\n%s -i eth1 08:00:2B:2B:AD:99\n", cmd); if (geteuid() != 0) fprintf(f, "\nYou will probably need to be root to run this program.\n"); fprintf(f, "\n"); return -1; } /* Send a MOP message to a specified MAC address */ static int send_message(unsigned char *buf, int len, int interface, u_int8_t *macaddr) { int status; if (len < 46) len = 46; status = iface->send_packet(interface, macaddr, buf, len); if (status < 0) perror("send message"); memmove(last_message, buf, len); last_message_len = len; return status; } static int send_last_message(int interface, u_int8_t *macaddr) { return send_message(last_message, last_message_len, interface, macaddr); } int main(int argc, char *argv[]) { int opt; int interface = -1; int trigger=0; int convert_bs = 0; int poll_interval = 200; /* in ms */ char ifname_buf[255]; char *ifname; struct ether_addr addr; if (argc < 2) { return usage(stdout, argv[0]); } /* Look for MOPRC_INTERFACE environment variable */ ifname = getenv("MOPRC_INTERFACE"); /* Get command-line options */ opterr = 0; while ((opt=getopt(argc,argv,"?hVvtbi:p:")) != EOF) { switch(opt) { case 'h': return usage(stdout, argv[0]); case '?': return usage(stdout, argv[0]); case 'v': show_info++; break; case 't': trigger++; break; case 'b': convert_bs++; break; case 'i': strcpy(ifname_buf, optarg); ifname = ifname_buf; break; case 'p': poll_interval = atoi(optarg); break; case 'V': printf("\nMoprc version %s\n\n", VERSION); exit(0); break; } } if (!argv[optind]) { return usage(stderr, argv[0]); } /* Check for a hostname in /etc/ethers */ if (ether_hostton(argv[optind], &addr) != 0) { #ifndef __APPLE__ struct ether_addr *addr1; /* Otherwise parse ethernet MAC address */ addr1 = ether_aton(argv[optind]); if (addr1) { addr = *addr1; } else #endif { fprintf(stderr, "unknown node name or bad MAC address %s\n", argv[optind]); return 3; } } /* Initialise the platform-specific interface code */ iface = LATinterfaces::Create(); if (iface->Start(LATinterfaces::ProtoMOP) == -1) { fprintf(stderr, "Can't create MOP protocol socket: %s\n", strerror(errno)); exit(1); } // If no interface on the command-line then use defaults interface = iface->find_interface(ifname); if (interface == -1) { if (ifname) fprintf(stderr, "Cannot resolve interface %s\n", ifname); else fprintf(stderr, "Cannot find any ethernet interfaces\n"); return 2; } mop_socket = iface->get_fd(interface); if (iface->bind_socket(interface)) return 3; if (trigger) { return send_boot(addr.ether_addr_octet, interface); } return do_moprc(addr.ether_addr_octet, interface, convert_bs, poll_interval*1000); } static int readmop(unsigned char *buf, int buflen) { int ifn; unsigned char macaddr[6]; bool more; return iface->recv_packet(mop_socket, ifn, macaddr, buf, buflen, more); } static int send_reserve(u_int8_t *macaddr, int interface) { unsigned char buf[32]; memset(buf, 0, sizeof(buf)); buf[0] = 9; buf[1] = 0; buf[2] = MOPRC_CMD_RESERVE; return send_message(buf, 11, interface, macaddr); } static int send_release(u_int8_t *macaddr, int interface) { unsigned char buf[32]; memset(buf, 0, sizeof(buf)); buf[0] = 1; buf[1] = 0; buf[2] = MOPRC_CMD_RELEASE; return send_message(buf, 3, interface, macaddr); } static int send_reqid(u_int8_t *macaddr, int interface) { unsigned char buf[32]; memset(buf, 0, sizeof(buf)); buf[0] = 5; buf[1] = 0; buf[2] = MOPRC_CMD_REQUESTID; return send_message(buf, 7, interface, macaddr); } static int send_boot(u_int8_t *macaddr, int interface) { unsigned char buf[32]; memset(buf, 0, sizeof(buf)); buf[0] = 12; buf[1] = 0; buf[2] = MOPRC_CMD_BOOT; buf[13] = 0xFF; return send_message(buf, 14, interface, macaddr); } static int send_data(unsigned char *data, int len, u_int8_t *macaddr, int interface) { unsigned char buf[len+46]; static char message = 0; memset(buf, 0, sizeof(buf)); buf[0] = len+2; buf[1] = 0; buf[2] = MOPRC_CMD_COMMANDPOLL; buf[3] = message; memcpy(buf+4, data, len); message = 1-message; return send_message(buf, len+4, interface, macaddr); } static void print_ascic(unsigned char *buf, int len) { int i; for (i=0; i = 0) { /* No response after 3 tries */ if (waiting_ack && resends >= 3) { printf("\nTarget does not respond\n"); break; } /* Waiting for an ACK but not got one. Resend the last packet */ if (status == 0 && waiting_ack) { send_last_message(interface, macaddr); resends++; continue; } /* No data, poll for any input from the terminal server */ if (status == 0 && !waiting_ack) { unsigned char dummybuf[1]; send_data(dummybuf, 0, macaddr, interface); waiting_ack = 1; resends = 0; } /* Data from the terminal server */ if (FD_ISSET(mop_socket, &in)) { int cmd; int datalen; len = readmop(buf, sizeof(buf)); if (len < 0) { perror("reading from Remote"); return -1; } if (len == 0) continue; waiting_ack = 0; cmd = buf[2]; datalen = buf[0] | buf[1] <<8; /* Ignore duplicates */ if (last_msg_tag == buf[3]) continue; last_msg_tag = buf[3]; switch (cmd) { case MOPRC_CMD_RESERVE: case MOPRC_CMD_RELEASE: case MOPRC_CMD_REQUESTID: fprintf(stderr, "Got unsupported MOPRC function %d\n", cmd); break; /* Got some data to display */ case MOPRC_CMD_RESPONSE: if (datalen > 2) { fwrite(buf+4, datalen-2, 1, stdout); fflush(stdout); last_packet_was_empty = 0; } else { last_packet_was_empty = 1; } break; /* Response to our REQUESTID message means we are connected */ case MOPRC_CMD_SYSTEMID: if (state == STARTING) { if (show_system_info(&buf[6], datalen-1) == 0) { printf("target does not support remote console\n"); goto finished; } if (stdin_is_tty) printf("Console connected (press CTRL/D when finished)\n"); state = CONNECTED; } break; default: fprintf(stderr, "Got unknown MOPRC function %d\n", cmd); break; } } /* Keyboard input */ if (FD_ISSET(STDIN_FILENO, &in)) { int i; len = read(STDIN_FILENO, buf, stdin_is_tty ? sizeof(buf) : 1); if (len < 0) { perror("reading from stdin"); return -1; } if (len == 0) break; /* Convert LF to CR & check for ^D */ for (i=0; i