;SRC:<SYS.MONITOR>CHAOS.MAC.397  7-May-81 19:35:46, Edit by MMCM
; Check uniquizer too in CHFNDX
;SRC:<SYS.MONITOR>CHAOS.MAC.397  2-May-81 12:42:15, Edit by MMCM
; Bug in arpa routing added by use of single temporary packet
;<FOONEX>CHAOS.MAC;392 21-Apr-81 17:30:08, Edit by MMCM
; Allow interrupts out of GETOUT hang
;SRC:<SYS.MONITOR>CHAOS.MAC.375  9-Apr-81 14:54:02, Edit by CPR
; Merge in HIC's 2020 support.
;<FOONEX>CHAOS.MAC;373 29-Mar-81 21:08:13, Edit by MMCM
; Don't try to use indexing in previous context on byte instructions.
;SRC:<SYS.MONITOR>CHAOS.MAC.371 21-Mar-81 14:11:50, Edit by MMCM
;<FOONEX>CHAOS.MAC;370 14-Mar-81 13:14:08, Edit by MMCM
; Add conditional assembly for Foonly Tenex.
;SRC:<SYS.MONITOR>CHAOS.MAC.329 20-Mar-81 15:16:27, Edit by CPR
; Use temporary packet buffer for ARPA to CHAOS routing instead of
; allocating and freeing a packet each time.
;SRC:<SYS.MONITOR>CHAOS.MAC.327 11-Mar-81 23:29:48, Edit by MMCM
; Fix some bugs with sending over ARPA Net
;SRC:<SYS.MONITOR>CHAOS.MAC.326 25-Feb-81 16:41:15, Edit by CPR
; Add subnet 13 (EECS pseudo-subnet) to routing tables.
;SRC:<SYS.MONITOR>CHAOS.MAC.321 20-Feb-81 20:56:46, Edit by CPR
; Fix throwing away of packets-over-window to still mark an NVT
; connection as needing input attention at TTCH7 time; also fix
; case where foreign NCP violating protocol (by sending over window)
; would choke the connection entirely (at CHIDAT): now we just
; throw away a packet when it arrives if it isn't within the real
; receive window (ie, the last user packet # + receive window size).
;SRC:<SYS.MONITOR>CHAOS.MAC.316 15-Feb-81 18:05:30, Edit by CPR
; Add new form of OPENF: opening "CHA:.-" will get you a connection
; (immediately) through which you can send RFCs to your heart's
; delight, and see all the ANS, FWD, LOS and CLS packets that come
; wafting back in reply.
;SRC:<SYS.MONITOR>CHAOS.MAC.306  8-Feb-81 18:10:14, Edit by CPR
; Disgusting hack to send over window in SNDPKT after waiting for a
; long time for it to open up; see the "to do" section on how to do
; this right (someday).  This is a temporary solution to avoid
; infinite hangage when a connection's window never opens up.
;SRC:<SYS.MONITOR>CHAOS.MAC.305  6-Feb-81 00:27:51, Edit by CPR
; When opening a listening connection, note that there's some RFC
; matching to do, potentially, to speed up the common case of a
; RFC coming in, not getting matched, and CHARFC starting up a
; server for it, which then listens for that contact name.
;SRC:<SYS.MONITOR>CHAOS.MAC.304  2-Feb-81 21:25:32, Edit by CPR
; Clear out any references to a connection in CHATTW at RELCON time.
;SRC:<SYS.MONITOR>CHAOS.MAC.299 28-Jan-81 16:54:03, Edit by CPR
; Super-paranoid locking in SNDPK0 to catch screw where a packet
; is ack'ed illegally by foreign NCP even before it's first
; transmitted (yes, it happens).
;SRC:<SYS.MONITOR>CHAOS.MAC.295 26-Jan-81 00:13:33, Edit by CPR
; Add variable transmit and receive window sizes for tuning.
;SRC:<SYS.MONITOR>CHAOS.MAC.264 18-Jan-81 12:19:08, Edit by CPR
; Obey the input "window" for the distinguished RFC handler so that
; if it dies, we won't fill up memory with unhandled-RFC packet copies.
;SRC:<SYS.MONITOR>CHAOS.MAC.214 12-Jan-81 12:35:55, Edit by CPR
; CHAXMT now calls RELPKM to get rid of a packet when done, in
; the case where it didn't make it onto any send lists and we didn't
; queue it for anywhere.
; Add extra checking for a hung Chaosnet main background fork (done
; by the local routing fork, which has little reason to hang), and
; for a wedged front-end (CHNPO1, fe quota, staying too low for too
; long).
;SRC:<SYS.MONITOR>CHAOS.MAC.180  9-Jan-81 16:45:33, Edit by CPR
; Make all calls to SNDPK0/SNDPK1 and CHAXMT ask for block/nonblock
; to allow guarantee of never blocking when don't want to;
; add separate background fork for just local routing;
; move actual server startup and shutdown worrying out of monitor
; (opening "CHA:." will let a privileged fork read copies of all
; unhandled RFCs).
;SRC:<SYS.MONITOR>CHAOS.MAC.168  7-Jan-81 19:53:52, Edit by CPR
; Put back calls to RELPKT for checking's sake only (when debugging,
; will complain if not releasable right away); add "reasons" to RELPKM/T
; calls for debugging; add settable RFC timeout period.
;SRC:<SYS.MONITOR>CHAOS.MAC.162 2-JAN-80 15:55:56, Edit by JIS
; Fix bug in error return from CPYPKZ
;SRC:<SYS.MONITOR>CHAOS.MAC.153 22-Dec-80 16:56:46, Edit by CPR
; Always call RELPKM instead of RELPKT since everyone is now careful to
; maintain the link fields of a packet.
;SRC:<SYS.MONITOR>CHAOS.MAC.108 15-Dec-80 14:32:58, Edit by CPR
; Local routing is now done via background fork (to insulate both sides
; of a connection from each other somewhat).
;SRC:<SYS.MONITOR>CHAOS.MAC.104 15-Dec-80 12:40:13, Edit by CPR
; Give up on efficiency attempt for Chaos NVT handling: put it back the
; way it was (too slow to be acceptable).
;SRC:<SYS.MONITOR>CHAOS.MAC.99 14-Dec-80 18:12:08, Edit by CPR
; Attempt at better Chaos NVT has-output handling
; (start-output now sets CF%TTO in an NVT's connection).
;SRC:<SYS.MONITOR>CHAOS.MAC.78  4-Dec-80 14:08:52, Edit by CPR
; Add debugging code for extra caution in dealing with connections, packets.
; Use HOSTS2.BIN for host table now.  General background fork cleanup.
;SRC:<SYS.MONITOR>CHAOS.MAC.61  3-Dec-80 17:00:58, Edit by CPR
; Add local routing for non-ARPA monitors.
;SRC:<SYS.MONITOR>CHAOS.MAC.59  3-Dec-80 16:44:12, Edit by CPR
; Let OKSKDP and NOSKDP be called nestedly; wrap them around local
; routing calls to CHIPKT for safety's sake.
;SRC:<SYS.MONITOR>CHAOS.MAC.58  3-Dec-80 16:25:58, Edit by CPR
; Various changes at EBM's suggestion
;<SYS.MONITOR>CHAOS.MAC.40 18-Oct-80 04:22:00, Edit by Jis
;206 Add in support for chaos-net-user capability
;SRC:<SYS.MONITOR>CHAOS.MAC.28 19-Sep-80 13:31:09, Edit by CPR
; Do Chaos NVT input processing at TTCH7 time.
;<SYS.MONITOR>CHAOS.MAC.22 16-Sep-80 19:50:01, Edit by Jis
; Fix up CPYPKT to have error and nonerror return
;<SYS.MONITOR>CHAOS.MAC.7  8-Aug-80 11:15:17, Edit by Jis
;199 Don't wait for non-open connections to flush output buffers
;<NEW.MONITOR>CHAOS.MAC.5 13-Jul-80 22:59:00, Edit by Jis
;197 Allow user to specify RFC packet contents in OPENF call
;<4.MONITOR>CHAOS.MAC.12  8-Feb-80 15:57:37, Edit by MMCM
;166 CHAOSnet packets over the ARPANET to LLL
;<4.MONITOR>CHAOS.MAC.5,  6-Jan-80 01:46:45, Edit by MT
; Fixed up NVT support
;<4.MONITOR>CHAOS.MAC.1  3-Jan-80 05:53:20, Edit by MMCM
; Merged into release 4 MIT-XX standard system

REPEAT 0,<		-- To do --

-- Doesn't currently support both DECnet and Chaosnet over DN20's
(separate, now, of course); in particular, the DEDMCB usage herein
doesn't let the DECnet one get control.  Will need work in both
areas of Chaos and DECnet support.

-- The various calls to UNLDIS herein are probably not right: they
have NOINTs after them to re-lock up processarily, but this doesn't
re-lock the JFN they're dealing with.  Have to figure how to do that
right in each case.

-- net-independent CVHST, GTHST, etc.  (needs thought)

-- at CHAXMT, we now never send a packet when the -11 is over quota,
and this helps solve the problem of the -11 getting a message when it
has no buffer space and crashing (in the case of 20F) or simply
ignoring the message (and thus no ack ever comes back from the -11),
which means we lose track of the -11 status.  However, this has the
bad side effect that short control messages generated at interrupt
level (eg, STS to stop duplicate retransmissions) mightn't get out when
they should.  A better solution is to reserve some "interrupt level"
space in the -11 as well as normal, process-level packet space, and to
use them separately, with the -11 reporting every second or so on its
space situation to keep the -10 in synch with both types of space.

-- at SNDPKT, we just go ahead and send over-window after a timeout
period, to avoid being locked up there forever (happens alot).  The
real solution, of course, is to re-arrange things so that SNDPKT
queues up packets to be sent when the window opens up, and requests a
BLKF (thus unlocking) from its various callers, with the callers
prepared to restart.

-- when someone attempts to listen for a connection name, that really
shouldn't fail if someone else is already listening unless the first
listener requested exclusive access in the OPENF%.  Otherwise, it is
hard to have "shelf" jobs, several of which can be waiting, listening
for a connection.  This would require reorganizing the RFC-listening
stuff (couldn't use a TBLUK% table any more), but it's worth it.

-- There is still some lossage with performance apropos packet pool
usage: a very active connection can nearly monopolize the interrupt-
level pool, making it hard for other connections to get their work
done; I'm currently playing with maximum window settings to see if
tweaking these can help.

-- There is also lossage in CLSWAT, where, in theory, we should be 
able to just wait for the transmit window to totally open up to ensure
all packets got out safely.  However, this doesn't work.  Figure out
why (it seems to confuse ITS NCPs).

>;REPEAT 0,

	SEARCH PROLOG
IFN ARPAF,<SEARCH IMPPAR>

IFNDEF FRNDLY,<FRDNLY==0>	;FRIENDLY HOST SUPPORT CODE

IFN FRNDLY,<
DEFINE FRIEND (SITE) <
IRP SITE,<
	[ASCIZ /SITE/]
>>>

;;;DEBUGGING/METERING SETTINGS
IFNDEF CHSDBG,<CHSDBG==-1>	;DEBUGGING ON BY DEFAULT
IFNDEF CHSMTR,<CHSMTR==0>	;METERING OFF BY DEFAULT

;;;FLAGS DOUBLE-CHECKEROO
IFE <KLFLG+SMFLG+F3FLG>,<PRINTX ?NO CPU TYPE SPECIFIED>
IFG <KLFLG+SMFLG+F3FLG>-1,<PRINTX ?MORE THAN ONE CPU TYPE SPECIFIED>
IFN ARPAF&SMFLG,<PRINTX ?NO ARPA KS10 SUPPORT (YET)>
IFN <KLFLG!SMFLG>&TNXFLG,<PRINTX ?NO TENEX KL OR KS SUPPORT>
IFN DTEFLG&SMFLG,<PRINTX ?NO KS DTE SUPPORT>
IFN T20FLG&F3FLG,<PRINTX ?NO F2 TOPS-20 SUPPORT>
IFN DTEFLG,<			;CHECK ON DTE CONFIGURATION
 IFL NETDTE,<PRINTX ?NETDTE MUST BE 0-3>
 IFGE NETDTE-4,<PRINTX ?NETDTE MUST BE 0-3>
>;IFN DTEFLG,

;+++IFN DTEFLG&<1-NETDTE>,<SEARCH PROKL> ;IF GOING THROUGH PRIMARY DTE
IFN T20FLG,<
	TTITLE CHAOS
IFN KLFLG,<SEARCH PROKL>	;GET DTE DEFINITIONS
IFN SMFLG,<SEARCH PROKS>	;GET CHAOS UNIBUS ADAPTER DEFINITIONS

	EXTN <MAXCON,CHRFMX,CHST2P,TMSCHR>

DEFINE CHABUG (X,Y) <BUG(X,<Y>)> ;COMPATIBLE BUG MACRO FOR BOTH SYSTEMS
OPDEF XCTUM [XCTU]		;DATA ONLY IN PREVIOUS CONTEXT

>;IFN T20FLG
IFN TNXFLG,<
	SEARCH STENEX,MONSYM,MACSYM
	TITLE CHAOS

	EXTN <ASGJFR,ASGPAG,ASGRES,ASGSWP,BLTMU,BLTUM>
	EXTN <CAPMSK,FILBCT,FILBFI,FILBFO,FILCOD,FKINT,FORKX,INSKED>
	EXTN <MRETN,PBYTSZ,PSIRQ,RELFRE,RELPAG,RELRES,RELSWP,SK2RET,TODCLK>
	EXTN <UNLCKF,.RESNP,.RESP1,.RESP3,LCKTST>
	EXTN <MRETNE,RELJFN,NVTPTR,TTNETW,TTOCT,TTECT,NVTCHS>
>;IFN TNXFLG
	
	SUBTTL DEFINITIONS

DEFINE DEBUG <IFN CHSDBG>
DEFINE NODEB <IFE CHSDBG>

;EXTERNAL REFERENCES
	EXTN <CHPMXC,CHPMXT,CHPMXW> ;CHAOS PACKET LIMITS
	EXTN <MXRWIN,MXTWIN,NMWIND,CHAON,CHAONL,CHAONC,CHAFLG,CHAPFG>
	EXTN <CHANPO,CHATIM,CHATM1,CHATM2,CHCNLK,CHNPF,CHNPKI,CHNSNS,CHNSTS,CHAFHN>
	EXTN <CHNRTR,CHNPOL,CHQRFC,CHRFLK,RFCTAB,CHACON,MYCHAD>
	EXTN <CTMSTM,CHNGTM,CHPIOF,CHPIDF,CHATMA,CHAT1A,CHNPO1>
	EXTN <CHKCVT,ASNCVT,DETCVT,CHANEG,CHATCS,CVTUPI,CHANPD>
	EXTN <CVTPTR,CHNNRS>
	EXTN <CHOSTB,CHOSTP,CHANET> ;TABLE, HAVE-TABLE, # PAGES, NET #
	EXTN <CHANAO>		;OFFSET IN CHOSTB OF CHAOS ADDRESS TABLE
	EXTN <CHQLCL,CHQRFP>
	EXTN <CHATTW,CHAPRO,MYHNAM,MYHTIM>
	EXTN <CHRFHC>
	EXTN <CHABFT,CHNPOW,CHNPWT,CHALRW,CHABFW>
	EXTN <CHANOL>
DEBUG,<	EXTN <RESFRP,RESFRZ> >	;FOR DEBUGGING ONLY: FREE POOL BEGINNING AND END
IFN DTEFLG,<EXTN <CHASBS,CHASBL>>
IFN DTEFLG,<EXTN <GATINC>>
IFN SMFLG,<
	EXTN <CHAACS,CHAIPL,CHAIPS,CHAXPC,CHATXQ>
	EXTN <NPKSIN,NPKSOU,NPKSAB,NPKSLS,NPKSER,NPKSRE,NPKSBB,NPKSIG>
>
IFN ARPAF,<			;166
	EXTN <CHARPQ>
	EXTN <CHATPB>
>;IFN ARPAF,
IFE ARPAF,<
	EXTN <NVTINI>
>;IFE ARPAF,

DEBUG,<IF1,< PRINTX Debugging support >>
DEFINE CHKCON <			;;;CHECK THE CONNECTION REF'ED BY CONN IF DEBUGGING
DEBUG,<	CALL CHKCNB >
>
DEFINE TCHKCN <			;;;CHECK THE CONN REF IN T1; FOR USE IN SCHED TESTS
DEBUG,<
	PUSH P,CONN
	HRRZI CONN,(T1)
	CHKCON
	POP P,CONN
>>
DEFINE CHKPKT <			;;;CHECK THE PACKET REF'ED BY PKT IF DEBUGGING
DEBUG,<	CALL CHKPKB >
>
DEFINE TCHKPK <			;;;CHECK PACKET REF IN T1; FOR USE IN SCHED TESTS
DEBUG,<	PUSH P,PKT
	HRRZI PKT,(T1)
	CHKPKT
	POP P,PKT
>>
DEFINE PKTPTH (PI) <		;;;NOTE PACKET HAS GONE BY THIS POINT IN ITS PATH
DEBUG,<	MOVE CX,PI
	CALL PKTPTS
>>

DEFINE CONPTH (PI) <		;;;NOTE CONNECTION HAS BEEN BY THIS POINT
DEBUG,<	MOVE CX,PI
	CALL CONPTS
>>

DEFINE RCALL (RTN,R) <		;;;CALL A ROUTINE WITH A 'REASON' WHEN DEBUGGING
DEBUG,<	MOVX CX,R >		;GET THE REASON CODE IN CX FOR THE CALL
	CALL RTN
>

DEFINE METER <IFN CHSMTR>
DEFINE NOMET <IFE CHSMTR>
METER,<IF1,< PRINTX Metering support >>

IFN DTEFLG,<
CHADTE==NETDTE			;USE THE NETWORK -11'S DTE IF THERE IS ONE
IFE CHADTE,<EXTN <CHBGPK>>	;THROUGH PRIMARY DTE, NEED ASSEMBLY AREA
IFN CHADTE,<EXTN <NSPQER>>	;SECONDARY DTE: INVALID PROTOCOL CALL
>;IFN DTEFLG
IFE DTEFLG,<CHADTE==0>

;PI CHANNEL ASSIGNMENT
CHACHN==-1			;BY DEFAULT, NO PI CHANNEL ASSIGNMENT
IFN T20FLG,<			;BUT UNDER TWENEX, ONE OF:
IFN KLFLG,<CHACHN==DLSCHN>	; KL: CHAOS HANDLING VIA DTE'S (DLS LEVEL)
IFN SMFLG,<CHACHN==UNBCHN&7>	; KS: VIA UNIBUS ADAPTER'S LEVEL
>;IFN T20FLG,

;LOCAL AC'S
DEFAC(CONN,Q1)
DEFAC(PKT,Q3)

;FILESYS AC'S
IFN T20FLG,<
DEFAC(STS,P1)
DEFAC(JFN,P2)
DEFAC(DEV,P4)
DEFAC(F1,P5)
>

;FILESYSTEM STORAGE USAGE
FILCON==FILOFN			;LOS ERROR STRING ADDR,,CONNECTION BLOCK
;FILBFO==FILMS1			;OUTPUT BUFFER POINTER
;FILBFI==FILMS2			;INPUT BUFFER POINTER
;FILBCT==FILFDB			;BYTE COUNTS OUTPUT,,INPUT
FILOBF==FILCOD			;OUTPUT BUFFER PACKET ADDR

IF1,<
;PACKET HEADER FORMAT (DESCRIBED IN REVERSE FORMAT SINCE IT GROWS BACKWARDS)
DEFINE PHE (E,L) <		;;;PACKET HEADER ENTRY
   IFB <L>,<PKTHLN==PKTHLN+1>
   IFNB<L>,<PKTHLN==PKTHLN+<L>>
	E==-PKTHLN
>
PKTHLN==0			;INITIALIZE HEADER LENGTH

IFN CHADTE!CHDR11,<
IFN CHADTE,<
 PHE PKTTYP			;NEED THIS TYPE FOR TO -11 PTCL
>;IFN CHADTE
IFN CHDR11,<
 PHE PKTCDR			;SIZE (16-BIT BYTES),,CDR FOR DR11 MICROCODE
>;IFN CHDR11
 IFN ARPAF,<			;UNLESS DOING ARPA ROUTING, WHEN NEED
  PHE PKTIMP,3			; 4 WORDS FOR ARPANET HEADER, SHARING ROOM
 >;IFN ARPAF			; WITH TO -11 HEADER
>;IFN CHADTE!CHDR11
DEBUG,<
 PHE PKTMAG			;MAGIC WORD FOR EXTRA CHECKING
 PHE PKTHSP			;PACKET HISTORY BYTE PTR (MUST PRECEDE PKTHST!)
 PHE PKTHST,3			;PACKET HISTORY: 6-BIT PATH NUMBERS
 PHE PKTHDW			;COPY OF ORIGINAL PACKET ASGRES HEADER
>;DEBUG
PHE PKTTIM			;TIME OF LAST ACTIVITY WITH THIS PACKET
IFN SMFLG,<PHE PKTTLK>		;RE-XMISSION COUNT,,LINK TO NEXT PKT TO BE XMITTED
PHE PKTLNK			;LINK WORD: <XMIT ACTIVE IF 1, NOTHING IF -1,
				; ELSE LINK TO NEXT ON LOCAL-Q LIST>,,
				; <LINK TO NEXT IF ON A LIST (OR NIL), ELSE -1>
PURGE PHE
>;IF1

;PACKET-HANDLING MACRO: ON KS10, WE TRY TO AVOID FREEING AND THEN
;IMMEDIATELY RE-ALLOCATING PACKETS, SO USE GETPKT INSTEAD OF CALLING
;CPYPKI DIRECTLY TO COPY AN INPUT PACKET.  IF SIZE ARG IS NOT BLANK,
;THEN T3 HAS NUMBER OF BYTES NEEDED.
;RETURNS +1 ON FAILURE.

DEFINE GETPKT(SIZE) <
IFN SMFLG,<
IFNB <SIZE>,<
	CALL CPYPKI
>>
IFE SMFLG,<
IFNB <SIZE>,<STOR T3,CPKNB,(PKT)>
	CALL CPYPKT
>>

;MISCELLANEOUS
IFN .CSCLS,<PRINTX ?Some code assumes .CSCLS==0>

;TIME CONSTANTS
CHTRFW==^D<30*1000>		;DEFAULT MS TO WAIT FOR RFC ANSWER

;OTHER PARAMETERS
IFN SMFLG,<
CHARTC==3			;RETRANSMIT THIS MANY TIMES IF XMIT ABORTS
>
;;STATUS ANS BYTE COUNT
IFN SMFLG,<CHSTBC==^D32+2+2+^D<8*4>> ;KS REPORTS ALL 8 REAL PACKET COUNTERS
IFE SMFLG,<CHSTBC==^D32+2+2+^D<2*4>> ;OTHERS REPORT ONLY IN AND OUT COUNTERS

	SUBTTL INITIALIZATION & PTCL VECTORS

;INITIALIZE NETWORK STUFF
	SWAPCD			;OK TO BE SWAPPABLE

CHAINI::SETOM CHCNLK		;UNLOCK CONNECTION LOCK
	SETOM CHRFLK		;AND RFC TABLE LOCK
	SETZM CHQRFC		;EMPTY OUT INCOMING RFC QUEUE
	SETOM CHATTW		;EMPTY OUT NVT-CONNECTION-WITH-DATA Q
	MOVE 1,[CHATTW,,CHATTW+1]
	BLT 1,CHATTW+NTTCVT	;CLEAR OUT WHOLE TABLE
	SETOM CHPIDF		;SET UP PI LOCKING VARIABLES
	SETZM CHAPRO		;206 DEFAULT IS NO NET PROTECTION
	SETZM CHOSTP		;NO HOST TABLE BUILT YET
	SETZM MYHNAM		;I DON'T HAVE A NAME YET, EITHER
	SETOM MYCHAD		;INDICATE WE DON'T KNOW OUR HARDWARE ADDRESS YET
	SETZM CHQLCL		;CLEAR OUT LOCAL-ROUTING QUEUE
	MOVEI T1,^D488		;LARGEST NUMBER OF BYTES PER PACKET
	MOVEM T1,CHPMXC		;SET IT FOR EVERYONE TO FIND
IFN DTEFLG,< IFE CHADTE,<	;BUT THIS IS LARGEST WE CAN TRANSMIT THROUGH
	MOVEI T1,300		; PRIMARY FRONT END
>>;IFE CHADTE & IFN DTEFLG
	MOVEM T1,CHPMXT		;LARGEST TRANSMITTABLE PACKET SIZE
	ADDI T1,3		;CALCULATE MAXIMUM NUMBER OF WORDS THIS
	LSH T1,-2		; IMPLIES
	MOVEM T1,CHPMXW
	MOVEI T1,CHRFMX		;MAXIMUM NUMBER OF RFC'S ALLOWED
	MOVEM T1,RFCTAB		;INIT TABLE OF CONNECTION NAMES FOR THEM
	MOVX T1,5		;NOMINAL WINDOW SIZE (VARIABLE FOR TWIDDLING)
	MOVEM T1,NMWIND
	MOVX T1,^D10		;MAXIMUM WINDOW SIZES
	MOVEM T1,MXRWIN		;(KEEP THIS REASONABLE SO WE DON'T LET ONE
	MOVX T1,^D15		; CONNECTION EAT ALL THE INTERRUPT-LEVEL POOL)
	MOVEM T1,MXTWIN
IFE ARPAF,<
	CALL NVTINI		;CLEAR OUT NVT TABLES IF ARPANET WON'T DO IT
>
	MOVSI T1,(CR%CAP)	;CREATE LOCAL-ROUTING FORK
	SETZ T2,
	CFORK			;MAKE A JOB0 FORK
	 CHABUG(CHLFRK)
	MOVEI T2,CHALRF		;START IT UP
	MSFRK
	SETZM CHAFLG		;CLEAR BACKGROUND FORK REQUEST FLAGS
	MOVSI T1,(CR%CAP)	;GIVE IT ALL OUR CAPABILITIES
	SETZ T2,
	CFORK			;MAKE A JOB0 FORK
	 CHABUG(CHIFRK)
	MOVEI T2,CHSFRK		;START IN MONITOR MODE
	MSFRK
	JRST CHARLD		;AND HANDLE LIKE RELOAD

	RESCD			;THIS CALLED FROM DTE INT LEVEL
IFN DTEFLG,<
IFN CHADTE,<
CHADTV::CHAPKT			;DATA IS A PACKET
	NSPQER			;SHOULD NEVER REQUEST STATUS
	CHSSTS			;HERE IS STATUS
	CHADON			;ACK OF PACKET SENT
>;IFN CHADTE
IFE CHADTE,<
;DTE PTCL VECTOR FOR CHAOS INTERFACE
CHADTV::CHAHSD			;STRING DATA (PACKET)
	CHADON			;ACK
	CHSSTS			;STATUS FROM -11
	0			;SET LINE ALLOCATION
	0			;SYSERR
	CHARLD			;-11 RELOAD ACTION
>;IFE CHADTE
>;IFN DTEFLG

	SWAPCD			;OK TO BE SWAPPABLE

;CHA: DEVICE DTB
CHADTB::DTBDSP (CHADIR)		;DIRECTORY LOOKUP
	DTBDSP (CHANAM)		;NAME LOOKUP
	DTBDSP (CHAEXT)		;EXTENSION LOOKUP
	DTBDSP (CHAVER)		;VERSION LOOKUP
	DTBBAD (DESX9)		;NO PROTECTION
	DTBBAD (DESX9)		;NOR ACCOUNT
	DTBBAD (DESX9)		;NOR STATUS
	DTBDSP (CHAOPN)		;OPENF
	DTBDSP (CHASQI)		;SEQUENTIAL INPUT
	DTBDSP (CHASQO)		;SEQUENTIAL OUTPUT
	DTBDSP (CHACLZ)		;CLOSF
 REPEAT 7,<
	DTBBAD (DESX9)>		;RANDOM ILLEGAL FUNCTIONS
	DTBDSP (CHAMTO)		;MTOPR
	DTBDSP (CHASTS)		;GET STATUS
	DTBBAD (DESX9)		;SET STATUS
IFN T20FLG,<
	DTBDSP (CHASQR)		;SOUTR
	DTBDSP (RFTADN)		;NO READ TOD
	DTBDSP (SFTADN)		;NOR SET TOD
	DTBDSP (CHAINP)		;SET FOR INPUT
	DTBDSP (CHAOUP)		;SET FOR OUTPUT
	DTBBAD (GJFX49)		;ATTRIBUTES
>;IFN T20FLG

	SUBTTL GTJFN AND OPENF DEVICE ROUTINES

;DIRECTORY LOOKUP
CHADIR:	TQNE <STEPF>		;STEPPING DIRECTORIES NOT ALLOWED
	 RETBAD (GJFX17)
	NOINT
	JRST SK2RET		;SKIP RETURN WITH INTERRUPTS OFF

;VERSION LOOKUP
CHAVER:	JUMPGE T1,OKRET
	TQNE <STEPF>		;TRYING TO STEP?
	 RETBAD (GJFX18,<OKINT>) ;YES, ERROR
OKRET:	TQNN <UNLKF>		;OK TO UNLOCK?
	 OKINT			;YES, TURN BACK ON INTERRUPTS
	JRST SK2RET

;NAME LOOKUP
CHANAM:	JUMPE T1,[RETBAD (GJFX18,<OKINT>)] ;WILDCARDS NOT ALLOWED
	CALL HSTNAM		;GET HOSTNAME
	 RETBAD (GJFX18,<OKINT>) ;NO GOOD
	JRST OKRET

;EXTENSION LOOKUP
CHAEXT:	JUMPE T1,[RETBAD (GJFX18,<OKINT>)] ;WILDCARDS NOT ALLOWED
	JRST OKRET		;ELSE LOOKS ALRIGHT

;CHA: DEVICE OPENF
CHAOPN:	SKIPL MYCHAD		;DO I KNOW MY HARDWARE ADDRESS YET?
	 SKIPN CHAON		;IS THE NETWORK IN FACT THERE YET?
	 RETBAD (OPNX19)	;NO OR NO
	SKIPE CHAPRO		;IS NET PROTECTION ON?
	 JRST [ MOVE T1,CAPMSK	;YES, CHECK POTENTIAL CAPAS
		TRNE T1,SC%WHL!SC%OPR!SC%CHA ;DO WE HAVE REQUIRED CAPAS?
		 JRST .+1	;YEP, GO ON...
		RETBAD(CHAOX5)]	;NO, GIVE ERROR
	TQZE <RNDF>		;APPEND
	 TQO <WRTF>		;BECOMES WRITE
	TQNN <READF,WRTF>	;SOME SORT OF ACCESS THERE?
	 RETBAD (OPNX14)	;NO, BAD OPENF
	LDB PKT,PBYTSZ		;GET BYTE SIZE REQUESTED
	CAIE PKT,10		;FOR NOW ONLY ALLOW 8-BIT BYTE CONNECTIONS
	 CAIN PKT,7		;OR ASCII FOR SIMPLICITY
	 CAIA
	 RETBAD (SFBSX2)	;ILLEGAL BYTE SIZE
	LOCK CHCNLK,<CALL LCKTST> ;LOCK UP THE CONNECTION LOCK
	MOVSI CONN,-MAXCON	;MAXIMUM NUMBER OF NETWORK CONNECTIONS ALLOWED
	 SKIPGE CHACON(CONN)	;THIS CONNECTION IN USE?
	  AOBJN CONN,.-1	;YES, KEEP LOOKING
	JUMPGE CONN,CHOPX4	;INSUFFICIENT RESOURCES
	CALL ASGPAG		;GET A FREE PAGE  +++SHOULD THIS CALL ASGPGS???
	 JRST CHOPX4		;FAILED, UNLOCK LOCK AND RETURN
	HRRM T1,FILWND(JFN)	;SAVE IT FOR BUFFER
	MOVE T1,[.RESP1,,CONSIZ] ;WHEN DEBUGGING, NEED PAGE-FAULT-FREENESS
	MOVEI T2,.RESNP		;FROM THE NETWORK POOL
	CALL ASGRES		;ASSIGN ZEROED RESIDENT STORAGE FOR IT
	 JRST CHOPX3		;FAILED, UNLOCK LOCK AND RETURN
	HLRZ T2,CHACON(CONN)	;GET UNIQUIZER
	ANDI T2,400000-1_12	;JUST UNIQIZER PART
	CAIN T2,400000-1_12	;MAXIMUM?
	 SETZ T2,		;YES, WRAP AROUND
	ADDI T2,1_12(CONN)	;INCREMENT UNIQUIZER AND ADD IN LOCAL IDX
	STOR T2,CHAIDX,(T1)	;STORE IN CONNECTION BLOCK
	HRLI T1,400000(T2)	;SET CONNECTION IN USE
	MOVEM T1,CHACON(CONN)	;SAVE THIS INDEX THEN
	UNLOCK CHCNLK		;DONE WITH CONNECTION LOCK
	HRRZ CONN,T1		;AND KEEP CONVENIENT FOR US LATER
DEBUG,<	MOVE T2,[CHSMGV]	;SET IN MAGIC VALUE IF DEBUGGING
	XORI T2,(CONN)		;MAKE IT KEYED TO CONNECTION IN QUESTION
	MOVEM T2,CONMAG(CONN)
	MOVEI T1,CONHST(CONN)	;BUILD HISTORY BYTE REF
	HRLI T1,331100
	MOVEM T1,CONHSP(CONN)
	CONPTH [1]		;NOTE GENESIS FOR CONNECTIONS
>;DEBUG
	HRRZM CONN,FILCON(JFN)	;SAVE BLOCK WITH JFN
	STOR PKT,CHABSZ,(CONN)	;STORE BYTE SIZE AWAY
	MOVE T1,MYCHAD		;PUT IN LOCAL HOST ADDRESS
	STOR T1,CHALCH,(CONN)
	MOVE T1,FORKX		;SAVE OWNING FORK
	STOR T1,CHAFRK,(CONN)
	SETONE CHAICN,(CONN)	;NO CHANNEL TO INTERRUPT YET
	SETONE CHAOCN,(CONN)
	MOVE T1,NMWIND		;NOMINAL WINDOW SIZE TO START
	HRLM T1,CHAWIN(CONN)	;RECEIVE WINDOW SIZE
	MOVX T1,CHTRFW		;DEFAULT RFC WAIT TIMEOUT PERIOD
	STOR T1,CHATRF,(CONN)
	HLRZ T1,FILNEN(JFN)	;GET POINTER TO NAME STRING
	CALL HSTNAM		;LOOKUP HOST NAME
	 JRST [	MOVEI T1,GJFX18
		JRST CHOPX1 ]
	JUMPE T1,CHOPIN		;IF NULL, WANTS TO LISTEN

;WANTS TO INITIATE AN RFC TO SOMEPLACE
	STOR T1,CHAHST,(CONN)	;SAVE REMOTE HOST DESIRED
	MOVE T1,TODCLK		;TIME OF LAST ACTIVITY
	MOVEM T1,CHAITM(CONN)
	MOVEI T1,.CSRFS		;RFC SENT STATE
	HRRM T1,CHASTA(CONN)
	MOVEI Q2,.CORFC		;REQUEST FOR CONNECTION
	RCALL ASGPKC,30		;ALLOCATE A PACKET FOR THIS CONNECTION
	 JRST [	MOVEI T1,MONX01
		JRST CHOPX1 ]
	HRRZ T2,FILNEN(JFN)
	AOJ T2,
	MOVE T1,T2
	HRLI T1,(<POINT 7,>)	;SAVE CONTACT NAME POINTER
	ILDB T1,T1		;GET FIRST BYTE OF CONTACT NAME
	JUMPE T1,[CALL CHOPI3	;IF ZERO (NULL CONTACT NAME)
		   JRST [MOVEI T1,CHAOX3 ;FILL IN RFC FROM USER AC3
			 JRST CHOPX1] ;FAILED
		  JRST CHOPI0]	;GO SEND IT
	CALL PKTSTR		;FILL IN PACKET DATA FROM STRING AND SEND IT
CHOPI0:	SETZ T1,
	CALL SNDPK0		;SEND THIS OFF, BLOCKING IS OK
	HRRI T1,RFCST		;RFC SENT HANDLING TEST
CHOPI1:	LOAD T2,IOMODE		;GET DATA MODE
	CAIE T2,6		;6 OR 7 IS IMMEDIATE RETURN
	CAIN T2,7
	 RETSKP
	CONPTH [2]		;NOTE WE'VE BEEN THIS ROUTE
	HRLI T1,(CONN)		;CONNECTION INDEX
	CALL CHOWAT		;WAIT FOR OPEN
	HRRZ T1,CHASTA(CONN)	;GET CONNECTION STATE NOW
	JUMPE T1,[HLRZ T1,CHAIBF(CONN) ;CLOSED, SEE IF THERE IS ANY DATA
		  JUMPE T1,CHOPI2
		  LOAD T1,CPKOP,(T1) ;IS IT A DATA TYPE PACKET
		  CAIE T1,.COANS ;ANS IS ACCEPTABLE DATA FOR THIS
		   CAIL T1,.CODAT
		   RETSKP
		   JRST CHOPI2]	;NO, MUST BE LOSING
	CAIE T1,.CSRFC
	 CAIN T1,.CSOPN		;OPENED OK?
	 RETSKP			;YES, RETURN OK
	CAIE T1,.CSLOS		;LOS RECEIVED FROM IT?
	 SKIPA T1,[OPNX20]	;NO, MUST HAVE TIMED-OUT AND GONE INC
	 CALL GETLOS		;YES, SET UP ERROR MESSAGE FROM THAT
CHOPX1:	PUSH P,T1		;SAVE ERROR CODE
	HRRZ T1,FILWND(JFN)
	CALL RELPAG		;GET RID OF INPUT WINDOW PAGE
	CALL RELCON		;RELEASE THE STORAGE BLOCK
	POP P,T1
	RET			;ERROR RETURN

;WAIT FOR CONNECTION TO OPEN, MDISMS ARG IN 1
IFN T20FLG,<
CHOWAT:	PUSH P,T1		;SAVE MDISMS ARGUMENT
	MOVEI T1,(CONN)		;SETUP FOR CONNECTION TO GET DEALLOCATED IF USER ^C'S
	MOVEI T2,STKCD5
	CALL JSBSTK
	POP P,T1		;GET BACK MDISMS ARG
	CALL UNLDIS		;WAIT FOR THAT STATE TO OCCUR
	NOINT			;PROTECT OURSELVES
	MOVEI T1,(CONN)		;FLUSH DEALLOCATION RECORD
	MOVEI T2,STKCD5
	CALLRET JSFRMV		;REMOVE FROM JSB STACK NOW THAT NOINT AGAIN
>;IFN T20FLG
IFN TNXFLG,<
CHOWAT:	MDISMS			;WAIT FOR IT
	RET			;AND RETURN
>;IFN TNXFLG

CHOPI2:	MOVEI T1,OPNX21
	JRST CHOPX1

;HERE TO FILL IN RFC FROM DATA REF'ED BY USER AC3
CHOPI3:	SAVEAC <T1,T2,T3>	;NOT SURE THIS IS NECESSARY
	XCTUM [HLRZ T1,3]	;GET USER SUPPLIED BYTE COUNT
	CAMLE T1,CHPMXT		;CURRENT BYTE COUNT LIMIT
	 RET			;PUNT IF TOO MUCH DATA
	PUSH P,T1		;SAVE BYTE COUNT FOR LATER
	ADDI T1,3		;ROUND APPROPRIATELY
	LSH T1,-2		;199 CONVERT TO WORD COUNT
	XCTUM [HRRZ T2,3]	;USER ADDRESS TO COPY FROM
	XMOVEI T3,CHPKDT(PKT)	;POINTER TO DATA AREA OF PACKET
	CALL BLTUM		;COPY AWAY...
	POP P,T1		;RECLAIM BYTE COUNT
	STOR T1,CPKNB,(PKT)	;STORE IN PACKET HEADER
	RETSKP			;WON

CHOPX3:	HRRZ T1,FILWND(JFN)
	CALL RELPAG		;GET RID OF INPUT WINDOW PAGE
CHOPX4:	UNLOCK CHCNLK		;UNLOCK CONNECTION LOCK
	RETBAD (MONX01)		;UNSUFFICIENT RESOURCES

	RESCD
RFCST:	TCHKCN			;IF DEBUGGING, CHECK CONNECTION
	HRRZ T2,CHASTA(T1)
	CAIE T2,.CSRFS		;STILL RFC SENT STATE?
	 JRST 1(4)		;NO, RETURN
IFN T20FLG,<
	JRST 0(4)
>;IFN T20FLG
IFN TNXFLG,<
RFCST1:	MOVE T3,FKINT(FX)	;LOOK FOR DEFERRED INTERRUPTS
	TLNN T3,(1B1)
	 JRST 0(4)		;NONE, CONTINUE BLOCKED
	MOVEI T2,.CSINC		;WAS ONE, TIME CONNECTION OUT
	HRRM T2,CHASTA(T1)
	JRST 1(T4)
>;IFN TNXFLG
	SWAPCD

;HERE TO LISTEN FOR A CONNECTION (CHA:.FOO), TO BECOME THE DISTINGUISHED RFC
;HANDLER (CHA:.) OR TO SET UP A RFC/ANS PERMANENT CONNECTION (CHA:.-)
CHOPIN:	HRRZ T2,FILNEN(JFN)	;GET CONNECTION NAME TO LISTEN FOR
	HRLI T2,(<POINT 7,0,34>)
	MOVE T1,T2		;NOW, SEE IF THIS
	ILDB T3,T1		; NAME IS NULL (WANTS TO LISTEN FOR ALL RFCS)
	JUMPE T3,[MOVX T2,SC%WHL!SC%OPR!SC%NWZ!SC%NAS ;YES, CHECK CAPAS
		MOVX T1,NTWZX1	;ERROR CODE IF NOT PRIVILEGED
		TDNN T2,CAPMSK	; (POTENTIAL IS GOOD ENOUGH)
		 JRST CHOPX1	;NO, GO CLEAN UP AND RETURN ERROR
		NOSKED		;ACQUIRE THIS CAREFULLY
		MOVX T1,OPNX9	;INVALID SIMULTANEOUS ACCESS IF ALREADY A LISTENER
		SKIPE CHRFHC	;SOMEONE ALREADY THERE?
		 JRST [	OKSKED	;YES, UNLOCK
			JRST CHOPX1 ] ; AND GIVE ERROR
		MOVEM CONN,CHRFHC ;NO, WE'RE NOW THE FELLOW IN COMMAND
		OKSKED
		MOVX T1,^D20	;THIS SHOULD BE ENOUGH INPUT WINDOW FOR IT,
		HRLM T1,CHAWIN(CONN) ; ASSUMING IT'S FAIRLY RESPONSIVE
		MOVX T1,.CSLSN	;PRETEND WE'RE LISTENING, BUT
		HRRM T1,CHASTA(CONN)
		RETSKP ]	; RETURN SUCCESS IMMEDIATELY
	CAIN T3,"-"		;PERHAPS WANTS TO SET UP A PERMANENT RFC-SENT
	 JRST [	ILDB T3,T1	; CONNECTION? ("CHA:.-")
		JUMPN T3,.+1	;NOPE
		MOVX T1,.CSPRF	;YES, SAY SO AND
		HRRM T1,CHASTA(CONN) ; SUCCEED
		RETSKP ]	; IMMEDIATELY
	CALL ADDLSN		;ADD NEW CONNECTION NAME
	 JRST CHOPX1		;FAILED: ERROR CODE IN T1 ALREADY
	MOVX T1,CH%RFC		;TELL THE BACKGROUND FORK TO CHECK AGAIN
	IORM T1,CHAFLG		; FOR POTENTIAL RFC MATCHES
	MOVX T1,.CSLSN		;LISTENING STATE
	HRRM T1,CHASTA(CONN)
	HRRI T1,RFCRT		;WAIT FOR AN INCOMING RFC
	JRST CHOPI1

	RESCD
RFCRT:	TCHKCN			;IF DEBUGGING, CHECK CONNECTION
	HRRZ T2,CHASTA(T1)
	CAIE T2,.CSLSN		;STILL LISTENING?
	 JRST 1(4)		;NO, RETURN
IFN T20FLG,<JRST 0(4)>
IFN TNXFLG,<JRST RFCST1>	;CHECK FOR USER ^C'ING AS WELL
	SWAPCD

;ADD STRING REF'ED BY T2 TO THE LISTENING RFC LIST; RETURN NONSKIP WITH
;T1/ ERROR CODE IF THERE ARE PROBLEMS.
ADDLSN:	STKVAR <ADLSAD,ADLSCT>
	MOVEM T2,ADLSAD		;SAVE STRING
	LOCK CHRFLK,<CALL LCKTST> ;GET THE RFC TABLE LOCK
	MOVEI T1,RFCTAB		;RFC LISTENING TABLE
	TBLUK
	 ERJMP ADDLSR		;SOME PROBLEM, LUMP UNDER 'NO RESOURCES'
	TXNE T2,TL%EXM		;EXACTLY MATCHED SOMETHING ALREADY THERE
	 JRST ADDLSF		; SO RETURN ERROR
	MOVE T2,ADLSAD		;GET BACK STRING POINTER
	SETZ T3,
	 ILDB T1,T2
	 JUMPE T1,.+2
	 AOJA T3,.-2		;COMPUTE LENGTH
	MOVEM T3,ADLSCT		;SAVE COUNT
	AOJ T3,			;BUMP UP FOR ENDING NULL
	MOVEI T1,5+4(T3)	; PLUS ONE WORD FOR HEADER
	IDIVI T1,5		;GET DESIRED LENGTH
	CALL ASGSWP		;GET SOME SWAPPABLE SPACE
	 JRST ADDLSR		;FAILED, RESOURCE PROBLEM
	MOVE T3,ADLSCT		;RECOVER COUNT
	MOVSI T2,1(T1)		;BUILD STRING REF IN LH FOR TBLUK FORMAT
	EXCH T2,ADLSAD		;SAVE ADDRESS, GET ORIGINAL STRING PTR
	HRLI T1,(<POINT 7,0,34>)
	 ILDB PKT,T2
	 IDPB PKT,T1
	 SOJG T3,.-2
	SETZ PKT,
	IDPB PKT,T1		;TIE OFF TO MAKE ASCIZ
	MOVE T2,ADLSAD		;GET BACK CONTACT NAME REF
	HRRI T2,(CONN)		;BUILD CONTACT REF,,CONNECTION TO HANDLE THIS RFC
	MOVEI T1,RFCTAB		;PUT THIS NEW ENTRY INTO TABLE
	TBADD
	 ERJMP ADDLSR		;IF TABLE FULL, FAIL
	UNLOCK CHRFLK
	RETSKP

ADDLSR:	SKIPA T1,[MONX01]	;RESOURCE PROBLEM HERE
ADDLSF:	 MOVEI T1,OPNX9		;NAME ALREADY EXISTS: INVALID SIMULTANEOUS ACCESS
	UNLOCK CHRFLK		;FAILED SOMEHOW: UNLOCK
	RET			; AND INDICATE FAILURE

;CHAOS NET CLOSF
CHACLZ:	HRRZ CONN,FILCON(JFN)	;GET CONNECTION INDEX
	CHKCON			;VALIDATE IT IF DEBUGGING
	HRRZ Q2,CHASTA(CONN)	;AND STATE
	CAIN Q2,.CSRFC		;RFC RECEIVED?
	 JRST CHACL2		;YES, STILL NEED TO SEND A CLS FOR IT
	CAIE Q2,.CSOPN		;STILL OPEN?
	 JRST CHACL3		;NO, SKIP SENDING ANYTHING
	CALL CHARTR		;YES, TRY TO RETRANSMIT WHATEVER NEEDS IT
	CALL FLSOUT		;SEND OFF LAST PACKET
	 TQZ <ERRF>		;IGNORE ERROR
	UMOVE T1,1
	TDNN T1,[1,,400000]	;IF NOT CALLED FROM CLOSF
	 TLNN T1,(CO%WCL)	;OR NOT REQUESTED
	 JRST CHACL2		;DONT WAIT FOR IT TO GET DONE
	MOVSI T1,(CONN)
	HRRI T1,CLSWAT		;WAIT FOR ALL DATA TO GET SENT OUT
IFN T20FLG,<
	CALL UNLDIS
	NOINT
>;IFN T20FLG
IFN TNXFLG,<
	MDISMS
>;IFN TNXFLG
CHACL2:	MOVEI Q2,.COCLS
	RCALL ASGPK0,31		;GET A PACKET FOR CONNECTION WITHOUT DATA
	 JRST CHACL3
	SETZ T1,
	CALL SNDPK0		;SEND IT OFF TOO, BLOCKING OK
CHACL3:	CALL RELCON		;RELEASE STORAGE ASSOCIATED WITH THIS CONNECTION
	AOS (P)			;WILL SKIP RETURN
CHACL4:	SKIPE PKT,FILOBF(JFN)	;HAVE AN OUTPUT BUFFER?
	 JRST [	RCALL RELPKT,3	;YES, FREE IT TOO
		JRST .+1 ]
	HRRZ T1,FILWND(JFN)
	SKIPE T1
	 CALL RELPAG
	SETZM FILBFO(JFN)
	SETZM FILBFI(JFN)
	HLRZ T2,FILCON(JFN)	;LOS ERROR MESSAGE STILL?
	JUMPE T2,R		;NO, DONE
	HRRZS (T2)
	MOVEI T1,JSBFRE
	CALL RELFRE		;RELEASE IT
	HRRZS FILCON(JFN)
	RET

;WAIT UNTIL ALL PACKETS FOR CONNECTION HAVE BEEN SENT OFF
	RESCD
CLSWAT:	TCHKCN			;IF DEBUGGING, CHECK CONNECTION
	HRRZ T2,CHASTA(T1)	;199 CHECK FOR NON-OPEN CONNECTION
	CAIE T2,.CSOPN		; BETTER BE OPEN
	 JRST 1(T4)		; UNBLOCK IF NOT
;+++ THIS APPEARS TO BE WRONG: YOU REALLY WANT TO WAIT UNTIL ALL PACKETS
;+++ HAVE BEEN GIVEN TO THE REMOTE FELLOW, NOT JUST RECEIPTED.
	HLRZ T2,CHAOBF(T1)	;GET HEAD OF CONNECTION OUTPUT PACKET LIST
	JUMPE T2,1(T4)		;NONE, UNBLOCK
REPEAT 0,<			;+++ HOWEVER, THIS DOESN'T WORK QUITE RIGHT!
	HRRZ T2,CHAWIN(T1)	;PICK UP CURRENT XMIT WINDOW
	CAMG T2,CHANOS(T1)	;SEE IF STILL THINGS TO BE ACK'ED
	 JRST 1(T4)		;NO, UNBLOCK
>;REPEAT 0,
IFN T20FLG,<JRST 0(T4)>		;YES, KEEP WAITING
IFN TNXFLG,<JRST RFCST1>

;RELEASE ALL STORAGE ASSOCIATED WITH A CONNECTION; SET THINGS UP SO
;AN INACTIVE CONNECTION WILL BE RECOGNIZED BY THE VARIOUS CONNECTION AND
;QUEUE MUNGING ROUTINES.
RELCON::CHKCON			;POSSIBLY CHECK THIS CONNECTION FOR VALIDITY
	CALL NOSKDP
	MOVEI Q2,CHAPBF(CONN)	;OUT OF ORDER PACKETS
	CALL CHALFR
	SETOM CHAPBF(CONN)	;MARK THIS Q AS INACTIVE NOW
	MOVEI Q2,CHAIBF(CONN)	;INPUT BUFFERS
	CALL CHALFR
	SETOM CHAIBF(CONN)	;THIS Q IS INACTIVE
	CALL CHALFO
	SETOM CHAOBF(CONN)	;DITTO
	SETZM CHANBF(CONN)
	CAMN CONN,CHRFHC	;IS THIS THE DISTINGUISHED RFC HANDLER?
	 SETZM CHRFHC		;YES, NO LONGER THERE
	CALL CH7CLN		;GET RID OF ANY QUEUED-FOR-INPUT REFS
	MOVN T1,RFCTAB		;CHECK THAT IT IS NOT IN THE RFC TABLE
	HRRI T1,RFCTAB
	AOBJP T1,RELCN2
RELCN1:	HRRZ T2,(T1)
	CAIN T2,(CONN)		;ONCE WE FIND A MATCHING ENTRY,
	 JRST [	CALL RFCFRE	; DELETE IT FROM THE RFC TABLE
		JRST RELCN2 ]	; AND GO FINISH CLEANUP
	AOBJN T1,RELCN1

RELCN2:	LOAD T1,CHALDX,(CONN)	;GET CONNECTION INDEX
	CAIL T1,MAXCON		;VALID?
	 CHABUG(CHARBC)		;NO, COMPLAIN ABOUT IT BUT GO ON (SIGH)
	MOVE T2,[400000,,-1]
	ANDCAM T2,CHACON(T1)	;CLEAR IN USE AND CONNECTION BLOCK POINTER
DEBUG,<	SETZM CONMAG(CONN) >	;MAKE SURE IT'S NEVER MISTAKEN AGAIN FOR VALID
	CALL OKSKDP
	MOVEI T1,(CONN)
	JRST RELRES		;RELEASE STORAGE BLOCK ITSELF AND RETURN

	SUBTTL NVT SUPPORT
	SWAPCD

; ATTACH CONNECTION TO PTY (FROM .ATNVT)
; CALL:	T1/ JFN OF OPENED NETWORK CONNECTION WITH CHKJFN DONE
;
; RETURNS
;	+1  CANNOT ATTACH
;	+2  OK.  THE JFN IS RELEASED, AC 1 HAS LINE NUMBER OF ATTACHED PTY.

CATNVT::MOVEI T1,ATNX2		;ERROR CODE IF TEST SKIPS
	TQNE <READF>		;MUST BE OPENED FOR READING AND WRITING
	 TQNN <WRTF>
	 JRST ATPER1
	MOVEI T1,ATNX3		;RECEIVE NOT OPEN
	TQNN <OPNF>		;IS IT OPEN?
	 JRST ATPER1
	HRRZ CONN,FILCON(JFN)	;GET CONNECTION
	CHKCON			;VALIDATE IT IF DEBUGGING
	HRRZ T1,CHASTA(CONN)	;GET CONNECTION STATUS
	CAIN T1,.CSRFC		;RFC RECEIVED?
	 JRST ATNVT1
	CAIN T1,.CSOPN		;OPENED OK
	 JRST ATNVT2
	MOVEI T1,ATNX6
	JRST ATPER1

ATNVT1:	CALL SNDOPN		;ACCEPT THE RFC (WAS IN RFC-RECEIVED STATE)
ATNVT2:	XCTUM [HLL CONN,1]	;99 GET FLAGS
IFN TNXFLG,<
	MOVE T1,CONN		;WHERE ROUTINE EXPECTS CONNECTION INDEX
>
	CALL ASNCVT		;ASSIGN NVT TO THESE UNITS
	 JRST [	MOVEI A,ATNX13	;CAN'T, NO PTY'S
		JRST ATPER1 ]
IFN T20FLG,<
	PUSH P,T2		;SAVE ADDRESS OF DYNAMIC AREA
>
	STOR T1,CHANVT,(CONN)	;SAVE TTY NUMBER
	IORI T1,.TTDES		;CONVERT PTY TO TTY DESIGNATOR
	UMOVEM T1,1		;RETURN TO USER
	CALL CHACL4		;RELEASE JFN STORAGE FOR WINDOWS
	CALL RELJFN		;RELEASE SEND JFN
IFN T20FLG,<
	POP P,T2		;GET BACK ADDRESS OF DYNAMIC DATA
	CALL ULKTTY		;UNLOCK DATA BASE
>
	SMRETN			;RETURN SKIPPING

ATPER1:	CALL UNLCKF
	JRST MRETNE		;SAVE ERROR RETURN IN AC1


;CLOSE THE CONNECTION ASSOCIATED WITH THIS NVT---CANNOT BLOCK (CAN BE CALLED
;WITH DEVICE LOCK LOCKED IF DETACHING MANUALLY!): REQUEST THAT THE
;CHAOS BACKGROUND FORK CLOSE IT.

CVTCLZ::CHKCON			;CHECK CONN REF IF DEBUGGING
	MOVX T1,CF%CLS		;MARK IT AS NEEDING
	IORM T1,CHASTA(CONN)	; CLOSING SOMETIME SOON
	MOVX T1,CH%CLS		;TELL CHAOS FORK THERE'S A CLOSE REQUEST
	IORM T1,CHAFLG
	RET

;START UP OUTPUT FOR A LINE; JUST ASKS BACKGROUND FORK TO LOOK AT THIS
;TTY NEXT SCAN.
;RETURNS +1 ALWAYS.
;	CONN/ CONNECTION IN QUESTION
;+++ UNUSED NOW, SINCE IT WAS TOO SLOW: THE BACKGROUND FORK FLUSHES
;+++ ALL NVT OUTPUT TO THE NET EVERY CYCLE INSTEAD OR WHEN CHAFLG GETS
;+++ SET (EG, WITH CH%TTY).

CHAVSO::CHKCON			;CHECK THIS CONNECTION REF IF DEBUGGING
	LOAD T2,CHANVT,(CONN)	;GET NVT LINE
	CALL CHKCVT		;MAKE SURE IT'S TRULY A CHAOS NVT
	 JRST CHAVSB
	MOVX T1,CF%TTO		;MARK THIS CONNECTION
	IORM T1,CHASTA(CONN)	; AS NEEDING OUTPUT ATTENTION
	RET			;DONE

CHAVSB:	CHABUG(CHAVSN)		;NO, COMPLAIN AND GET OUT
	RET

	SUBTTL TTCH7 TIME NVT INPUT PROCESSING

;CALLED FROM SCHEDULER AT TTCH7 TIME TO UNPACK CHARACTERS WAITING IN ANY
;NVT CONNECTIONS' INPUT PACKET LISTS.

	RESCD
CHTTC7::SKIPN CHAON		;IS THE CHAOSNET UP YET?
	 RET			;NO, NOTHING TO DO
	SAVEQ			;SAVE CONN, FX, Q2
IFN CHDR11,<
	CALL CCHKDR		;CHECK ON THE STATE OF THE DR11 PACKETS
>;IFN CHDR11
	STKVAR <CHT7DC,CHT7IX>
	MOVEI Q2,NTTCVT+1	;SAFETY DOWN-COUNTER
	MOVEM Q2,CHT7DC
	MOVEI Q2,CHATTW		;MARCHES THROUGH Q
	MOVEM Q2,CHT7IX		;SAVE IT INITIALLY
CHTC70:	SOSL CHT7DC		;BOUNDS CHECK THIS LOOP
	 CAIL Q2,CHATTW+NTTCVT+1 ; AND THIS REF; BOTH WITHIN BOUNDS?
	 CHABUG(CHT7QB)		;NOPE, SHOULDN'T HAPPEN
	SETO CONN,
	EXCH CONN,(Q2)		;PICK UP CONNECTION REF AND RESET ENTRY
	CAMN CONN,[-1]		;END OF Q?
	 JRST CHTCDN		;YES, GET OUT
	HRRZ CONN,CONN		;CLEAR OUT LEFT HALF (UNIQUIZER)
	CHKCON			;VALIDATE IT IF DEBUGGING
	LOAD T2,CHANVT,(CONN)	;GET NVT INDEX
	CALL CHKCVT		;IS THIS A VALID NVT (DOUBLE CHECK)?
	 JRST CHTC7B
	CALL CVTUPI		;EMPTY THIS CONNECTION'S DATA TO THE NVT'S INPUT
CHTC79:	AOS Q2,CHT7IX		;BUMP TO NEXT Q ENTRY
	JRST CHTC70		;KEEP GOING

CHTCDN:	SETOM CHATTW		;DONE, CLEAR OUT QUEUE
	RET

CHTC7B:	CHABUG(CHT7IN)		;NO (INVALID NVT INDEX), COMPLAIN
	JRST CHTCDN		;AND GET OUT

;CALLED AT RELCON TIME TO CLEAR OUT ANY REFERENCES TO CONN IN CHATTW
;(CALLED NOSKDP, OF COURSE).
CH7CLN:	SAVET
	MOVEI T1,CHATTW		;SCAN THE QUEUE FOR ANY OCCURENCES
CH7CLL:	MOVE T2,(T1)		;PICK UP ENTRY
	CAMN T2,[-1]		;DONE?
	 RET			;YEP, GET OUT
 	TLZ T2,-1		;CLEAR OUT ANY JUNK
	CAIE T2,(CONN)		;FOUND IT?
	 AOJA T1,CH7CLL		;NO, KEEP LOOKING
CH7CLR:	MOVE T2,1(T1)		;YES, PICK UP NEXT ENTRY
	MOVEM T2,(T1)		;MOVE IT IN OVER THIS ONE
	CAMN T2,[-1]		;END OF Q?
	 RET			;YES, GET OUT
	AOJA T1,CH7CLR		;NO, MOVE NEXT

	SWAPCD

	SUBTTL CHAOS NET SEQUENTIAL I/O

;NETWORK INPUT
CHASQI:	SOSGE FILCNT(JFN)	;ANY MORE BYTES?
	 JRST SQI1		;NO, MUST GO GET SOME MORE FROM NETWORK BUFFERS
	ILDB T1,FILBYT(JFN)
	RET
SQI1:	CALL GETINP		;PROCESS BUFFERS FROM NETWORK
	 JRST SQIBLK		;GO BLOCK MAYBE
	JRST CHASQI		;AND START AGAIN

;HERE IF SHOULD BLOCK
SQIBLK:	HRRZ CONN,FILCON(JFN)	;GET CONNECTION BLOCK
	CHKCON			;VALIDATE IT IF DEBUGGING
	CONPTH [3]
	HRRZ T1,CHASTA(CONN)
	CAIN T1,.CSPRF		;STILL HAVE A CHANCE OF MAKING DATA?
	 JRST INPWAT		;YES
	CAIE T1,.CSOPN		; ...
	 CAIN T1,.CSRFS
	 JRST INPWAT		;WAIT FOR INPUT BUFFERS TO APPEAR
	CAIN T1,.CSCLS		;JUST CLOSED NORMALLY?
	 JRST [	HLRZ T1,CHAIBF(CONN) ;YES, ANY DATA THERE?
		JUMPN T1,INPWAT	;OK, GO "WAIT" FOR IT
		TQO <EOFF>	;NO, IT'S END-OF-FILE TIME
		CONPTH [4]
		RET ]
	TQO <ERRF>		;ELSE IS AN ERROR TO TRY TO READ FROM IT
	CONPTH [5]
	RET

INPWAT:	TQNE <EOFF>		;SEEN AN EOF FOR CONNECTION?
	 JRST INPEOF		;YES, DONT GO BLOCKED THEN
	CONPTH [6]
	MOVSI T1,(CONN)
	HRRI T1,INPWTT		;WAIT FOR CHAOSNET INPUT
IFN T20FLG,<
CHAWAT:	TQO <BLKF>		;YES, SAY NEED TO GO BLOCKED
	RETBAD ()
>;IFN T20FLG
IFN TNXFLG,<
CHAWAT:	MOVE P,MPP
	MOVE B,0(P)		;GET AND DECREMENT RETURN PC
	SOS B
	HRRM B,0(P)		;BACK TO RETURN ON STACK
	PUSHJ P,UNLCKF		;UNLOCK JFN
	JSYS EDISMS		;WAIT FOR EVENT
	JRST MRETN		;BACK OUT TO USER
>;IFN TNXFLG

INPEOF:	SETZ T1,		;RETURN 0 FOR INPUT BYTE
	RET

	RESCD
INPWTT:	TCHKCN			;IF DEBUGGING, CHECK CONNECTION
	HRRZ T2,CHASTA(T1)	;MAKE SURE CONNECTION STILL IN GOOD STATE
	CAIE T2,.CSOPN
	 CAIN T2,.CSRFS
	 CAIA
	 JRST 1(T4)
	HLRZ T2,CHAIBF(T1)	;SEE IF ANYTHING ON INPUT BUFFER QUEUE
	JUMPN T2,1(T4)		;YES, UNBLOCK TO PROCESS IT
	JRST 0(T4)
	SWAPCD


;UNDO INPUT
CHAUIN:	TQZN <FILINP>		;REALLY DOING INPUT AT ALL?
	 RET			;NO, DONE
	SKIPGE T1,FILCNT(JFN)
	 SETZ T1,
	HRRM T1,FILBCT(JFN)	;SAVE CURRENT INPUT COUNT
	MOVE T1,FILBYT(JFN)
	MOVEM T1,FILBFI(JFN)	;AND CURRENT INPUT BYTE POINTER
	RET

;SETUP FOR INPUT
CHAINP::SAVET			;FOR THE SAKE OF TENEX
	TQOE <FILINP>		;NOW DOING INPUT
	 RET
	CALL CHAUOU		;UNDO OUTPUT
	HRRE T3,FILBCT(JFN)	;GET INPUT COUNT
	JUMPG T3,CHAIN2		;HAVE ANY INPUT ALREADY?
	CALL GETINP		;NO, TRY TO GET SOME
	 JFCL			;IGNORING LOSSAGE
	RET

CHAIN2:	MOVE T2,FILBFI(JFN)	;INPUT BYTE POINTER
	HRRE T1,FILBCT(JFN)	;AND COUNT
CHAIN3:	MOVEM T1,FILCNT(JFN)	;SETUP CURRENT COUNT
	ADDM T1,FILLEN(JFN)	;UPDATE LENGTH OF WHOLE
	MOVEM T2,FILBYT(JFN)	;AND BYTE POINTER
	RET

;SETUP FOR OUTPUT
CHAOUP::SAVET			;FOR THE SAKE OF TENEX
	TQOE <FILOUP>
	 RET
	CALL CHAUIN		;UNDO INPUT
	SKIPN FILOBF(JFN)	;IS THERE A PACKET TO STUFF INTO YET?
	 JRST GETOUT		;NO, GET ONE
	MOVE T2,FILBFO(JFN)
	HLRE T1,FILBCT(JFN)
	JRST CHAIN3

;UNDO OUTPUT
CHAUOU:	TQZN <FILOUP>
	 RET
	SKIPGE T1,FILCNT(JFN)
	 SETZ T1,
	HRLM T1,FILBCT(JFN)
	MOVE T1,FILBYT(JFN)
	MOVEM T1,FILBFO(JFN)
	RET

;GET SOME MORE INPUT FROM THE NETWORK BUFFERS; RETURN NON-SKIP IF NOTHING GOTTEN
;(EG, ERROR)
GETINP:	HRRZ CONN,FILCON(JFN)	;GET CONNECTION BLOCK
	CHKCON			;VALIDATE IT IF DEBUGGING
	CONPTH [7]
	HRRZ T3,CHASTA(CONN)
	CAIN T3,.CSRFC		;RFC RECEIVED?
	 JRST SNDOPN		;YES, DOING INPUT IMPLIES ACCEPTING THE CONNECTION
	LOAD T3,CHABSZ,(CONN)
	HRRZ T1,FILWND(JFN)	;INPUT WINDOW
	MOVE PKT,T3		;MAKE A BYTE POINTER TO THE WINDOW
	IORI T3,4400
	DPB T3,[POINT 12,T1,11]
	MOVEI T2,44
	IDIVI T2,(PKT)
	LSH T2,PGSFT
	MOVEM T1,FILBYT(JFN)
	SETZM FILCNT(JFN)	;RESET COUNT OF CHARS GOTTEN THIS TIME
GETIN1:	HLRZ PKT,CHAIBF(CONN)	;CHECK FIRST ON INPUT LIST
	JUMPE PKT,GETIN4	;NO MORE, RETURN
	CHKPKT			;VALIDATE IF DEBUGGING
	PKTPTH [42]
	LOAD T3,CPKOP,(PKT)
	CAIE T3,.COCLS
	 CAIN T3,.COLOS		;WAS THIS A LOS?
	 JRST [	CALL GETLOS	;SET ERROR MESSAGE FROM IT
		CONPTH [11]
		JRST GETIN4 ]
	LOAD T3,CPKNB,(PKT)	;GET BYTE COUNT FOR THIS PACKET
	SUBI T2,(T3)		;DECREMENT FREE COUNT
	JUMPL T2,GETIN4		;NO ROOM FOR ALL PACKETS NOW
	PUSH P,T1		;SAVE BYTE POINTER
	CALL CHGETP		;GET THIS PACKET, DO ACKING, ETC.
	 JRST [	ADJSP P,-1	;FLUSH BP
		JRST GETIN4 ]	;OOPS, NO MORE, JUST RETURN
	POP P,T1		;GET BACK BYTE POINTER
	JUMPE T3,GETIN3
	ADDM T3,FILCNT(JFN)
	PUSH P,T2
	MOVE T2,[POINT 8,CHPKDT(PKT)]
GETIN2:	ILDB T4,T2		;MOVE THIS BUFFER OVER
	IDPB T4,T1
	SOJG T3,GETIN2
	POP P,T2
GETIN3:	RCALL RELPKT,4		;NO LONGER NEED THIS PACKET
	JRST GETIN1		;TRY TO PROCESS NEXT ONE

GETIN4:	SKIPG T1,FILCNT(JFN)	;DID WE GET ANY?
	 JRST [	MOVX T1,CF%EOF	;HAVE WE SEEN AN EOF PACKET?
		TDNE T1,CHASTA(CONN)
		 TQO <EOFF>	;YES, SET EOF FOR THIS STREAM
		CONPTH [12]
		SETZ T1,	;SOMETHING VENTURED, NOTHING GAINED
		RET ]
	ADDM T1,FILLEN(JFN)	;GOT SOME, UPDATE LENGTH OF WHOLE
	RETSKP			;SUCCESS RETURN, WITH T1/NUMBER CHARS GOTTEN

;ROUTINE TO CALL TO GET A PACKET FROM A CONNECTION; RETURNS NON-SKIP IF
;NO PACKET THERE BY SURPRISE; THIS NEEDS TO BE LOCKED UP TO AVOID A RACE.
CHGETP:	CALL NOSKDP		;LOCK THIS UP
	MOVEI Q2,CHAIBF(CONN)
	CALL CHAQGF		;GET PACKET OFF LIST SINCE THERE IS ROOM
	JUMPE PKT,CHGETE	;NONE THERE, FAIL RETURN
	LOAD T1,CPKOP,(PKT)
	CAIE T1,.CORFC		;UNLESS READING A RFC
	 SOS CHANBF(CONN)	;ONE LESS ON LIST
	CALL CHPKIA		;HANDLE ACK OF IT IF EOF OR DATA PACKET
	AOS (P)			;SUCCESS
CHGETE:	CALLRET OKSKDP		;ALL DONE IN ANY CASE

	RESCD
;HANDLE ACK OF DATA AND EOF PACKETS; REMEMBER WE'VE SEEN AN EOF PACKET IF SO FOR
;STREAM I/O'S SAKE.
CHPKIA::SAVET			;SAVE AC'S
	LOAD T3,CPKOP,(PKT)	;GET OPCODE
	CAIE T3,.COEOF		;EOF?
	 CAIL T3,.CODAT		;OR DATA?
	 CAIA			;YES
	 RET			;NOPE, FORGET IT
	MOVX T1,CF%EOF		;MARK THIS CONNECTION AS HAVING SEEN AN EOF
	CAIN T3,.COEOF
	 IORM T1,CHASTA(CONN)	; IF WE'RE NOW LOOKING AT ONE
	HRRZ T1,CHASTA(CONN)	;THIS CONNECTION STILL OPEN?
	CAIE T1,.CSOPN
	 RET			;NO, DON'T SEND ANY STATI
	PUSH P,PKT		;SAVE PKT OVER POTENTIAL CHASTO CALL
	LOAD T1,CPKPN,(PKT)	;GET PACKET NUMBER
	HRLM T1,CHAPKN(CONN)	;UPDATE LAST GIVEN TO USER
	CONPTH [10]
	CONPTH T1		;REMEMBER, IF DEBUGGING, WHAT WE JUST SET
	HLRZ T2,CHAACK(CONN)	;GET LAST WE ACK'ED
	SUB T1,T2
	SKIPGE T1
	 ADDI T1,200000
	IMULI T1,3		;CHECK AGAINST 1/3 WINDOW SIZE
	HLRZ T2,CHAWIN(CONN)
	CAIE T3,.COEOF		;IF EOF, OR
	 CAML T1,T2		; NEED ACKING,
	 CALL CHASTO		;SEND STATUS NOW
	POP P,PKT
	RET
	SWAPCD

;ACCEPT AN RFC
SNDOPN:	HLRZ PKT,CHAIBF(CONN)	;GET HEAD OF INPUT QUEUE
	JUMPE PKT,SNDOP1	;NONE THERE
	LOAD T1,CPKOP,(PKT)	;GET THE OPCODE
	CAIE T1,.CORFC		;THE RFC STILL HANGING AROUND?
	 JRST SNDOP1		;NO
	MOVEI Q2,CHAIBF(CONN)	;YES, REMOVE IT THEN
	CALL CHAQGF
	JUMPE PKT,SNDOP1	;IF NOT THERE (?), DON'T FLUSH IT
	RCALL RELPKT,5		;AND FLUSH IT
SNDOP1:	MOVEI T1,.CSOPN		;MAKE CONNECTION BE OPENED
	HRRM T1,CHASTA(CONN)
	CONPTH [13]
	MOVEI Q2,.COOPN		;OPN OPCODE
	JRST CHASO2		;SEND LIKE A STS PACKET

;SEQUENTIAL OUTPUT
CHASQO:	PUSH P,T1		;SAVE CHARACTER
CHASQ1:	SOSL FILCNT(JFN)
	 JRST CHASQ2
	SETZM FILCNT(JFN)	;DIDNT REALLY PUT IN ANOTHER CHARACTER
	CALL FLSOUT		;FORCE OUT THIS BUFFER
	 JRST [POP P,(P)
	       RET]		;ERROR RETURN
	CALL GETOUT		;AND GET NEW ONE
	JRST CHASQ1

CHASQ2:	POP P,T1
	IDPB T1,FILBYT(JFN)
	RET

;FORCE OUT THE REST OF THIS BUFFER
CHASQR:	MTOSND:			;I GUESS FOR NOW
FLSOUT:	HRRZ CONN,FILCON(JFN)
	CHKCON			;VALIDATE IT IF DEBUGGING
	CONPTH [14]
	HRRZ PKT,FILOBF(JFN)
	JUMPE PKT,RSKP		;NONE THERE NOW, FORGET IT
	CHKPKT			;VALIDATE PACKET IF DEBUGGING
	PKTPTH [43]
	MOVE T1,CHPMXT
	SUB T1,FILCNT(JFN)	;GET SIZE OF PACKET DATA
	STOR T1,CPKNB,(PKT)
	SETZM FILCNT(JFN)
	SETZM FILOBF(JFN)
	CALL SNDPKT		;SEND OFF AS A DATA PACKET
	 TQOA <ERRF>
	 RETSKP
	MOVEI T1,IOX5		;ERROR RETURN
	RET

;GET ANOTHER OUTPUT BUFFER
GETOUT:	HRRZ CONN,FILCON(JFN)	;GET CONNECTION BLOCK
	CHKCON			;VALIDATE IT IF DEBUGGING
	HRRZ T1,CHASTA(CONN)	;GET STATE OF CONNECTION
	CAIN T1,.CSRFC		;RFC RECEIVED?
	 CALL SNDOPN		;YES, ACCEPT CONNECTION THEN
	MOVEI Q2,.CODAT		;RANDOM DATA OPCODE
	RCALL ASGPKC,32		;GET PACKET FOR THIS CONNECTION
	 JRST [	MOVEI T1,^D100
		DISMS
		CONPTH [15]
IFN TNXFLG,<
		MOVE T1,FORKX
		MOVE T1,FKINT(T1)
		TLNN T1,(1B1)	;CHECK MANUALLY FOR INTERRUPT
		 JRST GETOUT
		MOVE P,MPP	;AND UNWIND IF THERE IS ONE
		MOVE B,(P)
		SOS B
		HRRM B,(P)
		JRST MRETN]
>
IFN T20FLG,<
		JRST GETOUT]
>
	HRRZM PKT,FILOBF(JFN)
	ADD PKT,[POINT 8,CHPKDT]	;MAKE BYTE POINTER TO DATA PORTION
	MOVEM PKT,FILBYT(JFN)
	MOVE T1,CHPMXT
	MOVEM T1,FILCNT(JFN)
	RET

;HANDLE A LOS PACKET, MOVE THE STRING OF THE DATA INTO THE JSB SOMEPLACE;
;RETURN "LOS RECEIVED FOR CONNECTION" ERROR CODE IN T1 FOR USE BY CALLER.
GETLOS:	MOVEI Q2,CHAIBF(CONN)	;GET PACKET FROM CONNECTION
	CALL CHAQGF
	JUMPE PKT,R		;NONE THERE
	CHKPKT
	LOAD T3,CPKOP,(PKT)
	CAIE T3,.CSCLS
	 CAIN T3,.COLOS		;FIND THE LOS
	 JRST GETLS1
	RCALL RELPKT,6		;I DONT THINK THERE SHOULD EVER BE ANY OF THESE
	JRST GETLOS
GETLS1:	HLRZ T2,FILCON(JFN)
	JUMPE T2,GETLS2
	HRRZS (T2)
	MOVEI T1,JSBFRE
	CALL RELFRE		;RETURN OLD STRING TO FREE STORAGE IF ANY
	HRRZS FILCON(JFN)
GETLS2:	LOAD T2,CPKNB,(PKT)	;GET BYTE SIZE OF THIS PACKET
	JUMPE T2,GETLS4		;NOTHING THERE, FORGET IT
	MOVEI T2,4+1+3(T2)	;PLUS ONE WORD FOR HEADER AND ONE BYTE FOR NULL
	LSH T2,-2		;NUMBER OF WORDS
	NOINT			;UNTIL WHERE IT WILL BE REMEMBERED
	CALL ASGJFR
	 JRST [	OKINT
	      	JRST GETLS4]	;CAN'T, GO CLEAN UP AND REPORT ERROR
	HRLM T1,FILCON(JFN)	;SAVE STRING FOR ERROR REPORTING
	OKINT
	HRLI T1,(<POINT 8,0,32>)
	MOVE T2,[POINT 8,CHPKDT(PKT)]
	LOAD T3,CPKNB,(PKT)
	JUMPE T3,GETLS3
	 ILDB T4,T2		;MOVE OVER STRING OF DATA
	 IDPB T4,T1
	 SOJG T3,.-2
GETLS3:	IDPB T3,T1		;AND A NULL FOR GOOD MEASURE
GETLS4:	RCALL RELPKT,7
	MOVEI T1,CHAOX1
	RET

;CHA: DEVICE STATUS
CHASTS:
IFN TNXFLG,<
	TEST (NN,OPNF)
	 JRST [	SETZ T1,	;PRETEND STATE IS CLOSED IF NOT OPENED
		RET]
>
	HRRZ CONN,FILCON(JFN)
	CHKCON			;VALIDATE IT IF DEBUGGING
	HRRZ T1,CHASTA(CONN)	;WILL END UP IN USER AC2
	HRR T2,CHANBF(CONN)
	HRL T2,CHANOS(CONN)	;AC3: AVAILABLE OUTPUT WINDOW,,
	UMOVEM T2,3		; NUMBER OF PKTS WAITING IN RCV END
	RET

	SUBTTL CHAOS NET MTOPRS

CHAMTO:	HRRZ CONN,FILCON(JFN)
	CHKCON			;VALIDATE IT IF DEBUGGING
	XCTUM [HRRZ T2,2]
	MOVSI T1,-NCHMTS
CHAMT1:	HLRZ PKT,CHAMTB(T1)
	CAIN PKT,(T2)
	 JRST CHAMT2
	AOBJN T1,CHAMT1
	RETBAD (MTOX1)

CHAMT2:	HRRZ T2,CHAMTB(T1)
IFN T20FLG,<
	JRST (T2)
>
IFN TNXFLG,<
	MOVEI T3,CHAWAT		;SUPPLY WAIT COROUTINE
	CALL (T2)		;CALL ROUTINE
	 SKIPA
	 RET
	MOVEM T1,LSTERR##	;SAVE FOR GETER
	CALL UNLCKF		;UNLOCK FILE
	ITERR()			;SINGLE RETURN MEANS ERROR, GIVE PSI
>

CHAMTB:	.MOACN,,MTOACN		;SET INTERRUPT CHANNEL
	.MOERR,,MTOERR		;GET ERROR MESSAGE
	.MOSND,,MTOSND		;SEND OUT ANY BUFFERED OUTPUT
	.MOPKS,,MTOPKS		;SEND A SINGLE DATA PKT
	.MOPKR,,MTOPKR		;RECV A SINGLE DATA PKT
	.MOSWS,,MTOSWS		;SET WINDOW SIZE
	.MOOPN,,MTOOPN		;ACCEPT AN RFC
	.MOEOF,,MTOEOF		;SEND EOF FOR CONNECTION
	.MONOP,,MTONOP		;WAIT FOR DATA TO GET SENT
	.MOAWS,,MTOAWS		;AVAILABLE WINDOW SIZE
	.MOFHS,,MTOFHS		;FOREIGN HOST
	.MOSIZ,,MTOSIZ		;MAXIMUM SIZE OF PACKET AVAILABLE
	.MORWS,,MTORWS		;READ THE CURRENT WINDOW SIZES
	.MOUAC,,MTOUAC		;READ THE NUMBER OF UNACK'ED PKTS
	.MOSRT,,MTOSRT		;SET RFC TIMEOUT PERIOD IN MS
IFN FRNDLY,<
	.MOFRH,,MTOFRH		;CHECK FOR FRIENDLY HOST
>
NCHMTS==.-CHAMTB

IFN FRNDLY,<
FRHTAB:	FRENDS
FRHTBL==.-FRHTAB

;CHECK HOST FOR JFN FOR BEING FRIENDLY
MTOFRH:	XCTUM [SKIPN T4,3]	;GET HOST IF SPEC'ED
	 LOAD T4,CHAHST,(CONN)	;ELSE GET FOREIGN HOST FOR CONN
	MOVSI T3,-FRHTBL
MTOFR2:	MOVE T1,FRHTAB(T3)	;GET FRIENDLY HOST NAME
	SUBI T1,1		;STANDARDIZE POINTER
	CALL HSTNAM		;GET NAME FOR HOST
	 SETZ T1,
	CAMN T1,T4		;SAME HOST?
	 JRST MTOFR1		;YES, A WINNER
	AOBJN T3,MTOFR2
	TDZA T3,T3
MTOFR1:	 SETO T3,	
	UMOVEM T3,3		;RETURN TO USER
	RETSKP
>

;SET TIMEOUT PERIOD (IN MS) FOR RFC WAITING VIS A VIS THIS CONNECTION
MTOSRT:	UMOVE T3,3		;PICK UP TIMEOUT
	STOR T3,CHATRF,(CONN)	;SET IT IN (MAX ~256 SECS SINCE ONLY HALFWD)
	RETSKP


;NOTE: BY "UNACK'ED" PACKETS, I MEAN UNDELIVERED, IN DISTINCTION FROM UNRECEIPTED
;PACKETS.  THIS ISN'T CONSISTENT WITH OTHER COMMENTS IN THIS FILE; SIGH.
MTOUAC:	CALL NOSKDP		;LOCK OUT WINDOW HACKING FOR A JIFFY
	HRRZ T3,CHAWIN(CONN)	;GET TRANSMIT WINDOW
	SUB T3,CHANOS(CONN)	; SUBTRACT OUT AVAILABLE WINDOW
	CALL OKSKDP		;UNLOCK
	UMOVEM T3,3		;RETURN THIS AS NUMBER OF UNACKNOWLEDGED PACKETS
	RETSKP


MTORWS:	SKIPA T3,CHAWIN(CONN)	;GET CURRENT RECEIVE,,TRANSMIT WINDOW SETTINGS
MTOSIZ:	 MOVE T3,CHPMXT		;GET MAXIMUM SIZE IN BYTES OF PACKET WE CAN HANDLE
	UMOVEM T3,3
	RETSKP


;ASSIGN INTERRUPT CHANNELS FOR STATE CHANGE NOTIFICATION
MTOACN:	XCTUM [HRRZ T3,3]
	STOR T3,CHAICN,(CONN)
	XCTUM [HLRZ T3,3]
	STOR T3,CHAOCN,(CONN)
	MOVE T3,FORKX		;JUST IN CASE SOME OTHER FORK OPENED THIS UP
	STOR T3,CHAFRK,(CONN)
	RETSKP


;GET AN ERROR STRING FROM A LOS OR CLS
MTOERR:	HLRZ T2,FILCON(JFN)	;GET ERROR BYTE POINTER
	JUMPE T2,[RETBAD (CHAOX4)]
	HRLI T2,(<POINT 8,0,32>)
	UMOVE T3,3
	TLC T3,-1
	TLCN T3,-1
	 HRLI T3,(<POINT 7,>)	;STANDARDIZE BYTE POINTER FROM USER
MTOER1:	ILDB T1,T2
	JUMPE T1,MTOER2
	XCTBU [IDPB T1,T3]
	JRST MTOER1

MTOER2:	UMOVEM T3,3		;RETURN USER UPDATED BYTE POINTER
	XCTBU [IDPB T1,3]	;AND APPEND A NULL FOR GOOD MEASURE
	RETSKP


;SET RECEIVE WINDOW SIZE
MTOSWS:	UMOVE T1,3		;GET NEW SIZE
	CAMLE T1,MXRWIN		;RANGE CHECK IT
	 MOVE T1,MXRWIN
	SKIPG T1		;IS IT UNREASONABLE?
	 MOVE T1,1		;YES, LESS THAN 1 IS USELESS
	HRLM T1,CHAWIN(CONN)
	AOS (P)			;CAN'T FAIL FROM NOW ON
	HRRZ T1,CHASTA(CONN)	;GET STATE NOW
	CAIE T1,.CSOPN		;OPEN CONNECTION THERE?
	 RET			;NO, DONT TRY TO SEND ANYTHING
	JRST CHASO1		;YES, SEND A STS RIGHT AWAY SO IT TAKES EFFECT


;RETURN AVAILABLE WINDOW SIZE FOR SENDING
MTOAWS:	MOVE T3,CHANOS(CONN)
	UMOVEM T3,3
	RETSKP

MTOFHS:	LOAD T3,CHAHST,(CONN)	;GET FOREIGN HOST
	UMOVEM T3,3		;+++SHOULD ADD IN NETWORK NUMBER, I GUESS
	RETSKP


;SEND A SINGLE DATA PACKET
MTOPKS:
IFN KLFLG!SMFLG,<
	XCTBU [LOAD Q2,CPKOP,(3)] ;GET OPCODE
>
IFN F3FLG,<
	UMOVE T3,3
	HRLI T3,(<POINTR (0,CPKOP)>)
	XCTBU [LDB Q2,T3]
>
	HRRZ T3,CHASTA(CONN)	;AND CONNECTION STATE
	CAIN T3,.CSPRF		;IN PERMANENT-RFC-SENT STATE?
	 CAIE Q2,.CORFC		; AND TRYING TO SEND A RFC?
	 CAIA			;NO
	 JRST [	CALL MTPKS3	;YES, LET HER SEND IT; SET UP THE PACKET
		 RET		;FAILED; MIMIC
		SETZ T1,	;SEND OFF, BLOCKING (ON THE FE) IS OK
		CALL SNDPK0
		RETSKP ]	;SUCCESS
	CAIN T3,.CSOPN		;CONNECTION OPEN?
	 JRST MTPKS1		;YES, GO SEND THE PACKET AS DATA
	CAIE T3,.CSRFC		;RFC RECEIVED?
	 RETBAD(CHAOX2)		;NO, NOT IN THE RIGHT STATE
	CAIE Q2,.COANS		;LET USER HAVE SIMPLE CONNECTIONS
	 CAIN Q2,.COCLS		;OR SPECIFY A REASON FOR REFUSAL
	 JRST MTPKS2
	PUSH P,Q2		;SAVE OPCODE
	CALL SNDOPN		;DOING OUTPUT IMPLIES ACCEPTING THE CONNECTION
	POP P,Q2
MTPKS1:	CAIN Q2,.COEOF		;SENDING AN EOF?
	 JRST MTOEOF		;YES, HANDLE IT CANONICALLY OUR WAY
	CAIN Q2,.COCLS		;SPECIFYING REASON FOR FLUSHING?
	 JRST MTPKS2
	CAIGE Q2,.CODAT
	 MOVEI Q2,.CODAT	;MAKE IT LEGAL DATA OPCODE
	CALL MTPKS3		;SETUP THE PACKET
	 RET			;ERROR
	JRST SNDPKT		;GO SEND IT OFF

MTPKS2: CALL MTPKS3		;SETUP THE ANS OR CLS PACKET
	 RET			;FAILED
	SETZ T1,
	CALL SNDPK1		;SEND IT OFF, BLOCKING OK
	CALL CHACL4		;FLUSH DATA, ETC.
	MOVEI T1,.CSCLS		;NOW CLOSED
	HRRM T1,CHASTA(CONN)
	RETSKP

MTPKS3:
IFN KLFLG!SMFLG,<
	XCTBU [LOAD T1,CPKNB,(3)] ;GET NUMBER OF BYTES
>
IFN F3FLG,<
	UMOVE T3,3
	HRLI T3,(<POINTR (0,CPKNB)>)
	XCTBU [LDB T1,T3]
>
	CAMLE T1,CHPMXT
	 RETBAD(CHAOX3)
	PUSH P,T1
	ADDI T1,3		;ROUND UP
	LSH T1,-2		;INTO WORDS
	PUSH P,T1		;SAVE FOR LATER
	RCALL ASGPK1,33		;GET A PACKET FROM LENGTH IN 1 AND OPCODE IN Q2
	 JRST [	ADJSP P,-2
		RETBAD(MONX01) ] ;FAILED, NOT ENOUGH ROOM
	POP P,T1		;WORD COUNT
	XCTUM [HRRZ T2,3]	;ADDR IN USER SPACE OF BUFFER
	ADDI T2,CHPKDT
	XMOVEI T3,CHPKDT(PKT)
	CALL BLTUM		;MOVE IT OVER
	POP P,T1
	STOR T1,CPKNB,(PKT)	;SET UP BYTE COUNT
	RETSKP			;PACKET ALL SET UP NOW


;GIVE THE USER THE NEXT PACKET
MTOPKR:	HRRZ T3,CHASTA(CONN)
	CAMN CONN,CHRFHC	;IS THIS THE DISTINGUISHED RFC HANDLER?
	 JRST MTOPKP		;YES, GO GIVE IT ANY UNHANDLED RFCS
	HLRZ PKT,CHAIBF(CONN)	;LOOK AT FIRST ON INPUT QUEUE
	JUMPE PKT,SQIBLK	;NONE THERE, WAIT FOR ONE TO APPEAR
	CHKPKT			;CHECK THIS IF DEBUGGING, BEFORE USING IT
	PKTPTH [44]
	CALL CHGETP		;GET THIS PACKET
	 JRST SQIBLK		;OUCH, NOTHING THERE NOW, GO WAIT AGAIN
MTOPR1:	LOAD T1,CPKNB,(PKT)	;GET BYTE COUNT
	ADDI T1,3+CHPKDT*4
	LSH T1,-2		;INTO WORDS
	MOVEI T2,(PKT)
	XCTUM [HRRZ T3,3]	;DEST
	CALL BLTMU		;MOVE INTO USER SPACE
	RCALL RELPKT,10		;RID OF THIS PACKET
	RETSKP

;HERE TO HANDLE A PACKET-READ REQUEST FROM THE DISTINGUISHED RFC HANDLER:
;HAND IT THE NEXT PACKET ON ITS INPUT LIST, WHICH IS A COPY OF AN UNHANDLED
;RFC, OR WAIT TILL SOME APPEAR IF NECESSARY.
MTOPKP:	SKIPN CHAIBF(CONN)	;ANYTHING IN THE INPUT QUEUE?
	 JRST MTOPPW		;NO, GO WAIT FOR SOMETHING TO APPEAR
	MOVEI Q2,CHAIBF(CONN)	;YES, PULL OF FIRST PACKET
	CALL CHAQGF
	JUMPE PKT,MTOPPW	;OOPS, NOTHING THERE; GO WAIT FOR WORK
	SOS CHANBF(CONN)	;NOTE WE'VE TAKE THIS OFF THE INPUT LIST
	CHKPKT			;CHECK IT IF DEBUGGING
	PKTPTH [45]
	JRST MTOPR1		;ELSE, GIVE IT TO THE REQUESTING RFC HANDLER FORK

MTOPPW:	MOVEI T1,MTOPWT		;WAIT FOR SOMETHING TO APPEAR
	HRLI T1,(CONN)		; ON THIS CONNECTION
	JRST CHAWAT

	RESCD
MTOPWT:	TCHKCN
	SKIPN CHAIBF(T1)	;ANY NEW PACKETS FOR US TO LOOK AT?
	 JRST 0(T4)		;NO, KEEP WAITING
	JRST 1(T4)		;YES, GO GET 'EM
	SWAPCD


;ACCEPT A CONNECTION EXPLICITY
MTOOPN:	AOS (P)			;WILL SKIP RETURN
	JRST SNDOPN		;ACCEPT THE RFC


;SEND AN EOF PACKET ON A CONNECTION
MTOEOF:	CALL FLSOUT		;SEND ANY BUFFERED STREAM OUTPUT
	 JFCL
	MOVEI Q2,.COEOF		;SEND AN EOF
	RCALL ASGPK0,34		;GET A PACKET FOR CONNECTION
	 RETBAD(MONX01)
	SETZRO CPKNB,(PKT)	;ZERO BYTE COUNT
	JRST SNDPKT		;AND GO SEND IT OFF


;NOP: FLUSH ANY OUTPUT AND WAIT FOR IT TO GET SENT
MTONOP:	PUSH P,T3		;SAVE BLOCK PATH SUPPLIED BY .MTOPR
	CALL FLSOUT		;SEND ANY BUFFERED OUTPUT
	 JFCL
	HRRZ T2,CHAWIN(CONN)	;PICK UP CURRENT XMIT WINDOW
	CAMG T2,CHANOS(CONN)	;SEE IF STILL THINGS TO BE ACK'ED
	 JRST [	ADJSP P,-1	;NO, GET OUT
		RETSKP ]
	MOVSI T1,(CONN)		;WAIT FOR EVERYTHING TO GET ACKNOWLEDGED
	HRRI T1,CLSWAT
	POP P,T3		;USE BLOCK PATH SUPPLIED BY .MTOPR
	JRST (T3)

	SUBTTL	LOCAL ROUTING FORK

CHALRF:
IFN TNXFLG,<
	MOVSI 1,UMODF		;FAKE UP SLOW JSYS ENTRY
	MOVEM 1,FPC		; ..
>;IFN TNXFLG
	MCENTR			;START HERE: ENTER MONITOR CONTEXT
	MOVEI T1,1		;WE NEED PRIORITY, STAY IN HIGHEST Q
	MOVEM T1,JOBBIT
	MOVE T1,TODCLK		;INIT BACKGROUND FORK WATCHDOG TIMER
	ADDI T1,^D<5*1000>	;(GIVE IT SOME TIME TO GET GOING)
	MOVEM T1,CHABFT

CHALRL:	CALL CHALCR		;DO SOME ROUTING IF ANY TO DO
	MOVE T1,TODCLK
	ADDI T1,^D5000		;RESET OUR WAKEUP TIMER
	MOVEM T1,CHALRW
	MOVEI T1,CHLTST		;WAIT FOR SOME MORE WORK
	HDISMS (^D500)		;TRY TO STAY AROUND IN BALSET FOR SOME TIME
	JRST CHALRL

	RESCD
CHLTST:	MOVE T1,CHALRW		;TIME TO WAKE UP?
	SKIPN CHQLCL		;IF ANY WORK WAITING FOR US
	 CAMG T1,TODCLK		; OR IF TIME IS UP
	 JRST 1(T4)		; UNBLOCK
	JRST 0(T4)		;NOTHING TO DO YET
	SWAPCD

;DO SOME MAIN-BACKGROUND-FORK AND NFE-11 WEDGEDNESS CHECKING EVERY SO OFTEN
;THEN DO ANY LOCAL ROUTING THAT NEEDS BE DONE.
CHALCR:	MOVE T2,CHABFW		;WHERE THE BACKGROUND FORK IS,
	MOVE T3,CHATIM		; WHEN IT THINKS IT SHOULD RUN NEXT,
	MOVE T4,CHAFLG		; WHAT ITS REQUESTS ARE,
	MOVE Q2,TODCLK		; AND WHAT TODCLK IS NOW
IFN DTEFLG,<
	MOVE T1,Q2		;GET NOW
	SUB T1,CHABFT		;FIND OUT WHEN THE MAIN BACKGROUND FORK LAST CYCLED
	CAILE T1,^D<5*1000>	;IF MORE THAN A FEW SECONDS,
	 JRST CHALCB
CHALC0:	MOVE T1,TODCLK		;GET NOW
	SKIPE T2,CHNPWT		;FIGURE OUT WHEN WE NEED TO CHECK FOR 11 WEDGEDNESS
	 JRST CHLTS1		;INITIALIZE FIRST TIME THROUGH
	MOVE T2,T1
	ADDI T2,^D<5*1000>
	MOVEM T2,CHNPWT
	SETZM CHNPOW		;AND ASK TO SEE CHNPO1 DROP BELOW EMPTY
CHLTS1:	CAML T2,T1		;TIME'S UP?
	 JRST CHLTS3		;NO, DON'T CHECK NOW
	ADDI T1,^D<5*1000>
	MOVEM T1,CHNPWT		;YES, UPDATE TIME OF NEXT CHECK
	SKIPGE CHNPO1		;HOW'S THE -11 QUOTA DOING?
	 JRST CHLTS2		;IT'S OK
	SKIPG CHNPOW		;NO ROOM, HAS ANYONE SEEN ROOM IN PAST FEW SECS?
	 SKIPN CHAON		;-11 STILL UP?
	 CAIA			;YES OR NO
	 CHABUG(CHA11S)		;NO, COMPLAIN ABOUT IT
CHLTS2:	SETZM CHNPOW		;IN ANY CASE, ASK TO SEE IT DROP BELOW EMPTY AGAIN
CHLTS3:	
>;IFN DTEFLG
	SKIPN CHQLCL		;IF LOCAL-Q IS NON-EMPTY, HANDLE IT
	 RET
CHSLC1:	CALL NOSKDP		;LOCK OUT OTHER DIDDLERS OF THE LOCAL ROUTING Q
DEBUG,<	MOVEI Q2,CHQLCL		;CHECK THIS QUEUE HEADER
	CALL CHAQCK
	 JFCL			;ANY PROBLEM ALREADY REPORTED
>;DEBUG
	HLRZ PKT,CHQLCL		;GET A PACKET FROM LOCAL Q
	JUMPE PKT,OKSKDP	;NO MORE, GET OUT AFTER UNLOCKING THINGS
	CHKPKT			;CHECK IT IF DEBUGGING
	PKTPTH [46]
	HLRZ T1,PKTLNK(PKT)	;PICK UP LOCAL-Q LINK FROM THIS PACKET
	CAIN T1,1		;SOME PHONY XMIT-ACTIVE FLAG?
	 CAIE T1,-1		; OR NON-LINKED MARKER?
	 CAIA			;NO AND NO
	 CHABUG(CHSLCR)		;YES, COMPLAIN (JUST IN CASE)
	HRROS PKTLNK(PKT)	;MARK AS NOT ON LOCAL-Q LIST ANY MORE
	HRLM T1,CHQLCL		;MAKE NEXT THE NEW FIRST
	SKIPN T1		;WAS IT THE LAST?
	 SETZM CHQLCL		;YES, Q IS NOW EMPTY
	PUSH P,PKT		;SAVE THIS PACKET OVER CHIPKT CALL
	XMOVEI T1,		;REMEMBER OUR SECTION
	JUMPE T1,[CALL CHIPKT	;ALREADY SECTION 0, DON'T DO ANY
		  JRST CHSLC2]	; SWITCHING
	SE0ENT			;CHIPKT WANTS TO RUN IN SECTION 0
	CALL CHIPKT		;HERE'S A PACKET FROM MYSELF
	SE1ENT			;BACK TO 1 IF WE WERE ALREADY THERE
CHSLC2:	POP P,PKT		;GET BACK ORIGINAL PACKET
	RCALL RELPKM,11		;GET RID OF IT IF IT'S NOT ON OTHER LISTS
	CALL OKSKDP		;UNLOCK THINGS
	JRST CHSLC1		;BACK FOR MORE

IFN DTEFLG,<
CHALCB:	CHABUG(CHATBF,<<T2,WHAT>,<T3,WHEN>,<T4,FLAGS>,<Q2,NOW>>)
	MOVE T1,TODCLK		;COMPLAIN AND UPDATE SO WE DON'T BARF TOO OFTEN
	MOVEM T1,CHABFT
	JRST CHALC0
>;IFN DTEFLG

	SUBTTL CHAOS NETWORK FORK

DEFINE WCALL (R) <		;;;FOR DEBUGGING: NOTE WHAT WE'RE DOING
DEBUG,<	MOVEI T1,R
	MOVEM T1,CHABFW
	CALL R
>;DEBUG
NODEB,<	CALL R >
>

CHSFRK:
IFN TNXFLG,<
	MOVSI 1,UMODF		;FAKE UP SLOW JSYS ENTRY
	MOVEM 1,FPC		; ..
>;IFN TNXFLG
	MCENTR
	MOVE T1,FORKX		;SAVE OUR FORK INDEX
	MOVEM T1,CHAFHN
	MOVEI T1,1		;SAY WE SHOULD ALWAYS STAY IN HIGHEST-PRIORITY
	MOVEM T1,JOBBIT		; QUEUE
	MOVE T1,CHAON
	MOVEM T1,CHAONL		;REMEMBER LAST VALUE OF CHAON
	SETZM CHNPWT		;INITIALIZE -11 WEDGENESS TIMER
	SETZM CHATIM		;CLEAR OUR CYCLE CLOCKS: BASIC CYCLE,
	SETZM CHATM1		; TIMEOUT CYCLE
	SETZM CHATM2		; RFC CHECK CYCLE
	SETZM CHNGTM		; NEGOTIATION TIMEOUTS FOR NVT'S
	CALL CHSINI		;BUILD OUR HOST TABLE FROM HOSTS2 NOW

;BASIC CYCLE: PROCESS REQUESTS, AND HANDLE ALARMS FOR TIMEOUTS, ETC.
;EACH ROUTINE WORRIES ABOUT SEEING IF IT'S TIME TO HANDLE ITS PARTICULAR
;TASK, AND, IF SO, SETTING UP THE TIME TO RUN NEXT TIME.
CHIFRF:	MOVE T1,TODCLK		;UPDATE WHEN WE LAST RAN OUR BASIC CYCLE
	MOVEM T1,CHABFT
	SETZ T1,		;NOW, PICK UP FLAGS
	EXCH T1,CHAFLG		; AND RESET THEM
	MOVEM T1,CHAPFG		;SET LAST FLAG VALUE (WHAT WE USE BELOW)
	SETZM CHAONC		;ASSUME NET HASN'T CHANGED ON US
	MOVE T1,CHAON
	CAME T1,CHAONL		;ANY CHANGE IN NET STATUS?
	 JRST [	SETO T2,	;NO, ASSUME IT JUST WENT DOWN
		SKIPE CHAON	;DID IT?
		 MOVEI T2,1	;NO, JUST CAME UP
		MOVEM T2,CHAONC	;TELL WHAT HAPPENED
		JRST .+1 ]
	MOVEM T1,CHAONL		;REMEMBER WHAT WE JUST SAW FOR NEXT TIME THROUGH
	WCALL CHFCC		;DO SOME CONSISTENCY CHECKS
	WCALL CHATTS		;HANDLE ANY NVTS THAT NEED IT
	WCALL CHFCNS		;UPDATE BASIC CYCLE CLOCKS, SCAN CONNECTIONS
	WCALL CHFRFC		;DO ANY RFC HANDLING
	WCALL CHANEG		;DO ANY NVT NEGOTIATION TIMEOUTS
	MOVE T1,CHATIM
	SKIPN CHAFLG		;IF ANY FLAGS ARE SET AGAIN
	 CAMG T1,TODCLK		; OR IF BASIC CYCLE ALARM TIME IS HERE ALREADY
	 JRST CHIFRF		; GO HANDLE IT
DEBUG,<	MOVEI T1,.		;NOTE WE'RE WAITING HERE
	MOVEM T1,CHABFW		; FOR DEBUGGING PURPOSES
>;DEBUG
	MOVEI T1,CHFTST		;NO, WAIT UNTIL OUR TIME
	HDISMS (^D500)		; COMES OR UNTIL SOMETHING HAPPENS WE CARE ABOUT
	JRST CHIFRF		; (THE HDISMS IS TO STAY IN THE BALANCE SET)

	RESCD
CHFTST:	MOVE T1,CHATIM		;GET TIME FOR NEXT FULL FORK RUN
	SKIPN CHAFLG		;IF ANY REQUESTS FOR WORK, OR
	 CAMG T1,TODCLK		; IF TIME IS UP
	 JRST 1(T4)		;UNBLOCK
	JRST 0(T4)		;ELSE, NOTHING TO DO
	SWAPCD

;UPDATE BASIC CYCLE CLOCKS (RETRANSMISSION AND TIMEOUT CLOCKS) AND
;DO A FULL CONNECTION SCAN FOR VARIOUS KINDS OF LOVING CARE.
;(NOTE: DON'T DISTURB BASIC ORDER HERE UNLESS YOU UNDERSTAND THE IMPLICATIONS)

CHFCNS:	SETZM CHATMA		;ALARMS HAVEN'T GONE OFF YET
	SETZM CHAT1A
	MOVE T1,TODCLK		;GET "NOW"
	SKIPL CHAONC		;IF NET HAS JUST GONE DOWN, OR IF IT'S
	 CAMLE T1,CHATIM	; TIME TO SET OFF THE BASIC CYCLE TIME ALARM
	 CAIA			;THEN DO SO
	 JRST CHFCSS		;NO, MUST JUST BE SOME REQUEST TO PROCESS
	SETOM CHATMA		;MARK OUR BASIC-CYCLE ALARM AS BEING TRIPPED
	ADDI T1,^D500		;TRY TO LOOP THRU EVERY 500 MS
	MOVEM T1,CHATIM		;THIS IS OUR NEXT TARGET WAKEUP TIME
	SUBI T1,^D500		;GET BACK TODCLK WITHOUT POTENTIAL CHANGE
	CAMG T1,CHATM1		;TIME FOR TIMEOUT CYCLE TOO?
	 JRST CHFCSS		;NO
	SETOM CHAT1A		;YES, TURN ON TIMEOUT CYCLE ALARM
	ADDI T1,^D<5*1000>	;REMEMBER WHEN NEXT TIMEOUT CYCLE IS DUE
	MOVEM T1,CHATM1
CHFCSS:	MOVE T1,CHAPFG		;GET POSSIBLE LIST OF KINDS OF WORK AHEAD OF US
	SKIPN CHATMA		;IF NO BASIC-CYCLE WORK TO DO
	TXNE T1,CH%IIN!CH%OIN!CH%DIN!CH%CLS!CH%STS ; AND IF NO PER-CONN REQUESTS
	 CAIA
	 RET			;JUST GET OUT
	MOVSI F1,-MAXCON	;ELSE, SCAN ALL CONNECTIONS

;SCAN LOOP
CHFCSL:	SKIPL CONN,CHACON(F1)	;IS THIS IN USE?
	 JRST CHFCSE		;NO, SKIP IT
	HRRZS CONN		;CLEAR OUT UNIQUIZER (FOR NON-ZERO SECTIONS)
	CHKCON			;VALIDATE CONN IF DEBUGGING

;RETRANSMIT EVERY BASIC CYCLE
	SKIPE CHATMA		;DID THE BASIC CYCLE ALARM GO OFF?
	 CALL CHARTR		;YES, TRY TO RETRANSMIT STUFF FROM THIS CONNECTION

;TIMEOUT IDLE CONNECTIONS (AND HANDLE NET GOING DOWN CLEANLY)
	SKIPL CHAONC		;DID THE NET GO DOWN RECENTLY
	 SKIPE CHAT1A		;OR IS IT TIME FOR A TIMEOUT CYCLE?
	 CAIA			;YES
	 JRST CHIF21		;NO, TRY NEXT THEORY
	HRRZ T2,CHASTA(CONN)	;GET STATE OF CONNECTION
	CAIE T2,.CSRFS		;RFC-SENT STATE?
	 JRST CHIF19		;NO, CHECK FURTHER
	LOAD T2,CHATRF,(CONN)	;YES, PICK UP RFC TIMEOUT
	JRST CHIF9A		; AND GO JOIN TIMEOUT TEST
CHIF19:	CAIE T2,.CSOPN		;OPENED NOW?
	 JRST CHIF21		;NO, SKIP THIS ONE
	MOVX T2,^D<90*1000>	;YES, USE OPEN CONNECTION TIMEOUT LIMIT
CHIF9A:	MOVE T1,TODCLK
	SUB T1,CHAITM(CONN)	;GET TIME SINCE LAST ACTIVITY ON THIS CONNECTION
	SKIPL CHAONC		;DID THE NET JUST GO DOWN, OR HAS IT BEEN
	 CAML T1,T2		; MORE THAN OUR LIMIT?
	 CAIA			;YES OR YES
	 JRST CHIF20		;NO, GO ON
	MOVEI Q2,.CSINC		;INCOMPLETE TRANSMISSION: CONNECTION IS LOST
	CALL CHAINT		;POSSIBLY NOTIFY SOMEONE OF CONNECTION STATE CHANGE
	JUMPN CONN,CHIF21	;IF STILL HAVE CONNECTION REF, TRY SOME MORE
	SKIPL CONN,CHACON(F1)	;ELSE, GET BACK CONNECTION
	 JRST CHFCSE		; (NO CONNECTION ENTRY???  SKIP REST, THEN)
	HRRZS CONN		;CLEAR OUT UNIQUIZER
	JRST CHIF21		;AND TRY NEXT THEORY

;REQUEST STATUS FOR DELINQUENT CONNECTIONS
CHIF20:	HRRZ T2,CHASTA(CONN)	;STILL OPEN?
	CAIE T2,.CSOPN
	 JRST CHIF21		;NO, SKIP IT
	MOVEI Q2,.COSNS		;WILL WANT A SNS PACKET IF LOSING
	HRRZ T2,CHAACK(CONN)
	HRRZ T3,CHAPKN(CONN)
	CAMN T2,T3		;OUTSTANDING PACKETS?
	 CAIL T1,^D<60*1000>	;NO, NOTHING IN MORE THAN A MINUTE?
	 CAIA
	 JRST CHIF21		;NOTHING TO DO HERE
	RCALL ASGPK0,35		;YES, GET A PACKET WITHOUT DATA
	 JRST CHIF21		;NO PACKET AVAILABLE
	SETO T1,
	CALL SNDPK0		;SEND OFF PACKET, BUT NOT IF REQUIRES BLOCKING
	SKIPE T1
	 AOS CHNSNS		;ONE MORE SNS SENT IF IT GOT OUT
CHIF21:
;PARANOIC CHECKING, THEN NVT-UNWEDGING IF NECESSARY
	LOAD T2,CHANVT,(CONN)	;GET NVT INDEX, IF ANY
	MOVE T1,CHASTA(CONN)	;ALSO PICK THIS UP FOR EXTRA INFO
	SKIPN T2		;IS THERE ANYTHING THERE?
	 JRST CHIF22		;NO
	CALL CHKCVT		;YES, IS THIS A CVT?
	 CHABUG(CHANCV,<<CONN,CONREF>,<T1,CHASTA>>) ;NO, COMPLAIN FOR KICKS
CHIF22:

;CHECK STATUS REQUEST
	MOVX T1,CF%STS		;NEED STATUS DONE?
	TDNE T1,CHASTA(CONN)
	 CALL CHASO1		;YES, SEND THAT OUT

;CHECK INTERRUPT REQUESTS
	MOVX T1,CF%IIN		;INPUT INTERRUPT REQUESTED?
	TDNN T1,CHASTA(CONN)
	 JRST CHIF11		;NO
	ANDCAM T1,CHASTA(CONN)	;YES, CLEAR REQUEST
	LOAD T1,CHAICN,(CONN)	;GET INTERRUPT CHANNEL
	LOAD T2,CHAFRK,(CONN)	;AND OWNING FORK
	CAIGE T1,^D36		;HAVE A VALID CHANNEL?
	 CALL PSIRQ		;YES, INTERRUPT THE FORK

CHIF11:	MOVX T1,CF%OIN		;OUTPUT INTERRUPT?
	TDNN T1,CHASTA(CONN)
	 JRST CHIF10		;NO
	ANDCAM T1,CHASTA(CONN)	;YES, CLEAR REQUEST
	LOAD T1,CHAOCN,(CONN)
	LOAD T2,CHAFRK,(CONN)
	CAIGE T1,^D36
	 CALL PSIRQ

CHIF10:	MOVX T1,CF%DIN		;MARKED FOR DETACHMENT?
	TDNN T1,CHASTA(CONN)
	 JRST CHIF12		;NO
	ANDCAM T1,CHASTA(CONN)	;CLEAR REQUEST
	LOAD T2,CHANVT,(CONN)	;YES, DETACH NVT THEN
	CALL DETCVT		; (THIS REQUESTS A CLOSE; HANDLED BELOW)
	 JFCL			;IGNORE ANY FAILURE
CHIF12:
;HANDLE CLOSE REQUESTS FOR NVTS
	MOVX T1,CF%CLS		;DID SOMEONE REQUEST A FAST CLOSE?
	TDNN T1,CHASTA(CONN)
	 JRST CHRDC9		;NOT HERE, TRY NEXT THEORY
	LOAD T2,CHANVT,(CONN)	;GET NVT NUMBER
	CALL CHKCVT		;IS IT AN NVT?
	 CHABUG(CHAMCR)		;NOPE, MISBEGOTTEN CLOSE REQUEST: NOTE IT
	HRRZ T1,CHASTA(CONN)	;GET CURRENT STATE
	CAIE T1,.CSOPN		;STILL OPEN?
	 JRST CHRDC8		;NO LONGER IN USEFUL STATE, GET RID OF IT
	MOVEI Q2,.COCLS		;SEND A CLS
	RCALL ASGPK0,36
	 JRST CHRDC8		;CAN'T, BE RUDE AND FORGET ABOUT THE CONNECTION
	SETO T1,
	CALL SNDPK0		;SHIP CLS OFF, BUT NOT IF IT REQUIRES BLOCKING
CHRDC8:	CALL RELCON		;WE CAN THROW OUT THIS CONNECTION NOW
	JRST CHFCSE		;AND GO ON TO NEXT; CAN'T HELP ANY MORE HERE

;GET RID OF DEAD NVTS HERE
CHRDC9:	HRRZ T1,CHASTA(CONN)	;GET CONNECTION STATE
	CAIN T1,.CSLOS		;LOSING?
	 JRST CHRDCO		;YES, GET RID OF IT
	CAIE T1,.CSINC		;INCOMPLETE?
	 CAIN T1,.CSCLS		; OR CLOSED?
	 CAIA			;YES
	 JRST CHFDC0		;NO, CAN'T BE WHAT WE'RE LOOKING FOR
CHRDCO:	MOVE T1,TODCLK		;GET TIME SINCE LAST ACTIVITY ON THIS CONN
	SUB T1,CHAITM(CONN)
	CAIG T1,^D<60*1000>	;MORE THAN A MINUTE SINCE ANY ACTIVITY?
	 JRST CHFDC0		;NO, FORGET IT
	LOAD T2,CHANVT,(CONN)	;YES, GET POTENTIAL NVT INDEX FROM THIS CONNECTION
	CALL CHKCVT		;IS IT A CHAOS NVT?
	 JRST CHFDC0		;NO, DONE
	CALL RELCON		;YES, GET RID OF THIS CONNECTION
	CHABUG(CHADNV)		;AND TELL ABOUT THIS DEAD NVT
	JRST CHFCSE		;NOTHING MORE TO DO WITH THIS CONNECTION
CHFDC0:

CHFCSE:	AOBJN F1,CHFCSL		;LOOP OVER ALL CONNECTIONS
	RET			;DONE

;TRY MATCHING UP INCOMING RFC'S WITH LSN'S; IF NO MATCH, PUT A COPY
;ON THE DISTINGUISHED RFC HANDLER'S INPUT QUEUE FOR IT TO WORRY ABOUT.

CHFRFC:	MOVX T1,CH%RFC		;ANY WORK FOR US TO DO?
	TDNE T1,CHAPFG
	 JRST CHIF29		;YES, GO TO IT
	MOVE T1,TODCLK		;NO,
	CAMG T1,CHATM2		; TIME TO DO RFC CHECKS PERIODICALLY?
	 RET			;NO, THAT'S IT
	ADDI T1,^D<5*1000>	;YES, REMEMBER WHEN TO MAKE NEXT CHECK
	MOVEM T1,CHATM2
CHIF29:	SETZ F1,		;WHAT WE LAST SAW
CHIF30:	MOVEI Q2,CHQRFC		;GET RFC LIST
	CALL NOSKDP		;PREVENT INTERRUPT CODE FROM LOOKING
	CALL CHAQGF		;GET FIRST PKT
	MOVEM PKT,CHQRFP	;TELL INTERRUPT LEVEL WE OWN THIS PACKET
	CALL OKSKDP		;GET INTERRUPTS BACK
	JUMPE PKT,R		;Q WAS EMPTY
	CAIN F1,(PKT)		;IS THIS AS FAR AS WE GO ON Q?
	 JRST [	CALL NOSKDP	;YES, LOCK UP
		SETZM CHQRFP	; AND CLEAR OUT THIS PACKET
		CALL CHAQPF	; PUT PACKET BACK
		CALLRET OKSKDP ] ;UNLOCK AND LEAVE
	MOVEI T2,CHPKDT(PKT)
	HRLI T2,(<POINT 8,>)	;MAKE BYTE POINTER TO CONNECTION NAME
	MOVE T3,T2
	 ILDB T4,T3		;LOOK FOR A SPACE IN IT
	 CAIE T4," "
	  JUMPN T4,.-2		;NOTE THAT CONTACT NAME WAS MADE ASCIZ
	MOVEI T1,0
	DPB T1,T3		;PUT IN A NULL THERE JUST IN CASE
	PUSH P,T3		;SAVE WHERE TO RESTORE STRING
	PUSH P,T2		;SAVE REF TO START OF STRING
	HRROI T1,[ASCIZ /STATUS/] ;REQUEST FOR STATUS?
	STCMP
	JUMPE T1,[ADJSP P,-2	;YES, FLUSH TEMPS
		JRST CHIRFS]	; AND HANDLE THAT OURSELVES
	POP P,T2		;GET BACK ASCIZ REF
	MOVEI T1,RFCTAB
	TBLUK
	POP P,T3
	DPB T4,T3		;PUT BACK IN THE SPACE OR NULL
	TXNE T2,TL%EXM		;MATCHES?
	 JRST CHIF33		;YES, INTRODUCE THEM
	MOVE T1,TODCLK		;NO,
	SKIPN T2,PKTTIM(PKT)	; IS THIS THE FIRST TIME FOR THIS PACKET?
	 JRST CHIF37		;YES, SEE IF SHOULD START UP A SERVER
	SUB T1,T2		;NO, SEE WHEN THIS WENT ONTO THE QUEUE
	CAIG T1,^D<30*1000>	;BEEN AROUND A REASONABLE AMOUNT OF TIME?
	 JRST CHIF35		;NO, OK
	PUSH P,PKT		;YES,
DEBUG,<	DMOVE T1,CHPKDT(PKT)	;NOW, TELL ABOUT THIS UNHANDLED RFC
	LOAD T3,CPKNB,(PKT)	;TELL ITS LENGTH
	CHABUG(CHAUHR,<<T1,CONTC1>,<T2,CONTC2>,<T3,LENGTH>>)
>;DEBUG
	MOVEI T2,[ASCIZ /Timeout: no such server at this site/]
CHIF3A:	CALL CHALS2		; SEND A CLS TO IT
CHIF3B:	POP P,PKT
IFE SMFLG,<			;ON KS10, WE'VE ALREADY RECYCLED THE COPY IF ANY
	RCALL RELPKT,12		;FREE THIS PKT (WHAT WAS SENT WAS COPY)
>;IFE SMFLG,
	JRST CHIF30

CHIF37:	MOVEM T1,PKTTIM(PKT)	;FIRST UPDATE TIME OF PACKET
	SKIPN CONN,CHRFHC	;IS THERE A RFC HANDLER HARD AT WORK?
	 JRST CHIF35		;NO
	PUSH P,PKT		;SAVE THIS OVER POTENTIAL CPYPKT
	HRRZ T1,CHANBF(CONN)	;YES, PUT A COPY ON THE UNHANDLED RFC QUEUE
	HLRZ T2,CHAWIN(CONN)	; IF THERE'S STILL ROOM IN ITS "WINDOW"
	CAIGE T1,(T2)
	 CALL CPYPKT		;THERE'S ROOM IN THE WINDOW; TRY TO COPY IT
	 JRST CHIF3U		;NO ROOM OR CAN'T, COMPLAIN
	MOVEI Q2,CHAIBF(CONN)	;PUT THIS COPY ON THE INPUT LIST
	CALL CHAQPL		; FOR OUR RFC HANDLER (DON'T NEED TO COUNT IT)
	AOS CHANBF(CONN)	;ACCOUNT FOR THIS NEW PACKET
CHIF36:	POP P,PKT		;GET BACK ORIGINAL RFC PACKET
CHIF35:	JUMPE F1,[MOVE F1,PKT	;REMEMBER WE HAVE SEARCHED THIS FAR
		  JRST .+1]
	MOVEI Q2,CHQRFC		;PUT PACKET BACK ON RFC LIST FOR
				; LISTENING SERVER TO FIND EVENTUALLY
	CALL CHAQPL
	JRST CHIF30

CHIF3U:	CHABUG(CHANRU)		;COMPLAIN
	JRST CHIF36		;NO ROOM IN WINDOW OR FOR PACKET; GIVE UP

;STATUS RFC
CHIRFS:	PUSH P,PKT
	MOVX T3,CHSTBC		;THIS IS BYTE COUNT FOR STATUS ANSWER
	GETPKT T		;GET A PACKET C(T3) BYTES LONG
	 JRST CHIF39		;CAN'T DO THE COPY; DON'T BOTHER WITH IT
	MOVE T1,[BYTE (8) .COANS,0,0,CHSTBC]
	MOVEM T1,(PKT)
	MOVE T1,CHPKS(PKT)	;EXCHANGE SOURCE AND DESTINATION
	EXCH T1,CHPKD(PKT)
	MOVEM T1,CHPKS(PKT)
	MOVEI T1,CHPKDT(PKT)
	HRLI T1,(<POINT 8,>)
	MOVE T2,[POINT 7,MYHNAM]
	MOVEI T3,^D32
CHIRS1:	ILDB Q2,T2
	JUMPE Q2,CHIRS2
	IDPB Q2,T1
	SOJA T3,CHIRS1
CHIRS2:	MOVEI Q2,200		;PAD WITH 200'S
	 IDPB Q2,T1
	 SOJG T3,.-1
	MOVE T2,MYCHAD		;DTE SUBNET NUMBER: HIGH 8 BITS OF MY ADDRESS
	LSH T2,-8
	IORI T2,400		;MARK AS NEW FORMAT STATUS ANS
	CALL SWB16B
IFE SMFLG,<			;IF DON'T HAVE DIRECT HARDWARE CONNECTION,
	MOVEI T2,4		;4 MORE WORDS:
	CALL SWB16B
	MOVE T2,CHNPKI		; PACKETS IN
	CALL SWB32B
	MOVE T2,CHANPO		; AND OUT
	CALL SWB32B
>;IFE SMFLG,
IFN SMFLG,<			;ELSE, ON KS DRIVE THE INTERFACE OURSELVES:
	MOVEI T2,^D16		;16 MORE WORDS
	CALL SWB32B
	SETZ T4,
CHIRS3:	MOVE T2,NPKSIN(T4)
	CALL SWB32B		;OUTPUT WORD OF STATUS
	CAIE T4,7		;OUTPUT EXACTLY 16 WORDS
	 AOJA T4,CHIRS3
>;IFN SMFLG,
	SETO T1,
	CALL CHAXMT		;AND GO ACTUALLY SEND IT, BUT DON'T BLOCK
CHIF39:	JRST CHIF3B		;GO RESTORE AND FREE UP THE ORIGINAL PACKET

SWB32B:	CALL SWB16B		;LOW 16-BITS FIRST
	LSH T2,-8
SWB16B:	IDPB T2,T1		;OUTPUT A 16-BIT NUMBER, SWAB'ED
	LSH T2,-8
	IDPB T2,T1
	RET

;THIS RFC MATCHES A LSN, PUT THEM TOGETHER
CHIF33:	HRRZ CONN,(T1)		;GET CONNECTION INDEX
	NOINT
	CALL RFCFRE		;REMOVE ENTRY FROM RFCTAB
	OKINT
	CHKCON			;VALIDATE CONN IF DEBUGGING
	CHKPKT			;VALIDATE PKT, TOO, IF NEEDS BE
	LOAD T1,CPKPN,(PKT)	;GET PACKET NUMBER
	HRLM T1,CHAPKN(CONN)
	MOVE T1,CHPKS(PKT)	;AND FOREIGN HOST STUFF
	MOVEM T1,CHAFRN(CONN)
	MOVE T1,TODCLK		;SAVE THIS AS LAST TIME OF INPUT
	MOVEM T1,CHAITM(CONN)
	SETOM PKTLNK(PKT)	;MARK AS NOT TRANSMIT ACTIVE, ON NO LISTS
	MOVEI Q2,CHAIBF(CONN)	;PUT ON LIST SO USER CAN SEE CONTACT NAME
	CALL CHAQPL
	MOVEI Q2,.CSRFC
	CALL CHAINT		;INTERRUPT PROCESS MAYBE
	JRST CHIF30		;GO LOOK FOR MORE WORK

;RELEASE RCTAB ENTRY POINTED TO BY T1
RFCFRE:	MOVEI T2,(T1)		;GET ADDRESS OF ENTRY
	PUSH P,(T2)		;SAVE ENTRY
	MOVEI T1,RFCTAB
	TBDEL			;REMOVE FROM LIST OF GUYS NEEDED
	 ERJMP RFFREB
RFFRE1:	POP P,T2
	HLRZ T1,T2		;GET ADDRESS OF CONNECTION NAME
	SUBI T1,1		;POINT TO HEADER
	HRRZ T2,(T1)		;GET LENGTH
	JRST RELSWP		;FREE IT UP

RFFREB:	CHABUG(CHARFB)		;JUST IN CASE
	JRST RFFREB

;SCAN NET TTY LINES EVERY BACKGROUND CYCLE OR WHEN CH%TTY GETS SET.

CHATTS:
IFN T20FLG,<
	MOVE STS,CVTPTR		;COUNT THRU NVT LINES
CHATS1:	HRR T2,STS		;GET TERMINAL NUMBER IN T2
	PUSH P,STS		;+++SEE IF STS IS GETTING CLOBBERED
	CALL LCKTTY		;GET ADDRESS OF DYNAMIC DATA
	 JUMPLE T2,CHATS2	;IF NON-STANDARD BLOCK CHECK FOR OUTPUT
	PUSH P,T2		;SAVE ADDRESS OF DYNAMIC DATA
	CALL TTSOBE		;ANY OUTPUT?
	 CALL CHATCS		;YES, PROCESS IT
	POP P,T2		;GET BACK ADDRESS OF DYNAMIC DATA
CHATS2:	CALL ULKTTY		;UNLOCK TTY DATABASE
	POP P,STS		;+++
	AOBJN STS,CHATS1
	SKIPN T2,CTMSTM		;ANY TTMSG'S OUT
	 RET			;NOTHING TO DO RETURN
	CAMLE T2,TODCLK		;TIME TO FLUSH YET?
	 RET			;NO, RETURN
	NOSKED			;PREVENT ANYONE ELSE FROM CHANGING DATA
	CALL TMSCHR		;FLUSH ALL TTMSG'S TO NVT'S
	OKSKED
	SETZM CTMSTM		;CLEAR TIMER
	RET
>;IFN T20FLG

IFN TNXFLG,<
	PUSH P,10
	MOVE 10,NVTPTR		; COUNT THRU NVT LINES
CHATS1:	MOVEI 2,(10)
	MOVSI 1,NVTCHS
	TDNN 1,TTNETW(2)
	 JRST CHATS2		; ONLY  WHEN CHAOSNET TTY
	SKIPN TTOCT(2)		; Output ready?
	SKIPE TTECT(2)
	 CALL CHATCS		; Yes
CHATS2:	AOBJN 10,CHATS1
	POP P,10
	RET
>;IFN TNXFLG

	SUBTTL	CONSISTENCY CHECKING EVERY CYCLE

CHFCC:	SKIPGE CHAONC		;DID THE NET JUST GO DOWN?
	 CHABUG(CHADWN)		;YES, NOTE THAT FACT FOR FUN
	SKIPLE CHAONC		;OR JUST COME UP?
	 CHABUG(CHAUPN)		;YES
	RET			;THAT'S ALL FOR NOW

	SUBTTL	HOST TABLE SUPPORT

;GET IN HOSTS2.BIN IMAGE FOR OUR HOST TABLE.  ALSO SETS UP MYHNAM TO
;BE MY OFFICIAL NAME (WAITS FOR OUR HARDWARE ADDRESS TO APPEAR FROM
;THE -11 BEFORE DOING SO).

;The format of the compiled HOSTS2 file is:

HSTSID==0	; wd 0	SIXBIT /HOSTS2/
NAMPTR==10	; wd 10 Address in file of NAME table.
SITPTR==11	; wd 11	Address in file of SITE table.
NETPTR==12	; wd 12 Address in file of NETWORK table.

;NETWORK table
; wd 0	Number of entries in table.
; wd 1	Number of words per entry. (2)
NETNUM==0	; wd 0	network number
NTLNAM==1	; wd 1 LH - address in file of name of network
NTRTAB==1	; wd 1 RH - address in file of network's address table

;ADDRESS table(s)
; wd 0	Number of entries in table.
; wd 1	Number of words per entry. (2)
ADDADR==0	; wd 0	Network address of this entry including network number
 ADD%NW==377000000000		;Network number portion of address
 ADD%CA==000000177777		;Chaosnet hardware address portion
ADLSIT==1	; wd 1 LH - address in file of SITE table entry
ADRCDR==1	; wd 1 RH - address in file of next ADDRESS entry for this site
		;	    0 = end of list

;SITE table
; wd 0	Number of entries in table.
; wd 1	Number of words per entry. (3)
STLNAM==0	; wd 0 LH - address in file of official host name
STRADR==0	; wd 0 RH - address in file of first ADDRESS table entry for
		;	    this site.  Successive entries are threaded
		;	    together through ADRCDR.

;NAMES table:
; wd 0	Number of entries
; wd 1	Number of words per entry. (1)
NMLSIT==0	; lh	address in file of SITE table entry for this host.
NMRNAM==0	; rh	address in file of host name

; All names are ASCIZ strings, all letters upper case.
; The strings are stored before, after and between the tables.
; All strings are word-aligned, and fully zero-filled in the last word.

;Network addresses are defined as follows, for purposes of this table:
;    4.9     0
;    4.8-4.1 network number
;    Chaos net (number 7):
;	3.9-2.8	0
;	2.7-1.1 address (2.7-1.9 subnet, 1.8-1.1 host)
;    ARPANET (number 12):	(note, old-format ARPANET addresses
;	3.9-3.8	0	 	never appear in the host table.)
;	3.7-2.1	IMP
;	1.9	0
;	1.8-1.1	Host
;    Dialnet (number 26):
;	3.9-3.1	0
;	2.9-1.1	address in file of ASCIZ string of phone number

NOMNAM:	MYNAME			;NOMINAL HOST NAME AT BUILD TIME

IFE CHADTE,<
	RESCD
CHWHST:	MOVE T1,MYHTIM		;GET LIMIT OF WAIT
	CAMLE T1,TODCLK		;IS TIME UP YET?
	 SKIPL MYCHAD		; OR HAS MY ADDRESS APPEARED YET?
	 JRST 1(T4)		;YES, UNBLOCK
	JRST 0(T4)		;NO
	SWAPCD
>;IFE CHADTE,

CHSINI:	STKVAR <CINERR,CINHFJ,CINFAD>	;ERROR FLAG, HOSTS2.BIN JFN, MY FULL CHAOS ADDRESS
	SETZM CINERR		;NO ERROR YET
	SETOM CINHFJ		;NO JFN YET
	SETZM MYHNAM		;MAKE SURE WE KNOW WE DON'T KNOW OUR NAME YET
IFN DTEFLG,<IFE CHADTE,<	;THIS ONLY WORKS WITH PRIMARY FE CHAOS SUPPORT
	MOVE T1,TODCLK		;GET "NOW"
	ADDI T1,^D<10*1000>	;WAIT UP TO 10 SECONDS FOR
	MOVEM T1,MYHTIM		; MY HARDWARE ADDRESS TO APPEAR FROM -11
	MOVEI T1,CHWHST		;WAIT FOR MY ADDRESS
	SKIPL MYCHAD		;UNLESS IT'S ALREADY HERE
	 JRST CHSIN1		;YEP
	HDISMS(^D500)		;WAIT
CHSIN1:	SKIPGE MYCHAD		;DID IT ACTUALLY ARRIVE?
	 CHABUG(CHAINH)		;NO, COMPLAIN ABOUT IT
>>;IFE CHADTE, IFN DTEFLG,
	MOVX T1,GJ%OLD!GJ%SHT	;NOW, TRY TO FIND HOSTS2.BIN
IFN T20FLG,<
	HRROI T2,[ASCIZ/SYSTEM:HOSTS2.BIN/]
>
IFN TNXFLG,<
	HRROI T2,[ASCIZ/<SYSTEM>HOSTS2.BIN/]
>
	GTJFN
	 ERJMP [MOVEI T1,0	;CAN'T, COMPLAIN AND GET OUT
		JRST CHSIER]	; WITH ERROR TYPE
	MOVEM T1,CINHFJ		;GOT IT, REMEMBER THIS JFN
	MOVE T2,[2,,.FBBYV]	;GET THE BYTE SIZE INFO AND NUMBER OF BYTES
	MOVEI T3,T3		; TO T3, T4
	GTFDB
	 ERJMP [MOVEI T1,1	;CAN'T, GIVE UP
		JRST CHSIER]
	EXCH T3,T4		;T3/ NUMBER OF BYTES, T4/.FBBYV INFO
	LDB T2,[POINTR(T4,FB%BSZ)] ;GET ACTUAL BYTE SIZE
	LSH T2,<^D35-POS(OF%BSZ)> ;SHIFT IT INTO PLACE FOR OPENF
	IORX T2,OF%RD		;WE SIMPLY WANT TO READ THE FILE
	OPENF			;GET IT OPEN
	 ERJMP [MOVEI T1,2	;FAILED; GIVE UP
		JRST CHSIER]
	LDB T2,[POINTR(T4,FB%PGC)] ;GET PAGE COUNT
	CAILE T2,CHST2P		;WILL IT FIT?
	 JRST [	MOVEI T1,3	;NOPE, GIVE UP
		JRST CHSIER]
	LDB T2,[POINTR(T4,FB%BSZ)] ;GET BACK BYTE SIZE
	LSH T2,^D35-POS(<007700,,0>) ;SHIFT IT INTO PLACE FOR BP SIZE FIELD
	TLO T2,440000		;BUILD BYTE REF TO OUR HOST TABLE START
	HRRI T2,CHOSTB
	MOVNS T3		;NOW, GET SET TO SIN IT ALL IN
	SIN			;TRY IT
	 ERJMP [MOVEI T1,4	;SOMETHING FAILED,
		JRST CHSIER]	; NOTE IT
	MOVE T1,CHOSTB+HSTSID	;PICK UP PURPORTED SELF-ID
	CAME T1,[SIXBIT/HOSTS2/] ;IS IT OK?
	 JRST [	MOVEI T1,5	;NO, FAIL
		JRST CHSIER]
	MOVE T1,CHOSTB+NETPTR	;YES, GET REF TO START OF NETWORK TABLE
	DMOVE T2,CHOSTB(T1)	;NUMBER OF ENTRIES AND SIZE OF EACH
	MOVEI T1,CHOSTB+2(T1)	;FIRST ENTRY ADDRESS (REAL)

CHSIN2:	HLRZ T4,NTLNAM(T1)	;GET REF TO NAME OF THIS NET
	MOVE T4,CHOSTB(T4)	;GET NAME
	CAME T4,[ASCII/CHAOS/]	;THIS US?
	 SOJG T2,[ADDI T1,(T3)	;NO, BUMP TO NEXT ENTRY IF ANY MORE
		  JRST CHSIN2]	; AND TRY IT
	JUMPLE T2,[MOVEI T1,6	;COULDN'T FIND OUR NET NUMBER, COMPLAIN
		   JRST CHSIER]
	MOVE T2,NETNUM(T1)	;GOT IT, PICK UP OUR NUMBER
	MOVEM T2,CHANET		;SAVE IT HERE
	SETOM CHOSTP		;NOW HAVE A TOTALLY KOSHER HOST TABLE READY
	SKIPGE MYCHAD		;HAVE OUR ADDRESS?
	 JRST CHSIN4		;NO, TRY TO WORK THE OTHER WAY (FROM OUR NAME)
	LSH T2,<^D35-POS(ADD%NW)> ;PUT IT IN THE NETWORK FIELD
	IOR T2,MYCHAD		;BUILD MY FULL HOSTS2 ADDRESS HERE
	MOVEM T2,CINFAD		;SAVE IT FOR SCAN BELOW

	HRRZ T1,NTRTAB(T1)	;GET OFFSET OF ADDRESS TABLE FOR CHAOSNET
	MOVEM T1,CHANAO		;REMEMBER IT FOR LATER LOOKUPS
	DMOVE T2,CHOSTB(T1)	;GET NUMBER OF ENTRIES AND SIZE OF EACH
	MOVEI T1,CHOSTB+2(T1)	;GET REAL REF TO FIRST ENTRY

CHSIN3:	MOVE T4,ADDADR(T1)	;GET THIS ENTRY'S ADDRESS
	CAME T4,CINFAD		;IS IT I?
	 SOJG T2,[ADDI T1,(T3)	;NO, BUMP TO NEXT IF ANY MORE
		  JRST CHSIN3]	; AND KEEP LOOKING
	JUMPLE T2,[MOVEI T1,7	;COULDN'T FIND MY NAME
		   JRST CHSIER]
	HLRZ T1,ADLSIT(T1)	;GET OFFSET OF SITE ENTRY FOR ME
	HLRZ T1,CHOSTB+STLNAM(T1) ;GET OFFICIAL HOST NAME OFFSET
	ADD T1,[POINT 7,CHOSTB]	;TURN INTO BP
	SKIPA			;HAVE OUR NAME REF IN T1
CHSIN4:	 MOVE T1,[POINT 7,NOMNAM] ;DON'T KNOW OUR ADDRESS, USE NOMINAL NAME
	MOVE T2,[POINT 7,MYHNAM]
	 ILDB T3,T1		;MOVE IN MY ASCIZ OFFICIAL HOSTS2 NAME
	 IDPB T3,T2
	 JUMPN T3,.-2
	SKIPL MYCHAD		;STILL IN THE DARK ABOUT MY ADDRESS?
	 JRST CHSIDN		;NO, GET OUT
	MOVEI T1,MYHNAM-1	;YES, FIND OUR ADDRESS THE OTHER WAY
	CALL HSTNAM
	 SKIPA			;IF FAILS,
	 SKIPN T1		; OR IF OUR NAME ISN'T FOUND
	 JRST [	MOVEI T1,10	;REMEMBER THIS PROBLEM
		JRST CHSIER ]
	MOVEM T1,MYCHAD		;ELSE, REMEMBER MY HOST ADDRESS
	JRST CHSIDN		;ALL SET, GO CLEAN UP

;HERE ON ERROR
CHSIER:	MOVEM T1,CINERR		;NOTE SOME PROBLEM

;HERE WHEN DONE,TO CLEAN UP
CHSIDN:	SKIPL T1,CINHFJ		;GET JFN IF ANY
	 CLOSF			; AND TRY TO CLOSE IT
	 ERJMP .+2		;IF FAILS, TRY TO JUST RELEASE IT
	 JRST CHSIED		;NO JFN OR CLOSF WORKED, SKIP THE RELEASE
	 RLJFN			;GET RID OF THE JFN
	 ERJMP .+1		;AGAIN, IGNORE FILE ERRORS
CHSIED:	SKIPE T1,CINERR		;ANY REAL PROBLEMS ABOVE?
	 CHABUG(CHANHT,<<T1,PROB>>) ;YES, COMPLAIN APPROPRIATELY
	RET

;CONVERT HOSTNAME STRING (JFN NAME BLOCK REF IN T1) TO NUMBER
HSTNAM:	JUMPE T1,RSKP		;RETURN 0 (BUT OK) IF NO STRING
	SAVEAC <T2,T3,T4,Q2,F1>	;SAVE WORK REGS
	STKVAR <OHSTNT,<HSTNS,^D50/5>,LHSTNS> ;ORIGINAL STRING, COPY OF STRING, WD LENGTH
	HRLI T1,(<POINT 7,0,34>)
	MOVEM T1,OHSTNT		;SAVE NAME REF FOR LATER USE
	ILDB T1,T1		;GET FIRST
	JUMPE T1,RSKP		;IF NULL STRING, RETURN NULL (BUT OK)
	SKIPN CHOSTP		;HAVE A HOST TABLE?
	 JRST HSTNM1		;NONE, TRY NUMBER SPEC
	MOVEI T1,HSTNS		;CLEAR OUR
	SETZM (T1)
	MOVSI T2,(T1)		; LOCAL HOST FELLOW FOR WORD COMPARISON PURPOSES
	HRRI T2,1(T1)
	MOVEI T1,^D50/5-1(T1)
	BLT T2,(T1)
	MOVE T1,OHSTNT		;GET BACK ORIGINAL HOST SPEC
	MOVNI T3,^D100		;LIMIT COUNTER
	MOVEI T2,HSTNS		;WHERE WE BUILD OUR WORD-COMPARABLE HOSTNAME
	HRLI T2,440700
HSTNM0:	ILDB T4,T1
	CAIL T4,"a"
	 CAILE T4,"z"
	 CAIA
	 TRZ T4,40		;UPPER-CASIFY ALPHABETICS FOR SAFETY
	IDPB T4,T2
	SKIPE T4
	 AOJL T3,HSTNM0
	JUMPGE T3,HSTNM1	;TOO LONG, TRY NUMBER JUST FOR SPITE
	SETZ T4,
	 TLNN T2,760000		;FILL OUT TO FULL WORD
	  JRST .+3
	 IDPB T4,T2
	 JRST .-3
	HRRZS T2		;GET ADDRESS OF LAST WORD STORED
	SUBI T2,HSTNS		;GET LENGTH IN WORDS-1
	MOVEI T2,1(T2)		;ADJUST
	MOVNM T2,LHSTNS		;SAVE NEGATIVE FOR AOBJN USE BELOW
	MOVE T1,CHOSTB+NAMPTR	;GET OFFSET OF NAMES TABLE
	DMOVE T2,CHOSTB(T1)	;NUMBER OF ENTRIES AND SIZE OF EACH
	MOVEI T1,CHOSTB+2(T1)	;REAL REF TO FIRST ENTRY

HSTNM7:	HRRZ T4,NMRNAM(T1)	;PICK UP NAME OFFSET
	MOVEI T4,CHOSTB(T4)	;TURN INTO REAL ADDRESS
	MOVEI F1,HSTNS		;THIS IS COMPARAND
	HRL F1,LHSTNS		;MAKE LOOP CONTROLLER
HSTNM8:	MOVE Q2,(F1)		;SEE IF WORD-EQUAL
	CAME Q2,(T4)
	 JRST [	ADDI T1,(T3)	;NO, BUMP TO NEXT ENTRY
		SOJG T2,HSTNM7	; AND GO ON IF ANY MORE
		JRST HSTNM1 ]	;NO MORE, TRY NUMBER
	MOVEI T4,1(T4)
	AOBJN F1,HSTNM8		;COMPARE ALL WORDS
	HLRZ T1,NMLSIT(T1)	;FOUND IT; PICK UP SITE OFFSET FOR THIS GUY
	HRRZ T1,CHOSTB+STRADR(T1) ;PICK UP FIRST ADDRESS ENTRY OFFSET FOR THIS SITE
HSTNM9:	JUMPE T1,HSTNM1		;RAN OUT OF ENTRIES, TRY NUMBER SPEC
	MOVE T2,CHOSTB+ADDADR(T1) ;GET THIS ADDRESS
	LDB T3,HNMPNW		;PICK OUT NETWORK NUMBER
	CAME T3,CHANET		;IS THIS A CHAOS HOST ADDRESS?
	 JRST [	HRRZ T1,CHOSTB+ADRCDR(T1) ;NO, CDR DOWN LIST OF ADDRESSES
		JRST HSTNM9 ]	;AND KEEP LOOKING
	LDB T1,HNMPCA		;GET REAL HARDWARE ADDRESS
	RETSKP			;DONE

HNMPNW:	POINTR T2,ADD%NW
HNMPCA:	POINTR T2,ADD%CA

;TRY FOR A NUMBER SPEC IF THE ABOVE HAIR FAILS
HSTNM1:	SETZ T1,		;BUILD HOST NUMBER HERE
	MOVE T2,OHSTNT		;GET BACK ORIGINAL SPEC REF
HSTNM2:	ILDB T3,T2
	JUMPE T3,RSKP
	CAIL T3,"0"
	 CAILE T3,"7"
	 RET
	LSH T1,3
	ADDI T1,-"0"(T3)
	JRST HSTNM2

	RESCD			;HARDWARE SUPPORT ROUTINES

IFN DTEFLG,<
	SUBTTL DTE SERVICE

IFN CHADTE,<
;FROM -11 STATUS
CHSSTS:	MOVE T1,[-CHASBS,,CHASBL]	;POINT TO STATUS BLOCK
CHSST1:	ILDB T3,T2
	MOVEM T3,(T1)
	AOBJN T1,CHSST1
	SETOM CHAON		;SAY NET IS ON
	CALL GATINC		;POKE INTERNET GATEWAY
	RET

;ACK FROM -11
CHADON:	SOS T1,CHNPO1		;ONE LESS PACKET OUTSTANDING IN -11
	MOVEI T2,1		;FOR CHNPOW RESET
	CAMGE T1,CHNPOW		;DID WE GET BELOW SOMEONE'S WATCHDOG LIMIT?
	 MOVEM T2,CHNPOW	;YES, NOTE THAT FACT
	RET

;-11 CRASHED, TURN OFF NET; THIS WILL EVENTUALLY CAUSE ALL CONNECTIONS TO GO .CSINC
DEDMCB::SETZM CHAON
	RET

;-11 RELOAD ACTION, ALSO CALLED ONCE AT STARTUP
NODINI::
CHARLD:	SETZM CHAON		;NETWORK OFF FOR NOW
	MOVNI T1,^D10		;NUMBER OF PACKETS TO ALLOW OUTSTANDING IN -11
	MOVEM T1,CHNPO1
	MOVEI T1,CHADTE
	MOVE T2,[POINT 16,[BYTE (16) 0,1]]
	MOVEI T3,2
	CALL DTEQ
	 JFCL			;WILL GET SENT EVENTUALLY
	RET

;PACKET FROM -11
CHAPKT:	MOVEI PKT,1(T2)		;FALL INTO CHIPKT WITH PACKET SET UP
IF2,<IFN .-CHIPKT,<PRINTX ?CHIPKT MUST FOLLOW CHAPKT DIRECTLY>>	;DOUBLE-CHECK
>;IFN CHADTE

IFE CHADTE,<
;FROM -11 STATUS
CHSSTS:	MOVE T1,[-CHASBS,,CHASBL]	;POINT TO STATUS BLOCK
CHSST1:	ILDB T2,T4
	LSH T2,8
	ILDB T3,T4
	IORI T2,(T3)
	MOVEM T2,(T1)
	AOBJN T1,CHSST1
	SETOM CHAON		;SAY NET IS ON
	MOVEI T1,
	CALL GATINC		;POKE INTERNET GATEWAY
	RET

;ACK FROM -11
CHADON:	JUMPL T2,R		;IGNORE ACK ALL
	SOS T1,CHNPO1		;ONE LESS PACKET OUTSTANDING IN -11
	MOVEI T2,1		;FOR CHNPOW RESET
	CAMGE T1,CHNPOW		;DID WE GET BELOW SOMEONE'S WATCHDOG LIMIT?
	 MOVEM T2,CHNPOW	;YES, NOTE THAT FACT
	RET

;-11 RELOAD ACTION, ALSO CALLED ONCE AT STARTUP
CHARLD:	SETZM CHAON		;NETWORK OFF FOR NOW
	MOVNI T1,^D10		;NUMBER OF PACKETS TO ALLOW OUTSTANDING IN -11
	MOVEM T1,CHNPO1
	MOVSI T1,0		;GET HOSTNUMBER AND RELATED INFO FROM -11
	MOVE T2,[.DFRDS,,.FECHA]	;REQUEST DEVICE STATUS
	SETZB T3,T4
	CALL DTEQ
	 JFCL
	RET

;STRING DATA FROM -11
CHAHSD:	MOVE T3,(T4)		;FIRST WORD IS BYTE OFFSET INTO PACKET
	LSH T3,-24		;INTO T3
	MOVE T2,(T4)		;NEXT IS NUMBER OF BYTES STILL TO COME
	LSH T2,-4
	ANDI T2,177777		;INTO T2
	SUBI T1,4		;ACCOUNT FOR OUR HEADER
	JUMPN T2,CHAHS1		;IF BYTES STILL TO COME THIS PACKET
	JUMPE T3,CHAHS2		;OR IT IS OFFSET ANY
CHAHS1:	ADDI T1,3(T3)		;LAST DESTINATION BYTE, AND READY TO ROUND UP
	LSH T3,-2		;MAKE WORD OFFSET (NOTE OFFSET REM 4 = 0)
	LSH T1,-2		;AND THIS ALSO
	MOVEI T3,CHBGPK(T3)	;POINT INTO THE BIG PACKET
	HRLI T3,1(T4)		;SOURCE IS DTE BUFFER WITH PACKET IN IT
	BLT T3,CHBGPK(T1)	;COPY INTO BIG PACKET
	JUMPN T2,R		;DONE IF MORE DATA TO COME
	SKIPA PKT,[CHBGPK]	;HAVE ROUTINES PROCESS THE BIG PACKET
CHAHS2:  MOVEI PKT,1(T4)	;THIS IS A SHORT PACKET, USE DTE BUFFER ITSELF
	JRST CHIPKT
>;IFE CHADTE
>;IFN DTEFLG

IFN SMFLG,<
	SUBTTL	KS10-CHAOS INTERFACE SUPPORT

;;; HERE TO REINITIALIZE THE HARDWARE
CHARLD:	SETZM CHAON		;ASSUME CHAOSNET IS OFF
	MOVE T1,[CHAADR]	;CHECK FOR EXISTANCE OF CHAOS INTERFACE
	CALL UBGOOD
	 RET			;IT'S NOT THERE, SO CHAOSNET IS OFF
	SETZM CHAXPC+2		;SETUP XPCW BLOCK
	MOVEI T1,CHAHIN
	MOVEM T1,CHAXPC+3
	MOVE T1,[XPCW CHAXPC]	;THIS IS THE INTERRUPT INSTRUCTION
	MOVE T2,SMTEPT+CHAUBN	;INTERRUPT VECTOR FOR OUR UNIBUS ADAPTOR
	ADDI T2,CHAVEC/4	;OFFSET BASED ON OUR INTERRUPT VECTOR
	MOVEM T1,(T2)		;PLANT INTERRUPT INSTRUCTION
	MOVE T1,[CHAADR]
	MOVEI T2,CHSRST		;RESET THE INTERFACE
	WRIO T2,CHACSR(T1)
	RDIO T2,CHAMYN(T1)	;READ OUR HOST NUMBER
	MOVEM T2,MYCHAD		;AND REMEMBER IT
	SETZM CHATXQ		;CLEAR TRANSMIT QUEUE
	SETOM CHAON		;SAY NETWORK IS ON
	MOVEI T2,CHSTCL+CHSRCL+CHSREN
	WRIO T2,CHACSR(T1)	;CLEAR TRANSMITTER AND RECEIVER, AND ENABLE
				; RECEIVER INTERRUPTS
	RET


CHAHIN:	MOVEM 17,CHAACS+17	;SAVE AC 17
	MOVEI 17,CHAACS		;THEN SAVE REMAINDER WITH A BLT
	BLT 17,CHAACS+16
	MOVE 17,[-CHAIPS,,CHAIPL] ;INTERRUPT LEVEL PDL
	MOVE T1,[CHAADR]	;CHAOSNET I/O ADDRESS
	RDIO T2,CHACSR(T1)	;GET CURRENT DEVICE STATUS
	TRNE T2,CHSRDN		;RECEIVE DONE -- GO HANDLE INTERRUPT
	 JRST CHAIRV
	TRNE T2,CHSTEN		;TRANSMITTER INTERRUPT EXPECTED?
	 JRST CHAITX		;YES, CHECK TO SEE IF THAT'S IT
CHASPU:	CHABUG(CHASPI,<<T2,D>>)	;SPURIOUS INTERRUPT, SHOULDN'T HAPPEN
	CALL CHARLD		;THIS KNOWS HOW TO REALLY RESET THE WORLD

;;; RETURN FROM INTERRUPT
CHAIRT:	MOVSI 17,CHAACS		;RESTORE ALL AC'S BUT 17
	BLT 17,16
	MOVE 17,CHAACS+17	;NOW RESTORE 17
	XJEN CHAXPC		;THEN RETURN FROM WHENCE WE CAME...

;;; HERE WHEN WE SUSPECT THE TRANSMITTER
CHAITX:	TRNN T2,CHSTDN		;TRANSMIT DONE?
	 JRST CHASPU		;NOPE, SPURIOUS INTERRUPT
	PIOFF			;WILL BE HACKING THE QUEUE
	HRRZ PKT,CHATXQ		;THIS IS THE PACKET WE JUST TRANSMITTED
	TRNE T2,CHSTAB		;TRANSMIT ABORTED?
	 JRST CHATXA		;YES, HANDLE DIFFERENTLY
CHATXB:	HRRZ T1,PKTTLK(PKT)	;NEXT PACKET TO GO
	SETZM PKTTLK(PKT)	;MAKE SURE NOBODY LOOKS AT THIS INFO
	HLRZ T2,CHATXQ		;GET LAST PACKET ON QUEUE FOR ERROR CHECK
	JUMPN T1,CHATX0		;SOMETHING THERE, TRANSMIT IT
	SETZM CHATXQ		;CLEAR THE QUEUE
	PION			;DONE HACKING WITH IT ALSO
	CAME T2,PKT		;IS QUEUE CONSISTENT?
CHATX1:	 CHABUG(CHATQF)		;TRANSMIT QUEUE IS INCONSISTENT
	CALL CHAXIN		;PACKET IS DONE BEING TRANSMITTED
	MOVE T1,[CHAADR]
	MOVEI T2,CHSTEN
	BCIO T2,CHACSR(T1)	;TURN OFF TRANSMITTER INTERRUPT ENABLE
	JRST CHAIRT		;DISMISS INTERRUPT

CHATX0:	CAMN T2,PKT		;THE PACKET WE JUST SENT BETTER NOT HAVE BEEN
				; THE LAST ONE!
	 JRST [SETZM CHATXQ	;ERROR, REPORT IT AND FLUSH QUEUE
	       PION
	       JRST CHATX1]
	HRRM T1,CHATXQ		;THIS PACKET IS THE NEXT TO GO
	PUSH P,T1		;SAVE FOR LATER
	PION			;DONE WITH QUEUE FOR NOW
	CALL CHAXIN		;REPORT PACKET AS TRANSMITTED
	POP P,PKT		;GET THAT PACKET BACK
	CALL CHATXP		;SEND IT OFF
	JRST CHAIRT		;THEN DISMISS INTERRUPT

;;; HERE IF TRANSMIT ABORTED (PI SYSTEM IS OFF)
CHATXA:	AOS NPKSAB		;COUNT THE ABORT
	HLRZ T1,PKTTLK(PKT)	;GET THE RETRANSMISSION COUNT
	AOS T1			;ONE MORE TIME
	CAILE T1,CHARTC		;OK TO RETRANSMIT
	 JRST CHATXB		;NOPE, SO TREAT AS IF SUCCESFUL
	HRRZ T2,PKTTLK(PKT)	;GET NEXT PACKET
	HRLZM T1,PKTTLK(PKT)	;REMEMBER THE NUMBER OF TIMES
;;; *** THIS IS A CROCK -- IT SHOULD WAIT 1/60 OF A SEC OR SO, BUT THAT'S
;;; *** TOO HARD FOR NOW SO IT'LL WORK THIS WAY
	JUMPE T2,CHATXC		;WE ARE THE ONLY ONE, SO SEND US OFF RIGHT NOW
	HRRM T2,CHATXQ		;PROMOTE NEW PACKET TO THE HEAD OF THE QUEUE
	HLRZ T1,CHATXQ		;LAST PACKET ON QUEUE
	HRRM PKT,PKTTLK(T1)	;LINK US IN
	HRLM PKT,CHATXQ		;AND MAKE US LAST
	MOVEI PKT,(T2)
CHATXC:	PION			;QUEUES ARE CONSISTENT, TRANSMIT THE NEXT PKT
	CALL CHATXP		;SEND IT OFF
	JRST CHAIRT		;THEN DISMISS THE INTERRUPT


;;; HERE TO TRANSMIT PACKET IN PKT.  THE INTERFACE BETTER BE READY FOR ONE!
CHATXP:	MOVE T1,[CHAADR]
	MOVEI T2,CHSTCL
	BSIO T2,CHACSR(T1)	;CLEAR TRANSMITTER
	MOVE T4,[<442000,,0>(PKT)] ;BYTE POINTER TO BEGINNING OF PACKET
REPEAT 10,<			;OUTPUT THE 16 HEADER BYTES
	ILDB T2,T4
	WRIO T2,CHAWBF(T1)
>
	LOAD T3,CPKNB,(PKT)	;NUMBER OF DATA BYTES
	AOS T3
	LSH T3,-1		;ROUND OFF TO NUMBER OF 16 BIT WORDS
	JUMPE T3,CHATP1		;ONLY HEADER, SKIP DATA TRANSMISSION STUFF
	LOAD T2,CPKOP,(PKT)	;GET THE OPCODE
	CAIE T2,.COOPN		;16 BIT CONTROL OPCODE?
	 CAIN T2,.COSTS
	  JRST CHATP2
	CAIN T2,.CORUT
	 JRST CHATP2
	CAIGE T2,.CODAT+100	;BINARY DATA?
	 JRST CHATP0		;NOPE, USE THE SLOW LOOP
CHATP2:	ILDB T2,T4
	WRIO T2,CHAWBF(T1)	;WRITE DATA WORD TO INTERFACE
	SOJG T3,CHATP2
CHATP1:
;;; *** HERE IT SHOULD ROUTE, BUT FOR NOW JUST SEND IT OUT TO THE SPECIFIED
;;; *** HOST ON SUBNET 1 (OUR OWN SUBNET)
	LOAD T2,CPKDA,(PKT)
	WRIO T2,CHAWBF(T1)
	RDIO T2,CHAXMT(T1)	;TRANSMIT THE THING
	MOVEI T2,CHSTEN		;AND ENABLE TRANSMITTER INTERRUPTS
	BSIO T2,CHACSR(T1)
	RET


;;; HERE WHEN NEED TO DO BYTE SWAPPING ON OUTPUT
CHATP0:	MOVE T4,[<441000,,CHPKDT>(PKT)] ;8 BIT BYTE POINTER
CHATP4: ILDB T2,T4		;GET NEXT BYTE
	ILDB Q2,T4		;THIS NEEDS TO BE HIGH ORDER BYTE
	DPB Q2,[101000,,T2]	;SO PLANT IT IN AC
	WRIO T2,CHAWBF(T1)	;WORD OUT TO INTERFACE
	SOJG T3,CHATP4
	JRST CHATP1


;;; HERE TO RECEIVE A PACKET, T2 HAS HARDWARE CSR, T1 HAS CHAOS BASE ADDRESS
CHAIRV:	AOS NPKSIN		;COUNT THIS AS ANOTHER PACKET IN FORM INTERFACE
	TRNE T2,CHSERR		;CRC ERROR?
	 JRST CHARV5		;YES, COUNT IT, FLUSH THE PACKET, THEN PROCEED
	RDIO Q2,CHARBF(T1)	;GET FIRST 16 BIT WORD, WHICH CONTAINS OPCODE
	LSH Q2,-8		;SHIFT OPCODE INTO POSITION
	RDIO T2,CHARBF(T1)	;NEXT WORD IS FORWARDING COUNT AND LENGTH
	MOVEI T1,3(T2)		;GET NUMBER OF BYTES IN PACKET + 3 TO ROUND
	LSH T1,-2		;CONVERT TO NUMBER OF PDP-10 WORDS
	PUSH P,T2		;SAVE T2 OVER CALL TO ASGPKI
	CAIG T1,CHPMXW		;DON'T READ HARDWARE IF PACKET TOO LARGE
	 CALL ASGPKI		;GET APPROPRIATLY SIZED PACKET
	  JRST [POP P,T2
		AOS NPKSIG	;COUNT THIS PACKET IGNORED FOR "OTHER REASONS"
		CALL CHARVR	;RESET RECEIVER
	        JRST CHAIRT]	;PUNT RECEIVE -- RESET HARDWARE AND DISMISS INT
	POP P,T2		;RESTORE BYTE COUNT
	HRLZI T4,042000		;POINT TO SIZE/FORWARDING COUNT FIELD
	HRRI T4,(PKT)
	DPB T2,T4		;THEN STORE 16 BITS
	MOVE T1,[CHAADR]	;GET BACK CHAOS INTERFACE ADDRESS
REPEAT 6,<
	RDIO T2,CHARBF(T1)	;READ NEXT WORD
	IDPB T2,T4
>;END REPEAT
	LOAD T3,CPKNB,(PKT)	;BYTE COUNT
	JUMPE T3,CHARV2		;NO DATA, SKIP READING ANY
	AOS T3
	LSH T3,-1		;NUMBER OF 16 BIT WORDS
	ANDI Q2,377		;OPCODE PART
	CAIE Q2,.COOPN		;16 BIT CONTORL OPCODE?
	 CAIN Q2,.COSTS
	  JRST CHARV0
	CAIE Q2,.CORUT
	 CAIL Q2,.CODAT+100	;BYTE SWAP NECESSARY?
	  JRST CHARV0		;NOPE, JUST READ THEM IN FAST
	MOVE CONN,[201000,,T2]	;BYTE POINTER FOR REVERSING BYTES
CHARV1:	RDIO T2,CHARBF(T1)	;READ NEXT 16 BIT WORD
	DPB T2,CONN		;DUPLICATE LOW ORDER BYTE
	LSH T2,-10		;THEN FLUSH EXTRA COPY OF LOW ORDER BYTE
	IDPB T2,T4		;AND STORE WORD IN MEMORY
	SOJG T3,CHARV1		;LOOP UNTIL NO MORE
CHARV2:	RDIO T2,CHARBF(T1)	;THIS IS THE HARDWARE DESTINATION
	RDIO T3,CHARBF(T1)	;THIS IS THE HARDWARE SOURCE
	RDIO T4,CHARBF(T1)	;THIS IS THE CHECKSUM
	RDIO T4,CHARBC(T1)	;THE BIT COUNT
	CAIE T4,7777		;IS THE BIT COUNT CORRECT?
	 JRST CHARV3		;NO, BAD BIT COUNT -- FLUSH THE PACKET
	RDIO T4,CHACSR(T1)	;CHECK IF GOT CRC ERROR AFTER READING OUT
	TRNE T4,CHSERR
	 JRST CHARV4		;YES, COUNT IT AND RETURN PACKET
	CALL CHARVR		;RESET RECEIVER
	CALL CHIPKT		;HANDLE THIS PACKET
	JRST CHAIRT		;DISMISS INTERRUPT

;;; FAST(ER) DATA LOOP
CHARV0:	RDIO T2,CHARBF(T1)	;GET 16 BIT BYTE
	IDPB T2,T4		;PLANT IN PACKET
	SOJG T3,CHARV0		;LOOP UNTIL NO MORE
	JRST CHARV2

;;; ERROR ROUTINES
CHARV5:	AOS NPKSER		;CRC ERROR BEFORE READING
	CALL CHARVR		;RESET RECEIVER
	JRST CHAIRT		;THEN RETURN FROM INTERRUPT
CHARV3:	AOSA NPKSBB		;BAD BIT COUNT
CHARV4:	 AOS NPKSRE		;CRC ERROR AFTER READOUT
	CALL RELPKT		;RETURN PKT TO FREE POOL
	CALL CHARVR		;RESET RECEIVER
	JRST CHAIRT		;THEN DISMISS INTERRUPT


;;; RESET RECEIVER
CHARVR:	MOVE T1,[CHAADR]
	RDIO T2,CHACSR(T1)	;ACCOUNT FOR LOST PACKETS
	LDB T3,[110400,,T2]
	ADDM T3,NPKSLS
	MOVEI T3,CHSRCL		;THEN CLEAR THE RECEIVER
	BSIO T3,CHACSR(T1)
	RET

;;;NORMAL-ROUTING PACKET OUTPUT FOR KS10 (CALLED FROM CHAXMT)
CHXNOR:	AOS NPKSOU		;ONE MORE OUTPUT TO HARDWARE
	SKIPN CHAON		;IF NET ISN'T REALLY ON, DON'T SEND PACKET
	 JRST CHAXIN		;SO MAKE BELIEVE IT MADE IT OUT
	PIOFF			;HACK QUEUES UNINTERRUPTABLY
	SKIPN T1,CHATXQ		;ARE WE CURRENTLY TRANSMITTING?
	 JRST [MOVEI T1,(PKT)	;NOPE, SO QUEUE UP THE PACKET
	       HRLI T1,(PKT)
	       MOVEM T1,CHATXQ
	       SETZM PKTTLK(PKT) ;LAST PACKET IN QUEUE
	       PION		;TURN PI SYSTEM BACK ON
	       JRST CHATXP]	;THEN SEND THE PACKET OUT THE INTERFACE
	HLRZ T1,T1		;GET LAST PACKET ON QUEUE
	HRRM PKT,PKTTLK(T1)	;LINK US TO IT
	HRLM PKT,CHATXQ		;WE ARE NOW LAST PACKET ON QUEUE
	SETZM PKTTLK(PKT)	;FLAG THAT IN PACKET AS WELL
	PION			;DONE HACKING QUEUES
	RET

>;END IFN SMFLG

IFN CHDR11,<
	SUBTTL FOONLY DR11 SUPPORT

;SPECIAL LOCATIONS TO INTERFACE TO MICROCODE
DRINPD=2000			;INPUT DONE LIST
DROUTD=2001			;OUTPUT DONE LIST
DRINPR=2002			;INPUT READY LIST
DROUTR=2003			;OUTPUT READY LIST
DRINPP=2004			;INPUT PACKET IN PROGRESS
DROUTP=2005			;OUTPUT PACKET IN PROGRESS

;SPECIAL INSTRUCTIONS FOR HACKING DR11
OPDEF DR11R [744000,,0]		;RESET STATE
OPDEF DR11WI [744040,,0]	;WAKE UP INPUT MICROCODE
OPDEF DR11WO [744100,,0]	;WAKE UP OUTPUT MICROCODE
OPDEF DR11O [745000,,0]		;EFFECTIVE ADDRESS TO PDP-11

;INITIALIZE DR11 INTERFACE
CHARLD:	DR11R 60		;TURN OFF MICRO-INTERRUPTS
	MOVE T1,[DRINPD,,DRINPD+1]
	SETZM -1(T1)
	BLT T1,DROUTP		;CLEAR OUT SPECIAL LOCATIONS
	DR11O 0			;SEND 0 TO 11
	MOVEI Q2,^D5		;MAKE SOME INPUT PACKETS
CDRIN1:	MOVE T1,[.RESP1,,^D128]
	MOVEI T2,.RESNP
	CALL ASGRES
	 CHABUG(CHDR1F)
	MOVSI T3,^D254
	MOVEM T3,(T1)
	MOVEI T2,DRINPR
	CALL DR11Q		;PUT ON END OF INPUT QUEUE
	SOJG Q2,CDRIN1
	DR11WI			;INPUT WAKEUP
	SETOM CHAON		;NOW CAN DO THINGS
	RET

;CALLED FROM CLOCK LEVEL TO CHECK ON THINGS
CCHKDR:
CKDRIN:	SETZ T1,
	EXCH T1,DRINPD		;GET INPUT DONE LIST
	JUMPE T1,CKDRIR		;NO INPUT, CHECK OUTPUT
	HLRZ T1,T1		;GET HEAD OF LIST
CKDRI1:	PUSH P,T1		;SAVE ADDRESS
	MOVEI PKT,1(T1)		;POINT TO PACKET DATA
	CALL CHIPKT		;HANDLE IT
	POP P,T1
	MOVSI T3,^D254		;MAXIMUM NUMBER OF INPUT BYTES
	EXCH T3,(T1)		;GET CDR AND RESET SIZE AND CDR
	MOVEI T2,DRINPR		;PUT BACK ON INPUT READY LIST
	CALL DR11Q
	DR11WI			;LET IT GET FULL
	MOVEI T1,(T3)		;GET CDR
	JUMPN T1,CKDRI1		;AND PROCESS IT IF NECESSARY
CKDRIR:

;CHECK ON OUTPUT
CKDROU:	SETZ T1,
	EXCH T1,DROUTD
	JUMPE T1,CKDROR
	HLRZ T1,T1		;GET HEAD OF LIST
CKDRO1:	PUSH P,T1		;SAVE IT
	MOVEI PKT,1(T1)		;POINT TO PACKET ITSELF
	PKTPTH [61]		;NOTE WE GOT HERE WHEN DEBUGGING
DEBUG,<	HLRZ T1,PKTLNK(PKT)	;PICK UP XMIT ACTIVE FLAG
	MOVE T2,PKTMAG(PKT)	;GET MAGIC FIELD IF DEBUGGING
	CAIE T1,1		;BETTER BE WHAT WE LEFT IT AT
	 CHABUG(CHAXIB,<<T1,WHAT>,<PKT,PKTREF>,<T2,MAGIC>>) ;NO, COMPLAIN
>;DEBUG
	HRROS PKTLNK(PKT)	;CLEAR TRANSMIT ACTIVE
	RCALL RELPKM,16
	POP P,T1		;GET BACK PACKET
	HRRZ T1,(T1)		;GET CDR
	JUMPN T1,CKDRO1		;AND PROCESS IT
CKDROR:	RET			;ALL DONE

;TRANSMIT A PACKET
CHXNOR:
CHXDR1:	NOSKD1			;LOCK OUT ANY OTHERS
	PKTPTH [60]		;REMEMBER WE'VE BEEN HERE
	MOVE T1,TODCLK		;SET TIME OF LAST REAL
	MOVEM T1,PKTTIM(PKT)	; XMISSION FOR RE-XMISSION CHECKING
	LOAD T1,CPKNB,(PKT)	;GET BYTE COUNT
	ADDI T1,CHPKDT*4+1	;PLUS HEADER AND ROUND UP
	LSH T1,-1		;INPUT 16-BIT BYTES
	HRLZM T1,PKTCDR(PKT)	;STORE AND CLEAR CDR
	MOVEI T1,PKTCDR(PKT)	;POINT THERE
	MOVEI T2,DROUTR		;PUT ON OUTPUT READY LIST
	CALL DR11Q
	DR11WO			;WAKE UP MICROCODE
	OKSKD1
	RETSKP			;WE ALWAYS SUCCEED

;PUT PACKET IN T1 ONTO END OF DR11 READY LIST IN T2
DR11Q:	SETZ T4,
	EXCH T4,(T2)		;GET LIST AND ZERO
	JUMPE T4,[HRLI T4,(T1)	;IF PREVIOUSLY EMPTY, THIS IS HEAD AS WELL
		  JRST .+2]
	HRRM T1,(T4)		;STORE PACKET AS CDR(LAST)
	HRRI T4,(T1)		;MAKE IT NEW LAST
	MOVEM T4,(T2)		;SAVE UPDATED LIST
	RET
>;IFN CHDR11	

	SUBTTL PACKET INPUT

CHIPKT:	SKIPN CHAON		;IS NET FULLY ON?
	 JRST [			;NOPE
IFN SMFLG,<	CALL RELPKT  >	;ON KS, FIRST GET RID OF THIS PACKET
		JRST CHARLD ]
	LOAD T2,CPKDA,(PKT)	;GET DESTINATION ADDRESS
	CAME T2,MYCHAD		;MATCHES MINE?
	 JRST CHAPFW		;NO, FORWARD PACKET
	LOAD T2,CPKSA,(PKT)	;GET SOURCE ADDRESS
	CAME T2,MYCHAD		;FROM MYSELF (LOCALLY ROUTED)?
	 AOS CHNPKI		;NO, COUNT NUMBER OF REAL PACKETS INPUT
	MOVEI T2,[ASCIZ /Byte count too large/]
	LOAD T3,CPKNB,(PKT)	;GET BYTE COUNT
	CAMLE T3,CHPMXC		;SEE IF WITHIN LEGAL RANGE
	 JRST CHALOS		;NO, SEND A LOS BACK THEN
	SKIPGE (PKT)		;< SEE IF DATA OPCODE (>= 200)
	 JRST CHIDAT		;YES, HANDLE DATA PACKET THEN
	MOVEI T2,[ASCIZ /Illegal opcode/]
	LOAD T3,CPKOP,(PKT)	;GET OPCODE
	CAIL T3,.COMAX		;WITHIN RANGE?
	 SETZ T3,		;NO, HANDLE WITH LOS RESPONSE
	JRST @CHAHSO(T3)	;YES, GO HANDLE IT

CHAHSO:	CHALOS			;ZERO?
	CHIRFC			;.CORFC
	CHIOPN			;.COOPN
	CHICLS			;.COCLS
	CHIANS			;.COFWD
	CHIANS			;.COANS
	CHISNS			;.COSNS
	CHISTS			;.COSTS
	IGNPKT			;.CORUT
	CHILOS			;.COLOS
	CHALOS			;.COLSN
	IGNPKT			;.COMNT
	CHIDAT			;.COEOF

;FORWARDING
CHAPFW:	JUMPE T2,IGNPKT		;0 FOR DESTINATION, JUST FLUSH IT
IFN ARPAF,<
	LOAD T2,CPKDS,(PKT)	;CHECK FOR BAD ADDRESS ON SUBNET
	CAILE T2,MAXSBN		;RANGE CHECK
	 JRST IGNPKT		;OUT OF RANGE, DISCARD
	HLRZ T2,SBNRUT(T2)	;GET ROUTING METHOD
	CAIN T2,CHXLCL		;LOCAL SUBNET?
	 JRST IGNPKT		;YES, DISCARD
>;IFN ARPAF
	LOAD T2,CPKFC,(PKT)	;GET FORWARDING COUNT
	AOJ T2,
	CAIL T2,20		;CHECK FOR FORWARDING LOOP
	 JRST IGNPKT		;AND DISCARD IF SO
	STOR T2,CPKFC,(PKT)
	GETPKT			;GET PACKET COPY
	 RET			;CANNOT DO THE COPY, PUNT
	AOS CHNPF		;ONE MORE PACKET FORWARDED
	SETO T1,		;DON'T BLOCK
	JRST CHAXMT		;AND GO SEND THIS PACKET OFF AGAIN

;RFC RECEIVED: SEE IF IT IS A DUPLICATE; IF NOT PUT ON LIST TO BE HANDLED.
CHIRFC:	MOVE T2,CHPKS(PKT)	;GET THE SOURCE OF THIS PACKET
	HLRZ T1,CHQRFC		;LOOK DOWN RFC LIST FOR POSSIBLE ONES
	JUMPE T1,CHIRF3
CHIRF1:	CAMN T2,CHPKS(T1)	;FROM THE SAME SOURCE?
	 JRST IGNPKT		;YES, JUST FORGET THIS NEW ONE
	HRRZ T1,PKTLNK(T1)	;GET THE NEXT IN LIST
	CAIE T1,-1		;JUST IN CASE, MAKE SURE NOT EMPTY MARKER
	 JUMPN T1,CHIRF1
	SKIPE T1,CHQRFP		;FORK CODE HAVE HANDLE ON A PACKET?
	 CAME T2,CHPKS(T1)	;YES, DOES IT MATCH?
	 CAIA			;NOPE, SEE IF DUPLICATE CONNECTION
	 JRST IGNPKT		;ELSE FLUSH DUPLICATE RFC
CHIRF3:	MOVSI T1,-MAXCON
CHIRF4:	SKIPL CONN,CHACON(T1)	;IS THERE A CONNECTION HERE?
	 JRST CHIRF5		;NO
	HRRZS CONN		;CLEAR UNIQUIZER
	CAMN T2,CHAFRN(CONN)	;THE SAME?
	 JRST IGNPKT		;YES, FLUSH THIS DUPLICATE
CHIRF5:	AOBJN T1,CHIRF4		;NO, KEEP LOOKING
	CALL CPYPKZ		;MAKE AN ASCIZ COPY OF THE PACKET
	 JRST IGNPKT		;CANNOT MAKE COPY, PUNT
	SETZM PKTTIM(PKT)	;NOTE THAT WE'VE NOT SEEN IT YET
	MOVEI Q2,CHQRFC		;RFC RECEIVED LIST
	CALL CHAQPF		;ADD TO LIST
	MOVX T1,CH%RFC		;MARK ANOTHER RFC AS NEEDING HANDLING
	IORM T1,CHAFLG
	RET

;SNS RECEIVED
CHISNS:	CALL CHFNDX		;FIND OUR INDEX FOR THIS CONNECTION
	 JRST CHALOS
	CAIE Q2,.CSOPN		;IS IT NOW OPEN?
	 JRST IGNPKT		;NO, IGNORE REQUEST
IFN SMFLG,<CALL RELPKT>		;ON KS10, RETURN SNS PACKET TO FREE POOL
	JRST CHASTO		;TRY TO SEND STATUS NOW FOR THIS CONNECTION

;STS RECEIVED
CHISTS:	CALL CHFNDX		;FIND CONNECTION
	 JRST CHALOS
	CAIE Q2,.CSOPN		;MUST BE OPEN
	 JRST CHALOS
CHIST1:	LDB T1,[POINT 16,CHPKDT(PKT),31] ;GET WINDOW SIZE FROM PACKET
	CAMLE T1,MXTWIN		;RANGE CHECK
	 MOVE T1,MXTWIN
	JUMPLE T1,CHISTB
CHIST2:	HRRM T1,CHAWIN(CONN)	;STORE TRANSMIT WINDOW SIZE
	LDB T2,[POINT 16,CHPKDT(PKT),15] ;GET PACKET NUMBER BEING RECEIPTED
	CALL CHIAK0		;REMOVE THOSE PACKETS FROM HIS LIST
IFN SMFLG,<CALL RELPKT>		;ON KS, RETURN THE STS PACKET
	JRST CHARTR		;AND RETRANSMIT OTHERS LEFT ON IT FOR TOO LONG

CHISTB:	CHABUG(CHAZWN,<<T1,WINSIZ>,<CONN,CONREF>>)	;NO, COMPLAIN
	MOVX T1,1		;YES, SET IT TO MINIMUM
	JRST CHIST2

;FWD OR ANS RECEIVED
CHIANS:	CALL CHFNDX		;FIND INDEX FOR THIS CONNECTION
	 JRST IGNPKT		;NONE, NO CONN ON OTHER END TO TELL PRESUMABLY
	CAIN Q2,.CSRFS		;IN RFC-SENT STATE?
	 JRST CHICL1		;CLOSE CONNECTION, SETUP BUFFER W/ ERROR MESSAGE
	CAIE Q2,.CSPRF		;IN PERMANENT RFC-SENT STATE?
	 JRST IGNPKT		;NO, JUST IGNORE IT
CHIAN0:	HRRZ T1,CHANBF(CONN)	;YES, GET NUMBER OF UNEATEN INPUT PACKETS
	HLRZ T2,CHAWIN(CONN)	;GET INPUT WINDOW SIZE
	CAIGE T1,(T2)		;IF WINDOW ISN'T FULL,
	 GETPKT			; COPY PACKET INTO RESIDENT STORAGE IF NECESSARY
	 RET			;WINDOW FULL OR CAN'T COPY, GIVE UP
	SKIPN CHAIBF(CONN)	;PREVIOUSLY EMPTY?
	 CALL CHAIN1		;YES, PERHAPS INTERRUPT AN INTERESTED FORK
	AOS CHANBF(CONN)	;ONE MORE ON INPUT LIST
	MOVEI Q2,CHAIBF(CONN)	;PUT IT ON THE IN-ORDER LIST
	CALL CHAQPL
	RET			;DONE

;OPN RECEIVED
CHIOPN:	CALL CHFNDX		;FIND CONNECTION
	 JRST CHALOS
	CAIE Q2,.CSRFS		;MUST BE RFC SENT
	 JRST IGNPKT		;ELSE JUST IGNORE IT
	LOAD T2,CPKPN,(PKT)	;GET PACKET NUMBER
	HRLM T2,CHAPKN(CONN)	;SETUP RECEIVE PACKET NUMBERS FOR CONNECTION
	MOVE T2,CHPKS(PKT)	;GET SOURCE
	MOVEM T2,CHAFRN(CONN)	;THAT IS FOREIGN HOST FOR CONNECTION
	CALL CHIST1		;PROCESS WINDOW SIZE AND RECEIPT AS STS
	CALL CHASTO		;SEND BACK STATUS
	MOVEI Q2,.CSOPN		;STATE FOR CONNECTION NOW OPEN
	JRST CHAINT		;MAYBE WAKE UP SOME FORK

;LOS RECEIVED
CHILOS:	CALL CHFNDX		;TRY TO FIND CONNECTION
	 JRST IGNPKT		;IGNORE IT IF NOT
	JUMPE Q2,IGNPKT		;OR IS CLOSED
	CAIN Q2,.CSPRF		;PERMANENT-RFC STATE?
	 JRST CHIAN0		;YES, JUST GIVE THIS PACKET TO THE FELLOW
	PUSH P,PKT		;SAVE INCOMING PACKET
	CALL CHALFO		;FREE UP OUTPUT BUFFERS
	POP P,PKT
	MOVEI Q2,.CSLOS		;PUT INTO LOS STATE
	JRST CHICL2		;GIVE USER ERROR MESSAGE

;CLS RECEIVED
CHICLS:	CALL CHFNDX
	 JRST CHALOS
	CAIN Q2,.CSPRF		;PERMANENT-RFC STATE?
	 JRST CHIAN0		;YES, JUST GIVE THIS PACKET TO THE FELLOW
	CAIE Q2,.CSOPN		;STATE SHOULD BE OPEN
	 CAIN Q2,.CSRFS		;OR RFC SENT
CHICL1:	 TDZA Q2,Q2		;NEW STATE IS CLOSED
	 JRST CHALOS
CHICL2:	CALL CHAINT		;MAYBE INTERRUPT SOMEBODY
	JUMPE CONN,IGNPKT	;IF THIS KILLED THE CONNECTION, FORGET PKT
	PUSH P,PKT		;SAVE INCOMING PACKET
	MOVEI Q2,CHAPBF(CONN)	;POINTER TO OUT OF ORDER PACKETS
	CALL CHALFR		;FREE THEM ALL
	HRRZS CHANBF(CONN)	;NO MORE ON THAT LIST
	POP P,PKT
	JRST CHIDT1		;RETURN LOS PACKET AS DATA

;DATA PACKET RECEIVED
CHIDAT:	CALL CHFNDX
	 JRST CHALOS
	CAIE Q2,.CSOPN		;MUST BE OPENED
	 JRST CHALOS
	CALL CHIACK		;PROCESS THE ACKNOWLEDGEMENT FIELD
	HLRZ T2,CHAPKN(CONN)	;GET LAST PACKET GIVEN TO USER
	LOAD T1,CPKPN,(PKT)	; AND GET NEW PACKET'S NUMBER
	HLRZ T4,CHAWIN(CONN)	;GET WINDOW SIZE
	ADDI T4,(T2)		;FIGURE THE HIGHEST LEGAL PACKET NUMBER
	SUB T4,T1
	TRNE T4,100000		;IS THIS WITHIN THE WINDOW SIZE (T4 LEQ T1)?
	 JRST [	CONPTH [20]	;NO, REMEMBER AND IGNORE THIS PACKET
		CALL CHINVT	; AFTER NOTING THAT THIS NVT MAY NEED ATTN
		JRST IGNPKT ]
	HRRZ T2,CHAIBF(CONN)	;ANY INPUT BUFFERS ASSOCIATED WITH THIS?
	JUMPN T2,[LOAD T2,CPKPN,(T2) ;YES, GET PACKET NUMBER FOR LAST ON LIST
		  JRST .+2]
	 HLRZ T2,CHAPKN(CONN)	;NO, GET LAST PACKET GIVEN TO USER
	CAIL T2,177777		;INCREMENT THIS PACKET NUMBER
	 TDZA T2,T2
	 ADDI T2,1
	CAMN T1,T2		;THIS THE NEXT PACKET IN THE SEQUENCE?
	 JRST CHIDT1		;YES, QUEUE IT ONTO THE END OF THE LIST
	SUB T2,T1
	TRNN T2,100000		;COMPARE MOD 2^16
	 JRST CHIDTD		;LAST SEEN GREATER, DISCARD DUPLICATE PKT

	MOVEI T3,0		;AT FRONT OF LIST
	HLRZ Q2,CHAPBF(CONN)	;GET FIRST PACKET IN OUT OF ORDER LIST
	JUMPE Q2,CHIDT4		;THIS IS THE FIRST

CHIDT3:	LOAD T2,CPKPN,(Q2)	;GET ITS PACKET NUMBER
	SUB T2,T1
	JUMPE T2,CHIDTD		;SAME AS THIS NEW ONE, DISCARD
	TRNN T2,100000
	 JRST CHIDT4		;T1 LESS, THIS IS WHERE IT GOES
	MOVE T3,Q2		;T2 LESS, KEEP LOOPING
	HRRZ Q2,PKTLNK(T3)
	JUMPN Q2,CHIDT3		;UNLESS REACHED END
CHIDT4:	GETPKT			;ELSE SAVE THE PACKET IF NECESSARY
	 JRST [	CONPTH [21]
		CONPTH T1	;REMEMBER THE PACKET NUMBER WHEN WE PUNTED
		RET ]		;CANNOT COPY, PUNT FOR NOW
DEBUG,<	PKTPTH [53]		;IF DEBUGGING, REMEMBER WHERE WE STARTED
	CONPTH [22]
	CONPTH T1		; AND REMEMBER THE PACKET NUMBER AT THIS POINT
>;DEBUG
	SKIPE T3
	 HRRM PKT,PKTLNK(T3)	;THREAD ONTO PREVIOUS PACKET
	SKIPN Q2
	 HRRM PKT,CHAPBF(CONN)	;THREAD ONTO BACK OF LIST
	SKIPN T3
	 HRLM PKT,CHAPBF(CONN)	;THREAD ONTO FRONT OF LIST
	HRRM Q2,PKTLNK(PKT)
	MOVSI T3,1
	ADDM T3,CHANBF(CONN)	;ONE MORE ON OUT OF ORDER LIST
	RET

;HERE IF IT GOES ONTO THE END OF THE REGULAR LIST; T2/ PACKET NUMBER.
CHIDT1:	GETPKT			;MOVE PACKET INTO RESIDENT STORAGE IF NECESSARY
	 JRST [	CONPTH [23]
		CONPTH T2
		RET ]		;CANNOT DO THE COPY, PUNT
	PKTPTH [54]		;WHEN DEBUGGING, REMEMBER OUR ROOTS
	CONPTH [24]
	CONPTH T2		;NOTE THIS PACKET NUMBER
	SKIPN CHAIBF(CONN)	;PREVIOUSLY EMPTY?
	 CALL CHAIN1		;WAKE UP FORK MAYBE
CHIDT2:	AOS CHANBF(CONN)	;ONE MORE ON IN ORDER LIST
	MOVEI Q2,CHAIBF(CONN)
	CALL CHAQPL		;PUT ONTO END OF LIST
CHIDT9:	HLRZ PKT,CHAPBF(CONN)	;GET TOP OF OUT OF ORDER LIST
	JUMPE PKT,CHINVT	;NO MORE, GO UPDATE NVT BUFFERS IF ANY
	LOAD T3,CPKPN,(PKT)	;GET ITS PACKET NUMBER
	CAIL T2,177777
	 TDZA T2,T2
	 ADDI T2,1
	CAME T3,T2		;IS THIS THE NEXT ONE TO GO?
	 JRST CHINVT		;NO, SEE IF THIS BELONGS TO AN NVT
	CONPTH [25]
	CONPTH T3
	MOVEI Q2,CHAPBF(CONN)
	CALL CHAQGF		;YES, PULL OFF OUT OF ORDER LIST
	JUMPE PKT,CHIDTB
	MOVSI T3,-1
	ADDM T3,CHANBF(CONN)	;ONE LESS ON THAT LIST
	JRST CHIDT2		;AND ONE MORE FOR IN ORDER LIST

CHIDTB:	CHABUG(CHAOOL)		;OUCH, NOT THERE NOW?  COMPLAIN
	RET			; AND GET OUT

;HERE IF HAVE TO DISCARD A PACKET, ALSO SEND RECEIPT TO STOP RETRANSMISSION SOON
CHIDTD:	AOS CHANPD		;ONE MORE PACKET DISCARDED
	CONPTH [26]
IFN SMFLG,<CALL RELPKT>		;ON KS, FREE UP THIS DISCARD
	JRST CHASTO		;AND GO MAKE SURE DO ACK

;IF THIS INPUT WAS FOR AN NVT, QUEUE UP THIS CONNECTION AS NEEDING ATTENTION
CHINVT:	LOAD T2,CHANVT,(CONN)	;GET NVT NUMBER
	CALL CHKCVT		;IS IT AN NVT?
	 JRST CHINVR		;NOPE
	SETZ T3,		;EMPTY SLOT REF EVENTUALLY
	MOVEI T1,CHATTW		;SCAN Q FOR THIS CONNECTION
CHNVT0: CAIL T1,CHATTW+NTTCVT	;CHECKED ALL OF Q?
	 JRST CHNVT2		;YES, GO STORE NEW ENTRY
	JUMPN T3,CHNVT1		;ALREADY HAVE EMPTY SLOT
	MOVE T2,(T1)		;GET THIS ELEMENT
	CAMN T2,[-1]		;END OF Q MARKER?
	 MOVEI T3,(T1)		;YES, REMEMBER IT
CHNVT1:	CAMN CONN,(T1)		;IS THIS CONNECTION ALREADY MARKED AS NEEDING HELP?
	 JRST CHINVR		;YES, NOTHING TO DO
	AOJA T1,CHNVT0		;NO, KEEP LOOKING
CHNVT2:	SKIPN T3		;NON-ZERO MEANS FOUND A FREE SLOT
	 CHABUG(CHNVBQ)		;WOW BAD Q: GIVE UP
	MOVEM CONN,(T3)		;STASH THIS NEW ELEMENT
CHINVR:	RET			;DONE

;HANDLE RECEIVED PACKET ACKNOWLEDGEMENT
CHIACK:	LOAD T2,CPKAN,(PKT)	;GET PACKET NUMBER BEING RECEIPTED
CHIAK0:	LOAD T3,CPKAN,(PKT)
	HRRZ T1,CHAACK(CONN)	;GET MAX OF THIS AND PREVIOUS ACKNOWLEDGED
	SUB T1,T3
	TRNE T1,100000
	 HRRM T3,CHAACK(CONN)
	PUSH P,PKT
	HLRZ PKT,CHAOBF(CONN)	;GO DOWN CONNECTION SEND LIST
	JUMPE PKT,CHIAK2
CHIAK1:	CHKPKT			;VALIDATE PACKET IF DEBUGGING
	LOAD T1,CPKOP,(PKT)	;GET OPCODE
	CAIE T1,.CORFC		;RFC OR
	 CAIN T1,.COOPN		;OPN THAT WE ARE RETRANSMITTING?
	 JRST CHIAK3		;YES, CAN FLUSH IT NOW
	LOAD T1,CPKPN,(PKT)	;GET THIS PACKET'S NUMBER
	SUBM T2,T1
	TRNE T1,100000
	 JRST CHIAK2
CHIAK3:	HRRZ Q2,PKTLNK(PKT)	;GET NEXT PACKET
	HLLOS PKTLNK(PKT)	;MARK PKT AS NOT ON ANY SEND LIST
	RCALL RELPKM,14		;RELEASE PACKET IF NOT BEING SENT NOW
CHIAK4:	HRLM Q2,CHAOBF(CONN)
	SKIPE PKT,Q2
	 JRST CHIAK1		;KEEP TRYING REST OF SEND LIST
	SETZM CHAOBF(CONN)	;NOTHING ON SEND LIST NOW
CHIAK2:	MOVE T2,CHANOS(CONN)	;GET PREVIOUS STATE
	HRRZ T3,CHAACK(CONN)
	HRRZ Q2,CHAPKN(CONN)
	SUB T3,Q2
	SKIPLE T3
	 SUBI T3,200000
	ADD T3,CHAWIN(CONN)
	HRREM T3,CHANOS(CONN)
	JUMPG T2,CHIAK5		;ALREADY HAD WINDOW?
	LOAD T1,CHAOCN,(CONN)
	SKIPLE CHANOS(CONN)	;AND SOME NOW?
	 CAIL T1,^D36
	 JRST CHIAK5		;SKIP IT
	MOVX T1,CF%OIN		;GENERATE OUTPUT INTERRUPT
	IORM T1,CHASTA(CONN)	;NOTE THIS NEED
	MOVX T1,CH%OIN		; AND TELL BACKGROUND FORK THERE'S WORK HERE
	IORM T1,CHAFLG
CHIAK5:	POP P,PKT
	RET

;FIND INDEX FOR THIS CONNECTION INTO CONN, STATE INTO Q2
CHFNDX:	MOVEI T2,[ASCIZ /Connection does not exist at this end/] ;HANDY MESSAGE
	LOAD CONN,CPKD1,(PKT)	;GET DESTINATION INDEX
	CAIGE CONN,MAXCON	;WITHIN RANGE
	 SKIPL CONN,CHACON(CONN) ;AND IN USE
	 RET			;NO, FAIL
	HRRZS CONN		;CLEAR OUT UNIQUIZER
	CHKCON			;VALIDATE IT IF DEBUGGING, REGARDLESS OF OUTCOME
	HRRZ Q2,CHASTA(CONN)
	MOVE T1,CHPKS(PKT)
	MOVE T3,CHPKD(PKT)
	CAIN Q2,.CSRFS		;IF IN RFC SENT, DONT CARE ABOUT INDEX
	 AND T1,[BYTE (16) -1, 0]
	CAMN T3,CHALCL(CONN)	;LOCAL AND
	 CAME T1,CHAFRN(CONN)	;FOREIGN THE SAME?
	 RET			;NO, NO GOOD
	MOVE T1,TODCLK
	MOVEM T1,CHAITM(CONN)	;TIME OF LAST INPUT ON THIS CONNECTION
	MOVEI T2,[ASCIZ /Connection not in right state at this end/]
	RETSKP			;OK, BUT HANDY MESSAGE IN T2 IF ANYONE NEEDS IT

	SUBTTL	PACKET MUNGING SUPPORT

;GET STORAGE FOR PACKET, OPCODE IN Q2; WHEN DEBUGGING, REASON IS IN CX
ASGPKI:	ADD T1,[.RESP1,,CHPKDT+PKTHLN] ;ASSIGN A PACKET AT INTERRUPT LEVEL
	JRST ASGPK2		; WITH LENGTH IN T1
ASGPK0:	TDZA T1,T1		;NO DATA NEEDED
ASGPKC:	 MOVE T1,CHPMXW		;MAXIMUM NUMBER OF WORDS OF DATA
ASGPK1::ADD T1,[.RESP3,,CHPKDT+PKTHLN]	;PACKET HEADER PLUS HEADER WORDS
ASGPK2:	MOVEI T2,.RESNP		;FROM THE NETWORK POOL
DEBUG,<	PUSH P,CX >		;SAVE REASON CODE (FOR WHEN DEBUGGING)
	CALL ASGRES
	 JRST [	DEBUG,<ADJSP P,-1> ;IF DEBUGGING, FLUSH REASON
		RET ]		;FAIL RETURN
	MOVEI PKT,PKTHLN(T1)	;RETURN ADDRESS OF PACKET IN PKT
	SETOM PKTLNK(PKT)	;NOT ON ANY TRANSMIT QUEUES YET
	MOVE T1,TODCLK		;SET IN PACKET-CREATION TIME
	MOVEM T1,PKTTIM(PKT)
	STOR Q2,CPKOP,(PKT)	;SET IN OPCODE GIVEN
DEBUG,<	MOVE T1,[CHSMGV]	;BUILD MAGIC VALUE
	XORI T1,(PKT)		; KEYED TO CURRENT PACKET
	MOVEM T1,PKTMAG(PKT)	;SET IT
	MOVE T1,-PKTHLN-1(PKT)	;GET ASGRES HEADER WORD
	MOVEM T1,PKTHDW(PKT)	;SAVE IT HERE FOR DUAL-CHECKING
	MOVEI T1,PKTHST(PKT)	;BUILD BYTE REF TO HISTORY TRAIL
	HRLI T1,360600		; (DPB REF)
	POP P,T2		;PICK UP ASSIGN-PACKET REASON
	DPB T2,T1		; AND DROP IT IN
	IBP T1			;BUMP AND
	MOVEM T1,PKTHSP(PKT)	; SAVE REF
>;DEBUG
	RETSKP

IFN SMFLG,<
;ON KS, MAKE COPY OF PACKET ONLY IF HAVE TO; T3/ BYTE COUNT.
;ONCE COPIED, WE FREE ORIGINAL.

CPYPKI:	SAVET
	LOAD T1,CPKNB,(PKT)	;GET BYTE COUNT
	CAML T1,T3		;IF PACKET IS BIG ENOUGH
	 RETSKP			; JUST RETURN IT
	MOVE T1,T3		;ELSE, GET NUMBER OF BYTES WE NEED
	PUSH P,PKT		;SAVE ORIGINAL PACKET REF
	CALL CPYPK1		;DO THE WORK
	 CAIA
	 AOS -1(P)		;MIMIC SUCCESS
	EXCH PKT,(P)		;GET ORIGINAL PACKET AND SAVE NEW REF
	CALL RELPKT		; AND FREE UP ORIGINAL
	POP P,PKT		;GET BACK NEW PACKET REF
	RET			;RETURN SUCCESS OR FAILURE
>;IFN SMFLG,

;MAKE A COPY OF THE PACKET IN PKT IN RESIDENT STORAGE,
;SINCE IT IS JUST A DTE BUFFER NOW.  NON-SKIP RETURN ON FAILURE.

CPYPKT:	SAVET			;SAVE TEMP ACS
	LOAD T1,CPKNB,(PKT)	;GET BYTE COUNT
CPYPK1:	ADDI T1,3		;ROUND TO WORD
	LSH T1,-2		;TURN INTO INTO WORDS
	PUSH P,T1		;SAVE SIZE
	PUSH P,PKT		; AND ORIGINAL PACKET REF
	RCALL ASGPKI,37		;GET A PACKET FROM INTERRUPT-LEVEL POOL
	 JRST [	AOS CHNNRS	;JUST COUNT THESE NOW: PERFECTLY NORMAL
		JRST CPYPK9 ]
	MOVE T3,-1(P)		;GET BACK SIZE OF ORIGINAL PACKET'S DATA IN WORDS
	ADDI T3,CHPKDT-1(PKT)	; AND REF TO END OF NEW PACKET
	HRL T2,(P)		;GET BACK ORIGINAL PACKET REF AS SOURCE,,
	HRRI T2,(PKT)		; THEN ADD DESTINATION
	BLT T2,(T3)		;MOVE DATA
	AOS -2(P)		;INDICATE WINNAGE (ISN'T OBSCURITY WONDERFUL?)
CPYPK9:	ADJSP P,-2		;FLUSH TWO TEMPS
	RET			;GET OUT; SKIP OR NON-SKIP ALREADY SET

;MAKE A COPY WITH AN ASCIZ CONTACT NAME; ON KS, ORIGINAL PACKET IS FREED UP,
;UNLESS THE COPYING FAILS.
CPYPKZ:	LOAD T1,CPKNB,(PKT)	;GET BYTE COUNT
	PUSH P,T1		;SAVE FOR LATER
IFN SMFLG,<PUSH P,PKT>		;SAVE THIS PACKET REF, TOO, ON KS
	AOJ T1,			;MAKE ROOM FOR THE NULL
	CALL CPYPK1		;GO DO THIS SIZE COPY THEN
	 JRST [	ADJSP P,-1	;MIMIC FAILURE, FLUSHING TEMPS ON THE WAY
IFN SMFLG,<	POP P,PKT>
		RET]
IFN SMFLG,<			;ON KS, HAVE TO FLUSH OLD PACKET
	EXCH PKT,(P)		;SAVE AND GET OLD PACKET
	CALL RELPKT		;GET RID OF IT
	POP P,PKT		;GET BACK COPY REF
>;IFN SMFLG,
	POP P,T1		;GET BACK COUNT
IFN KLFLG!SMFLG,<
	ADJBP T1,[POINT 8,CHPKDT(PKT)] > ;REF LAST BYTE
IFN F3FLG,<
	IDIVI T1,4		;BYTES PER WORD
	ADD T1,[POINT 8,CHPKDT(PKT)]
	SOJL T2,.+3
	IBP T1
	JRST .-2
>;IFN F3FLG,
	MOVEI T2,0
	IDPB T2,T1		;APPEND A NULL TO IT
	RETSKP


;TOTALLY IGNORE AN INPUT PACKET (WHICH, ON THE KS, IS A FULL-BLOWN PACKET, AS
;ALL ARE, AND ON OTHER SYSTEMS, IS A VESTIGIAL PACKET WHICH DOESN'T NEED
;ANY FURTHER HANDLING).

IGNPKT:
IFE SMFLG,<RET>			;NOOP ON NON-KS
IFN SMFLG,<CALLRET RELPKT>	;KS NEEDS TO FREE IT UP


;RELEASE A PACKET IF IT IS NOT RETRANSMITTABLE (IE, IF NOT TRANSMITTING OR
;QUEUED UP FOR OURSELVES, AND NOT ON ANY LISTS NOW, AS INDICATED BY ITS
;LINK WORD).  IF DEBUGGING, THE REASON CODE IS IN CX.
;CALL RELPKT WHEN YOU EXPECT THE PACKET TO BE FREEABLE RIGHT NOW.

RELPKT::
DEBUG,<	PUSH P,T1
	MOVE T1,PKTLNK(PKT)	;PICK UP LINK WORD
	CAME T1,[-1,,-1]	;FREEABLE NOW?
	 CHABUG(CHANFP,<<PKT,PKTREF>>) ;NO, COMPLAIN
	POP P,T1		;GET BACK TEMP AND FALL INTO RELPKM
>;DEBUG
RELPKM::PUSH P,T1		;SAVE TEMPS
	CHKPKT			;CHECK PACKET IF DEBUGGING
	MOVE T1,PKTLNK(PKT)	;GET XMIT-ACTIVE FLAG,,LINK HALF-WORD
	CAME T1,[-1,,-1]	;IF EITHER ACTIVE OR QUEUED LOCALLY OR ON A LIST
	 JRST RELPKD		; THEN DON'T BOTHER IT: WILL GET FREED LATER
	PUSH P,T2		;SAVE FURTHER TEMPS NOW THAT WE HAVE WORK TO DO
	PUSH P,T3
	PUSH P,T4
DEBUG,<	MOVEI T3,(CX)		;GET REASON CODE
	MOVEM T3,PKTMAG(PKT)	;CLEAR OUT MAGIC AND SET IN REASON FOR RELEASE
	PKTPTH T3		;SET THIS IN ITS HISTORY, TOO
>;DEBUG
	MOVEI T1,-PKTHLN(PKT)	;POINT TO START OF ACTUAL BLOCK FOR RELRES
	SETZ PKT,		;INDICATE GONE
	CALL RELRES		;RELEASE IT
	POP P,T4		;GET BACK TEMPS
	POP P,T3
	POP P,T2
RELPKD:	POP P,T1
	RET

;SEND BACK A LOS FOR PACKET REF'ED BY PKT; ASCIZ REF TO REASON IN T2
CHALOS:	SKIPA T1,[.COLOS]
CHALS2:	 MOVEI T1,.COCLS	;RECEIVED A LOSING RFC
	MOVEI T3,100
	GETPKT T		;JUST A DTE BUFFER OR RFC PKT THAT WE SHOULD COPY
	 RET			;CAN'T?  JUST IGNORE IT THEN
	PKTPTH [55]
	STOR T1,CPKOP,(PKT)	;SETUP OPCODE FIELD
	MOVE T1,CHPKS(PKT)	;EXCHANGE SOURCE AND DESTINATION
	EXCH T1,CHPKD(PKT)
	MOVEM T1,CHPKS(PKT)
	CALL PKTSTR		;PUT THE ASCIZ STRING FROM T2 INTO THE DATA PORTION
	SETO T1,
	JRST CHAXMT		; OF THE PKT AND GO ACTUALLY SEND IT

PKTSTR:	SETZ T3,		;EVENTUAL COUNT
	TLNN T2,-1		;MIGHT BE AN 8-BIT BYTE POINTER ALREADY
	 HRLI T2,(<POINT 7,>)
	MOVE T1,[POINT 8,CHPKDT(PKT)]
PKTST1:	ILDB Q2,T2
	CAIN Q2,"_"
	 MOVEI Q2," "		;CONVERT _'S TO SPACES IN CONTACT NAMES
	IDPB Q2,T1
	JUMPE Q2,PKTST2
	AOJA T3,PKTST1
PKTST2:	STOR T3,CPKNB,(PKT)	;SETUP BYTE COUNT
	RET

;SEND A STS PACKET OR MARK FOR NETWORK FORK TO DO IT
CHASTO:	MOVEI T1,1		;JUST NEED 4 BYTES OF DATA (1 WORD)
	MOVEI Q2,.COSTS
	RCALL ASGPKI,40		;GET PACKET FROM INTERRUPT POOL
	 JRST [	MOVX T1,CF%STS	;FAILED:
		IORM T1,CHASTA(CONN) ;MARK THIS ONE AS NEEDING STS
		MOVX T1,CH%STS	;AND TELL CHAOS FORK THERE'S ANOTHER TO HANDLE
		IORM T1,CHAFLG
		RET ]
CHSTO2:	MOVEI T1,4		;FOUR BYTES OF DATA
	STOR T1,CPKNB,(PKT)
	HLRZ T1,CHAWIN(CONN)
	DPB T1,[POINT 16,CHPKDT(PKT),31] ;PUT IN THE RECEIVE WINDOW SIZE
	HLRZ T2,CHAPKN(CONN)	;GET LAST PACKET SEEN BY USER
	HRRZ T1,CHAIBF(CONN)
	SKIPE T1
	 LOAD T2,CPKPN,(T1)	;OR THAT GOT INTO THE IN-ORDER QUEUE
	DPB T2,[POINT 16,CHPKDT(PKT),15] ;STORE AWAY AS RECEIPT PACKET NUMBER
	CONPTH [30]		;WHEN DEBUGGING, REMEMBER WE SEND THIS STS
	CONPTH T2
	AOS CHNSTS		;ONE MORE STS SENT
	SETO T1,
	CALLRET SNDPK0		;AND HANDLE LIKE DATA (BUT DON'T BLOCK FOR IT)

;SEND STS OR OPN PACKET FROM PROCESS LEVEL
	SWAPCD
CHASO1:	MOVEI Q2,.COSTS
CHASO2:	HRRZ T1,CHASTA(CONN)	;MAKE SURE STILL WORTH DOING
	CAIE T1,.CSOPN
	 RET			;NOPE, JUST IGNORE
	MOVEI T1,1		;(ENTER HERE WITH Q2/ OPCODE) ONE WORD OF DATA
	RCALL ASGPK1,41		;GET A PACKET FOR THIS CONNECTION
	 RET			;FAILED, LET NORMAL MECHANISMS DO IT LATER
	MOVX T1,CF%STS		;NOTE WE'VE HANDLED THIS NEED FOR STATUS
	ANDCAM T1,CHASTA(CONN)
	JRST CHSTO2		;GO SEND IT OFF
	RESCD

;RETRANSMIT ANYTHING LYING AROUND FOR TOO LONG FOR THIS CONNECTION.
CHARTR:	HRRZ T1,CHASTA(CONN)	;MAKE SURE STILL IN VALID STATE FOR RETRANSMISSION
	CAIE T1,.CSOPN
	 CAIN T1,.CSRFS
	 CAIA
	 RET
	HLRZ PKT,CHAOBF(CONN)	;IS THERE ANY WORK HERE?
	JUMPE PKT,R		;NO
DEBUG,<	PUSH P,Q2		;COUNT OF PACKETS RE-XMITTED
	SETZ Q2,		; FOR DEBUGGING
>;DEBUG
	CALL NOSKDP		;PREVENT TAMPERING WITH QUEUE
	SETZ T1,		;LAST PACKET NUMBER WE RE-XMITTED
CHART1:	HLRZ PKT,CHAOBF(CONN)
	CAIA
CHART2:	 HRRZ PKT,PKTLNK(PKT)
	JUMPE PKT,CHARTD	;NO MORE, DONE
	CHKPKT
	LOAD T2,CPKPN,(PKT)	;GET PACKET NUMBER
	SUBM T1,T2
	TRNN T2,100000
	 JRST CHART2		;ALREADY RETRANSMITTED, TRY NEXT
	MOVE T1,PKTTIM(PKT)	;TRANSMIT TIME
	ADDI T1,^D33		;DON'T RETRANSMIT IF SENT IN LAST 30TH SEC
	HLRZ T2,PKTLNK(PKT)	;XMIT ACTIVE FLAG
	CAMGE T1,TODCLK
	 CAIE T2,-1		;IF -1, NOTHING GOING ON WITH IT (ELSE, COULD BE
				; XMIT ACTIVE, OR ROUTED TO OURSELVES LOCALLY)
	 JRST CHARTD		;FORGET IT IF TOO SOON, OR ALREADY BEING XMITTED
	PKTPTH [50]
	LOAD T1,CPKPN,(PKT)	;SAVE PACKET NUMBER
	PUSH P,T1
	SETO T1,
	CALL CHAXMT		;REXMIT IT WITHOUT BLOCKING
	SKIPE T1		;DID IT GET SENT?
	 AOS CHNRTR		;YES, ONE MORE RETRANSMISSION
DEBUG,<	AOS Q2 >
	POP P,T1		;GET BACK PACKET NUMBER
	JRST CHART1

;HERE WHEN DONE WITH RETRANSMISSION: UNLOCK AND GET OUT
CHARTD:	CALL OKSKDP		;DONE
DEBUG,<	CONPTH [31]
	CONPTH Q2
	POP P,Q2
>;DEBUG
	RET


;SEE ABOUT TELLING SOMETHING THAT THERE HAS BEEN A STATE CHANGE
;FOR THIS CONNECTION:
;   Q2/	NEW CONNECTION STATE
;RETURNS
; CONN/	0 IF IT HAS BEEN ESSENTIALLY FLUSHED, ELSE NOT CHANGED

CHAINT:	HRRM Q2,CHASTA(CONN)	;SAVE NEW CONNECTION STATE
	CONPTH [32]
	CONPTH Q2
	MOVE T1,TODCLK
	MOVEM T1,CHAITM(CONN)	;SET LAST INPUT ACTIVITY FOR THIS CONNECTION
	LOAD T2,CHANVT,(CONN)
	CAIE Q2,.CSOPN		;IS THIS ANY STATE OTHER THAN OPENED?
	 CALL CHKCVT		;AND ASSOCIATED WITH AN NVT?
	 JRST CHAIN1		;NO, SEE IF THERE IS A FORK TO INTERRUPT
	MOVX T1,CF%DIN		;YES, TELL CHAOS FORK TO DO DETACH AND FLUSH
	IORM T1,CHASTA(CONN)	
	MOVX T1,CH%DIN
	IORM T1,CHAFLG		;AND NOTE A DETACH INTERRUPT REQUEST PENDING
	SETZ CONN,		;TELL CALLER CONNECTION IS ESSENTIALLY FLUSHED
	RET

CHAIN1:	LOAD T1,CHAICN,(CONN)	;GET INTERRUPT CHANNEL
	CAIL T1,^D36
	 RET
	MOVX T1,CF%IIN		;MARK THIS CONNECTION AS NEEDING AN
	IORM T1,CHASTA(CONN)	; INPUT INTERRUPT
	MOVX T1,CH%IIN
	IORM T1,CHAFLG		;TELL BACKGROUND FORK ABOUT IT, TOO
	RET

;SEND A DATA PACKET ON CONNECTION IN CONN; RETURNS NONSKIP ON FAILURE

SNDPKT:	HRRZ T1,CHASTA(CONN)	;GET CONNECTION STATUS
	CAIE T1,.CSOPN		;OPENED?
	 JRST SNDPKE		;NO, COMPLAIN AND FAIL
	SKIPLE CHANOS(CONN)	;ROOM WITHIN WINDOW SIZE?
	 JRST SNDPKW		;YEP, GO ON
	MOVE T1,TODCLK		;NO, REMEMBER WHEN WE BLOCKED
	MOVEM T1,CHAOTM(CONN)
	MOVSI T1,(CONN)		;BLOCK UNTIL ROOM APPEARS
	HRRI T1,SNPKBT
	NOINT			;CANCEL OUT NOINT GIVEN ON UNLDIS
IFN T20FLG,<
	CALL UNLDIS		;WAIT FOR IT, LOCKED
>;IFN T20FLG
IFN TNXFLG,<
	CALL UNLCKF
	MDISMS
>;IFN TNXFLG
	HRRZ T1,CHASTA(CONN)	;CONNECTION
	CAIN T1,.CSOPN		; STILL IN VALID STATE?
	 JRST SNDPKW		;YES, GO ON, REGARDLESS OF WINDOW STATE
SNDPKE:	RCALL RELPKM,15		;RELEASE THE PACKET IF NOT OPEN
	RETBAD(CHAOX2)		;AND RETURN ERROR

SNDPKW:	AOS (P)			;CAN'T FAIL FROM THIS POINT ON; RETURN SUCCESS
	SETZ T1,		;BLOCKING IS OK FROM HERE

;SEND A DATA PACKET WITHOUT CHECKING CONNECTION STATUS OR AVAIL XMIT WINDOW;
;RETURNS NON-SKIP ALWAYS.  T1/ NON-ZERO MEANS DON'T BLOCK.
SNDPK1::HRRZ T2,CHAPKN(CONN)	;GET NEXT PACKET NUMBER TO USE
	CAIL T2,177777
	 TDZA T2,T2
	 ADDI T2,1
	HRRM T2,CHAPKN(CONN)
	STOR T2,CPKPN,(PKT)

;LIKE SNDPK1, BUT DON'T WORRY ABOUT PACKET NUMBER (EG, FOR SNS PACKETS)
SNDPK0:	MOVE T4,T1		;SAVE BLOCKING-OK ARG
DEBUG,<	MOVE T1,PKTLNK(PKT)	;MAKE SURE THIS PACKET HAS NO STRINGS ATTACHED
	CAME T1,[-1,,-1]	;SHOULD BE TOTALLY VANILLA
	 CHABUG(CHASPS,<<PKT,PKTREF>,<T1,LINK>>) ;OOPS
>;DEBUG
	HLRZ T1,CHAPKN(CONN)	;PACKET NUMBER TO ACKNOWLEDGE
	HRLM T1,CHAACK(CONN)	;REMEMBER WE DID SO
	STOR T1,CPKAN,(PKT)	;FILL IN ACK FIELD
	SETZRO CPKFC,(PKT)	;CLEAR FORWARDING COUNT
	MOVE T1,CHALCL(CONN)
	MOVEM T1,CHPKS(PKT)	;SOURCE
	MOVE T1,CHAFRN(CONN)
	MOVEM T1,CHPKD(PKT)	;DESTINATION
	LOAD T1,CPKOP,(PKT)	;GET THE OPCODE
	CAIE T1,.CORFC		;RFC AND OPN GET RETRANSMITTED
	 CAIN T1,.COOPN
	 JRST SNDPK2		; BUT DON'T COUNT TOWARD THE WINDOW
	CAIN T1,.COEOF		;AS DOES EOF
	 JRST SNDPK4
	CAIGE T1,.CODAT		; OR DATA
	 JRST SNDPK3		;NO, GUESS ONLY SEND IT ONCE THEN
SNDPK4:	SOSGE CHANOS(CONN)	;ONE LESS AVAILABLE WINDOW SLOT (DATA AND EOF ONLY)
	 SETZM CHANOS(CONN)	;DON'T LET IT DROP BELOW ZERO, THOUGH
SNDPK2:	MOVEI Q2,CHAOBF(CONN)	;PUT ONTO END OF SEND LIST
	CALL NOSKDP		;HAVE TO LOCK UP JUST IN CASE IT'S ILLEGALLY
	CALL CHAQPL		; ACKED BEFORE WE EVEN GET AROUND TO XMITTING IT
	XMOVEI T1,OKSKDP	;***KLUDGE*** UNLOCK WHEN LEAVING
	PUSH P,T1
SNDPK3:	MOVE T1,T4		;GET BACK BLOCKING-OK ARG
DEBUG,<	CALL CHAXMT		;SEND THIS PACKET OFF, WHEN DEBUGGING
	CONPTH [34]
	CONPTH T1		;REMEMBER WHAT HAPPENED
	RET
>;DEBUG

;SEND THE PACKET IN PKT; T1/ NON-ZERO MEANS JUST RETURN IF NEED TO BLOCK;
;RETURNS T1/ NON-ZERO IFF SHIPPED THE PACKET OFF SOMEWHERE.
CHAXMT:	STKVAR <CHXMNB,CHXRTM>
	MOVEM T1,CHXMNB		;SAVE ARGUMENT
	CHKPKT			;CHECK PACKET IF DEBUGGING
	PKTPTH [51]
	MOVE T1,TODCLK		;SET TIME OF LAST TRANSMISSION, EVEN IF WE DON'T
	MOVEM T1,PKTTIM(PKT)	; XMIT IT RIGHT AWAY, FOR CHECKING PURPOSES
	CALL CHXRUT		;FIND OUT HOW IT'S GOING TO BE SENT
	MOVEM T2,CHXRTM		;REMEMBER
IFN DTEFLG,<
	CAIE T2,CHXDTE		;IF NOT THROUGH FE-11,
	 JRST CHAXM1		; DON'T WORRY ABOUT -11 STATUS
	SKIPL CHNPO1		;TOO MANY PACKETS OUTSTANDING IN -11?
	 CONSZ PI,177B27	;OR PI IN PROGRESS?
	 JRST CHAXM1		;NO, ROOM EXISTS, OR AT PI LEVEL, GO ON
	SKIPN INSKED		;IF WE ARE IN THE SCHEDULER
	 SKIPE NSKED		;OR CANNOT GO BLOCKED
	 JRST CHAXM1		;SEND IT ANYWAY
	SETZ T1,		;ASSUME NOT OK
	EXCH T1,CHXMNB		;OK TO BLOCK? (SAY WE DIDN'T SEND, IF NOT)
	JUMPN T1,CHXDN1		;NOPE, GET OUT
	MOVEI T1,CHXMTT		;ELSE WAIT FOR ROOM
	HRLI T1,(PKT)		;PACKET REF IS DATA TO CHXMTT FOR TIMEOUT CHECK
	NOINT			;CANCEL OUT OKINT GIVEN IN UNLDIS
	CALL UNLDIS		;WAIT FOR ROOM TO APPEAR IN -11
	PKTPTH [52]		;REMEMBER WE WAITED FOR IT
>;IFN DTEFLG
CHAXM1:	SETZM CHXMNB		;ASSUME THE WORST ABOUT SENDING THE PACKET
	CALL NOSKDP		;LOCK UP HERE SO WE DON'T SEND AN XMIT-ACTIVE PKT
	CHKPKT			;MAKE SURE THIS PACKET IS STILL OK AFTER WAITING
	HLRZ T1,PKTLNK(PKT)
	CAIE T1,-1		;MUST BE TOTALLY QUIESCED FOR US TO DEAL W/IT
	 JRST CHXDON		;YEP, ALREADY ACTIVE IN SOME WAY, SO FORGET IT
	MOVSI T1,1
	HLLM T1,PKTLNK(PKT)	;FLAG XMIT ACTIVE NOW
	MOVE T2,CHXRTM		;GET ROUTING METHOD
	CALL (T2)		;CALL THE ROUTER WE'VE CHOSEN
	 JRST [	HRROS PKTLNK(PKT) ;FAILED: NO LONGER XMIT ACTIVE, REMEMBER THAT
		PKTPTH [56]	;(NOTE FAILURE WHEN DEBUGGING)
		JRST CHXDON ]	; AND RETURN "NOT SENT"
	SETOM CHXMNB		;ELSE, SAY WE'VE SENT THIS PACKET
CHXDON:	CALL OKSKDP		;UNLOCK
CHXDN1:	SKIPE T1,CHXMNB		;FIND OUT IF WE ACTUALLY SENT THIS PKT OR NOT
	 RET			;YES, ALL DONE
	RCALL RELPKM,22		;ELSE, THIS GUY WASN'T QUEUED TO GO, SO IF IT'S
	RET			; NO LISTS, GET RID OF IT

	SUBTTL	SNDPKT SUPPORT ROUTINES

;WAIT FOR ROOM TO APPEAR IN THE FE -11
CHXMTT::SKIPE CHAON		;NET STILL UP?
	 SKIPGE CHNPO1		;ANY ROOM IN -11?
	 JRST 1(T4)		;NO, OR YES, UNBLOCK TO DISCOVER THE TRUTH
	TCHKPK			;CHECK THIS PACKET REF IF DEBUGGING
	MOVE T2,PKTTIM(T1)	;NET UP, AND NO ROOM IN -11, GET TIME OF XMIT START
	ADDI T2,^D<5*1000>	;IF WE'RE WAITING ON THE -11 FOR THIS LONG
	CAMG T2,TODCLK
	 JRST CHXMTB
	JRST 0(T4)		;KEEP WAITING

CHXMTB:	CHABUG(CHAXOD)		;SOMETHING'S PROBABLY WRONG: COMPLAIN
	MOVE T2,TODCLK		;AND RESET THE TIME SO WE WON'T COMPLAIN TOO MUCH
	MOVEM T2,PKTTIM(T1)
	JRST 0(T4)

;DTEQ PACKET SENT TO -11 OK; IF IT ISNT ON ANY TRANSMIT LIST, IT CAN BE 
;DEALLOCATED
CHAXIN:
IFE SMFLG,<MOVEI PKT,(T1)>	;ON KS, PKT IS ALREADY PROPERLY SET UP
	PKTPTH [61]		;NOTE WE GOT HERE WHEN DEBUGGING
DEBUG,<	PUSH P,T2
	HLRZ T1,PKTLNK(PKT)	;PICK UP XMIT ACTIVE FLAG
	MOVE T2,PKTMAG(PKT)	;GET MAGIC FIELD IF DEBUGGING
	CAIE T1,1		;BETTER BE WHAT WE LEFT IT AT
	 CHABUG(CHAXIB,<<T1,WHAT>,<PKT,PKTREF>,<T2,MAGIC>>) ;NO, COMPLAIN
>;DEBUG
	HRROS PKTLNK(PKT)	;CLEAR TRANSMIT ACTIVE
	RCALL RELPKM,16
DEBUG,<	POP P,T2 >
	RET

;SCHEDULER TEST FOR WINDOW TO OPEN UP ON A CONNECTION
SNPKBT:	TCHKCN			;IF DEBUGGING, CHECK CONNECTION
	HRRZ T2,CHASTA(T1)	;GET STATE OF CONNECTION
	CAIE T2,.CSOPN		;VERIFY STILL OPENED
	 JRST 1(T4)
	SKIPLE CHANOS(T1)	;ANY WINDOW AVAILABLE?
	 JRST 1(T4)		;YES, UNBLOCK
	MOVE T2,TODCLK		;NO, GET NOW
	SUB T2,CHAOTM(T1)	;FIND OUT HOW LONG WE'VE BEEN WAITING
	CAIL T2,^D<10*1000>	;IF OVER SOME RATHER LONG TIME,
	 JRST 1(T4)		; UNBLOCK TO SEND OVER WINDOW
	JRST 0(T4)		;ELSE, KEEP WAITING

	SUBTTL	ROUTING SUPPORT

;CHOOSE A ROUTING METHOD; RETURNS T2/ ROUTINE TO USE
CHXRUT:	SETZ T2,		;ASSUME NORMAL (THROUGH FE -11) ROUTING
IFN ARPAF,<			;166
	LOAD T1,CPKDS,(PKT)	;GET DESTINATION SUBNET
	CAIG T1,MAXSBN		;RANGE CHECK
	 HLRZ T2,SBNRUT(T1)	;OK, GET ROUTING METHOD
>
	LOAD T1,CPKDA,(PKT)	;BUT ALSO CHECK DESTINATION HOST ADDRESS
	CAMN T1,MYCHAD		;IS IT I?
	 MOVEI T2,CHXLCL	;YES, SEND LOCALLY
	SKIPN T2		;ANY ROUTING CHOSEN YET?
	 MOVEI T2,CHXNOR	;NO, GO THROUGH NORMAL ROUTE
	TLZ T2,-1		;MAKE SURE NO SECTION FUNNINESSES
	RET

;ROUTE TO OURSELVES; DON'T EVEN HACK ANY HARDWARE (LET BACKGROUND FORK DO IT)
CHXLCL:	AOS CHNPOL		;COUNT THIS LOCAL ROUTING
	PKTPTH [57]
	HRRZS PKTLNK(PKT)	;THIS WILL BE THE END OF LOCAL-Q LIST
	HRRZ T1,CHQLCL		;GET CURRENT TAIL
	HRRM PKT,CHQLCL		; AND MAKE THIS THE NEW TAIL
	JUMPN T1,[HRLM PKT,PKTLNK(T1) ;IF NON-NIL OLD TAIL, MAKE IT REF NEW TAIL
		  JRST .+2]
	 HRLM PKT,CHQLCL	;ELSE, WAS EMPTY, ON BOTH ENDS, MAKE IT TAIL, TOO
	RETSKP			;NO PROBLEMS


IFN DTEFLG,<
;ROUTE NORMALLY THROUGH THE (PRIMARY OR SECONDARY) FRONT END
CHXNOR:
CHXDTE:	SKIPN CHAON		;IF NETWORK ISN'T UP,
	 RET			; THIS IS FUTILE, FAIL RETURN
	AOS CHANPO		;ONE MORE PACKET REALLY OUTPUT TO -11
	AOSLE CHNPO1		;ONE MORE PACKET OUTSTANDING IN -11
	 JRST [	SETZM CHNPO1	;OOPS, WENT TOO FAR: PUT IT BACK
		AOS CHANOL	;COUNT OVERESTIMATIONS
		RET ]		; AND FAIL RETURN TO SAY WE DIDN'T SEND IT
	PKTPTH [60]		;REMEMBER WE'VE BEEN HERE
	MOVE T1,TODCLK		;SET TIME OF LAST REAL
	MOVEM T1,PKTTIM(PKT)	; XMISSION FOR RE-XMISSION CHECKING
	PUSH P,F
	MOVEI F,(PKT)		;UNIQUE CODE IS PACKET POINTER
	MOVSI A,CHAXIN		;WHERE TO GO WHEN -11 GETS IT
	LOAD C,CPKNB,(PKT)	;BYTE SIZE
IFE CHADTE,<
	ADDI C,CHPKDT*4+3	;PLUS PACKET HEADER
	TRZ C,3			;MAKING EVEN NUMBER OF WORDS
	MOVE B,[.DFHSD,,.FECHA]
	MOVEI D,(PKT)
	HRLI D,(<POINT 8,>)
>;IFE CHADTE
IFN CHADTE,<
	ADDI C,<CHPKDT-PKTTYP>*4+3 ;PLUS PACKET HEADER AND INTERNAL HEADER
	TRZ C,3			;MAKING EVEN NUMBER OF WORDS
	LSH C,-1		;MAKE 16 BIT BYTE COUNT
	HRRI A,CHADTE		;DTE NUMBER TO SEND TO
	MOVEI B,PKTTYP(PKT)
	SETZM (B)		;CLEAR TYPE FIELD
	HRLI B,(<POINT 16,>)
>;IFN CHADTE
	CALL DTEQ
	 SKIPA			;I GUESS WILL RETRANSMIT SOMETIME SOON IF NECESSARY
	 AOS -1(P)		;WORKED: RETURN SUCCESS
	POP P,F
	RET

>;IFN DTEFLG

IFN ARPAF,<
;ROUTING TABLE: ROUTING ROUTINE,,GATEWAY HOST (IF ANY)

SBNRUT:	CHXNOR,,0		;SUBNET 0, NOT USED
	CHXDTE,,0		;SUBNET 1, MAIN CAMPUS LOOP
	CHXDTE,,0		;SUBNET 2, ETHERNET
	CHXDTE,,0		;SUBNET 3, MC
	CHXDTE,,0		;SUBNET 4, AI
	CHXDTE,,0		;SUBNET 5, XX
	CHXDTE,,0		;SUBNET 6, 9TH FLOOR OF TECH SQUARE
	CHXNOR,,0		;SUBNET 7, NOT USED
	CHXDTE,,0		;SUBNET 10, LCSNET
	CHXIMP,,0		;SUBNET 11, ARPANET
	        0		;SUBNET 12, NOT USED
	CHXDTE,,0		;SUBNET 13, EECS
	REPEAT 4,<0>		;SUBNETS 14-17 NOT USED
	REPEAT 14,<CHXIMI,,225>	;SUBNETS 20-33, LLL
	REPEAT 4,<0>		;SUBNETS 34-37 NOT USED
MAXSBN==.-SBNRUT-1

;ROUTE TO SUBNET THROUGH ARPANET HOST
CHXIMI:	LOAD T1,CPKDS,(PKT)	;GET DESTINATION SUBNET
	SKIPA T1,SBNRUT(T1)	;GET GATEWAY ADDRESS FOR THAT
CHXIMP:	 LOAD T1,CPKDA,(PKT)	;GET DESTINATION ADDRESS
	HRLZM T1,PKTIMP(PKT)	;SAVE AWAY FIRST STEP DESTINATION
	PIOFF
	HLRZ T1,CHARPQ		;END OF ARPANET QUEUE
	JUMPE T1,[HRRM PKT,CHARPQ ;HEAD OF QUEUE TOO IF EMPTY
		  JRST .+2]
	HRRM PKT,PKTIMP(T1)	;LINK IN
	HRLM PKT,CHARPQ		;TAIL OF QUEUE
	PION
	RETSKP			;ALL DONE FOR NOW
>;IFN ARPAF,

;PUT PACKET AS FIRST ON Q
CHAQPF:	CALL NOSKDP
	CHKPKT			;CHECK IF DEBUGGING
DEBUG,<	CALL CHAQCK		;CHECK Q HEADER FOR VALIDITY
	 JRST OKSKDP		;NO GOOD, GET OUT
>;DEBUG
	HLRZ T1,(Q2)		;GET PRESENT HEAD
	HRRM T1,PKTLNK(PKT)	;PUT AS SECOND
	HRLM PKT,(Q2)		;PUT US AS HEAD
	SKIPN T1		;AND IF EMPTY
	 HRRM PKT,(Q2)		;AS TAIL TOO
	JRST OKSKDP

;PUT AS LAST ON Q
CHAQPL:	CALL NOSKDP
	CHKPKT			;CHECK PKT IF DEBUGGING
DEBUG,<	CALL CHAQCK		;CHECK Q HEADER
	 JRST OKSKDP		;NO GOOD, JUST GET OUT
>;DEBUG
	HLLZS PKTLNK(PKT)	;THIS WILL BE THE END OF A LIST
	HRRZ T1,(Q2)
	HRRM PKT,(Q2)
	JUMPN T1,[HRRM PKT,PKTLNK(T1)
		  JRST OKSKDP]
	HRLM PKT,(Q2)		;WAS EMPTY, ON BOTH ENDS
	JRST OKSKDP

;GET FIRST OFF LIST
CHAQGF::CALL NOSKDP
DEBUG,<	CALL CHAQCK		;CHECK Q HEADER
	 JRST [	SETZ PKT,	;NO GOOD, RETURN NIL PKT REF
		JRST CHAQG0 ]	;JOIN EXIT CODE
>;DEBUG
	HLRZ PKT,(Q2)
	JUMPE PKT,CHAQG0
	HRRZ T1,PKTLNK(PKT)
	HLLOS PKTLNK(PKT)	;MARK AS NOT ON ANY LIST
	HRLM T1,(Q2)
	JUMPN T1,CHAQG0
	SETZM (Q2)		;NOW EMPTY
CHAQG0:	JRST OKSKDP

;FREE RESIDENT BUFFERS
CHALFR:	CALL CHAQGF		;GET FIRST FROM LIST
	JUMPE PKT,R
	RCALL RELPKT,17
	JRST CHALFR

;FREE RESIDENT OUTPUT BUFFERS, BUT NOT ANY THAT ARE XMIT ACTIVE
CHALFO:	MOVEI Q2,CHAOBF(CONN)
CHALF1:	CALL CHAQGF		;GET FIRST FROM LIST
	JUMPE PKT,R		;END OF LIST
	RCALL RELPKM,20		;FREE PACKET
	JRST CHALF1

;LOCK OUT SCHEDULING AND PI INTERRUPTS; CAN BE CALLED NESTEDLY.
NOSKDP:	AOSG CHPIDF		;IF ALREADY ACTIVE OR
	 CONSZ PI,177B27	; IF AT PI LEVEL, DO NOTHING
	 RET
	NOSKD1			;NO SCHEDULING PLEASE (CAN BE IN SCHEDULER)
IFGE CHACHN,<
	CONSO PI,1B<28+CHACHN>
	 JRST [ SETZM CHPIOF
		RET ]
	SETOM CHPIOF		;REMEMBER WE CHNOFF'ED
	CHNOFF CHACHN
>;IFGE CHACHN,
	RET

OKSKDP:	SOSGE CHPIDF		;LEAVING THIS LEVEL OF LOCKING; IF STILL NESTED
	 CONSZ PI,177B27	; OR IF AT PI LEVEL,
	 RET			; DO NOTHING
	OKSKD1
IFGE CHACHN,<
	SKIPE CHPIOF		;DID WE DO A CHNOFF?
	 CHNON CHACHN		;YES, RESTORE STATE
>;IFGE CHACHN,
	RET

	SUBTTL	ARPANET ROUTING SUPPORT
IFN ARPAF,<			;166

;GET NEXT ENTRY FOR CHAOSNET ARPANET OUTPUT QUEUE
; RETURNS +1 QUEUE EMPTY
; +2 IMP BUFFER POINTER IN A

CHRIMQ::HRRZ A,CHARPQ
	JUMPE A,R		;NONE, RETURN EMPTY
	HRRZ B,PKTIMP(A)	;GET LINK
	JUMPE B,[SETZM CHARPQ	;WAS END, QUEUE NOW EMPTY
		  JRST .+2]
	HRRM B,CHARPQ		;NEW HEAD OF QUEUE
	HLRZ C,PKTIMP(A)	;GET ARPANET DESTINATION ADDRESS
	MOVEI A,PKTIMP(A)	;POINT TO IMP HEADER
	SETZM .NBLD0(A)		;CLEAR SPACE FOR THE 96 BIT LEADER
	SETZM .NBLD1(A)
	SETZM .NBLD2(A)
	MOVEI B,ITY%LL		;SET LONG LEADER FLAG
	STOR B,IHFTY,(A)
	MOVEI B,HTY%NP		;SET CONNECTION SIZE
	STOR B,IHHTY,(A)
	MOVEI B,(C)		;DESTINATION
	ANDI B,77		;SIX BITS OF IMP
	STOR B,IHIMP,(A)
	LSH C,-6
	ANDI C,3		;TWO BITS OF HOST
	STOR C,IHHST,(A)
	MOVEI B,CHSLNK		;LINK
	STOR B,IHLNK,(A)
	LOAD B,CPKNB,-PKTIMP(A)	;GET BYTE COUNT
	ADDI B,3+<CHPKDT-PKTIMP>*4 ;INCLUDE LENGTH OF HEADER
	LSH B,-2		;INTO WORDS
	STOR B,NBBSZ,(A)	;AND STORE
	RETSKP

;MESSAGE DONE TO ARPANET INTERFACE
CHIMDN::PUSH P,PKT
	MOVEI PKT,-PKTIMP(A)	;IF NOT RETRANSMITTABLE
	HRROS PKTLNK(PKT)	;CLEAR TRANSMIT ACTIVE
	RCALL RELPKM,21		;CAN DEALLOCATE IT NOW
POPPKJ:	POP P,PKT
	RET

;INPUT MESSAGE FROM THE ARPANET, MAY BE IN NON-ZERO SECTION, SO
;WE CANNOT JUST CALL CPYPKT
CHIIMP::PUSH P,PKT
	MOVE T2,IMIB		;GET POINTER TO IMP BUFFER
	ADDI T2,.NBHHL		;POINT TO ACTUAL DATA
	LOAD T1,CPKNB,(T2)	;GET BYTE COUNT
	ADDI T1,CHPKDT*4+3	;PLUS PACKET HEADER
	LSH T1,-2		;TURN INTO WORDS
	MOVEI T3,CHATPB		;THIS TEMP PACKET IS THE DESTINATION
	MOVEI PKT,(T3)		; AND LEAVE HERE FOR CHIPKT
	HRRZ T4,IMPINP		;GET NEXT WORD TO READ
	SUB T4,T2		;FIGURE LENGTH TO IMP
	ANDI T4,-1		;ONLY RH MEANINGFUL
	CAMG T1,CHPMXW		;COMPARE SIZE AGAINST MAXIMUM
	 CAILE T1,(T4)		;COMPARE THE TWO SIZES
	 JRST POPPKJ		;BAD, FLUSH IT
	CALL XBLTA		;COPY IN THE PACKET FROM IMP BUFFER
	PUSH P,CONN		;PRESERVE CONN HERE
	SE0ENT			;MAKE LIFE EASIER ON DTE CODE
	CALL NOSKDP		;LOCK THINGS APPROPRIATELY FOR CHIPKT
	CALL CHIPKT		;PROCESS INPUT OF IT
	CALL OKSKDP		;UNLOCK
	SE1ENT			;BACK TO SECTION 1 FOR IMP CODE
	POP P,CONN
	JRST POPPKJ
>;166 IFN ARPAF

	SUBTTL DEBUGGING SUPPORT

DEBUG,<

;CHECK THE CONNECTION REF'ED BY CONN FOR VALIDITY (USING MAGIC VALUE)
CHKCNB:	PUSH P,T2
	PUSH P,T1		;GET WORK REGISTERS
	MOVE T2,-2(P)		;GET CALLER'S ADDRESS+1
	MOVE T1,CONMAG(CONN)	;GET MAGIC VALUE
	XORI T1,(CONN)		;TURN BACK INTO VANILLA MAGIC VALUE, HOPEFULLY
	CAME T1,[CHSMGV]	;IS IT OK?
	 CHABUG(CHABDC,<<CONN,CONREF>,<T2,WHERE>>) ;NO, COMPLAIN LOUDLY
	POP P,T1
	POP P,T2
	RET


;CHECK PACKET REF'ED BY PKT FOR VALIDITY
CHKPKB:	PUSH P,T2
	HRRZ T2,-1(P)		;GET CALLER'S ADDRESS+1 (NO SECTION, FLAGS)
	SOS T2			; BUMP BACK TO CHKPKB CALL POINT
	PUSH P,T1
	PUSH P,T3
	PUSH P,T4
	PUSH P,Q2
	MOVE T1,PKTMAG(PKT)	;GET KEYED MAGIC VALUE
	MOVE T4,PKTLNK(PKT)	;GET THIS FOR LATER REPORTING
	MOVE Q2,PKTHDW(PKT)	;GET PURPORTED ASGRES HEADER WORD
	MOVE T3,T1		;SAVE IT HERE
	XORI T1,(PKT)		;TURN BACK INTO VANILLA VERSION
	CAMN Q2,-PKTHLN-1(PKT)	;IS THE HEADER WORD OK
	 CAME T1,[CHSMGV]	; AND THE MAGIC VALUE OK?
	 CHABUG(CHABDP,<<PKT,PKTREF>,<T2,WHERE>,<T3,WHY>,<T4,LINKS>>) ;NO TO EITHER
	HLRZ T1,T4		;CHECK LH OF LINK WORD
	CAIE T1,-1		;THIS IS OK (INACTIVE)
	 CAIN T1,0		;AS IS THIS (END OF LOCAL-Q LIST)
	 JRST CHKPBN
	CAIN T1,1		;THIS IS OK (XMIT ACTIVE)
	 JRST CHKPBN
	CAIL T1,RESFRP		;ELSE, MUST BE REF: CHECK RES FREE POOL
	 CAILE T1,RESFRZ	; BOUNDS
	 JRST CHKPBE		;OUCH, NO GOOD: COMPLAIN
CHKPBN:	HRRZ T1,T4		;NOW, CHECK RH
	CAIE T1,-1		;THIS IS OK (INACTIVE)
	 CAIN T1,0		;AS IS THIS (END OF SOME LIST)
	 JRST CHKPBD
	CAIL T1,RESFRP		;ELSE, MUST BE REF: CHECK W/IN FREE POOL
	 CAILE T1,RESFRZ	; BOUNDS
CHKPBE:	 CHABUG(CHABDR,<<PKT,PKTREF>,<T2,WHERE>,<T3,WHY>,<T4,LINKS>>) ;BAD, BARF
CHKPBD:	POP P,Q2
	POP P,T4		;GET BACK TEMPS
	POP P,T3
	POP P,T1
	POP P,T2
	RET


;MAKE SURE WE'RE LOCKED UP: EITHER AT PI LEVEL OR HAVE CALLED NOSKDP.
CHKLCK:	SKIPGE CHPIDF		;HAS NOSKDP BEEN CALLED?
	 CONSZ PI,177B27	;NO, AT PI LEVEL?
	 RET			;YES, WE'RE LOCKED UP
	CHABUG(CHALCK)		;OOPS, UNPROTECTED
	RET


;SET UP A PACKET HISTORY PATH ENTRY (CX HAS ENTRY)
PKTPTS:	PUSH P,CX		;SAVE THIS OVER POTENTIAL NOSKD1 CALL
	CALL NOSKDP		;DON'T LET ANYONE ELSE HACK THIS
	POP P,CX
	DPB CX,PKTHSP(PKT)	;DROP THIS IN
	IBP PKTHSP(PKT)		;BUMP TO NEXT
	HRRZ CX,PKTHSP(PKT)	;PICK UP HISTORY BYTE REF (ADDRESS ONLY)
	CAIL CX,PKTHSP(PKT)	;IF WE'VE GOTTEN TO THE BOTTOM,
	 JRST [	MOVEI CX,PKTHST(PKT) ;WRAP AROUND
		HRLI CX,360600
		MOVEM CX,PKTHSP(PKT) ;RESET IT TO TOP
		JRST .+1 ]
	CALLRET OKSKDP		;UNLOCK AND GET OUT


;SET UP A CONNECTION HISTORY ENTRY
CONPTS:	PUSH P,CX		;SAVE THIS OVER NOSKD1 CALL
	CALL NOSKDP		;DON'T LET ANYONE ELSE HACK THIS
	POP P,CX
	DPB CX,CONHSP(CONN)	;DROP THIS IN
	IBP CONHSP(CONN)	;BUMP TO NEXT
	HRRZ CX,CONHSP(CONN)	;PICK UP HISTORY BYTE REF (ADDRESS ONLY)
	CAIL CX,CONHSP(CONN)	;IF WE'VE GOTTEN TO THE BOTTOM,
	 JRST [	MOVEI CX,CONHST(CONN) ;WRAP AROUND
		HRLI CX,331100
		MOVEM CX,CONHSP(CONN) ;RESET IT TO TOP
		JRST .+1 ]
	CALLRET OKSKDP		;UNLOCK AND GET OUT


;CHECK A PACKET QUEUE HEADER TO MAKE SURE IT'S NOT MARKED AS INACTIVE
CHAQCK:	MOVE T1,(Q2)		;GET HEADER WORD
	SKIPN T1		;OK IF NOTHING THERE
	 RETSKP
	CAME T1,[-1]		;MARKED AS EMPTY?
	 JRST [	HLRZ T1,(Q2)	;NO, PICK UP FIRST
		TCHKPK		; AND MAKE SURE IT'S OK
		HRRZ T1,(Q2)	;AND LAST
		TCHKPK
		RETSKP ]	;OK, ANYWAY
	CHABUG(CHAQHI)		;YES, COMPLAIN
	RET			;FAIL RETURN

IFN T20FLG,<TNXEND>
	END
