home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Garbo
/
Garbo.cdr
/
mac
/
source
/
kboot22.zoo
/
kboot22.1
/
cmd.c
next >
Wrap
C/C++ Source or Header
|
1991-02-22
|
16KB
|
630 lines
#ifndef lint
static char *RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/cmd.c,v 1.2 91/02/12 19:38:49 root Exp $";
#endif lint
/*
* $Log: cmd.c,v $
* Revision 1.2 91/02/12 19:38:49 root
* Removed unused commands.
*
* Revision 1.1 91/01/29 17:36:59 root
* Initial revision
*
*/
/*
* cmd.c - Send commands to kboxes.
*/
#include <stdio.h>
#include <syslog.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include "appletalk.h"
#include "cmdidx.h"
#include "kbox.h"
#include "config.h"
extern struct hostent *gethostbyaddr ();
extern char *inet_ntoa ();
struct kbox *get_kbox ();
extern int errno;
extern char *sys_errlist[];
extern int numkbox;
extern int debug;
extern struct ether_addr ebc;
extern struct ether_header eh;
extern struct kbox *kboxtab[HTSIZE];
extern long atalkaddr;
extern unsigned char kboxstate[STATE_LENGTH];
extern unsigned char newstate[STATE_LENGTH];
extern char *etcdir;
extern unsigned char *zonelistp;
#define HEX(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10)
/*
* Globals.
*/
int (*recv_copyproc) () = NULL;
struct ether_fastpath fppkt;
struct fp_promram promram;
int num_resp;
int expected_resp;
int destkbox;
struct kbox *kboxaddr[MAXKBOX];
struct timeval timeout;
/*
* Receive functions. There should be a recv_ function for each send_
* function.
*/
/*
* recv_who - Process who packet. Algorithm is to look up the ethernet
* address in the ethers file and then add this kbox to the hash
* table it's not already there. It would probably be more efficient
* to look up the ethernet address directly in a table hashed by ethernet
* address, however recv_who isn't called very often so I won't bother.
*/
recv_who (p)
struct fp_packet *p;
{
char name[MAXHOSTNAME];
char buf[20];
struct kbox *kp;
if (ether_ntohost (name, &p->fp_shost) != 0) {
logerr ("recv_who: Can't find %s in ethers table\n",
ether_ntoa (&p->fp_shost));
return;
}
if (kp = get_kbox (name)) {
if (!bcmp (&kp->ea, &p->fp_shost, sizeof(struct ether_addr))) {
if (kp->aa == AT_Broadcast) {
kp->aa = p->fp_lapsrc;
kboxaddr[kp->aa] = kp;
if (debug)
fprintf (stderr, "recv_who: Adding kbox %s %s\n",
name, ether_ntoa (&p->fp_shost));
num_resp++;
}
} else {
strcpy (buf, ether_ntoa (&kp->ea));
logerr ("recv_who: Mismatched ether address for %s: %s != %s\n",
name, buf, ether_ntoa (&p->fp_shost));
}
} else if (debug)
fprintf (stderr, "recv_who: Unknown kbox %s %s\n",
name, ether_ntoa (&p->fp_shost));
}
/*
* recv_promram - Receive promram vector. On sparc machines the
* fp_promram structure doesn't align properly, so copy the count
* field separately.
*/
recv_promram (p)
struct fp_packet *p;
{
bcopy (p->fp_data, &promram.fpr_count, sizeof(promram.fpr_count));
bcopy (&p->fp_data[sizeof(promram.fpr_count)], &promram.fpr_jtable,
PROMRAMSIZE - sizeof(promram.fpr_count));
num_resp++;
}
/*
* recv_getstate - Receive state vector.
*/
recv_getstate (p)
struct fp_packet *p;
{
bcopy (&p->fp_data[FPCOPYSIZE], kboxstate, STATE_LENGTH);
if (debug) {
fprintf (stderr, "recv_getstate: Received state...\n");
show_state (stderr, kboxstate);
}
num_resp++;
}
/*
* inet_ntos - Translate ip address to hostname.
*/
char *inet_ntos (addr)
unsigned char *addr;
{
struct in_addr a;
struct hostent *he;
bcopy (addr, &a.s_addr, 4);
if ((he = gethostbyaddr (&a, 4, AF_INET)) == NULL)
return (inet_ntoa (a));
else
return (he->h_name);
}
/*
* show_state - Print state vector.
*/
show_state (f, s)
FILE *f;
unsigned char s[STATE_LENGTH];
{
int options;
int i;
int first;
long l;
short st;
fprintf (f, "\tAppletalk: %d.%d.%d Ethertalk: %d.%d.%d IPtalk: %d.%d.%d",
s[O_ATNET], s[O_ATNET+1], s[O_NODE],
s[O_ETNET], s[O_ETNET+1], s[O_ETNODE],
s[O_UDPNET], s[O_UDPNET+1], s[O_UDPNODE]);
fprintf (f, " Bridge: %d\n", s[O_BRIDGE]);
fprintf (f, "\tEthernet: %s Name: \"%s\" File: \"%s\"\n",
ether_ntoa (&s[O_ETHER]), &s[O_NAME], &s[O_FILE]);
fprintf (f, "\tConfig: \"%s\"\n", &s[O_CONFIG]);
fprintf (f, "\tATzone: \"%s\" ETzone: \"%s\" UDPzone: \"%s\"\n",
&s[O_ATZONE], &s[O_ETZONE], &s[O_UDPZONE]);
fprintf (f, "\tPforce: %d Autoconfig: %s", s[O_PFORCE],
(s[O_AUTOCONFIG] || s[O_AUTOCONFIG+1]) ? "yes" : "no");
fprintf (f, " Autoboot: %s",
(s[O_AUTOBOOT] || s[O_AUTOBOOT+1]) ? "yes\n" : "no\n");
fprintf (f, "\tOptions: ");
bcopy (&s[O_OPTIONS], &options, sizeof(options));
if (options) {
for (first = 1, i = 0; i < 32; i++)
if ((1 << i) & options)
if (first) {
first = 0;
fprintf (f, "%d", i + 1);
} else
fprintf (f, ", %d", i+1);
} else
fprintf (f, "none");
bcopy (&s[O_SN], &l, sizeof (l));
bcopy (&s[O_TYPE], &st, sizeof (st));
fprintf (f, " Serial: %d Type: %d\n", l, st);
fprintf (f, "\tRouter: \"%s\"", inet_ntos (&s[O_IPDEFROUTER]));
fprintf (f, " ETip: \"%s\"", inet_ntos (&s[O_IPADDRESS]));
fprintf (f, " ATip: \"%s\"", inet_ntos (&s[O_ATIPADDRESS]));
fprintf (f, " Broadcast: \"%s\"\n", inet_ntos (&s[O_IPBROADCAST]));
fprintf (f, "\tSubnet: \"%s\"", inet_ntos (&s[O_IPSUBMASK]));
fprintf (f, " KIP: \"%s\"", inet_ntos (&s[O_IPKIPSERVER]));
fprintf (f, " Name: \"%s\"", inet_ntos (&s[O_NAMESERVER]));
fprintf (f, " File: \"%s\"\n", inet_ntos (&s[O_FILESERVER]));
bcopy (&s[O_LP1], &l, sizeof (l));
fprintf (f, "\tLocal1: 0x%x", l);
bcopy (&s[O_LP2], &l, sizeof (l));
fprintf (f, " Local2: 0x%x", l);
bcopy (&s[O_LP3], &l, sizeof (l));
fprintf (f, " Local3: 0x%x", l);
bcopy (&s[O_LP4], &l, sizeof (l));
fprintf (f, " Local4: 0x%x\n", l);
bcopy (&s[O_NDYNAMICS], &st, sizeof (st));
fprintf (f, "\tDynamics: %d", st);
bcopy (&s[O_NSTATICS], &st, sizeof (st));
fprintf (f, " Statics: %d", st);
bcopy (&s[O_ZONELIST], &l, sizeof (l));
fprintf (f, " Zonelist 0x%X\n", l);
}
/*
* recv_gen - Generic receive routine.
*/
recv_gen (p)
struct fp_packet *p;
{
num_resp++;
}
/*
* recv_pkt - Call appropriate function to deal with packet from fastpath.
*/
recv_pkt (p)
struct fp_packet *p;
{
char buf[100];
if (p->fp_laptype != FP_TYPE) {
return;
}
if (destkbox != AT_Broadcast && p->fp_lapsrc != destkbox) {
/*
* X_WHO responses from unconfigured fastpaths to broadcasts may come
* in after we've already started talking to a real fastpath, so
* just ignore all X_WHO responses with no error message.
*/
if (p->fp_scmd != X_WHO)
logerr ("recv_pkt: Bogus response %d from %s\n",
p->fp_scmd, ether_ntoa (&p->fp_shost));
return;
}
if (p->fp_cmd == FP_ACK) {
num_resp++;
return;
}
if (p->fp_cmd != FP_RESP)
return;
switch (p->fp_scmd) {
case X_COPYMEM : if (recv_copyproc)
(*recv_copyproc) (p);
break;
case X_PROMRAM : recv_promram (p); break;
case X_WHO : recv_who (p); break;
case X_RESET : recv_gen ();
break;
default : ether_ntohost (buf, &p->fp_shost);
logerr ("recv_pkt: Received %d from %s\n",
p->fp_scmd, buf);
break;
}
}
/*
* Send procedures. Those that have no parameters are macros that invoke
* send_gen(), defined in kbox.h.
*/
/*
* send_who - Broadcast who packet.
*/
int send_who ()
{
int i;
for (i = 0; i < MAXKBOX; i++)
if (kboxaddr[i])
kboxaddr[i]->aa = AT_Broadcast;
nit_timeout (60, &timeout);
return (send_pkt (NULL, (int) FP_CMD, X_WHO, 0, 5, &timeout));
}
/*
* send_boot - Download file to kbox.
*/
int send_boot (kp, zonedata, zonelen)
struct kbox *kp;
unsigned char *zonedata;
int zonelen;
{
FILE *f;
int l;
int ch;
int cmd;
int scmd;
char fn[MAXFN];
int size = 0;
int lastlen;
int lastaddr;
sprintf (fn, "%s/%s", etcdir, kp->bootfile);
if ((f = fopen (fn, "r")) == NULL) {
logerr ("send_boot: %s to %s - %s\n", fn, kp->name, sys_errlist[errno]);
return (0);
}
nit_timeout (30, &timeout);
while ((cmd = fgetc (f)) > 0) {
if (cmd != 'S') {
logerr ("send_boot: Bad S record %d\n", cmd);
return (-1);
}
scmd = fgetc (f);
if (scmd == '8') {
/*
* With KSTAR 8.0 it is necessary to download a zonelist with
* KSTAR. The following code converts the zonelist read from
* the config file written by the Fastpath Manager into
* s-records and sends them to the kbox. The address where
* the zonelist is downloaded is the first even address after
* the last s-record, which is the address of the last s-record
* plus its length, rounded up to the nearest even address.
* The first s-record describes the following data, it looks like:
*
* short num_elements;
* struct {
* short type;
* short length;
* } element[NUMELEMENTS];
*
* For a zonelist the type is 1. The second s-record contains
* the zonelist itself. These extra s-records get sent right
* before the last s-record, which seems to have scmd == 8.
* Much of the information on the format of the s-records and
* their location was reverse engineered from packet traces,
* I don't guarantee this code to be correct, although it
* works for me.
*/
lastlen = atox (fppkt.fastpath_data, 2);
lastaddr = atox (&fppkt.fastpath_data[2], 6);
zonelistp = (unsigned char *) (lastaddr + lastlen - 4);
if ((int) zonelistp % 2 == 1)
zonelistp++;
makeelemlist (fppkt.fastpath_data, zonelen);
if (debug)
fprintf (stderr, "send_boot: %s\n", fppkt.fastpath_data);
if (send_pkt (kp, 'S', '2', strlen(fppkt.fastpath_data),
5, &timeout) != 1)
return (0);
makezonedata (fppkt.fastpath_data, zonedata, zonelen);
if (debug)
fprintf (stderr, "send_boot: %s\n", fppkt.fastpath_data);
if (send_pkt (kp, 'S', '2', strlen(fppkt.fastpath_data),
5, &timeout) != 1)
return (0);
}
l = 0;
while ((ch = fgetc (f)) > 0 && ch != '\r' && ch != '\n')
fppkt.fastpath_data[l++] = ch;
size += l;
if (send_pkt (kp, cmd, scmd, l, 5, &timeout) != 1)
return (0);
}
if (debug)
fprintf (stderr, "send_boot: Downloaded %d bytes\n", size);
return (1);
}
/*
* atox - Convert ascii string of length l to hex.
*/
int atox (s, l)
char *s;
int l;
{
int r = 0;
int i;
for (i = 0; i < l; i++)
r = (r << 4) | ((s[i] >= '0' && s[i] <= '9') ? s[i] - '0' :
(s[i] >= 'a' && s[i] <= 'f') ? s[i] - 'a' + 10 :
s[i] - 'A' + 10);
return (r);
}
/*
* csumsrec - Compute checksum for s-record.
*/
unsigned char csumsrec (s, l)
unsigned char *s;
int l;
{
unsigned char sum;
static char buf[3];
sum = 0;
while (l--)
sum += *s++;
sum ^= 0xFF;
return (sum);
}
/*
* makeelemlist - Make element list srecord.
*/
makeelemlist (p, l)
unsigned char *p;
int l;
{
static elemlist el = {1, 1, 0};
unsigned char buf[BUFSIZ];
el.bytes = l + 2; /* Don't know why +2 */
bcopy (&zonelistp, buf, sizeof (zonelistp)); /* First byte is length */
*buf = 4 + sizeof (el); /* so overwrite it */
bcopy (&el, &buf[4], sizeof (el));
buf[4 + sizeof (el)] = csumsrec (buf, 4 + sizeof (el));
hexify (buf, p, 4 + sizeof (el) + 1);
}
/*
* makezonedata - Make zone data srecord.
*/
makezonedata (p, data, l)
unsigned char *p;
unsigned char *data;
int l;
{
unsigned char *addr;
unsigned char buf[BUFSIZ];
addr = zonelistp + sizeof (elemlist);
bcopy (&addr, buf, sizeof (addr));
*buf = 4 + l;
bcopy (data, &buf[4], l);
buf[4 + l] = csumsrec (buf, 4 + l);
hexify (buf, p, 4 + l + 1);
}
/*
* hexify - Convert buffer to hex ascii characters.
*/
hexify (buf, p, len)
unsigned char *buf;
unsigned char *p;
int len;
{
int i;
for (i = 0; i < len; i++) {
p[2 * i] = HEX (buf[i] >> 4);
p[2 * i + 1] = HEX (buf[i] & 0xF);
}
p[2 * len] = '\0';
}
/*
* send_getstate - Get state vector.
*/
int send_getstate (kp)
struct kbox *kp;
{
struct fp_copy copy;
copy.fpc_from = (char *) promram.fpr_state;
copy.fpc_to = (char *) -1;
copy.fpc_count = STATE_LENGTH;
bcopy (©, fppkt.fastpath_data, FPCOPYSIZE);
recv_copyproc = recv_getstate;
nit_timeout (30, &timeout);
return (send_pkt (kp, (int) FP_CMD, X_COPYMEM, FPCOPYSIZE, 5, &timeout));
}
/*
* send_putstate - Put state vector.
*/
int send_putstate (kp)
struct kbox *kp;
{
struct fp_copy copy;
copy.fpc_from = (char *) -1;
copy.fpc_to = (char *) promram.fpr_state;
copy.fpc_count = htons (STATE_LENGTH);
bcopy (©, fppkt.fastpath_data, FPCOPYSIZE);
newstate[O_NODE] = kboxstate[O_NODE];
bcopy (newstate, &fppkt.fastpath_data[FPCOPYSIZE], STATE_LENGTH);
if (debug) {
fprintf (stderr, "send_putstate: Sending state...\n");
show_state (stderr, newstate);
}
recv_copyproc = recv_gen;
nit_timeout (30, &timeout);
return (send_pkt (kp, (int) FP_CMD, X_COPYMEM,
FPCOPYSIZE + STATE_LENGTH, 5, &timeout));
}
/*
* send_gen - Generic send command.
*/
int send_gen (kp, scmd, retries)
struct kbox *kp;
int scmd;
int retries;
{
nit_timeout (60, &timeout);
return (send_pkt (kp, (int) FP_CMD, scmd, 0, retries, &timeout));
}
/*
* send_pkt - Send command packet (in fppkt). Returns # of responders,
* or -1 on error. If retries is 0, don't expect any response.
*/
int send_pkt (kp, cmd, scmd, len, retries, timeout)
struct kbox *kp;
int cmd;
int scmd;
int len;
int retries;
struct timeval *timeout;
{
short count;
int h;
struct kbox *p;
struct timeb tstart;
struct timeb tcur;
int utotal;
int ucur;
if (kp) {
if (kp->aa == AT_Broadcast) {
logerr ("send_pkt: Invalid appletalk address for %s\n", kp->name);
return (-1);
}
destkbox = kp->aa;
ether_copy (&kboxaddr[destkbox]->ea, &eh.ether_dhost);
if (retries == 0) {
expected_resp = 0;
retries = 1;
} else
expected_resp = 1;
} else {
destkbox = AT_Broadcast;
ether_copy (&ebc, &eh.ether_dhost);
expected_resp = numkbox;
}
num_resp = 0;
fppkt.fastpath_lapdest = destkbox;
fppkt.fastpath_lapsrc = atalkaddr;
fppkt.fastpath_laptype = FP_TYPE;
fppkt.fastpath_cmd = cmd;
fppkt.fastpath_scmd = scmd;
count = htons (len + 4);
bcopy (&count, fppkt.fastpath_len, sizeof(count));
utotal = timeout->tv_sec * 1000000 + timeout->tv_usec;
for (count = 0; count < retries; count++) {
if (debug && count >= 1)
fprintf (stderr, "send_pkt: Retransmitting cmd %d scmd %d\n",
fppkt.fastpath_cmd, fppkt.fastpath_scmd);
nit_write (&eh, &fppkt, len + sizeof(struct ether_fastpath) - MAXFPPKT);
ftime (&tstart);
ucur = 0;
while (num_resp < expected_resp && utotal > ucur) {
nit_dispatch (recv_pkt, 1, NULL, NULL, timeout);
ftime (&tcur);
ucur = (tcur.time - tstart.time) * 1000000 +
(tcur.millitm - tstart.millitm) * 1000;
}
if (num_resp >= expected_resp)
break;
}
if (num_resp != expected_resp)
if (destkbox == AT_Broadcast) {
for (h = 0; h < HTSIZE; h++)
for (p = kboxtab[h]; p; p = p->nxt)
if (p->aa == AT_Broadcast)
logerr ("send_pkt(%d,%d): No response from %s\n",
cmd, scmd, p->name);
} else
logerr ("send_pkt(%d,%d): No response from %s\n",
cmd, scmd, kboxaddr[destkbox]->name);
return (num_resp);
}