bobs@randvax.UUCP (Rober Schwartzkopf) (02/14/91)
Version 2.2 of kboot includes a new option that allows users to force kboot daemons to reload kboxes even if they appear to be up, and fixes a few bugs and documentation errors. This version no longer includes several copyrighted files I didn't have permission to post originally. These files are not needed by kboot (I used them during the development process and mistakenly included them in my original posting). Please delete any old copies of kboot (v2.1) and use this one. Thank you, 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 2)." # Contents: cmd.c icmp.c kboot.c nitlib.c # Wrapped by bobs@chumley on Wed Feb 13 22:14:58 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'cmd.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cmd.c'\" else echo shar: Extracting \"'cmd.c'\" \(15515 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.2 91/02/12 19:38:49 root Exp $"; X#endif lint X X/* X * $Log: cmd.c,v $ X * Revision 1.2 91/02/12 19:38:49 root X * Removed unused commands. X * 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 "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 * 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_PROMRAM : recv_promram (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_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 15515 -ne `wc -c <'cmd.c'`; then echo shar: \"'cmd.c'\" unpacked with wrong size! fi # end of 'cmd.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'\" \(15749 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.3 91/02/13 11:47:07 root Exp $"; X#endif lint X X/* X * $Log: kboot.c,v $ X * Revision 1.3 91/02/13 11:47:07 root X * Accept rpc requests from privileged ports only. X * X * Revision 1.2 91/02/12 19:27:39 root X * Remove -m option, add -t. X * 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 <rpc/rpc.h> X#include "appletalk.h" X#include "cmdidx.h" X#include "kbox.h" X#include "config.h" X#include "patchlevel.h" X#include "kboot.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 rbootf = 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 char *errmsg; X char *rhost; 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 '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 't' : X if (argc <= 1) X usage (); X argv++; argc--; X rbootf++; X name = *argv; X if (argc > 1 && *argv[1] != '-') { X argv++; argc--; X rhost = *argv; X } else X rhost = NULL; 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 (rbootf) { X kboot_reload (name, rhost); X exit (0); 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 errmsg = clnt_sperrno (i); X logerr ("getaa: %s\n", errmsg); 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 } 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 * ping - Ping kboxes, reload any that don't respond or any that've X * been flagged for reloading. X */ Xping () X X{ X int i; X struct kbox *kp; X X for (i = 0; i < HTSIZE; i++) X for (kp = kboxtab[i]; kp; kp = kp->nxt) X if (kp->reload || !icmp_ping (kp)) { X logerr ("ping: Reloading %s\n", kp->name); X nit_open (0, P_AppleTalk); X download (kp); X kp->reload = 0; X nit_close (); X } X alarm (pinginterval); X} X X/* X * watch - Watch kboxes, rebooting if not answering pings or if someone X * asks us to. X */ Xwatch () X X{ X signal (SIGHUP, reconfig); X signal (SIGALRM, ping); X icmp_init (); X rpc_init (); X alarm (pinginterval); X svc_run (); 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], NAMELEN); X strncpy (&newstate[O_FILE], &kboxstate[O_FILE], NAMELEN); X strncpy (&newstate[O_CONFIG], kp->conffile, CONFIGLEN); 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 * 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 kp->reload = 0; 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} X X/* X * kboot_rpcsvr - Handle rpc requests. X */ Xkboot_rpcsvr (request, xprt) X Xstruct svc_req *request; XSVCXPRT *xprt; X X{ X struct sockaddr_in *sa; X char *kbox; X int r; X struct kbox *kp; X X sa = svc_getcaller (xprt); X if (debug) X fprintf (stderr, "kboot_rpcsvr: Request %d from %s\n", X request->rq_proc, inet_ntoa (sa->sin_addr)); X if (sa->sin_port >= IPPORT_RESERVED) { X logerr ("kboot_rpcsvr: Bad port %d from %s\n", X sa->sin_port, inet_ntoa (sa->sin_addr)); X r = -1; X if (!svc_sendreply (xprt, xdr_int, (caddr_t) &r)) X logerr ("kboot_rpcsvr: svc_sendreply failed\n"); X return; X } X switch (request->rq_proc) { X case NULLPROC: X if (!svc_sendreply (xprt, xdr_void, 0)) X logerr ("kboot_rpcsvr(NULLPROC): svc_sendreply failed\n"); X break; X X case KBOOTPROC_RELOAD: X kbox = NULL; X if (svc_getargs (xprt, xdr_wrapstring, &kbox)) { X if (!(kp = get_kbox (kbox))) { X logerr ("kboot_rpcsvr: No such kbox %s\n", kbox); X r = -1; X } else X r = 0; X } else { X logerr ("kboot_rpcsvr(RELOAD): svc_getargs failed\n"); X r = -1; X } X if (!svc_sendreply (xprt, xdr_int, (caddr_t) &r)) X logerr ("kboot_rpcsvr(RELOAD): svc_sendreply failed\n"); X if (r >= 0) { X kp->reload++; X alarm (1); X if (debug) X fprintf (stderr, "kboot_rpcsvr: Requesting load of %s\n", kbox); X } X xdr_free (xdr_wrapstring, &kbox); X break; X X default: X svcerr_noproc (xprt); X break; X } X} X X/* X * Initialize RPC stuff. X */ Xrpc_init () X X{ X SVCXPRT *xprt; X X if ((xprt = svcudp_create (RPC_ANYSOCK)) == NULL) { X logerr ("rpc_init: svcudp_create failed\n"); X exit (1); X } X pmap_unset (KBOOTPROG, KBOOTVERS); X if (!svc_register (xprt, KBOOTPROG, KBOOTVERS, kboot_rpcsvr, IPPROTO_UDP)) { X logerr ("rpc_init: Can't register %d %d\n", KBOOTPROG, KBOOTVERS); X exit (1); X } X} X X/* X * kboot_reload - Ask kboot on rhost to reload kbox. X */ Xkboot_reload (kbox, rhost) X Xchar *kbox; Xchar *rhost; X X{ X int s; X int r; X X if (rhost == NULL) X rhost = "localhost"; X if (debug) X fprintf (stderr, "kboot_reload: Requesting reboot of %s on %s\n", X kbox, rhost); X/* X * kboot will only accept rpc requests from privileged ports. callrpc X * will use a privileged port by default if it can (we're root). X */ X if ((s = callrpc (rhost, KBOOTPROG, KBOOTVERS, KBOOTPROC_RELOAD, X xdr_wrapstring, &kbox, xdr_int, &r)) != 0) { X clnt_perrno (s); X exit (1); X } X printf ("%s reload request %s\n", kbox, r == 0 ? "accepted" : "failed"); X} END_OF_FILE if test 15749 -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'\" \(6314 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.2 91/02/12 19:38:10 root Exp $"; X#endif lint X X/* X * $Log: nitlib.c,v $ X * Revision 1.2 91/02/12 19:38:10 root X * Don't call fdfunc() if NULL. X * 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 if (fdfunc) { 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 6314 -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 2\). cp /dev/null ark1isdone MISSING="" for I in 1 2 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked both 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