bobs@randvax.UUCP (Rober Schwartzkopf) (01/30/91)
Due to the large number of people interested in kboot I've decided to
post it here.
Bob Schwartzkopf (bobs@rand.org)
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 1 (of 3)."
# Contents: aarpd.c cmd.c getaa.c icmp.c kboot.c nitlib.c
# Wrapped by bobs@chumley on Tue Jan 29 17:41:51 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'aarpd.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'aarpd.c'\"
else
echo shar: Extracting \"'aarpd.c'\" \(7348 characters\)
sed "s/^X//" >'aarpd.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char *RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/aarpd.c,v 1.1 91/01/29 17:36:55 root Exp $";
X#endif lint
X
X/*
X * $Log: aarpd.c,v $
X * Revision 1.1 91/01/29 17:36:55 root
X * Initial revision
X *
X */
X
X/*
X * aarpd - Appletalk ARP daemon. Obtain an appletalk protocol address,
X * then listen forever, responding to any appletalk probes and
X * requests sent to us. Depends on SunOS 4.x NIT interface.
X *
X * Author: Bob Schwartzkopf, The RAND Corporation. Based on an earlier
X * version written by Dan Tappan at BBN that ran under SunOS 3.x.
X *
X * Comments, suggestions, patches, bug reports, etc. may be sent to
X * bobs@rand.org.
X */
X
X#include <stdio.h>
X#include <syslog.h>
X#include <sys/types.h>
X#include <sys/errno.h>
X#include <sys/socket.h>
X#include <sys/fcntl.h>
X#include <sys/termios.h>
X#include <net/if.h>
X#include <netinet/in.h>
X#include <netinet/if_ether.h>
X#include <rpc/rpc.h>
X#include <sys/time.h>
X#include <sys/timeb.h>
X#include "appletalk.h"
X#include "aarpd.h"
X#include "config.h"
X#include "patchlevel.h"
X
Xextern char *rindex ();
Xint aarp_read ();
X
Xextern struct ether_addr myether; /* Setup by nit_init */
Xextern int errno;
Xextern char *sys_errlist[];
X
X#define VERSION 2
X
X/*
X * Globals.
X */
Xchar *progname;
Xchar *interface = NULL;
Xstruct ether_addr ebc = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Xlong atalkaddr; /* Current appletalk address */
Xint haveaddr = 0; /* Have appletalk address */
Xint conflict; /* We're in confict with someone*/
Xint detached = 0; /* Detached from tty */
Xint debug = 0; /* Debugging */
Xstruct ether_header eh; /* Output ethernet header */
Xstruct ether_aarp ap; /* Output packet */
X
Xmain (argc, argv)
X
Xint argc;
Xchar **argv;
X
X{
X char c;
X int i;
X
X if ((progname = rindex (argv[0], '/')) == NULL)
X progname = *argv;
X else
X progname++;
X while (--argc > 0) {
X argv++;
X c = (*argv)[0] == '-' ? (*argv)[1] : (*argv)[0];
X switch (c) {
X case 'd' :
X debug++;
X break;
X case 'i' :
X if (argc <= 1)
X usage ();
X argv++;
X argc--;
X interface = *argv;
X break;
X case 'v' :
X printf ("%s version number %d.%d\n", progname, VERSION, PATCHLEVEL);
X exit (0);
X default :
X usage ();
X }
X }
X if (!debug) { /* Detach ourselves */
X detached++;
X if (fork ())
X exit (0);
X if ((i = open ("/dev/tty", O_RDONLY)) >= 0)
X ioctl (i, TIOCNOTTY, 0);
X i = getdtablesize ();
X while (--i >= 0)
X close (i);
X open ("/dev/null", 0);
X dup2 (0, 1);
X dup2 (0, 2);
X openlog (progname, 0, LOG_DAEMON);
X }
X nit_init (interface);
X nit_open (sizeof (ap) + sizeof (eh), AARP);
X aarp_probe (); /* Get appletalk address */
X initrpc (); /* Prepare for RPC */
X ap.aarp_op = htons (AARPResp); /* Set up for sending replies */
X nit_dispatch (aarp_read, 0, &svc_fdset, svc_getreqset, NULL);
X}
X
X/*
X * usage - Print usage and die.
X */
Xusage ()
X
X{
X fprintf (stderr, "Usage: %s [-d] [-i interface]\n", progname);
X exit (1);
X}
X
X/*
X * aarp_probe - Get unused appletalk address. Algorithm is to try each
X * in turn, probing to see if anyone else is using each address. When
X * no one answers a probe, we use that address. Note this routine
X * initializes some global data structures (eh, ap), parts of which are
X * used later by aarp_read ().
X */
Xaarp_probe ()
X
X{
X u_long spa;
X int i;
X struct timeval timeout;
X struct timeb tstart;
X struct timeb tcur;
X int utotal;
X int ucur;
X
X /* Init ether header */
X ether_copy (&ebc, &eh.ether_dhost);
X ether_copy (&myether, &eh.ether_shost);
X eh.ether_type = htons (AARP);
X /* Init aarp header */
X ap.aarp_hrd = htons (H_Ethernet);
X ap.aarp_pro = htons (P_AppleTalk);
X ap.aarp_hln = HL_Ethernet;
X ap.aarp_pln = PL_AppleTalk;
X ap.aarp_op = htons (AARPProbe);
X ether_copy (&myether, &ap.aarp_sha);
X bzero (&ap.aarp_tha, HL_Ethernet);
X nit_timeout (APrbTicks, &timeout);
X utotal = timeout.tv_sec * 1000000 + timeout.tv_usec;
X for (atalkaddr = 1; atalkaddr < 254; atalkaddr++) {
X spa = htonl (atalkaddr);
X bcopy (&spa, ap.aarp_spa, PL_AppleTalk);
X bcopy (&spa, ap.aarp_tpa, PL_AppleTalk);
X conflict = 0;
X for (i = 0; !conflict && i < APrbTries; i++) {
X nit_write ((caddr_t) &eh, (caddr_t) &ap, sizeof ap);
X ftime (&tstart);
X do {
X nit_dispatch (aarp_read, 1, NULL, NULL, &timeout);
X ftime (&tcur);
X ucur = (tcur.time - tstart.time) * 1000000 +
X (tcur.millitm - tstart.millitm) * 1000;
X } while (!conflict && utotal > ucur);
X }
X if (!conflict) {
X if (debug)
X fprintf (stderr, "aarp_probe: Using appletalk address %d\n",
X atalkaddr);
X break;
X }
X }
X if (conflict) {
X logerr ("aarp_probe: Couldn't find appletalk address, exiting...\n");
X exit (1);
X }
X haveaddr++;
X}
X
X/*
X * aarp_read - Handle AARP response packets.
X */
Xaarp_read (p, pl)
X
Xstruct aarp_packet *p;
Xint pl;
X
X{
X int op;
X long spa;
X long tpa;
X
X if (pl != sizeof (*p)) {
X if (debug)
X fprintf (stderr, "aarp_read: Truncated packet len %d\n", pl);
X return;
X }
X op = ntohs (p->ap_op);
X bcopy ((caddr_t) p->ap_spa, &spa, PL_AppleTalk);
X spa = ntohl (spa);
X switch (op) {
X case AARPProbe :
X case AARPReq :
X bcopy ((caddr_t) p->ap_tpa, &tpa, PL_AppleTalk);
X tpa = ntohl (tpa);
X if (haveaddr && tpa == atalkaddr) {
X /*
X * Most of the output header and packet (eh, ap) should already be
X * set up since it was used for probing initially. Should only need
X * to fill in destination addresses.
X */
X ether_copy (&p->ap_sha, &eh.ether_dhost);
X ether_copy (&p->ap_sha, &ap.aarp_tha);
X bcopy (p->ap_spa, ap.aarp_tpa, PL_AppleTalk);
X if (debug) {
X fprintf (stderr, "aarp_read: Replying to %s from %d (%s)\n",
X op == AARPProbe ? "probe" : "request",
X spa, ether_ntoa (&p->ap_sha));
X }
X nit_write ((caddr_t) &eh, (caddr_t) &ap, sizeof ap);
X }
X break;
X
X case AARPResp :
X if (debug)
X fprintf (stderr, "aarp_read: Reply from %d (%s)\n",
X spa, ether_ntoa (&p->ap_sha));
X if (!haveaddr && spa == atalkaddr)
X conflict++;
X break;
X
X default :
X logerr ("aarp_read: Unknown AARP operation %d\n", op);
X }
X}
X
X/*
X * getaa - Return appletalk address for this host.
X */
Xgetaa (request, xprt)
X
Xstruct svc_req *request;
XSVCXPRT *xprt;
X
X{
X struct sockaddr_in *sa;
X
X if (debug) {
X sa = svc_getcaller (xprt);
X fprintf (stderr, "getaa: Returning %d to %s\n",
X atalkaddr, inet_ntoa (sa->sin_addr));
X }
X switch (request->rq_proc) {
X case NULLPROC:
X if (!svc_sendreply (xprt, xdr_void, 0)) {
X logerr ("getaa(NULLPROC): svc_sendreply failed\n");
X exit (1);
X }
X break;
X
X case GETAAPROC:
X if (!svc_sendreply (xprt, xdr_u_long, (caddr_t) &atalkaddr)) {
X logerr ("getaa(GETAAPROC): svc_sendreply failed\n");
X exit (1);
X }
X break;
X
X default:
X svcerr_noproc (xprt);
X break;
X }
X}
X
X/*
X * Initialize RPC stuff.
X */
Xinitrpc ()
X
X{
X SVCXPRT *xprt;
X
X if ((xprt = svcudp_create (RPC_ANYSOCK)) == NULL) {
X logerr ("initrpc: svcudp_create failed\n");
X exit (1);
X }
X pmap_unset (GETAAPROG, GETAAVERS);
X if (!svc_register (xprt, GETAAPROG, GETAAVERS, getaa, IPPROTO_UDP)) {
X logerr ("initrpc: Can't register %d %d\n", GETAAPROG, GETAAVERS);
X exit (1);
X }
X}
END_OF_FILE
if test 7348 -ne `wc -c <'aarpd.c'`; then
echo shar: \"'aarpd.c'\" unpacked with wrong size!
fi
# end of 'aarpd.c'
fi
if test -f 'cmd.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cmd.c'\"
else
echo shar: Extracting \"'cmd.c'\" \(19050 characters\)
sed "s/^X//" >'cmd.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char *RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/cmd.c,v 1.1 91/01/29 17:36:59 root Exp $";
X#endif lint
X
X/*
X * $Log: cmd.c,v $
X * Revision 1.1 91/01/29 17:36:59 root
X * Initial revision
X *
X */
X
X/*
X * cmd.c - Send commands to kboxes.
X */
X
X#include <stdio.h>
X#include <syslog.h>
X#include <netdb.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/errno.h>
X#include <net/if.h>
X#include <netinet/in.h>
X#include <netinet/if_ether.h>
X#include <sys/time.h>
X#include <sys/timeb.h>
X#include "appletalk.h"
X#include "cmdidx.h"
X#include "cmdmacro.h"
X#include "kbox.h"
X#include "config.h"
X
Xextern struct hostent *gethostbyaddr ();
Xextern char *inet_ntoa ();
Xstruct kbox *get_kbox ();
Xextern int errno;
Xextern char *sys_errlist[];
Xextern int numkbox;
Xextern int debug;
Xextern struct ether_addr ebc;
Xextern struct ether_header eh;
Xextern struct kbox *kboxtab[HTSIZE];
Xextern long atalkaddr;
Xextern unsigned char kboxstate[STATE_LENGTH];
Xextern unsigned char newstate[STATE_LENGTH];
Xextern char *etcdir;
Xextern unsigned char *zonelistp;
X
X#define HEX(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10)
X
X/*
X * Globals.
X */
Xint (*recv_copyproc) () = NULL;
Xstruct ether_fastpath fppkt;
Xstruct fp_promram promram;
Xint num_resp;
Xint expected_resp;
Xint destkbox;
Xstruct kbox *kboxaddr[MAXKBOX];
Xstruct timeval timeout;
X
X/*
X * Receive functions. There should be a recv_ function for each send_
X * function.
X */
X
X/*
X * recv_who - Process who packet. Algorithm is to look up the ethernet
X * address in the ethers file and then add this kbox to the hash
X * table it's not already there. It would probably be more efficient
X * to look up the ethernet address directly in a table hashed by ethernet
X * address, however recv_who isn't called very often so I won't bother.
X */
Xrecv_who (p)
X
Xstruct fp_packet *p;
X
X{
X char name[MAXHOSTNAME];
X char buf[20];
X struct kbox *kp;
X
X if (ether_ntohost (name, &p->fp_shost) != 0) {
X logerr ("recv_who: Can't find %s in ethers table\n",
X ether_ntoa (&p->fp_shost));
X return;
X }
X if (kp = get_kbox (name)) {
X if (!bcmp (&kp->ea, &p->fp_shost, sizeof(struct ether_addr))) {
X if (kp->aa == AT_Broadcast) {
X kp->aa = p->fp_lapsrc;
X kboxaddr[kp->aa] = kp;
X if (debug)
X fprintf (stderr, "recv_who: Adding kbox %s %s\n",
X name, ether_ntoa (&p->fp_shost));
X num_resp++;
X }
X } else {
X strcpy (buf, ether_ntoa (&kp->ea));
X logerr ("recv_who: Mismatched ether address for %s: %s != %s\n",
X name, buf, ether_ntoa (&p->fp_shost));
X }
X } else if (debug)
X fprintf (stderr, "recv_who: Unknown kbox %s %s\n",
X name, ether_ntoa (&p->fp_shost));
X}
X
X/*
X * recv_promram - Receive promram vector. On sparc machines the
X * fp_promram structure doesn't align properly, so copy the count
X * field separately.
X */
Xrecv_promram (p)
X
Xstruct fp_packet *p;
X
X{
X bcopy (p->fp_data, &promram.fpr_count, sizeof(promram.fpr_count));
X bcopy (&p->fp_data[sizeof(promram.fpr_count)], &promram.fpr_jtable,
X PROMRAMSIZE - sizeof(promram.fpr_count));
X num_resp++;
X}
X
X/*
X * recv_getstate - Receive state vector.
X */
Xrecv_getstate (p)
X
Xstruct fp_packet *p;
X
X{
X bcopy (&p->fp_data[FPCOPYSIZE], kboxstate, STATE_LENGTH);
X if (debug) {
X fprintf (stderr, "recv_getstate: Received state...\n");
X show_state (stderr, kboxstate);
X }
X num_resp++;
X}
X
X/*
X * recv_rcsid - Receive rcs id string.
X */
Xrecv_rcsid (p)
X
Xstruct fp_packet *p;
X
X{
X char rcsid[MAXFPPKT];
X
X strcpy (rcsid, p->fp_data);
X printf ("RCS ID: %s\n", rcsid);
X num_resp++;
X}
X
X/*
X * recv_whereis - Receive whereis packet.
X */
Xrecv_whereis (p)
X
Xstruct fp_packet *p;
X
X{
X struct fp_whereis w;
X
X bcopy (p->fp_data, &w, sizeof(w));
X printf ("Rom0: %x Rom1: %x Z8530: %x Port0: %x Port1: %x\n",
X w.fpw_rom0, w.fpw_rom1, w.fpw_8530, w.fpw_0port, w.fpw_1port);
X printf ("Ramstart: %x Ramend: %x\n", w.fpw_ram2, w.fpw_ramtop);
X num_resp++;
X}
X
X/*
X * recv_where2 - Receive where2 packet.
X */
Xrecv_where2 (p)
X
Xstruct fp_packet *p;
X
X{
X struct fp_where2 w2;
X char *m;
X
X bcopy (p->fp_data, &w2.fpw2_model, sizeof(w2.fpw2_model));
X bcopy (&p->fp_data[sizeof(w2.fpw2_model)], &w2.fpw2_enetprom,
X sizeof(w2) - sizeof(w2.fpw2_model));
X m = (w2.fpw2_model == FPMODEL123) ? "FPMODEL123" :
X (w2.fpw2_model == FPMODEL4) ? "FPMODEL4" : "UNKNOWN";
X printf ("Model: %s (%d) Ethernet address ROM: %x\n",
X m, w2.fpw2_model, w2.fpw2_enetprom);
X printf ("Extension RAM first word: %x last word: %x\n",
X w2.fpw2_exrambot, w2.fpw2_exramtop);
X num_resp++;
X}
X
X/*
X * recv_state - Receive kbox state.
X */
Xrecv_state (p)
X
Xstruct fp_packet *p;
X
X{
X int state;
X char *s;
X
X bcopy (p->fp_data, &state, sizeof(state));
X switch (state) {
X case BOOTME : s = "BOOTME"; break;
X case DOWNLOAD_VALID : s = "DOWNLOAD VALID"; break;
X case FORCE_PROM_EXECUTION : s = "FORCE PROM EXECUTION"; break;
X case PROM1_VALID : s = "PROM1 VALID"; break;
X case BE_A_BRIDGE : s = "BE A BRIDGE"; break;
X case EXECUTING_BRIDGE : s = "EXECUTING BRIDGE"; break;
X case EXECUTING_DOWNLOAD : s = "EXECUTING DOWNLOAD"; break;
X case EXECUTING_PROM1 : s = "EXECUTING PROM1"; break;
X default : s = "UNKNOWN";
X }
X printf ("State: %s (%d)\n", s, state);
X num_resp++;
X}
X
X/*
X * recv_version - Receive prom version.
X */
Xrecv_version (p)
X
Xstruct fp_packet *p;
X
X{
X struct fp_version ver;
X char model[5];
X
X bcopy (p->fp_data, &ver, sizeof(ver));
X bcopy (&ver.fpv_model, model, sizeof(ver.fpv_model));
X model[4] = '\0';
X printf ("Jump table entries: %d Prom version: %d Model: %s\n",
X ver.fpv_entries, ver.fpv_version, model);
X num_resp++;
X}
X
X/*
X * recv_hwstatus - Receive hardware status.
X */
Xrecv_hwstatus (p)
X
Xstruct fp_packet *p;
X
X{
X int status;
X
X bcopy (p->fp_data, &status, sizeof(status));
X printf ("Hardware status:");
X if (status) {
X if (status & SCC_BAD)
X printf (" SCC_BAD");
X if (status & I82586_BAD)
X printf (" I82586_BAD");
X if (status & BATTERY_LOW)
X printf (" BATTERY_LOW");
X if (status & FUSE_BLOWN)
X printf (" FUSE_BLOWN");
X if (status & RAMTEST_FAILED)
X printf (" RAMTEST_FAILED");
X } else
X printf (" OK");
X printf (" (0x%x)\n", status);
X num_resp++;
X}
X
X/*
X * inet_ntos - Translate ip address to hostname.
X */
Xchar *inet_ntos (addr)
X
Xunsigned char *addr;
X
X{
X struct in_addr a;
X struct hostent *he;
X
X bcopy (addr, &a.s_addr, 4);
X if ((he = gethostbyaddr (&a, 4, AF_INET)) == NULL)
X return (inet_ntoa (a));
X else
X return (he->h_name);
X}
X
X/*
X * show_state - Print state vector.
X */
Xshow_state (f, s)
X
XFILE *f;
Xunsigned char s[STATE_LENGTH];
X
X{
X int options;
X int i;
X int first;
X long l;
X short st;
X
X fprintf (f, "\tAppletalk: %d.%d.%d Ethertalk: %d.%d.%d IPtalk: %d.%d.%d",
X s[O_ATNET], s[O_ATNET+1], s[O_NODE],
X s[O_ETNET], s[O_ETNET+1], s[O_ETNODE],
X s[O_UDPNET], s[O_UDPNET+1], s[O_UDPNODE]);
X fprintf (f, " Bridge: %d\n", s[O_BRIDGE]);
X fprintf (f, "\tEthernet: %s Name: \"%s\" File: \"%s\"\n",
X ether_ntoa (&s[O_ETHER]), &s[O_NAME], &s[O_FILE]);
X fprintf (f, "\tConfig: \"%s\"\n", &s[O_CONFIG]);
X fprintf (f, "\tATzone: \"%s\" ETzone: \"%s\" UDPzone: \"%s\"\n",
X &s[O_ATZONE], &s[O_ETZONE], &s[O_UDPZONE]);
X fprintf (f, "\tPforce: %d Autoconfig: %s", s[O_PFORCE],
X (s[O_AUTOCONFIG] || s[O_AUTOCONFIG+1]) ? "yes" : "no");
X fprintf (f, " Autoboot: %s",
X (s[O_AUTOBOOT] || s[O_AUTOBOOT+1]) ? "yes\n" : "no\n");
X fprintf (f, "\tOptions: ");
X bcopy (&s[O_OPTIONS], &options, sizeof(options));
X if (options) {
X for (first = 1, i = 0; i < 32; i++)
X if ((1 << i) & options)
X if (first) {
X first = 0;
X fprintf (f, "%d", i + 1);
X } else
X fprintf (f, ", %d", i+1);
X } else
X fprintf (f, "none");
X bcopy (&s[O_SN], &l, sizeof (l));
X bcopy (&s[O_TYPE], &st, sizeof (st));
X fprintf (f, " Serial: %d Type: %d\n", l, st);
X fprintf (f, "\tRouter: \"%s\"", inet_ntos (&s[O_IPDEFROUTER]));
X fprintf (f, " ETip: \"%s\"", inet_ntos (&s[O_IPADDRESS]));
X fprintf (f, " ATip: \"%s\"", inet_ntos (&s[O_ATIPADDRESS]));
X fprintf (f, " Broadcast: \"%s\"\n", inet_ntos (&s[O_IPBROADCAST]));
X fprintf (f, "\tSubnet: \"%s\"", inet_ntos (&s[O_IPSUBMASK]));
X fprintf (f, " KIP: \"%s\"", inet_ntos (&s[O_IPKIPSERVER]));
X fprintf (f, " Name: \"%s\"", inet_ntos (&s[O_NAMESERVER]));
X fprintf (f, " File: \"%s\"\n", inet_ntos (&s[O_FILESERVER]));
X bcopy (&s[O_LP1], &l, sizeof (l));
X fprintf (f, "\tLocal1: 0x%x", l);
X bcopy (&s[O_LP2], &l, sizeof (l));
X fprintf (f, " Local2: 0x%x", l);
X bcopy (&s[O_LP3], &l, sizeof (l));
X fprintf (f, " Local3: 0x%x", l);
X bcopy (&s[O_LP4], &l, sizeof (l));
X fprintf (f, " Local4: 0x%x\n", l);
X bcopy (&s[O_NDYNAMICS], &st, sizeof (st));
X fprintf (f, "\tDynamics: %d", st);
X bcopy (&s[O_NSTATICS], &st, sizeof (st));
X fprintf (f, " Statics: %d", st);
X bcopy (&s[O_ZONELIST], &l, sizeof (l));
X fprintf (f, " Zonelist 0x%X\n", l);
X}
X
X/*
X * recv_gen - Generic receive routine.
X */
Xrecv_gen (p)
X
Xstruct fp_packet *p;
X
X{
X num_resp++;
X}
X
X/*
X * recv_pkt - Call appropriate function to deal with packet from fastpath.
X */
Xrecv_pkt (p)
X
Xstruct fp_packet *p;
X
X{
X char buf[100];
X
X if (p->fp_laptype != FP_TYPE) {
X return;
X }
X if (destkbox != AT_Broadcast && p->fp_lapsrc != destkbox) {
X /*
X * X_WHO responses from unconfigured fastpaths to broadcasts may come
X * in after we've already started talking to a real fastpath, so
X * just ignore all X_WHO responses with no error message.
X */
X if (p->fp_scmd != X_WHO)
X logerr ("recv_pkt: Bogus response %d from %s\n",
X p->fp_scmd, ether_ntoa (&p->fp_shost));
X return;
X }
X if (p->fp_cmd == FP_ACK) {
X num_resp++;
X return;
X }
X if (p->fp_cmd != FP_RESP)
X return;
X switch (p->fp_scmd) {
X case X_COPYMEM : if (recv_copyproc)
X (*recv_copyproc) (p);
X break;
X
X case X_HWSTATUS : recv_hwstatus (p); break;
X
X case X_PROMRAM : recv_promram (p); break;
X
X case X_RCSID : recv_rcsid (p); break;
X
X case X_STATE : recv_state (p); break;
X
X case X_VERSION : recv_version (p); break;
X
X case X_WHEREIS : recv_whereis (p); break;
X
X case X_WHERE2 : recv_where2 (p); break;
X
X case X_WHO : recv_who (p); break;
X
X case X_RESET : recv_gen ();
X break;
X
X default : ether_ntohost (buf, &p->fp_shost);
X logerr ("recv_pkt: Received %d from %s\n",
X p->fp_scmd, buf);
X break;
X }
X}
X
X/*
X * Send procedures. Those that have no parameters are macros that invoke
X * send_gen(), defined in kbox.h.
X */
X
X/*
X * send_who - Broadcast who packet.
X */
Xint send_who ()
X
X{
X int i;
X
X for (i = 0; i < MAXKBOX; i++)
X if (kboxaddr[i])
X kboxaddr[i]->aa = AT_Broadcast;
X nit_timeout (60, &timeout);
X return (send_pkt (NULL, (int) FP_CMD, X_WHO, 0, 5, &timeout));
X}
X
X/*
X * send_boot - Download file to kbox.
X */
Xint send_boot (kp, zonedata, zonelen)
X
Xstruct kbox *kp;
Xunsigned char *zonedata;
Xint zonelen;
X
X{
X FILE *f;
X int l;
X int ch;
X int cmd;
X int scmd;
X char fn[MAXFN];
X int size = 0;
X int lastlen;
X int lastaddr;
X
X sprintf (fn, "%s/%s", etcdir, kp->bootfile);
X if ((f = fopen (fn, "r")) == NULL) {
X logerr ("send_boot: %s to %s - %s\n", fn, kp->name, sys_errlist[errno]);
X return (0);
X }
X nit_timeout (30, &timeout);
X while ((cmd = fgetc (f)) > 0) {
X if (cmd != 'S') {
X logerr ("send_boot: Bad S record %d\n", cmd);
X return (-1);
X }
X scmd = fgetc (f);
X if (scmd == '8') {
X /*
X * With KSTAR 8.0 it is necessary to download a zonelist with
X * KSTAR. The following code converts the zonelist read from
X * the config file written by the Fastpath Manager into
X * s-records and sends them to the kbox. The address where
X * the zonelist is downloaded is the first even address after
X * the last s-record, which is the address of the last s-record
X * plus its length, rounded up to the nearest even address.
X * The first s-record describes the following data, it looks like:
X *
X * short num_elements;
X * struct {
X * short type;
X * short length;
X * } element[NUMELEMENTS];
X *
X * For a zonelist the type is 1. The second s-record contains
X * the zonelist itself. These extra s-records get sent right
X * before the last s-record, which seems to have scmd == 8.
X * Much of the information on the format of the s-records and
X * their location was reverse engineered from packet traces,
X * I don't guarantee this code to be correct, although it
X * works for me.
X */
X lastlen = atox (fppkt.fastpath_data, 2);
X lastaddr = atox (&fppkt.fastpath_data[2], 6);
X zonelistp = (unsigned char *) (lastaddr + lastlen - 4);
X if ((int) zonelistp % 2 == 1)
X zonelistp++;
X makeelemlist (fppkt.fastpath_data, zonelen);
X if (debug)
X fprintf (stderr, "send_boot: %s\n", fppkt.fastpath_data);
X if (send_pkt (kp, 'S', '2', strlen(fppkt.fastpath_data),
X 5, &timeout) != 1)
X return (0);
X makezonedata (fppkt.fastpath_data, zonedata, zonelen);
X if (debug)
X fprintf (stderr, "send_boot: %s\n", fppkt.fastpath_data);
X if (send_pkt (kp, 'S', '2', strlen(fppkt.fastpath_data),
X 5, &timeout) != 1)
X return (0);
X }
X l = 0;
X while ((ch = fgetc (f)) > 0 && ch != '\r' && ch != '\n')
X fppkt.fastpath_data[l++] = ch;
X size += l;
X if (send_pkt (kp, cmd, scmd, l, 5, &timeout) != 1)
X return (0);
X }
X if (debug)
X fprintf (stderr, "send_boot: Downloaded %d bytes\n", size);
X return (1);
X}
X
X/*
X * atox - Convert ascii string of length l to hex.
X */
Xint atox (s, l)
X
Xchar *s;
Xint l;
X
X{
X int r = 0;
X int i;
X
X for (i = 0; i < l; i++)
X r = (r << 4) | ((s[i] >= '0' && s[i] <= '9') ? s[i] - '0' :
X (s[i] >= 'a' && s[i] <= 'f') ? s[i] - 'a' + 10 :
X s[i] - 'A' + 10);
X return (r);
X}
X
X/*
X * csumsrec - Compute checksum for s-record.
X */
Xunsigned char csumsrec (s, l)
X
Xunsigned char *s;
Xint l;
X
X{
X unsigned char sum;
X static char buf[3];
X
X sum = 0;
X while (l--)
X sum += *s++;
X sum ^= 0xFF;
X return (sum);
X}
X
X/*
X * makeelemlist - Make element list srecord.
X */
Xmakeelemlist (p, l)
X
Xunsigned char *p;
Xint l;
X
X{
X static elemlist el = {1, 1, 0};
X unsigned char buf[BUFSIZ];
X
X el.bytes = l + 2; /* Don't know why +2 */
X bcopy (&zonelistp, buf, sizeof (zonelistp)); /* First byte is length */
X *buf = 4 + sizeof (el); /* so overwrite it */
X bcopy (&el, &buf[4], sizeof (el));
X buf[4 + sizeof (el)] = csumsrec (buf, 4 + sizeof (el));
X hexify (buf, p, 4 + sizeof (el) + 1);
X}
X
X/*
X * makezonedata - Make zone data srecord.
X */
Xmakezonedata (p, data, l)
X
Xunsigned char *p;
Xunsigned char *data;
Xint l;
X
X{
X unsigned char *addr;
X unsigned char buf[BUFSIZ];
X
X addr = zonelistp + sizeof (elemlist);
X bcopy (&addr, buf, sizeof (addr));
X *buf = 4 + l;
X bcopy (data, &buf[4], l);
X buf[4 + l] = csumsrec (buf, 4 + l);
X hexify (buf, p, 4 + l + 1);
X}
X
X/*
X * hexify - Convert buffer to hex ascii characters.
X */
Xhexify (buf, p, len)
X
Xunsigned char *buf;
Xunsigned char *p;
Xint len;
X
X{
X int i;
X
X for (i = 0; i < len; i++) {
X p[2 * i] = HEX (buf[i] >> 4);
X p[2 * i + 1] = HEX (buf[i] & 0xF);
X }
X p[2 * len] = '\0';
X}
X
X
X/*
X * send_getstate - Get state vector.
X */
Xint send_getstate (kp)
X
Xstruct kbox *kp;
X
X{
X struct fp_copy copy;
X
X copy.fpc_from = (char *) promram.fpr_state;
X copy.fpc_to = (char *) -1;
X copy.fpc_count = STATE_LENGTH;
X bcopy (©, fppkt.fastpath_data, FPCOPYSIZE);
X recv_copyproc = recv_getstate;
X nit_timeout (30, &timeout);
X return (send_pkt (kp, (int) FP_CMD, X_COPYMEM, FPCOPYSIZE, 5, &timeout));
X}
X
X/*
X * send_putstate - Put state vector.
X */
Xint send_putstate (kp)
X
Xstruct kbox *kp;
X
X{
X struct fp_copy copy;
X
X copy.fpc_from = (char *) -1;
X copy.fpc_to = (char *) promram.fpr_state;
X copy.fpc_count = htons (STATE_LENGTH);
X bcopy (©, fppkt.fastpath_data, FPCOPYSIZE);
X newstate[O_NODE] = kboxstate[O_NODE];
X bcopy (newstate, &fppkt.fastpath_data[FPCOPYSIZE], STATE_LENGTH);
X if (debug) {
X fprintf (stderr, "send_putstate: Sending state...\n");
X show_state (stderr, newstate);
X }
X recv_copyproc = recv_gen;
X nit_timeout (30, &timeout);
X return (send_pkt (kp, (int) FP_CMD, X_COPYMEM,
X FPCOPYSIZE + STATE_LENGTH, 5, &timeout));
X}
X
X/*
X * send_state - Send state request.
X */
Xint send_state (kp)
X
Xstruct kbox *kp;
X
X{
X static int state = 0;
X
X bcopy (&state, fppkt.fastpath_data, sizeof(state));
X nit_timeout (30, &timeout);
X return (send_pkt (kp, (int) FP_CMD, X_STATE, sizeof(state), 5, &timeout));
X}
X
X/*
X * send_hwstatus - Send hwstatus request.
X */
Xint send_hwstatus (kp)
X
Xstruct kbox *kp;
X
X{
X nit_timeout (30, &timeout);
X return (send_pkt (kp, (int) FP_CMD, X_HWSTATUS, sizeof(long), 5, &timeout));
X}
X
X/*
X * send_gen - Generic send command.
X */
Xint send_gen (kp, scmd, retries)
X
Xstruct kbox *kp;
Xint scmd;
Xint retries;
X
X{
X nit_timeout (60, &timeout);
X return (send_pkt (kp, (int) FP_CMD, scmd, 0, retries, &timeout));
X}
X
X/*
X * send_pkt - Send command packet (in fppkt). Returns # of responders,
X * or -1 on error. If retries is 0, don't expect any response.
X */
Xint send_pkt (kp, cmd, scmd, len, retries, timeout)
X
Xstruct kbox *kp;
Xint cmd;
Xint scmd;
Xint len;
Xint retries;
Xstruct timeval *timeout;
X
X{
X short count;
X int h;
X struct kbox *p;
X struct timeb tstart;
X struct timeb tcur;
X int utotal;
X int ucur;
X
X if (kp) {
X if (kp->aa == AT_Broadcast) {
X logerr ("send_pkt: Invalid appletalk address for %s\n", kp->name);
X return (-1);
X }
X destkbox = kp->aa;
X ether_copy (&kboxaddr[destkbox]->ea, &eh.ether_dhost);
X if (retries == 0) {
X expected_resp = 0;
X retries = 1;
X } else
X expected_resp = 1;
X } else {
X destkbox = AT_Broadcast;
X ether_copy (&ebc, &eh.ether_dhost);
X expected_resp = numkbox;
X }
X num_resp = 0;
X fppkt.fastpath_lapdest = destkbox;
X fppkt.fastpath_lapsrc = atalkaddr;
X fppkt.fastpath_laptype = FP_TYPE;
X fppkt.fastpath_cmd = cmd;
X fppkt.fastpath_scmd = scmd;
X count = htons (len + 4);
X bcopy (&count, fppkt.fastpath_len, sizeof(count));
X utotal = timeout->tv_sec * 1000000 + timeout->tv_usec;
X for (count = 0; count < retries; count++) {
X if (debug && count >= 1)
X fprintf (stderr, "send_pkt: Retransmitting cmd %d scmd %d\n",
X fppkt.fastpath_cmd, fppkt.fastpath_scmd);
X nit_write (&eh, &fppkt, len + sizeof(struct ether_fastpath) - MAXFPPKT);
X ftime (&tstart);
X ucur = 0;
X while (num_resp < expected_resp && utotal > ucur) {
X nit_dispatch (recv_pkt, 1, NULL, NULL, timeout);
X ftime (&tcur);
X ucur = (tcur.time - tstart.time) * 1000000 +
X (tcur.millitm - tstart.millitm) * 1000;
X }
X if (num_resp >= expected_resp)
X break;
X }
X if (num_resp != expected_resp)
X if (destkbox == AT_Broadcast) {
X for (h = 0; h < HTSIZE; h++)
X for (p = kboxtab[h]; p; p = p->nxt)
X if (p->aa == AT_Broadcast)
X logerr ("send_pkt(%d,%d): No response from %s\n",
X cmd, scmd, p->name);
X } else
X logerr ("send_pkt(%d,%d): No response from %s\n",
X cmd, scmd, kboxaddr[destkbox]->name);
X return (num_resp);
X}
END_OF_FILE
if test 19050 -ne `wc -c <'cmd.c'`; then
echo shar: \"'cmd.c'\" unpacked with wrong size!
fi
# end of 'cmd.c'
fi
if test -f 'getaa.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'getaa.c'\"
else
echo shar: Extracting \"'getaa.c'\" \(787 characters\)
sed "s/^X//" >'getaa.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char *RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/getaa.c,v 1.1 91/01/29 17:37:21 root Exp $";
X#endif lint
X
X/*
X * $Log: getaa.c,v $
X * Revision 1.1 91/01/29 17:37:21 root
X * Initial revision
X *
X */
X
X#include <stdio.h>
X#include <rpc/rpc.h>
X#include "aarpd.h"
X
X/*
X * getaa - Return appletalk address of "host". If host is NULL get
X * local host address. Makes RPC call to aarpd on host.
X */
Xint getaa (host, aa)
X
Xchar *host;
Xint *aa;
X
X{
X int i;
X int s;
X
X if (host == NULL)
X host = "localhost";
X/*
X * Give aarpd a chance to register with portmap...
X */
X for (i = 0; i < 3; i++)
X if ((s = callrpc (host, GETAAPROG, GETAAVERS, GETAAPROC,
X xdr_void, 0, xdr_u_long, aa)) == 0)
X break;
X else
X sleep (2);
X return (s);
X}
END_OF_FILE
if test 787 -ne `wc -c <'getaa.c'`; then
echo shar: \"'getaa.c'\" unpacked with wrong size!
fi
# end of 'getaa.c'
fi
if test -f 'icmp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'icmp.c'\"
else
echo shar: Extracting \"'icmp.c'\" \(3355 characters\)
sed "s/^X//" >'icmp.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char *RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/icmp.c,v 1.1 91/01/29 17:37:23 root Exp $";
X#endif lint
X
X/*
X * $Log: icmp.c,v $
X * Revision 1.1 91/01/29 17:37:23 root
X * Initial revision
X *
X */
X
X#include <stdio.h>
X#include <syslog.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <sys/errno.h>
X#include <netdb.h>
X#include <net/if.h>
X#include <netinet/in_systm.h>
X#include <netinet/in.h>
X#include <netinet/ip.h>
X#include <netinet/ip_icmp.h>
X#include <netinet/if_ether.h>
X#include "kbox.h"
X#include "config.h"
X
Xextern int errno;
Xextern char *sys_errlist[];
Xextern int debug;
X
X/*
X * Globals.
X */
Xstruct icmp icmp_pkt;
Xint icmp_sock;
Xfd_set icmp_fds;
X
X/*
X * icmp_init - Initialize icmp stuff.
X */
Xicmp_init ()
X
X{
X if ((icmp_sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
X logerr ("icmp_init: %s\n", sys_errlist[errno]);
X exit (1);
X }
X FD_SET (icmp_sock, &icmp_fds);
X icmp_pkt.icmp_type = ICMP_ECHO;
X icmp_pkt.icmp_code = 0;
X icmp_pkt.icmp_seq = 0;
X icmp_pkt.icmp_id = (getpid () & 0xFFFF);
X}
X
X
X/*
X * in_cksum - Compute IP checksum.
X */
Xu_short in_cksum (a, l)
X
Xu_short *a;
Xint l;
X
X{
X int sum = 0;
X
X while (l > 1) {
X sum += *a++;
X l -= 2;
X }
X if (l == 1)
X sum += *(u_char *) a;
X sum += (sum >> 16);
X return ((~sum) & 0xFFFF);
X}
X
X/*
X * icmp_ping - Ping kbox.
X */
Xint icmp_ping (kp)
X
Xstruct kbox *kp;
X
X{
X struct sockaddr_in dest;
X struct sockaddr_in from;
X static struct timeval icmp_timeout = {PINGTIMEOUT, 0};
X char buf[BUFSIZ];
X struct ip *ip;
X struct icmp *p;
X int i;
X int r;
X fd_set readfds;
X
X icmp_pkt.icmp_seq++;
X icmp_pkt.icmp_cksum = 0;
X icmp_pkt.icmp_cksum = in_cksum (&icmp_pkt, sizeof (icmp_pkt));
X bzero (&dest, sizeof (dest));
X dest.sin_family = AF_INET;
X dest.sin_addr.s_addr = kp->ip.sin_addr.s_addr;
X for (i = 0; i < PINGRETRIES; i++) {
X p = NULL;
X /*
X * Send ping
X */
X if (debug)
X fprintf (stderr, "icmp_ping: Pinging %s id %d seq %d\n",
X inet_ntoa (dest.sin_addr), icmp_pkt.icmp_id,
X icmp_pkt.icmp_seq);
X if (sendto (icmp_sock, &icmp_pkt, sizeof (icmp_pkt), 0,
X &dest, sizeof (dest)) != sizeof (icmp_pkt)) {
X logerr ("icmp_ping: sendto - %s\n", sys_errlist[errno]);
X exit (1);
X }
X /*
X * Wait for reply
X */
Xwaitreply:
X readfds = icmp_fds;
X r = select (icmp_sock+1, &readfds, NULL, NULL, &icmp_timeout);
X if (r < 0) {
X logerr ("icmp_ping: select - %s\n", sys_errlist[errno]);
X exit (1);
X } else if (r == 0)
X continue;
X /*
X * Read reply
X */
X r = sizeof (from);
X if (recvfrom (icmp_sock, buf, BUFSIZ, 0, &from, &r) <= 0) {
X logerr ("icmp_ping: recvfrom - %s\n", sys_errlist[errno]);
X exit (1);
X }
X /*
X * Verify reply
X */
X ip = (struct ip *) buf;
X p = (struct icmp *) (buf + (ip->ip_hl << 2));
X if (p->icmp_type == ICMP_ECHOREPLY &&
X p->icmp_id == icmp_pkt.icmp_id &&
X p->icmp_seq == icmp_pkt.icmp_seq &&
X from.sin_addr.s_addr == kp->ip.sin_addr.s_addr) {
X if (debug)
X fprintf (stderr, "icmp_ping: Reply from %s id %d seq %d\n",
X inet_ntoa (from.sin_addr), p->icmp_id, p->icmp_seq);
X return (1);
X } else {
X if (debug)
X fprintf (stderr, "icmp_ping: Discarding packet from %s\n",
X inet_ntoa (from.sin_addr));
X goto waitreply;
X }
X }
X return (0);
X}
END_OF_FILE
if test 3355 -ne `wc -c <'icmp.c'`; then
echo shar: \"'icmp.c'\" unpacked with wrong size!
fi
# end of 'icmp.c'
fi
if test -f 'kboot.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'kboot.c'\"
else
echo shar: Extracting \"'kboot.c'\" \(12925 characters\)
sed "s/^X//" >'kboot.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char *RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/kboot.c,v 1.1 91/01/29 17:37:26 root Exp $";
X#endif lint
X
X/*
X * $Log: kboot.c,v $
X * Revision 1.1 91/01/29 17:37:26 root
X * Initial revision
X *
X */
X
X/*
X * kboot - Boot and configure fastpaths over an ethernet. Depends on NIT
X * interface in SunOS 4.x.
X *
X * Author: Bob Schwartzkopf, The RAND Corporation. Based on an earlier
X * version written by Dan Tappan at BBN that ran under SunOS 3.x.
X *
X * Comments, suggestions, patches, bug reports, etc. may be sent to
X * bobs@rand.org.
X */
X
X#include <stdio.h>
X#include <syslog.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/errno.h>
X#include <sys/termios.h>
X#include <netdb.h>
X#include <net/if.h>
X#include <netinet/in.h>
X#include <netinet/if_ether.h>
X#include "appletalk.h"
X#include "cmdidx.h"
X#include "cmdmacro.h"
X#include "kbox.h"
X#include "config.h"
X#include "patchlevel.h"
X
X#define VERSION 2
X
Xextern char *rindex ();
Xstruct kbox *get_kbox ();
Xextern int errno;
Xextern char *sys_errlist[];
Xextern struct ether_addr myether;
X
X/*
X * Globals.
X */
Xchar *progname;
Xstruct ether_addr ebc = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Xstruct ether_header eh;
Xchar *interface = NULL;
Xlong atalkaddr;
Xchar *etcdir = ETCDIR;
Xint detached = 0;
Xint debug = 0;
Xint watchf = 0;
Xint downloadf = 0;
Xint configf = 0;
Xint liststatef = 0;
Xint savestatef = 0;
Xint resetf = 0;
Xint statusf = 0;
Xstruct kbox *kboxtab[HTSIZE];
Xint numkbox;
Xunsigned char kboxstate[STATE_LENGTH];
Xunsigned char newstate[STATE_LENGTH];
Xunsigned char zonedata[MAXZONELIST];
Xint zonelen;
Xint pinginterval = PINGINTERVAL;
Xunsigned char *zonelistp;
X
Xmain (argc, argv)
X
Xint argc;
Xchar **argv;
X
X{
X int i;
X char c;
X char *name = NULL;
X struct kbox *kp;
X
X if ((progname = rindex (argv[0], '/')) == NULL)
X progname = *argv;
X else
X progname++;
X while (--argc > 0) {
X argv++;
X c = (*argv)[0] == '-' ? (*argv)[1] : (*argv)[0];
X switch (c) {
X case 'b' :
X if (argc <= 1)
X usage ();
X argv++; argc--;
X downloadf++;
X name = *argv;
X break;
X case 'c' :
X if (argc <= 1)
X usage ();
X argv++; argc--;
X configf++;
X name = *argv;
X break;
X case 'd' :
X debug++;
X break;
X case 'i' :
X if (argc <= 1)
X usage ();
X argv++; argc--;
X interface = *argv;
X break;
X case 'l' :
X if (argc <= 1)
X usage ();
X argv++; argc--;
X liststatef++;
X name = *argv;
X break;
X case 'm' :
X if (argc <= 1)
X usage ();
X argv++; argc--;
X statusf++;
X name = *argv;
X break;
X case 'p' :
X if (argc <= 1)
X usage ();
X argv++; argc--;
X pinginterval = atoi (*argv);
X break;
X case 'r' :
X if (argc <= 1)
X usage ();
X argv++; argc--;
X resetf++;
X name = *argv;
X break;
X case 's' :
X if (argc <= 1)
X usage ();
X argv++; argc--;
X savestatef++;
X name = *argv;
X break;
X case 'v' :
X printf ("%s version %d.%d\n", progname, VERSION, PATCHLEVEL);
X exit (0);
X case 'w' :
X watchf++;
X break;
X default :
X usage ();
X break;
X }
X }
X if (watchf && !debug) { /* Detach ourselves */
X detached++;
X if (fork ())
X exit (0);
X if ((i = open ("/dev/tty", O_RDONLY)) >= 0)
X ioctl (i, TIOCNOTTY, 0);
X i = getdtablesize ();
X while (--i >= 0)
X close (i);
X open ("/dev/null", 0);
X dup2 (0, 1);
X dup2 (0, 2);
X openlog (progname, 0, LOG_DAEMON);
X writepid ();
X }
X if ((i = getaa (NULL, &atalkaddr)) != 0) {
X logerr (clnt_sperrno (i));
X exit (1);
X }
X if (debug)
X fprintf (stderr, "main: Using appletalk address %d\n", atalkaddr);
X nit_init (interface);
X ht_init ();
X readcf ();
X ether_copy (&myether, &eh.ether_shost);
X eh.ether_type = htons (P_AppleTalk);
X if (watchf)
X watch ();
X else {
X if (!name)
X usage ();
X if (!(kp = get_kbox (name))) {
X logerr ("main: No such kbox %s\n", name);
X exit (1);
X }
X nit_open (0, P_AppleTalk);
X if (downloadf)
X download (kp);
X else if (configf)
X config (kp);
X else if (savestatef)
X savestate (kp);
X else if (resetf)
X reset (kp);
X else if (liststatef)
X liststate (kp);
X else if (statusf)
X status (kp);
X }
X exit (0);
X}
X
X/*
X * reconfig - Free old kbox hash table and reread config file.
X */
Xreconfig ()
X
X{
X if (debug)
X fprintf (stderr, "reconfig: Reading config file\n");
X ht_free ();
X readcf ();
X}
X
X/*
X * watch - Watch kboxes, rebooting if not answering pings.
X */
Xwatch ()
X
X{
X int i;
X struct kbox *kp;
X
X signal (SIGHUP, reconfig);
X icmp_init ();
X while (1) {
X for (i = 0; i < HTSIZE; i++)
X for (kp = kboxtab[i]; kp; kp = kp->nxt)
X if (!icmp_ping (kp)) {
X logerr ("watch: %s not responding, loading...\n", kp->name);
X nit_open (0, P_AppleTalk);
X download (kp);
X nit_close ();
X }
X sleep (pinginterval);
X }
X}
X
X/*
X * download - Download kstar to kbox.
X */
Xdownload (kp)
X
Xstruct kbox *kp;
X
X{
X int i;
X
X if ((i = readstate (kp, newstate, zonedata)) != STATE_LENGTH) {
X logerr ("config: State file wrong length %d for %s\n", i, kp->name);
X return;
X }
X if (send_who () < 0)
X return;
X if (send_reset (kp) < 0)
X return;
X sleep (3); /* Give kbox time to reset */
X if (send_who () < 0)
X return;
X if (send_promram (kp) <= 0)
X return;
X if (send_boot (kp, zonedata, zonelen) <= 0)
X return;
X if (send_getstate (kp) <= 0)
X return;
X newstate[O_NODE] = kboxstate[O_NODE];
X newstate[O_ETNODE] = kboxstate[O_ETNODE];
X strcpy (&newstate[O_NAME], kp->name);
X strcpy (&newstate[O_FILE], kp->bootfile);
X strcpy (&newstate[O_CONFIG], kp->conffile);
X if (debug)
X fprintf (stderr, "download: Setting zonelist to %X\n", zonelistp);
X bcopy (&zonelistp, &newstate[O_ZONELIST], sizeof (zonelistp));
X if (send_putstate (kp) <= 0)
X return;
X send_execute (kp);
X}
X
X/*
X * config - Config kbox.
X */
Xconfig (kp)
X
Xstruct kbox *kp;
X
X{
X int i;
X
X if ((i = readstate (kp, newstate, zonedata)) != STATE_LENGTH) {
X logerr ("config: State file wrong length %d for %s\n", i, kp->name);
X return;
X }
X if (send_who () < 0)
X return;
X if (send_exprom (kp) < 0)
X return;
X if (send_who () < 0)
X return;
X if (send_promram (kp) <= 0)
X return;
X if (send_getstate (kp) <= 0)
X return;
X newstate[O_NODE] = kboxstate[O_NODE];
X newstate[O_ETNODE] = kboxstate[O_ETNODE];
X strncpy (&newstate[O_NAME], &kboxstate[O_NAME], SNAMESIZE);
X strncpy (&newstate[O_FILE], &kboxstate[O_FILE], SNAMESIZE);
X strncpy (&newstate[O_CONFIG], kp->conffile, FNAMESIZE);
X if (send_putstate (kp) <= 0)
X return;
X if (send_who () < 0)
X return;
X send_execute (kp);
X}
X
X/*
X * savestate - Read state for kbox and save to file.
X */
Xsavestate (kp)
X
Xstruct kbox *kp;
X
X{
X char fn[MAXFN];
X int fd;
X
X if (send_who () < 0)
X return;
X if (send_promram (kp) <= 0)
X return;
X if (send_getstate (kp) <= 0)
X return;
X sprintf (fn, "%s/%s.state", etcdir, kp->name);
X if ((fd = open (fn, O_WRONLY|O_CREAT, 0644)) == -1) {
X logerr ("savestate: %s - %s\n", fn, sys_errlist[errno]);
X return;
X }
X write (fd, kboxstate, STATE_LENGTH);
X close (fd);
X}
X
X/*
X * liststate - Read state for kbox and print.
X */
Xliststate (kp)
X
Xstruct kbox *kp;
X
X{
X char fn[MAXFN];
X int fd;
X
X if (send_who () < 0)
X return;
X if (send_promram (kp) <= 0)
X return;
X if (send_getstate (kp) <= 0)
X return;
X show_state (stdout, kboxstate);
X}
X
X/*
X * reset - Reset kbox.
X */
Xreset (kp)
X
Xstruct kbox *kp;
X
X{
X if (send_who () < 0)
X return;
X send_reset (kp);
X}
X
X/*
X * status - Read and print miscellaneous things from kbox.
X */
Xstatus (kp)
X
Xstruct kbox *kp;
X
X{
X if (send_who () < 0)
X return;
X if (send_version (kp) <= 0)
X return;
X if (send_whereis (kp) <= 0)
X return;
X if (send_where2 (kp) <= 0)
X return;
X if (send_rcsid (kp) <= 0)
X return;
X if (send_state (kp) <= 0)
X return;
X if (send_hwstatus (kp) <= 0)
X return;
X}
X
X/*
X * writepid - Save pid to file.
X */
Xwritepid ()
X
X{
X char fn[MAXFN];
X FILE *f;
X
X sprintf (fn, "%s/kboot.pid", etcdir);
X if ((f = fopen (fn, "w")) == NULL)
X logerr ("main: Can't write pid file %s\n", fn);
X else {
X fprintf (f, "%d\n", getpid ());
X fclose (f);
X }
X}
X
X/*
X * usage - Print usage and die.
X */
Xusage ()
X
X{
X fprintf (stderr, "Usage: %s options\n", progname);
X exit (1);
X}
X
X/*
X * hash - Return hash index into kbox hash table.
X */
Xint hash (s)
X
Xregister char *s;
X
X{
X register int h;
X
X while (*s)
X h = (h << 1) ^ *s++;
X return (h % HTSIZE);
X}
X
X/*
X * ht_init - Init kbox hash table.
X */
Xht_init ()
X
X{
X int i;
X
X for (i = 0; i < HTSIZE; i++)
X kboxtab[i] = NULL;
X}
X
X/*
X * ht_free - Clear out hash table.
X */
Xht_free ()
X
X{
X int i;
X struct kbox *kp;
X struct kbox *nkp;
X
X for (i = 0; i < HTSIZE; i++) {
X for (kp = kboxtab[i]; kp; kp = nkp) {
X nkp = kp->nxt;
X free (kp);
X }
X kboxtab[i] = NULL;
X }
X}
X
X/*
X * add_kbox - Add kbox to hash table.
X */
Xadd_kbox (name, bootfile)
X
Xchar *name;
Xchar *bootfile;
X
X{
X int h;
X struct kbox *kp;
X char *p;
X struct hostent *he;
X struct ether_addr e;
X
X if (ether_hostton (name, &e) != 0) {
X logerr ("add_kbox: Can't find %s in ethers file\n", name);
X return;
X }
X if ((he = gethostbyname (name)) == NULL) {
X logerr ("add_kbox: Can't find %s in host table\n", name);
X return;
X }
X if ((kp = (struct kbox *) malloc (sizeof (struct kbox))) == NULL) {
X logerr ("add_kbox: No memory for %s in table\n", name);
X exit (1);
X }
X h = hash (name);
X kp->nxt = kboxtab[h];
X kboxtab[h] = kp;
X strcpy (kp->name, name);
X strcpy (kp->bootfile, bootfile);
X kp->aa = AT_Broadcast; /* Set to bogus value until get from kb */
X ether_copy (&e, &kp->ea);
X bcopy (he->h_addr, &kp->ip.sin_addr.s_addr, he->h_length);
X}
X
X/*
X * get_kbox - Find kbox in hash table.
X */
Xstruct kbox *get_kbox (name)
X
Xchar *name;
X
X{
X register struct kbox *kp;
X
X kp = kboxtab[hash (name)];
X while (kp)
X if (!strcmp (name, kp->name))
X return (kp);
X else
X kp = kp->nxt;
X return (NULL);
X}
X
X/*
X * readcf - Read config file.
X */
Xreadcf ()
X
X
X{
X FILE *f;
X char fn[MAXFN];
X char name[MAXHOSTNAME];
X char bootfile[MAXFN];
X
X sprintf (fn, "%s/kbootcf", etcdir);
X if ((f = fopen (fn, "r")) == NULL) {
X logerr ("readcf: %s - %s\n", fn, sys_errlist[errno]);
X exit (1);
X }
X while (!feof (f)) {
X numkbox++;
X if (fscanf (f, "%s %s\n", name, bootfile) != 2) {
X logerr ("readcf: Badly formatted config file '%s' line %d\n",
X fn, numkbox);
X exit (1);
X }
X add_kbox (name, bootfile);
X }
X fclose (f);
X}
X
X/*
X * readstate - Read kbox config. Returns length. Looks for ascii file
X * generated by fastpath manager first, then looks for binary file
X * made by savestate().
X */
Xint readstate (kp, state, zonedata)
X
Xstruct kbox *kp;
Xunsigned char *state;
Xunsigned char *zonedata;
X
X{
X FILE *f;
X int c;
X unsigned char *cp;
X int fd;
X int len;
X
X zonelen = 0;
X sprintf (kp->conffile, "%s/%s.config", etcdir, kp->name);
X if ((f = fopen (kp->conffile, "r")) == NULL) {
X sprintf (kp->conffile, "%s/%s.state", etcdir, kp->name);
X if ((fd = open (kp->conffile, O_RDONLY)) == -1) {
X logerr ("readstate: Can't read state file for %s\n", kp->name);
X return;
X }
X len = read (fd, state, STATE_LENGTH);
X close (fd);
X } else {
X cp = state;
X len = 0;
X while ((c = fgetc (f)) >= 0) {
X if (c == '*') {
X while ((c = fgetc (f)) >= 0 && c != '\n' && c != '\r');
X continue;
X }
X while (c >= 0 && c != '\n' && c != '\r') {
X *cp = fromhex (c) << 4;
X *cp++ |= fromhex (c = fgetc (f));
X c = fgetc (f);
X }
X if (cp - state == STATE_LENGTH) {
X zonelen = readzones (f, c, zonedata);
X break;
X }
X }
X fclose (f);
X len = cp - state;
X }
X if (zonelen == 0) {
X zonedata[0] = 0;
X zonedata[1] = 0;
X zonelen = 2;
X }
X return (len);
X}
X
X/*
X * readzones - Read zone list from config file, c is first char.
X */
Xint readzones (f, c, zonedata)
X
XFILE *f;
Xint c;
Xunsigned char *zonedata;
X
X{
X unsigned char *cp;
X unsigned char *lenp;
X short numzones;
X
X cp = zonedata + 2; /* Skip # zones */
X numzones = 0;
X while ((c = fgetc (f)) >= 0) {
X if (c == '\r' || c == '\n')
X continue;
X if (c == '*') {
X while ((c = fgetc (f)) >= 0 && c != '\n' && c != '\r');
X continue;
X }
X lenp = cp++;
X while (c >= 0 && c != '\n' && c != '\r') {
X *cp++ = c;
X c = fgetc (f);
X }
X *lenp = (cp - lenp) - 1;
X numzones++;
X }
X bcopy (&numzones, zonedata, sizeof (numzones));
X return (cp - zonedata);
X}
X
X/*
X * fromhex - Convert char from hex to decimal.
X */
Xint fromhex (c)
X
Xchar c;
X
X{
X if (c >= '0' && c <= '9')
X return (c - '0');
X else if (c >= 'a' && c <= 'f')
X return (c - 'a' + 10);
X else
X return (c - 'A' + 10);
X}
END_OF_FILE
if test 12925 -ne `wc -c <'kboot.c'`; then
echo shar: \"'kboot.c'\" unpacked with wrong size!
fi
# end of 'kboot.c'
fi
if test -f 'nitlib.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'nitlib.c'\"
else
echo shar: Extracting \"'nitlib.c'\" \(6224 characters\)
sed "s/^X//" >'nitlib.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char *RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/nitlib.c,v 1.1 91/01/29 17:37:28 root Exp $";
X#endif lint
X
X/*
X * $Log: nitlib.c,v $
X * Revision 1.1 91/01/29 17:37:28 root
X * Initial revision
X *
X */
X
X#include <stdio.h>
X#include <syslog.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <sys/file.h>
X#include <sys/signal.h>
X#include <netdb.h>
X#include <net/if.h>
X#include <sys/ioctl.h>
X#include <sys/stropts.h>
X#include <net/nit_if.h>
X#include <net/nit_pf.h>
X#include <netinet/in.h>
X#include <netinet/in_systm.h>
X#include <netinet/if_ether.h>
X#include <net/packetfilt.h>
X#include "config.h"
X
X#define MAXPKT 1500
X#define OFFSET(t,f) ((int) &(((t *) NULL)->f))
X
Xextern char *malloc ();
Xextern char *strdup ();
X
Xextern int debug;
Xextern int detached;
Xextern int errno;
Xextern char *sys_errlist[];
X
X/*
X * Globals.
X */
Xstruct ether_addr myether;
Xint nit_fd;
Xchar nitbuf[MAXPKT];
Xint numfds;
Xchar *interface;
X
X/*
X * nit_init - Initialize nit library.
X */
Xnit_init (dev)
X
Xchar *dev;
X
X{
X struct ifconf ifc;
X int s;
X char buf[BUFSIZ];
X
X numfds = getdtablesize ();
X if (dev == NULL) {
X if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
X logerr ("nit_init: socket - %s\n", sys_errlist[errno]);
X exit(1);
X }
X ifc.ifc_len = BUFSIZ;
X ifc.ifc_buf = buf;
X if (ioctl (s, SIOCGIFCONF, (caddr_t) &ifc) < 0) {
X logerr ("nit_init: ioctl(SIOCGIFCONF) - %s\n", sys_errlist[errno]);
X exit(1);
X }
X close(s);
X interface = strdup (ifc.ifc_req->ifr_name);
X } else
X interface = dev;
X if (debug)
X fprintf (stderr, "nit_init: Using interface %s\n", interface);
X}
X
X/*
X * nit_open - Open NIT device and bind to an interface.
X * Prints an error and exits if there's a problem.
X */
Xnit_open (snaplen, pkttype)
X
Xint snaplen;
Xint pkttype;
X
X{
X int s;
X struct packetfilt pf;
X u_short *pfp;
X struct ifreq ifr;
X
X if ((nit_fd = open ("/dev/nit", O_RDWR)) < 0) { /* Open NIT dev */
X logerr ("nit_open: open(/dev/nit) - %s\n", sys_errlist[errno]);
X exit (1);
X }
X if (ioctl (nit_fd, I_SRDOPT, (caddr_t) RMSGD) < 0) { /* Discrete msgs*/
X logerr ("nit_open: ioctl(I_SRDOPT) - %s\n", sys_errlist[errno]);
X exit (1);
X }
X if (pkttype) {
X if (ioctl (nit_fd, I_PUSH, "pf") < 0) { /* Setup packet filter */
X logerr ("nit_open: ioctl(I_PUSH: pf) - %s\n", sys_errlist[errno]);
X exit (1);
X }
X pfp = pf.Pf_Filter;
X *pfp++ = ENF_PUSHWORD +
X OFFSET (struct ether_header, ether_type) / sizeof (u_short);
X *pfp++ = ENF_PUSHLIT | ENF_EQ;
X *pfp++ = htons (pkttype);
X pf.Pf_FilterLen = ((int) pfp - (int) pf.Pf_Filter) / sizeof (u_short);
X if (ioctl (nit_fd, NIOCSETF, (caddr_t) &pf) < 0) {
X logerr ("nit_open: ioctl(NIOCSETF) - %s\n", sys_errlist[errno]);
X exit (1);
X }
X }
X strncpy (ifr.ifr_name, interface, sizeof ifr.ifr_name);
X ifr.ifr_name[sizeof ifr.ifr_name - 1] = '\0';
X if (ioctl (nit_fd, NIOCBIND, &ifr) < 0) {
X logerr ("nit_open: ioctl(NIOCBIND) - %s\n", sys_errlist[errno]);
X exit(1);
X }
X /* Get ethernet address */
X if (ioctl (nit_fd, SIOCGIFADDR, (caddr_t) &ifr) < 0) {
X logerr ("nit_open: ioctl(SIOCGIFADDR) - %s\n", sys_errlist[errno]);
X exit (1);
X }
X ether_copy (ifr.ifr_addr.sa_data, &myether);
X if (snaplen > 0) { /* Set snapshot length */
X if (ioctl (nit_fd, NIOCSSNAP, (caddr_t) &snaplen) < 0) {
X logerr ("nit_open: ioctl (NIOCSSNAP) - %s\n", sys_errlist[errno]);
X exit (1);
X }
X }
X}
X
X/*
X * nit_close - Close nit file descriptor.
X */
Xnit_close ()
X
X{
X close (nit_fd);
X}
X
X/*
X * timeout - Return timeval structure for timeout specified in ticks for
X * reads from nit device. Ticks are 1/60 of a second. A timeout of 0
X * means reads will not timeout.
X */
Xnit_timeout (ticks, tv)
X
Xint ticks;
Xstruct timeval *tv;
X
X{
X tv->tv_sec = ticks / 60; /* Set timeout */
X tv->tv_usec = ((ticks * 1000000) / 60) % 1000000;
X}
X
X/*
X * nit_write - Send a raw ethernet packet.
X */
Xnit_write (eh, pkt, len)
X
Xstruct ether_header *eh;
Xcaddr_t pkt;
Xint len;
X
X{
X struct sockaddr sa;
X struct strbuf cbuf;
X struct strbuf dbuf;
X
X sa.sa_family = AF_UNSPEC;
X bcopy (eh, sa.sa_data, sizeof (*eh));
X cbuf.len = sizeof sa;
X cbuf.buf = (caddr_t) &sa;
X dbuf.len = len;
X dbuf.buf = pkt;
X if (putmsg (nit_fd, &cbuf, &dbuf, 0) < 0) {
X logerr ("nit_write: putmsg - %s\n", sys_errlist[errno]);
X exit (1);
X }
X}
X
X/*
X * nit_dispatch - Read and process n packets. If n is 0 read forever.
X * Calls "func" for each packet with the arguments:
X *
X * (*func) (pp, pl)
X * pp = packet pointer
X * pl = length of packet
X *
X * If an application is waiting for input on other file descriptors
X * they can be specified in "fds". "fdfunc" will be called with
X * the set of descriptors that have input waiting before the current
X * packet is processed. Returns 0 on timeout, 1 otherwise.
X */
Xint nit_dispatch (func, n, fds, fdfunc, timeout)
X
Xint (*func)();
Xint n;
Xfd_set *fds;
Xint (*fdfunc)();
Xstruct timeval *timeout;
X
X{
X int i;
X int numpkts;
X fd_set fdset;
X fd_set rfds;
X
X numpkts = 0;
X if (fds)
X fdset = *fds;
X else
X FD_ZERO (&fdset);
X FD_SET (nit_fd, &fdset);
X while (n == 0 || numpkts < n) {
X rfds = fdset;
X i = select (numfds, &rfds, NULL, NULL, timeout);
X if (i == 0)
X return (0); /* Timeout */
X if (FD_ISSET (nit_fd, &rfds)) {
X numpkts++;
X FD_CLR (nit_fd, &rfds);
X if (i > 1)
X (*fdfunc) (&rfds);
X } else {
X (*fdfunc) (&rfds);
X continue;
X }
X if ((i = read (nit_fd, nitbuf, MAXPKT)) < 0) {
X lseek (nit_fd, 0, 0); /* File pointer may've wrapped */
X if ((i = read (nit_fd, nitbuf, MAXPKT)) < 0) {
X logerr ("nit_dispatch: read - %s\n", sys_errlist[errno]);
X exit (1);
X }
X }
X (*func) (nitbuf, i);
X }
X return (1);
X}
X
X/*
X * logerr - Log error to stderr (if debug) or syslog.
X */
Xlogerr (fmt, a1, a2, a3)
X
Xchar *fmt;
Xchar *a1;
Xchar *a2;
Xchar *a3;
X
X{
X if (detached)
X syslog (LOG_ERR, fmt, a1, a2, a3);
X else
X fprintf (stderr, fmt, a1, a2, a3);
X}
END_OF_FILE
if test 6224 -ne `wc -c <'nitlib.c'`; then
echo shar: \"'nitlib.c'\" unpacked with wrong size!
fi
# end of 'nitlib.c'
fi
echo shar: End of archive 1 \(of 3\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 3 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0