1
0
mirror of https://github.com/PDP-10/klh10.git synced 2026-02-06 00:15:26 +00:00

Add ch11 files and apply patch from http://victor.se/bjorn/its/ch11.tar.gz

This commit is contained in:
Lars Brinkhoff
2017-02-02 20:39:08 +01:00
parent 1cfe638d1c
commit 78fa98ac15
7 changed files with 2463 additions and 16 deletions

View File

@@ -199,7 +199,7 @@ OFILES_KS = klh10.o prmstr.o fecmd.o feload.o wfio.o osdsup.o \
DPROCS_KL = dprpxx dptm03 dpni20
DPROCS_KS = dprpxx dptm03
DPROCS_KSITS = dprpxx dptm03 dpimp
DPROCS_KSITS = dprpxx dptm03 dpimp dpchudp
# Base utility programs, independent of KN10
@@ -290,6 +290,8 @@ install:
mv ${KLH10_HOME}/dpni20 ${KLH10_HOME}/flushed; fi
@if [ -x ${KLH10_HOME}/dpimp ]; then \
mv ${KLH10_HOME}/dpimp ${KLH10_HOME}/flushed; fi
@if [ -x ${KLH10_HOME}/dpchudp ]; then \
mv ${KLH10_HOME}/dpchudp ${KLH10_HOME}/flushed; fi
@if [ -x kn10-ks ]; then cp -p kn10-ks ${KLH10_HOME}/; fi
@if [ -x kn10-ks-its ]; then cp -p kn10-ks-its ${KLH10_HOME}/; fi
@if [ -x kn10-kl ]; then cp -p kn10-kl ${KLH10_HOME}/; fi
@@ -297,6 +299,7 @@ install:
@if [ -x dptm03 ]; then cp -p dptm03 ${KLH10_HOME}/; fi
@if [ -x dpni20 ]; then cp -p dpni20 ${KLH10_HOME}/; fi
@if [ -x dpimp ]; then cp -p dpimp ${KLH10_HOME}/; fi
@if [ -x dpchudp ]; then cp -p dpchudp ${KLH10_HOME}/; fi
@if [ -x enaddr ]; then cp -p enaddr ${KLH10_HOME}/; fi
@if [ -x tapedd ]; then cp -p tapedd ${KLH10_HOME}/; fi
@if [ -x udlconv ]; then cp -p udlconv ${KLH10_HOME}/; fi
@@ -546,6 +549,14 @@ kl0i-rtmopt:
$(CONFFLAGS_AUX) \
$(CONFFLAGS_USR) "
# --------- CHUDP subprocess (ITS KS only; counterpart for dvch11)
#
dpchudp.o: $(SRC)/dpchudp.c $(SRC)/dpchudp.h $(SRC)/dpsup.h
$(BUILDMOD) $(SRC)/dpchudp.c
dpchudp: dpchudp.o dpsup.o
$(LINKER) $(LDFLAGS) $(LDOUTF) dpchudp dpchudp.o dpsup.o $(LIBS)
####################################################################
## Device Process (DP) programs

910
src/dpchudp.c Normal file
View File

@@ -0,0 +1,910 @@
/* DPCHUDP.C - Chaos over UDP process
*/
/* Copyright © 2005 Björn Victor and Kenneth L. Harrenstien
** All Rights Reserved
**
** This file may become part of the KLH10 Distribution. Use, modification, and
** re-distribution is permitted subject to the terms in the file
** named "LICENSE", which contains the full text of the legal notices
** and should always accompany this Distribution.
**
** This software is provided "AS IS" with NO WARRANTY OF ANY KIND.
**
** This notice (including the copyright and warranty disclaimer)
** must be included in all copies or derivations of this software.
*/
/* This is based on DPIMP.C, to some extent.
Some things are irrelevant inheritage from dpimp, and could be cleaned up... */
/*
This is a program intended to be run as a child of the KLH10
PDP-10 emulator, in order to provide a Chaos-over-UDP tunnel.
Given a Chaos packet and a mapping between Chaosnet and IP addresses,
it simply sends the packet encapsulated in a UDP datagram.
The protocol is very similar to the original Chaosnet link protocol,
with the addition of a four-byte protocol header:
| V | F | A1 | A2 |
where
V is the CHUDP protocol version (currently 1)
F is the function code (initially only CHUDP_PKT)
A1, A2 are arguments for the function
For F = CHUDP_PKT, A1 and A2 are zero (ignored), followed by the Chaos packet,
and a trailer
| D1 | D2 | S1 | S2 |
| C1 | C2 |
where D1,D2 are the destination Chaos address (subnet, address)
S1,S2 source
C1,C2 are the two bytes of Chaosnet checksum
(for the Chaos packet + trailer)
*note* that this is (currently) the standard Internet
checksum, not the original Chaosnet checksum
"Messages" to and from the IMP are sent over the standard DP
shared memory mechanism; these are composed of 8-bit bytes in exactly
the same order as if a CH11 was sending or receiving them. Packets to
and from the NET are CHUDP packets.
There are actually two processes active, one which pumps data
from the NET to the CH11-output buffer, and another that pumps in the
opposite direction from an input buffer to the NET. Generally they
are completely independent.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include "klh10.h" /* Get config params */
/* This must precede any other OSD includes to ensure that DECOSF gets
the right flavor sockaddr (sigh)
*/
#define OSN_USE_IPONLY 1 /* Only need IP stuff */
#include "osdnet.h" /* OSD net defs, shared with DPNI20 and DPIMP */
#include <sys/resource.h> /* For setpriority() */
#include <sys/mman.h> /* For mlockall() */
#include "dpchudp.h" /* DPCHUDP specific defs, grabs DPSUP if needed */
/* Globals */
struct dp_s dp; /* Device-Process struct for DP ops */
int cpupid; /* PID of superior CPU process */
int chpid; /* PID of child (R proc) */
int swstatus = TRUE;
int sock; /* UDP socket */
int myaddr; /* My chaos address */
struct in_addr ihost_ip; /* My host IP addr, net order */
/* FROM HERE: replace
"dpchudp" for "dpimp",
"chudp" for "imp",
*/
/* Debug flag reference. Use DBGFLG within functions that have "dpchudp";
* all others must use DP_DBGFLG. Both refer to the same location.
* Caching a local copy of the debug flag is a no-no because it lives
* in a shared memory location that may change at any time.
*/
#define DBGFLG (dpchudp->dpchudp_dpc.dpc_debug)
#define DP_DBGFLG (((struct dpchudp_s *)dp.dp_adr)->dpchudp_dpc.dpc_debug)
/* Local predeclarations */
void chudptohost(struct dpchudp_s *);
void hosttochudp(struct dpchudp_s *);
void net_init(struct dpchudp_s *);
void dumppkt(unsigned char *, int);
void ihl_hhsend(register struct dpchudp_s *dpchudp, int cnt, register unsigned char *pp);
void ip_write(struct in_addr *ipa, in_port_t ipport, unsigned char *buf, int len, struct dpchudp_s *dpchudp);
/* Error and diagnostic output */
static const char progname_i[] = "dpchudp";
static const char progname_r[] = "dpchudp-R";
static const char progname_w[] = "dpchudp-W";
static const char *progname = progname_i;
static void efatal(int num, char *fmt, ...)
{
fprintf(stderr, "\r\n[%s: Fatal error: ", progname);
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
fputs("]\r\n", stderr);
/* DP automatically kills any child as well. */
dp_exit(&dp, num);
}
static void esfatal(int num, char *fmt, ...)
{
fprintf(stderr, "\r\n[%s: ", progname);
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
fprintf(stderr, " - %s]\r\n", dp_strerror(errno));
/* DP automatically kills any child as well. */
dp_exit(&dp, num);
}
static void dbprint(char *fmt, ...)
{
fprintf(stderr, "[%s: ", progname);
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
fputs("]", stderr);
}
static void dbprintln(char *fmt, ...)
{
fprintf(stderr, "[%s: ", progname);
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
fputs("]\r\n", stderr);
}
static void error(char *fmt, ...)
{
fprintf(stderr, "\r\n[%s: ", progname);
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
fputs("]\r\n", stderr);
}
static void syserr(int num, char *fmt, ...)
{
fprintf(stderr, "\r\n[%s: ", progname);
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
fprintf(stderr, " - %s]\r\n", dp_strerror(num));
}
int initdebug = 0;
int
main(int argc, char **argv)
{
register struct dpchudp_s *dpchudp; /* Ptr to shared memory area */
/* Search for a "-debug" command-line argument so that we can start
debug output ASAP if necessary.
*/
if (argc > 1) {
int i;
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-debug") == 0) {
initdebug = TRUE;
break;
}
}
}
if (initdebug)
dbprint("Starting");
/* Right off the bat attempt to get the highest scheduling priority
** we can, since a slow response will cause the 10 monitor to declare
** the interface dead.
*/
#if CENV_SYS_SOLARIS || CENV_SYS_DECOSF || CENV_SYS_XBSD || CENV_SYS_LINUX
if (setpriority(PRIO_PROCESS, 0, -20) < 0)
syserr(errno, "Warning - cannot set high priority");
#elif CENV_SYS_UNIX /* Try old generic Unix call */
if (nice(-20) == -1)
syserr(errno, "Warning - cannot set high priority");
#else
error("Warning - cannot set high priority");
#endif
/* Next priority is to quickly close the vulnerability window;
disable TTY cruft to ensure that any TTY hacking done by superior
process doesn't inadvertently kill us off.
*/
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
if (initdebug)
dbprint("Started");
/* General initialization */
if (!dp_main(&dp, argc, argv)) {
efatal(1, "DP init failed!");
}
dpchudp = (struct dpchudp_s *)dp.dp_adr; /* Make for easier refs */
/* Verify that the structure version is compatible */
if (dpchudp->dpchudp_ver != DPCHUDP_VERSION) {
efatal(1, "Wrong version of DPCHUDP: ch11=%0lx dpchudp=%0lx",
(long)dpchudp->dpchudp_ver, (long)DPCHUDP_VERSION);
}
/* Now can access DP args!
From here on we can use DBGFLG, which is actually a shared
memory reference that dpchudp points to. Check here to accomodate the
case where it's not already set but "-debug" was given as a command
arg; leave it alone if already set since the exact bits have
significance.
*/
if (initdebug && !DBGFLG)
DBGFLG = 1;
if (DBGFLG)
dbprint("DP inited");
/* Always attempt to lock memory since the DP processes are fairly
** small, must respond quickly, and SU mode is more or less guaranteed.
** Skip it only if dp_main() already did it for us.
*/
#if CENV_SYS_DECOSF || CENV_SYS_SOLARIS || CENV_SYS_LINUX
if (!(dpchudp->dpchudp_dpc.dpc_flags & DPCF_MEMLOCK)) {
if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) {
dbprintln("Warning - cannot lock memory");
}
}
#endif
/* Now set up legacy variables based on parameters passed through
shared DP area.
*/
if ((myaddr = dpchudp->dpchudp_myaddr) == 0) /* My chaos address */
efatal(1, "no CHAOS address specified");
/* Initialize various network info */
net_init(dpchudp);
/* Make this a status (rather than debug) printout? */
if (swstatus) {
int i;
char ipbuf[OSN_IPSTRSIZ];
dbprintln("ifc \"%s\" => chaos %lo",
dpchudp->dpchudp_ifnam, (long)myaddr);
for (i = 0; i < dpchudp->dpchudp_chip_tlen; i++)
dbprintln(" chaos %6o => ip %s:%d",
dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_chaddr,
ip_adrsprint(ipbuf,
(unsigned char *)&dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_ipaddr),
dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_ipport);
}
/* Now start up a child process to handle input */
if (DBGFLG)
dbprint("Forking R process");
if ((chpid = fork()) < 0)
esfatal(1, "fork failed");
if (chpid == 0) {
/* Child process.
** Child inherits signal handlers, which is what we want here.
*/
/* Fix up xfer mechanism so ACK of DP input goes to correct proc */
dp.dp_adr->dpc_frdp.dpx_donpid = getpid();
/* And ensure its memory is locked too, since the lockage isn't
** inherited over a fork(). Don't bother warning if it fails.
*/
#if CENV_SYS_DECOSF || CENV_SYS_SOLARIS || CENV_SYS_LINUX
(void) mlockall(MCL_CURRENT|MCL_FUTURE);
#endif
progname = progname_r; /* Reset progname to indicate identity */
chudptohost(dpchudp); /* Child process handles input */
}
progname = progname_w; /* Reset progname to indicate identity */
hosttochudp(dpchudp); /* Parent process handles output */
return 1; /* Never returns, but placate compiler */
}
/* NET_INIT - Initialize net-related variables,
** given network interface we'll use.
*/
void
net_init(register struct dpchudp_s *dpchudp)
{
struct ifreq ifr;
/* Ensure network device name, if specified, isn't too long */
if (dpchudp->dpchudp_ifnam[0] && (strlen(dpchudp->dpchudp_ifnam)
>= sizeof(ifr.ifr_name))) {
esfatal(0, "interface name \"%s\" too long - max %d",
dpchudp->dpchudp_ifnam, (int)sizeof(ifr.ifr_name));
}
#if 0
/* Don't determine network device to use, if none was specified
** (since we simply use all interfaces in that case).
*/
if (dpchudp->dpchudp_ifnam[0]) {
/* Find host's IP address for this interface */
if (!osn_ifipget(-1, dpchudp->dpchudp_ifnam, (unsigned char *)&ihost_ip)) {
efatal(1,"osn_ifipget failed for \"%s\"", dpchudp->dpchudp_ifnam);
}
#endif
/* Set up appropriate net fd.
*/
{
struct sockaddr_in mysin;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
efatal(1,"socket failed: %s", dp_strerror(errno));
mysin.sin_family = AF_INET;
mysin.sin_port = htons(dpchudp->dpchudp_port);
mysin.sin_addr.s_addr = INADDR_ANY;
#if 0
if (dpchudp->dpchudp_ifnam[0] && ihost_ip.s_addr != 0)
mysin.sin_addr.s_addr = ihost_ip.s_addr;
#endif
if (bind(sock, (struct sockaddr *)&mysin, sizeof(mysin)) < 0)
efatal(1,"bind failed: %s", dp_strerror(errno));
}
}
/* CHUDPTOHOST - Child-process main loop for pumping packets from CHUDP to HOST.
** Reads packets from net and feeds CHUDP packets to DP superior process.
*/
#define NINBUFSIZ (DPCHUDP_DATAOFFSET+MAXETHERLEN)
/* Duplicated from dvch11.c - should go in dpsup.c */
static unsigned int
ch_checksum(const unsigned char *addr, int count)
{
/* RFC1071 */
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
register long sum = 0;
while( count > 1 ) {
/* This is the inner loop */
sum += *(addr)<<8 | *(addr+1);
addr += 2;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
return (~sum) & 0xffff;
}
void
chudptohost(register struct dpchudp_s *dpchudp)
{
register struct dpx_s *dpx = dp_dpxfr(&dp);
register int cnt;
unsigned char *inibuf;
unsigned char *buffp;
size_t max;
int stoploop = 50;
struct sockaddr_in ip_sender;
socklen_t iplen;
inibuf = dp_xsbuff(dpx, &max); /* Get initial buffer ptr */
/* Tell KLH10 we're initialized and ready by sending initial packet */
dp_xswait(dpx); /* Wait until buff free, in case */
dp_xsend(dpx, DPCHUDP_INIT, 0); /* Send INIT */
if (DBGFLG)
fprintf(stderr, "[dpchudp-R: sent INIT]\r\n");
for (;;) {
/* Make sure that buffer is free before clobbering it */
dp_xswait(dpx); /* Wait until buff free */
if (DBGFLG)
fprintf(stderr, "[dpchudp-R: InWait]\r\n");
/* Set up buffer and initialize offsets */
buffp = inibuf;
/* OK, now do a blocking read on UDP socket! */
errno = 0; /* Clear to make sure it's the actual error */
memset(&ip_sender, 0, sizeof(ip_sender));
memset(&iplen, 0, sizeof(iplen));
cnt = recvfrom(sock, buffp, DPCHUDP_MAXLEN, 0, (struct sockaddr *)&ip_sender, &iplen);
if (cnt <= DPCHUDP_DATAOFFSET) {
if (DBGFLG)
fprintf(stderr, "[dpchudp-R: ERead=%d, Err=%d]\r\n",
cnt, errno);
if (cnt < 0 && (errno == EINTR)) /* Ignore spurious signals */
continue;
/* Error of some kind */
fprintf(stderr, "[dpchudp-R: Eread = %d, ", cnt);
if (cnt < 0) {
if (--stoploop <= 0)
efatal(1, "Too many retries, aborting]");
fprintf(stderr, "errno %d = %s]\r\n",
errno, dp_strerror(errno));
} else if (cnt > 0)
fprintf(stderr, "no chudp data]\r\n");
else fprintf(stderr, "no packet]\r\n");
continue; /* For now... */
}
if (DBGFLG) {
if (DBGFLG & 0x4) {
fprintf(stderr, "\r\n[dpchudp-R: Read=%d\r\n", cnt);
dumppkt(buffp, cnt);
fprintf(stderr, "]");
}
else
fprintf(stderr, "[dpchudp-R: Read=%d]", cnt);
}
/* Have packet, now dispatch it to host */
if (((struct chudp_header *)buffp)->chudp_version != CHUDP_VERSION) {
if (DBGFLG)
error("wrong protocol version %d",
((struct chudp_header *)buffp)->chudp_version);
continue;
}
switch (((struct chudp_header *)buffp)->chudp_function) {
case CHUDP_PKT:
break; /* deliver it */
default:
error("Unknown CHUDP function: %0X",
((struct chudp_header *)buffp)->chudp_function);
continue;
}
/* Check who it's from, update Chaos/IP mapping */
{
/* check that the packet is complete:
4 bytes CHUDP header, Chaos header, add Chaos pkt length, plus 6 bytes trailer */
int chalen = ((buffp[DPCHUDP_DATAOFFSET+2] & 0xf)<<4) | buffp[DPCHUDP_DATAOFFSET+3];
int datalen = (DPCHUDP_DATAOFFSET + CHAOS_HEADERSIZE + chalen);
int chafrom = (buffp[cnt-4]<<8) | buffp[cnt-3];
unsigned char *ip = (unsigned char *)&ip_sender.sin_addr.s_addr;
in_port_t port = ntohs(ip_sender.sin_port);
time_t now = time(NULL);
int i, cks;
if ((cks = ch_checksum(buffp+DPCHUDP_DATAOFFSET,cnt-DPCHUDP_DATAOFFSET)) != 0) {
if (1 || DBGFLG)
dbprintln("Bad checksum 0x%x",cks);
/* #### must free buffer first(?) */
/* return; */
}
if (cnt < datalen + CHAOS_HW_TRAILERSIZE) { /* may have a byte of padding */
if (1 || DBGFLG) {
dbprintln("Rcvd bad length: %d. < %d. (expected), chaos data %d bytes, errno %d",
cnt, datalen + CHAOS_HW_TRAILERSIZE, chalen, errno);
dumppkt(buffp, cnt);
}
/* #### must free buffer first(?) */
/* return; */
}
#if 0
if (DBGFLG) {
dbprintln("Rcv from chaos %o = ip %d.%d.%d.%d port %d., %d. bytes (datalen %d)",
chafrom,
ip[0],ip[1],ip[2],ip[3], port,
cnt, datalen);
dumppkt(buffp,cnt);
}
#endif
/* #### remove cks when buffer freed instead */
if ((cks == 0) && (chafrom != myaddr) && (dpchudp->dpchudp_chip_tlen < DPCHUDP_CHIP_MAX)) {
/* Space available, see if we need to add this */
/* Look for old entries: if one is found which is either
static (from config file) or sufficiently fresh,
keep it and update the freshness (if not static) */
for (i = 0; i < dpchudp->dpchudp_chip_tlen; i++)
if (chafrom == dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_chaddr) {
if (dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_lastrcvd != 0) {
if (now - dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_lastrcvd >
DPCHUDP_CHIP_DYNAMIC_AGE_LIMIT) {
/* Old, update it (in case he moved) */
if (1 || DBGFLG)
dbprintln("Updating CHIP entry %d for %o/%d.%d.%d.%d:%d",
i, chafrom, ip[0],ip[1],ip[2],ip[3], port);
dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_ipport = port;
memcpy(&dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_ipaddr, ip, IP_ADRSIZ);
}
/* update timestamp */
dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_lastrcvd = now;
}
chafrom = -1; /* Not it shouldn't be added */
break;
}
if (chafrom > 0) {
/* It's OK to write here, the other fork will see it when tlen is updated */
i = dpchudp->dpchudp_chip_tlen;
if (1 || DBGFLG)
dbprintln("Adding CHIP entry %d for %o/%d.%d.%d.%d:%d",
i, chafrom, ip[0],ip[1],ip[2],ip[3], port);
dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_chaddr = chafrom;
dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_ipport = port;
dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_lastrcvd = now;
memcpy(&dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_ipaddr, ip, IP_ADRSIZ);
dpchudp->dpchudp_chip_tlen++;
}
#if 0
else if (0 && DBGFLG) {
dbprintln("Already know chaos %o",chafrom);
}
#endif
}
else if ((dpchudp->dpchudp_chip_tlen >= DPCHUDP_CHIP_MAX) && DBGFLG) {
dbprintln("CHIP table full - cannot add %o", chafrom);
}
}
ihl_hhsend(dpchudp, cnt, buffp);
}
}
/* Send regular message from CHUDP to HOST.
*/
void
ihl_hhsend(register struct dpchudp_s *dpchudp,
int cnt,
register unsigned char *pp)
/* "pp" is packet data ptr, has room for header preceding */
{
/* Send up to host! Assume we're already in shared buffer. */
register struct dpx_s *dpx = dp_dpxfr(&dp);
size_t off = DPCHUDP_DATAOFFSET;
dpchudp->dpchudp_inoff = off; /* Tell host what offset is */
dp_xsend(dpx, DPCHUDP_RPKT, cnt-off);
if (DBGFLG)
fprintf(stderr, "[dpchudp-R: sent RPKT %d+%d]", (int)off, cnt-off);
}
/* HOSTTOCHUDP - Parent main loop for pumping packets from HOST to CHUDP.
** Reads CHUDP message from DP superior
** and interprets it. If a regular message, bundles it up and
** outputs to NET.
*/
void
hosttochudp(register struct dpchudp_s *dpchudp)
{
register struct dpx_s *dpx = dp_dpxto(&dp); /* Get ptr to "To-DP" dpx */
register unsigned char *buff;
size_t max;
register int rcnt;
unsigned char *inibuf;
struct in_addr ipdest;
in_port_t ipport;
struct chudp_header chuhdr = { CHUDP_VERSION, CHUDP_PKT, 0, 0 };
inibuf = dp_xrbuff(dpx, &max); /* Get initial buffer ptr */
if (DBGFLG)
fprintf(stderr, "[dpchudp-W: Starting loop]\r\n");
for (;;) {
if (DBGFLG)
fprintf(stderr, "[dpchudp-W: CmdWait]\r\n");
/* Wait until 10 has a command for us */
dp_xrwait(dpx); /* Wait until something there */
/* Process command from 10! */
switch (dp_xrcmd(dpx)) {
default:
fprintf(stderr, "[dpchudp: Unknown cmd %d]\r\n", dp_xrcmd(dpx));
dp_xrdone(dpx);
continue;
case DPCHUDP_SPKT: /* Send regular packet */
rcnt = dp_xrcnt(dpx);
/* does rcnt include chudp header size? yes. */
buff = inibuf;
memcpy(buff, (void *)&chuhdr, sizeof(chuhdr)); /* put in CHUDP hdr */
if (DBGFLG) {
if (DBGFLG & 0x2) {
fprintf(stderr, "\r\n[dpchudp-W: Sending %d\r\n", rcnt);
dumppkt(buff, rcnt);
fprintf(stderr, "]");
}
else
fprintf(stderr, "[dpchudp-W: SPKT %d]", rcnt);
}
break;
}
/* Come here to handle output packet */
#if 1
{
int chlen = ((buff[DPCHUDP_DATAOFFSET+2] & 0xf) << 4) | buff[DPCHUDP_DATAOFFSET+3];
if ((chlen + CHAOS_HEADERSIZE + DPCHUDP_DATAOFFSET + CHAOS_HW_TRAILERSIZE) > rcnt) {
if (1 || DBGFLG)
dbprintln("NOT sending less than packet: pkt len %d, expected %d (Chaos data len %d)",
rcnt, (chlen + CHAOS_HEADERSIZE + DPCHUDP_DATAOFFSET + CHAOS_HW_TRAILERSIZE),
chlen);
dp_xrdone(dpx); /* ack it to dvch11, but */
return; /* #### don't send it! */
}
}
#endif
/* find IP destination given chaos packet */
if (hi_iproute(&ipdest, &ipport, &buff[DPCHUDP_DATAOFFSET], rcnt - DPCHUDP_DATAOFFSET,dpchudp)) {
ip_write(&ipdest, ipport, buff, rcnt, dpchudp);
}
/* Command done, tell 10 we're done with it */
if (DBGFLG)
fprintf(stderr, "[dpchudp-W: CmdDone]");
dp_xrdone(dpx);
}
}
int
hi_lookup(struct dpchudp_s *dpchudp,
struct in_addr *ipa, /* Dest IP addr to be put here */
in_port_t *ipport, /* dest IP port to be put here */
unsigned int chdest, /* look up this chaos destination */
int sbnmatch) /* just match subnet part */
{
int i;
for (i = 0; i < dpchudp->dpchudp_chip_tlen; i++)
if (
#if DPCHUDP_DO_ROUTING
((!sbnmatch && (chdest == dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_chaddr))
||
/* handle subnet matching */
(sbnmatch && ((chdest >> 8) == (dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_chaddr >> 8))))
#else
(chdest == dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_chaddr)
#endif
&& dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_ipaddr.s_addr != 0) {
memcpy(ipport, &dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_ipport, sizeof(in_port_t));
memcpy((void *)ipa, &dpchudp->dpchudp_chip_tbl[i].dpchudp_chip_ipaddr,
sizeof(struct in_addr));
if (DBGFLG) {
char ipbuf[OSN_IPSTRSIZ];
dbprintln("found Chaos address %o at %s:%d",
chdest, ip_adrsprint(ipbuf, (unsigned char *)ipa), *ipport);
}
return TRUE;
}
if (DBGFLG)
dbprintln("failed looking up Chaos address %o",chdest);
return FALSE;
}
/* HI_IPROUTE - Determine where to actually send Chaos packet.
** Fill in ipa with IP address, based on Chaos header in lp,
** or if DPCHUDP_DO_ROUTING, based on Chaos trailer,
** and also do some basic routing if destination is DEFAULT_CHAOS_ROUTER (3040)
** or just some other subnet we know about.
*/
int
hi_iproute(struct in_addr *ipa, /* Dest IP addr to be put here */
in_port_t *ipport, /* dest IP port to be put here */
unsigned char *lp, /* Ptr to start of Chaos packet */
int cnt, /* Cnt of data including header */
struct dpchudp_s *dpchudp)
{
unsigned int chdest;
#if DPCHUDP_DO_ROUTING
unsigned int hwdest;
#endif
if (cnt < CHAOS_HEADERSIZE) {
error("Chaos packet too short: %d", cnt);
return FALSE;
}
#if !DPCHUDP_DO_ROUTING
/* Derive destination IP address from Chaos header */
chdest = lp[DPCHUDP_CH_DESTOFF]<<8 | lp[DPCHUDP_CH_DESTOFF+1];
#else
/* Use hw trailer instead */
hwdest = lp[cnt-6] << 8 | lp[cnt-5];
if ((hwdest == DEFAULT_CHAOS_ROUTER) || ((hwdest >> 8) != (myaddr >> 8))) {
/* Look up header dest,
if successful, change trailer dest, increase FW count, recompute checksum */
if ((lp[DPCHUDP_CH_FC] >> 4) == 0xf) /* FC about to wrap */
return FALSE; /* drop it */
/* look in header */
chdest = lp[DPCHUDP_CH_DESTOFF]<<8 | lp[DPCHUDP_CH_DESTOFF+1];
} else
/* my subnet */
chdest = hwdest;
if (DBGFLG)
dbprintln("looking for route to chaos %o (hw %o) (FC %d.)", chdest, hwdest,
lp[DPCHUDP_CH_FC] >> 4);
#endif
if (hi_lookup(dpchudp, ipa, ipport, chdest, 0)
#if DPCHUDP_DO_ROUTING
/* try subnet match */
|| ((chdest != hwdest) && hi_lookup(dpchudp, ipa, ipport, chdest, 1))
#endif
) {
#if DPCHUDP_DO_ROUTING
if (chdest != hwdest) {
int cks;
if (DBGFLG)
dbprintln("found route");
/* change hw dest */
lp[cnt-6] = chdest >> 8;
lp[cnt-5] = chdest & 0xff;
/* make sure it's got the right hw source addr */
lp[cnt-4] = myaddr >> 8;
lp[cnt-3] = myaddr & 0xff;
/* increase FW count */
lp[DPCHUDP_CH_FC] = (lp[DPCHUDP_CH_FC] & 0xf) | ((lp[DPCHUDP_CH_FC]>>4)+1)<<4;
/* recompute checksum */
cks = ch_checksum(lp,cnt-2); /* w/o orig checksum */
lp[cnt-2] = cks >> 8;
lp[cnt-1] = cks & 0xff;
}
#endif
return TRUE;
}
return FALSE;
}
/* IP_WRITE - Send IP packet out over UDP
*/
void
ip_write(struct in_addr *ipa, in_port_t ipport, unsigned char *buf, int len, struct dpchudp_s *dpchudp)
{
struct sockaddr_in sin;
if (DBGFLG) {
dbprintln("sending to port %d",ipport);
}
sin.sin_family = AF_INET;
sin.sin_port = htons(ipport);
memcpy((void *)&sin.sin_addr, ipa, sizeof(struct in_addr));
if (sendto(sock, buf, len, 0, (struct sockaddr *) &sin, (socklen_t) (sizeof(sin))) != len) {
error("sendto failed - %s", dp_strerror(errno));
}
}
void
dumppkt_raw(unsigned char *ucp, int cnt)
{
int i;
while (cnt > 0) {
for (i = 8; --i >= 0 && cnt > 0;) {
if (--cnt >= 0)
fprintf(stderr, " %02x", *ucp++);
if (--cnt >= 0)
fprintf(stderr, "%02x", *ucp++);
}
fprintf(stderr, "\r\n");
}
}
static char
*ch_opc[] = { "NIL",
"RFC", "OPN", "CLS", "FWD", "ANS", "SNS", "STS", "RUT",
"LOS", "LSN", "MNT", "EOF", "UNC", "BRD" };
static char *
ch_opcode(int op)
{
char buf[7];
if (op < 017 && op > 0)
return ch_opc[op];
else if (op == 0200)
return "DAT";
else if (op == 0300)
return "DWD";
else
return "bogus";
}
void
dumppkt(unsigned char *ucp, int cnt)
{
int i, row;
fprintf(stderr,"CHUDP version %d, function %d\r\n", ucp[0], ucp[1]);
fprintf(stderr,"Opcode: %o (%s), unused: %o\r\nFC: %o, Nbytes %o\r\n",
ucp[0+DPCHUDP_DATAOFFSET], ch_opcode(ucp[0+DPCHUDP_DATAOFFSET]),
ucp[1+DPCHUDP_DATAOFFSET], ucp[2+DPCHUDP_DATAOFFSET]>>4, ((ucp[2+DPCHUDP_DATAOFFSET]&0xf)<<4) | ucp[3+DPCHUDP_DATAOFFSET]);
fprintf(stderr,"Dest host: %o, index %o\r\nSource host: %o, index %o\r\n",
(ucp[4+DPCHUDP_DATAOFFSET]<<8)|ucp[5+DPCHUDP_DATAOFFSET], (ucp[6+DPCHUDP_DATAOFFSET]<<8)|ucp[7+DPCHUDP_DATAOFFSET],
(ucp[8+DPCHUDP_DATAOFFSET]<<8)|ucp[9+DPCHUDP_DATAOFFSET], (ucp[10+DPCHUDP_DATAOFFSET]<<8)|ucp[11+DPCHUDP_DATAOFFSET]);
fprintf(stderr,"Packet #%o\r\nAck #%o\r\n",
(ucp[12+DPCHUDP_DATAOFFSET]<<8)|ucp[13+DPCHUDP_DATAOFFSET], (ucp[14+DPCHUDP_DATAOFFSET]<<8)|ucp[15+DPCHUDP_DATAOFFSET]);
fprintf(stderr,"Data:\r\n");
/* Skip headers */
ucp += DPCHUDP_DATAOFFSET+CHAOS_HEADERSIZE;
/* Show only data portion */
cnt -= DPCHUDP_DATAOFFSET+CHAOS_HEADERSIZE+CHAOS_HW_TRAILERSIZE;
for (row = 0; row*8 < cnt; row++) {
for (i = 0; (i < 8) && (i+row*8 < cnt); i++) {
fprintf(stderr, " %02x", ucp[i+row*8]);
fprintf(stderr, "%02x", ucp[(++i)+row*8]);
}
fprintf(stderr, " (hex)\r\n");
#if 0
for (i = 0; (i < 8) && (i+row*8 < cnt); i++) {
fprintf(stderr, " %2c", ucp[i+row*8]);
fprintf(stderr, "%2c", ucp[(++i)+row*8]);
}
fprintf(stderr, " (chars)\r\n");
for (i = 0; (i < 8) && (i+row*8 < cnt); i++) {
fprintf(stderr, " %2c", ucp[i+1+row*8]);
fprintf(stderr, "%2c", ucp[(i++)+row*8]);
}
fprintf(stderr, " (11-chars)\r\n");
#endif
}
/* Now show trailer */
fprintf(stderr,"HW trailer:\r\n Dest: %o\r\n Source: %o\r\n Checksum: 0x%x\r\n",
(ucp[cnt]<<8)|ucp[cnt+1],(ucp[cnt+2]<<8)|ucp[cnt+3],(ucp[cnt+4]<<8)|ucp[cnt+5]);
}
/* Add OSDNET shared code here */
/* OSDNET is overkill and assumes a lot of packet filter defs,
which we're not at all interested in providing */
#if 0
# include "osdnet.c"
#else
char *
ip_adrsprint(char *cp, unsigned char *ia)
{
sprintf(cp, "%d.%d.%d.%d", ia[0], ia[1], ia[2], ia[3]);
return cp;
}
#endif

108
src/dpchudp.h Normal file
View File

@@ -0,0 +1,108 @@
/* DPCHUDP.H - Definitions for CHUDP process
*/
/* Copyright © 2005 Björn Victor and Kenneth L. Harrenstien
** All Rights Reserved
**
** This file may become part of the KLH10 Distribution. Use, modification, and
** re-distribution is permitted subject to the terms in the file
** named "LICENSE", which contains the full text of the legal notices
** and should always accompany this Distribution.
**
** This software is provided "AS IS" with NO WARRANTY OF ANY KIND.
**
** This notice (including the copyright and warranty disclaimer)
** must be included in all copies or derivations of this software.
*/
#ifndef DPCHUDP_INCLUDED
#define DPCHUDP_INCLUDED 1
#ifndef DPSUP_INCLUDED
# include "dpsup.h"
#endif
#ifndef OSDNET_INCLUDED
# include "osdnet.h"
#endif
/* Version of DPCHUDP-specific shared memory structure */
#define DPCHUDP_VERSION ((1<<10) | (0<<5) | (0)) /* 1.0.0 */
#ifndef DPCHUDP_CHIP_MAX
# define DPCHUDP_CHIP_MAX 10
#endif
/* If a dynamically added CHIP entry is older than this (seconds), it can get updated */
#ifndef DPCHUDP_CHIP_DYNAMIC_AGE_LIMIT
# define DPCHUDP_CHIP_DYNAMIC_AGE_LIMIT (60*5)
#endif
/* Chaos/IP mapping entry - see ch_chip */
struct dpchudp_chip {
unsigned int dpchudp_chip_chaddr; /* Chaos address */
struct in_addr dpchudp_chip_ipaddr; /* IP address */
in_port_t dpchudp_chip_ipport; /* IP port */
time_t dpchudp_chip_lastrcvd; /* When last received, if dynamically added */
};
/* DPCHUDP-specific stuff */
/* C = controlling parent sets, D = Device proc sets */
/* If both, 1st letter indicates inital setter */
struct dpchudp_s {
struct dpc_s dpchudp_dpc; /* CD Standard DPC portion */
int dpchudp_ver; /* C Version of shared struct */
int dpchudp_attrs; /* C Attribute flags */
char dpchudp_ifnam[16]; /* CD Interface name if any */
unsigned int dpchudp_myaddr;
/* probably not used */
int dpchudp_inoff; /* C Offset in buffer of input (I->H) data */
int dpchudp_outoff; /* D Offset in buffer of output (H->I) data */
int dpchudp_backlog; /* C Max sys backlog of rcvd packets */
int dpchudp_dedic; /* C TRUE if dedicated ifc, else shared */
in_port_t dpchudp_port; /* C port for CHUDP protocol */
/* Chaos/IP mapping */
int dpchudp_chip_tlen; /* C table length */
struct dpchudp_chip dpchudp_chip_tbl[DPCHUDP_CHIP_MAX];
};
/* Buffer offset:
CHUDP protocol header is 4 bytes; read/write data after those
*/
struct chudp_header {
char chudp_version;
char chudp_function;
char chudp_arg1;
char chudp_arg2;
};
/* CHUDP protocol port - should perhaps be registered? */
#define CHUDP_PORT 42042
/* Protocol version */
#define CHUDP_VERSION 1
/* Protocol function codes */
#define CHUDP_PKT 1 /* Chaosnet packet */
#include "dvch11.h"
#define DPCHUDP_DATAOFFSET (sizeof(struct chudp_header))
#define DPCHUDP_MAXLEN (CHAOS_MAXDATA+DPCHUDP_DATAOFFSET+42) /* some slack */
#ifndef DPCHUDP_DO_ROUTING
# define DPCHUDP_DO_ROUTING 1
#endif
#define DEFAULT_CHAOS_ROUTER 03040 /* default router (MX-11.LCS.MIT.EDU) */
#define DPCHUDP_CH_DESTOFF 4 /* offset to dest addr in chaos pkt */
#define DPCHUDP_CH_FC 2 /* offset to forwarding count */
/* Commands to and from DP and KLH10 CH11 driver */
/* From 10 to DP */
#define DPCHUDP_RESET 0 /* Reset DP */
#define DPCHUDP_SPKT 1 /* Send data packet to ethernet */
/* From DP to 10 */
#define DPCHUDP_INIT 1 /* DP->10 Finished init */
#define DPCHUDP_RPKT 2 /* DP->10 Received data packet from net */
#endif /* ifndef DPCHUDP_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@@ -107,4 +107,9 @@ extern struct device *dvch11_init(FILE *, char *);
#define UB_CH11END (UB_CHXMT+2) /* First addr not used by CH11 regs */
#define CHAOS_HW_TRAILERSIZE (6) /* "hw" trailer bytes */
#define CHAOS_HEADERSIZE (4*4) /* chaos packet header size */
#define CHAOS_MAXDATA 488 /* Max data bytes per packet #### incl header? */
#endif /* ifndef DVCH11_INCLUDED */

111
src/dvch11.txt Normal file
View File

@@ -0,0 +1,111 @@
================================
CHAOS is restored!
or
CH11 support for ITS in KLH10
================================
The ch11 device in KLH10 for ITS, which was originally just a dummy
inteface to keep ITS running, is now a functional Unibus Chaosnet
device, which tunnels Chaosnet packets over UDP. It does not support
SPY (promiscuous) mode, LUP (loopback), or broadcast, but ITS doesn't
seem to use/need these.
Latest update: 2005-04-23
Why Chaos when we have the IMP?
* Some ITS services use Chaos but not IP, e.g. the DIR device.
* The IMP needs to run as root on most Unix flavors, but the UDP
tunnel can go over unprivileged ports. (This can also make it avoid
firewalls.)
* It's historically interesting, and makes KLH10 more complete.
* It's FUN!
Like other KLH10 network devices, ch11 works together with a Device
Process which communicates with the device and reads/writes network
data over UDP. A 4-byte protocol header is added, with only one
defined function code yet (sending a Chaos packet). The "original"
Chaos trailer (destination, source, and checksum) is also added.
The protocol, CHUDP, by default uses UDP port 42042, but this can be
configured in case, e.g., that port doesn't pass through your
firewall.
The code is a (very) stripped-down version of dvlhdh.c and dpimp.c,
and includes minimal patches to the makefile and to kn10dev.c.
It can be downloaded via http://victor.se/bjorn/its. I would
appreciate if you send me an email if you do, e.g. so I have an idea
about who to notify about updates.
To configure the CH11 device, as a minimum, use
devdef chaos ub3 ch11 addr=764140 br=6 vec=270 myaddr=3132
where the new parameter is "myaddr", which is the octal Chaosnet
address of the system. ITS seems to think the "br" param should be 6,
not 5 as used in the old dummy device definition (see CHXCHN in ITS).
It uses the generic Unibus parameters "addr", "br", "vec" etc, plus
additional parameters:
chudpport=50043
changes the UDP port used
chip=3131/10.0.1.42:50011
defines a Chaos/IP mapping for Chaos host 3131, which should
be contacted at IP 10.0.1.42 at UDP port 50011. You can use
hostnames in place of IP addresses, which will use the first
address returned by gethostbyname(), if it is an IPv4 address.
The port suffix is optional and defaults to 42042. You can
define up to 10 such Chaos/IP mappings (without changing the
constants in the code).
If a CHUDP packet is received from an unknown host, a Chaos/IP mapping
is dynamically added to the table, so return traffic can find its
way. This is useful e.g. if you accept connections from other ITSes
without static IP addresses. (There is currently no way to avoid
potentially filling your table this way.)
To make use of the interface, you need to recompile ITS after defining
CHAOSP, MYCHAD, NINDX, and CH11P in SYSTEM;CONFIG (and following the
instructions in distrib.its, of course). See also BEWARE note below.
Don't forget to compile SYSENG;@CHAOS and install as DEVICE;ATSIGN
CHAOS. Don't forget to keep names of your friends' ITSes in
SYSEN2;MLDEV, SYSENG;@DEV, etc. More notes on the web page.
I would appreciate very much to get feedback and testing, especially
from people who actually *know* how the original interface was
supposed to act. I've discovered many things by reading SYSTEM;CHAOS
and by testing locally, but I can't say I know exactly how it *should*
work...
*BEWARE*:
If you have both CHAOSP and IMPP, you run into a bug which results in
all non-local IP packets being routed via Chaosnet... (unfortunately
noone is listenting at Chaos address 3040).
The bug is caused by the IPMASK macro defined and used in
SYSTEM;CONFIG, which results in the netmask NM%CHA being zero, which
matches anything. The easy fix is to change the line
IFN CHAOSP,DEFOPT NM%CHA==<IPMASK IMPUS4> ; Set default netmask for it
to
IFN CHAOSP,DEFOPT NM%CHA==<IPADDR 255,255,0,0> ; Set default netmask for it
but the real fix would be to the IPMASK macro.
Ideas for future work:
- Better routing support.
- Use DNS to find Chaos addresses - this seems more awkward than helpful.
- Implement loopback (not LUP, but Chaos pkts to self). Currently
they are in practice dropped. I'm not sure ITS handles this very
well anyway.
- Chaos broadcast can easily be implemented by UDP broadcast, but it's
probably not very useful. Another implementation would be to send
(individually) to all known hosts (in the CHIP table) on the same
subnet, but this is probably not very useful either. (Does any ITS
program do broadcast?)
- More CHUDP protocol functions?
- Security?
- Chaosnet library for Linux/Unix???
Cheers,
--
Bjorn Victor Bjorn.Victor@it.uu.se
Dept. of Information Technology tel: +46 18 471 3169
Uppsala University mobile: +46 70 425 0239
Box 337 fax: +46 18 511925
S-751 05 Uppsala, SWEDEN web: http://user.it.uu.se/~victor

View File

@@ -293,7 +293,7 @@ extern struct device *dvlhdh_create(FILE *f, char *s);
extern struct device *dvdz11_init(FILE *f, char *s);
#endif
#if KLH10_DEV_CH11
extern struct device *dvch11_init(FILE *f, char *s);
extern struct device *dvch11_create(FILE *f, char *s);
#endif
/* Table binding static device driver modules with their names
@@ -329,7 +329,7 @@ static struct dvdrv_s dvdrvtab[KLH10_DEVMAX+1] = {
{ "dz11", dvdz11_init, NULL, NULL, "DZ11 dummy (Unibus)" },
#endif
#if KLH10_DEV_CH11
{ "ch11", dvch11_init, NULL, NULL, "Chaosnet dummy (Unibus)" },
{ "ch11", dvch11_create, NULL, NULL, "Chaosnet interface (Unibus)" },
#endif
{ NULL, NULL, NULL }
};