OpenBSD-4.6/usr.sbin/mopd/mopd/process.c
/* $OpenBSD: process.c,v 1.17 2006/04/29 16:26:56 maja Exp $ */
/*
* Copyright (c) 1993-95 Mats O Jansson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef lint
static const char rcsid[] =
"$OpenBSD: process.c,v 1.17 2006/04/29 16:26:56 maja Exp $";
#endif
#include "os.h"
#include "common/common.h"
#include "common/mopdef.h"
#include "common/nmadef.h"
#include "common/get.h"
#include "common/put.h"
#include "common/print.h"
#include "common/pf.h"
#include "common/cmp.h"
#include "common/dl.h"
#include "common/rc.h"
#include "common/file.h"
extern int DebugFlag;
struct dllist dllist[MAXDL]; /* dump/load list */
void
mopProcessInfo(u_char *pkt, int *idx, u_short moplen, struct dllist *dl_rpr,
int trans)
{
u_short itype, tmps;
u_char ilen, tmpc, device;
device = 0;
switch (trans) {
case TRANS_ETHER:
moplen = moplen + 16;
break;
case TRANS_8023:
moplen = moplen + 14;
break;
}
itype = mopGetShort(pkt, idx);
while (*idx < (int)(moplen)) {
ilen = mopGetChar(pkt, idx);
switch (itype) {
case 0:
tmpc = mopGetChar(pkt, idx);
*idx = *idx + tmpc;
break;
case MOP_K_INFO_VER:
*idx = *idx + 3;
break;
case MOP_K_INFO_MFCT:
case MOP_K_INFO_RTM:
case MOP_K_INFO_CSZ:
case MOP_K_INFO_RSZ:
mopGetShort(pkt, idx);
break;
case MOP_K_INFO_CNU:
case MOP_K_INFO_HWA:
*idx = *idx + 6;
break;
case MOP_K_INFO_TIME:
*idx = *idx + 10;
break;
case MOP_K_INFO_SOFD:
device = mopGetChar(pkt, idx);
break;
case MOP_K_INFO_SFID:
tmpc = mopGetChar(pkt, idx);
*idx = *idx + tmpc;
break;
case MOP_K_INFO_PRTY:
case MOP_K_INFO_DLTY:
mopGetChar(pkt, idx);
break;
case MOP_K_INFO_DLBSZ:
tmps = mopGetShort(pkt, idx);
dl_rpr->dl_bsz = tmps;
break;
default:
if (((device == NMA_C_SOFD_LCS) || /* DECserver 100 */
(device == NMA_C_SOFD_DS2) || /* DECserver 200 */
(device == NMA_C_SOFD_DP2) || /* DECserver 250 */
(device == NMA_C_SOFD_DS3)) && /* DECserver 300 */
((itype > 101) && (itype < 107))) {
switch (itype) {
case 102:
case 103:
case 105:
case 106:
*idx = *idx + ilen;
break;
case 104:
mopGetShort(pkt, idx);
break;
}
} else
*idx = *idx + ilen;
}
itype = mopGetShort(pkt, idx);
}
}
void
mopSendASV(u_char *dst, u_char *src, struct if_info *ii, int trans)
{
u_char pkt[200];
int idx;
idx = 0;
mopPutHeader(pkt, &idx, dst, src, MOP_K_PROTO_DL, trans);
mopPutChar(pkt, &idx, MOP_K_CODE_ASV);
mopPutLength(pkt, trans, idx);
if ((DebugFlag == DEBUG_ONELINE))
mopPrintOneline(stdout, pkt, trans);
if ((DebugFlag >= DEBUG_HEADER)) {
mopPrintHeader(stdout, pkt, trans);
mopPrintMopHeader(stdout, pkt, trans);
}
if ((DebugFlag >= DEBUG_INFO))
mopDumpDL(stdout, pkt, trans);
if (pfWrite(ii->fd, pkt, idx, trans) != idx)
if (DebugFlag)
warnx("pfWrite() error");
}
void
mopStartLoad(u_char *dst, u_char *src, struct dllist *dl_rpr, int trans)
{
int len;
int i, slot;
u_char pkt[BUFSIZE];
int idx;
u_char mopcode = MOP_K_CODE_MLD;
slot = -1;
/* Look if we have a non terminated load, if so, use it's slot */
for (i = 0; i < MAXDL; i++)
if (dllist[i].status != DL_STATUS_FREE)
if (mopCmpEAddr(dllist[i].eaddr, dst) == 0)
slot = i;
/* If no slot yet, then find first free */
if (slot == -1)
for (i = 0; i < MAXDL; i++)
if (dllist[i].status == DL_STATUS_FREE)
if (slot == -1) {
slot = i;
bcopy(dst, dllist[i].eaddr, 6);
}
/* If no slot yet, then return. No slot is free */
if (slot == -1)
return;
/* Ok, save info from RPR */
dllist[slot] = *dl_rpr;
dllist[slot].status = DL_STATUS_READ_IMGHDR;
/* Get Load and Transfer Address. */
GetFileInfo(dllist[slot].ldfd, &dllist[slot].loadaddr,
&dllist[slot].xferaddr, &dllist[slot].aout,
&dllist[slot].a_text, &dllist[slot].a_text_fill,
&dllist[slot].a_data, &dllist[slot].a_data_fill,
&dllist[slot].a_bss, &dllist[slot].a_bss_fill, 0);
dllist[slot].nloadaddr = dllist[slot].loadaddr;
dllist[slot].lseek = lseek(dllist[slot].ldfd, 0L, SEEK_CUR);
dllist[slot].a_lseek = 0;
dllist[slot].count = 0;
if ((dllist[slot].dl_bsz >= 1492) || (dllist[slot].dl_bsz == 0))
dllist[slot].dl_bsz = 1492;
if (dllist[slot].dl_bsz == 1030) /* VS/uVAX 2000 needs this */
dllist[slot].dl_bsz = 1000;
if (trans == TRANS_8023)
dllist[slot].dl_bsz = dllist[slot].dl_bsz - 8;
idx = 0;
mopPutHeader(pkt, &idx, dst, src, MOP_K_PROTO_DL, trans);
mopPutChar(pkt, &idx, mopcode);
mopPutChar(pkt, &idx, dllist[slot].count);
mopPutLong(pkt, &idx, dllist[slot].loadaddr);
len = mopFileRead(&dllist[slot], &pkt[idx]);
dllist[slot].nloadaddr = dllist[slot].loadaddr + len;
idx = idx + len;
mopPutLength(pkt, trans, idx);
if ((DebugFlag == DEBUG_ONELINE))
mopPrintOneline(stdout, pkt, trans);
if ((DebugFlag >= DEBUG_HEADER)) {
mopPrintHeader(stdout, pkt, trans);
mopPrintMopHeader(stdout, pkt, trans);
}
if ((DebugFlag >= DEBUG_INFO))
mopDumpDL(stdout, pkt, trans);
if (pfWrite(dllist[slot].ii->fd, pkt, idx, trans) != idx)
if (DebugFlag)
warnx("pfWrite() error");
dllist[slot].status = DL_STATUS_SENT_MLD;
}
void
mopNextLoad(u_char *dst, u_char *src, u_char new_count, int trans)
{
int len;
int i, slot;
u_char pkt[BUFSIZE];
int idx, pidx;
char line[100],hname[17],*p;
slot = -1;
for (i = 0; i < MAXDL; i++)
if (dllist[i].status != DL_STATUS_FREE) {
if (mopCmpEAddr(dst, dllist[i].eaddr) == 0)
slot = i;
}
/* If no slot yet, then return. No slot is free */
if (slot == -1)
return;
if ((new_count == ((dllist[slot].count+1) % 256))) {
dllist[slot].loadaddr = dllist[slot].nloadaddr;
dllist[slot].count = new_count;
} else
return;
if (dllist[slot].status == DL_STATUS_SENT_PLT) {
close(dllist[slot].ldfd);
dllist[slot].ldfd = 0;
dllist[slot].status = DL_STATUS_FREE;
snprintf(line, sizeof(line),
"%x:%x:%x:%x:%x:%x Load completed",
dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
syslog(LOG_INFO, "%s", line);
return;
}
dllist[slot].lseek = lseek(dllist[slot].ldfd, 0L, SEEK_CUR);
if (dllist[slot].dl_bsz >= 1492)
dllist[slot].dl_bsz = 1492;
idx = 0;
mopPutHeader(pkt, &idx, dst, src, MOP_K_PROTO_DL, trans);
pidx = idx;
mopPutChar(pkt, &idx, MOP_K_CODE_MLD);
mopPutChar(pkt, &idx, dllist[slot].count);
mopPutLong(pkt, &idx, dllist[slot].loadaddr);
len = mopFileRead(&dllist[slot], &pkt[idx]);
if (len > 0) {
dllist[slot].nloadaddr = dllist[slot].loadaddr + len;
idx = idx + len;
mopPutLength(pkt, trans, idx);
} else {
if (len == 0) {
i = gethostname(hname, sizeof(hname));
p = index(hname, '.');
if (p != NULL)
*p = 0;
idx = pidx;
mopPutChar(pkt, &idx, MOP_K_CODE_PLT);
mopPutChar(pkt, &idx, dllist[slot].count);
mopPutChar(pkt, &idx, MOP_K_PLTP_HSN);
mopPutChar(pkt, &idx, (int)strlen(hname));
mopPutMulti(pkt, &idx, (u_char *)hname, (int)strlen(hname));
mopPutChar(pkt, &idx, MOP_K_PLTP_HSA);
mopPutChar(pkt, &idx, 6);
mopPutMulti(pkt, &idx, src, 6);
mopPutChar(pkt, &idx, MOP_K_PLTP_HST);
mopPutTime(pkt, &idx, 0);
mopPutChar(pkt, &idx, 0);
mopPutLong(pkt, &idx, dllist[slot].xferaddr);
mopPutLength(pkt, trans, idx);
dllist[slot].status = DL_STATUS_SENT_PLT;
} else {
dllist[slot].status = DL_STATUS_FREE;
return;
}
}
if ((DebugFlag == DEBUG_ONELINE))
mopPrintOneline(stdout, pkt, trans);
if ((DebugFlag >= DEBUG_HEADER)) {
mopPrintHeader(stdout, pkt, trans);
mopPrintMopHeader(stdout, pkt, trans);
}
if ((DebugFlag >= DEBUG_INFO))
mopDumpDL(stdout, pkt, trans);
if (pfWrite(dllist[slot].ii->fd, pkt, idx, trans) != idx)
if (DebugFlag)
warnx("pfWrite() error");
}
/* ARGSUSED */
void
mopProcessDL(FILE *fd, struct if_info *ii, u_char *pkt, int *idx, u_char *dst,
u_char *src, int trans, u_short len)
{
u_char tmpc;
u_short moplen;
u_char pfile[129], mopcode;
char filename[FILENAME_MAX];
char line[100];
int i, nfd;
struct dllist dl, *dl_rpr;
u_char load;
if ((DebugFlag == DEBUG_ONELINE))
mopPrintOneline(stdout, pkt, trans);
if ((DebugFlag >= DEBUG_HEADER)) {
mopPrintHeader(stdout, pkt, trans);
mopPrintMopHeader(stdout, pkt, trans);
}
if ((DebugFlag >= DEBUG_INFO))
mopDumpDL(stdout, pkt, trans);
moplen = mopGetLength(pkt, trans);
mopcode = mopGetChar(pkt, idx);
switch (mopcode) {
case MOP_K_CODE_MLT:
break;
case MOP_K_CODE_DCM:
break;
case MOP_K_CODE_MLD:
break;
case MOP_K_CODE_ASV:
break;
case MOP_K_CODE_RMD:
break;
case MOP_K_CODE_RPR:
mopGetChar(pkt, idx); /* Device Type */
tmpc = mopGetChar(pkt, idx); /* Format Version */
if ((tmpc != MOP_K_RPR_FORMAT) &&
(tmpc != MOP_K_RPR_FORMAT_V3)) {
fprintf(stderr, "mopd: Unknown RPR Format (%d) from ",
tmpc);
mopPrintHWA(stderr, src);
fprintf(stderr, "\n");
}
mopGetChar(pkt, idx); /* Program Type */
tmpc = mopGetChar(pkt, idx); /* Software ID Len */
if (tmpc > sizeof(pfile) - 1)
return;
for (i = 0; i < tmpc; i++) {
pfile[i] = mopGetChar(pkt, idx);
pfile[i+1] = '\0';
}
if (tmpc == 0) {
/* In a normal implementation of a MOP Loader this */
/* would cause a question to NML (DECnet) if this */
/* node is known and if so what image to load. But */
/* we don't have DECnet so we don't have anybody */
/* to ask. My solution is to use the ethernet addr */
/* as filename. Implementing a database would be */
/* overkill. */
snprintf((char *)pfile, sizeof pfile,
"%02x%02x%02x%02x%02x%02x%c",
src[0], src[1], src[2], src[3], src[4], src[5], 0);
}
mopGetChar(pkt, idx); /* Processor */
dl_rpr = &dl;
bzero(dl_rpr, sizeof(*dl_rpr));
dl_rpr->ii = ii;
bcopy(src, dl_rpr->eaddr, 6);
mopProcessInfo(pkt, idx, moplen, dl_rpr, trans);
snprintf(filename, sizeof(filename), "%s.SYS", pfile);
if ((mopCmpEAddr(dst, dl_mcst) == 0)) {
if ((nfd = open(filename, O_RDONLY, 0)) != -1) {
close(nfd);
mopSendASV(src, ii->eaddr, ii, trans);
snprintf(line, sizeof(line),
"%x:%x:%x:%x:%x:%x (%d) Do you have %s? "
"(Yes)", src[0], src[1], src[2], src[3],
src[4], src[5], trans, pfile);
} else {
snprintf(line, sizeof(line),
"%x:%x:%x:%x:%x:%x (%d) Do you have %s? "
"(No)", src[0], src[1], src[2], src[3],
src[4], src[5], trans, pfile);
}
syslog(LOG_INFO, "%s", line);
} else {
if ((mopCmpEAddr(dst, ii->eaddr) == 0)) {
dl_rpr->ldfd = open(filename, O_RDONLY, 0);
mopStartLoad(src, ii->eaddr, dl_rpr, trans);
snprintf(line, sizeof(line),
"%x:%x:%x:%x:%x:%x Send me %s",
src[0], src[1], src[2], src[3], src[4],
src[5], pfile);
syslog(LOG_INFO, "%s", line);
}
}
break;
case MOP_K_CODE_RML:
load = mopGetChar(pkt, idx); /* Load Number */
mopGetChar(pkt, idx); /* Error */
if ((mopCmpEAddr(dst, ii->eaddr) == 0))
mopNextLoad(src, ii->eaddr, load, trans);
break;
case MOP_K_CODE_RDS:
break;
case MOP_K_CODE_MDD:
break;
case MOP_K_CODE_CCP:
break;
case MOP_K_CODE_PLT:
break;
default:
break;
}
}
/* ARGSUSED */
void
mopProcessRC(FILE *fd, struct if_info *ii, u_char *pkt, int *idx, u_char dst,
u_char *src, int trans, u_short len)
{
u_char tmpc;
u_short tmps, moplen = 0;
u_char mopcode;
struct dllist dl, *dl_rpr;
if ((DebugFlag == DEBUG_ONELINE))
mopPrintOneline(stdout, pkt, trans);
if ((DebugFlag >= DEBUG_HEADER)) {
mopPrintHeader(stdout, pkt, trans);
mopPrintMopHeader(stdout, pkt, trans);
}
if ((DebugFlag >= DEBUG_INFO))
mopDumpRC(stdout, pkt, trans);
moplen = mopGetLength(pkt, trans);
mopcode = mopGetChar(pkt, idx);
switch (mopcode) {
case MOP_K_CODE_RID:
break;
case MOP_K_CODE_BOT:
break;
case MOP_K_CODE_SID:
tmpc = mopGetChar(pkt, idx); /* Reserved */
if ((DebugFlag >= DEBUG_INFO))
fprintf(stderr, "Reserved : %02x\n", tmpc);
tmps = mopGetShort(pkt, idx); /* Receipt # */
if ((DebugFlag >= DEBUG_INFO))
fprintf(stderr, "Receipt Nbr : %04x\n", tmps);
dl_rpr = &dl;
bzero(dl_rpr, sizeof(*dl_rpr));
dl_rpr->ii = ii;
bcopy(src, dl_rpr->eaddr, 6);
mopProcessInfo(pkt, idx, moplen, dl_rpr, trans);
break;
case MOP_K_CODE_RQC:
break;
case MOP_K_CODE_CNT:
break;
case MOP_K_CODE_RVC:
break;
case MOP_K_CODE_RLC:
break;
case MOP_K_CODE_CCP:
break;
case MOP_K_CODE_CRA:
break;
default:
break;
}
}