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