;;; Copyright (c) 1999 Massachusetts Institute of Technology
;;; See the COPYING file at the top-level directory of this project.

IFE IMPP, IFE CH11P, .ERR NOT EVERYTHING IN CHAOS WILL WORK WITHOUT IMP
IFNDEF FTRCHK, FTRCHK==0 ;PROBABLY FOUND ALL THE BUGS THIS WAS GOOD FOR
			 ; LONG AGO
IFN FTRCHK, .ERR REDUNDANT CHECKING ENABLED IN CHAOS ROUTINES

;NOTES:
; WINDOW SIZE ADJUSTMENT STUFF
; ROUND TRIP TIME MEASUREMENT & OTHER METERING
; BETTER METERING, SOME METERS ARE CURRENTLY MISSING

SUBTTL CH-10 HARDWARE DEFINITIONS

IFN CH10P,[
CHX==470	;I/O DEVICE NUMBER

;CONI/CONO BITS
		;1.1-1.3 PIA
CHXTEN==10	;1.4 TRANSMIT INTERRUPT ENABLE
CHXREN==20	;1.5 RECEIVE INTERRUPT ENABLE
CHXSPY==40	;1.6 MATCH ANY DESTINATION
CHXLUP==100	;1.7 LOOP BACK
CHXSWB==200	;1.8 SWAP BYTES
CHXHLF==400	;1.9 HALFWORD DATAO
CHXXMT==1000	;2.1 TRANSMIT DONE (CONI)
		;    TRANSMIT OR RETRANSMIT PACKET (CONO)
CHXRCV==2000	;2.2 RECEIVE DONE (CONI)
		;    ENABLE TO RECEIVE NEXT PACKET (CONO)
CHXABT==4000	;2.3 TRANSMIT ABORTED (CONI)
		;    RESET TRANSMITTER (CONO)
$CHXLC==140400	;2.4-2.7 LOST COUNT (CONI)
CHXRST==10000	;2.4 RESET (CONO)
CHXCRC==200000	;2.8 CRC ERROR (CONI)
CHXWLE==400000	;2.9 WORD LENGTH ERROR (CONI)
CHXPLE==1,,	;3.1 PACKET LENGTH ERROR (CONI)
CHXOVR==2,,	;3.2 OVERRUN (CONI)
$CHXAD==242000	;3.3-4.9 CHAOSNET ADDRESS (CONI)
];CH10P

IFN CH11P,[
$INSRT KSNET
];CH11P

SUBTTL CHAOS NET VARIABLES

EBLK

$CHXRI==001200		;REAL INDEX PART (LOW TEN BITS) -  IS IN LH(IOCHNM)
$CHXUN==120600		;UNIQUIZATION PART (TOP SIX BITS)
CHXMUN==1_6-1		;MAXIMUM VALUE OF UNIQUIZER
MXWIND==100		;MAXIMUM WINDOW SIZE (8K WORDS)
.SEE MYCHAD		;SUBNET AND HOST OF MYSELF
.SEE DLCP		;1 MEANS USE DL10 TO GET TO CHAOS NET
.SEE T11CHP		;1 MEANS USE TEN-11 INTERFACE TO GET TO CHAOS NET
.SEE CH10P		;1 MEANS USE CH10 HARDWARE TO GET TO CHAOS NET
.SEE CH11P		;1 MEANS USE UNIBUS CHAOSNET HARDWARE ON KS10

;Internet address of my Chaosnet Interface
.SEE IMPUS4		; Should now be defined in CONFIG >
;IMPUS4==<.BYTE 4 ? 0 ? .BYTE 8 ? 128. ? 31. ? .BYTE 16. ? MYCHAD>

;PER-INDEX VARIABLES

CHSUSR:	REPEAT NINDX,-1		;-1 INDEX NOT IN USE
				;OTHERWISE RH USER
 $CHSUO==220600			;3.1-3.6 OUTPUT CHANNEL NUMBER (77=IOPUSHED)
 $CHSUI==300600			;3.7-4.3 INPUT CHANNEL NUMBER (77=IOPUSHED)
				;4.9 ZERO IF IN USE

CHSSTA:	REPEAT NINDX,-1		;RH STATE, LH FLAGS
 %CF==525252(1)
 %CFOFF==400000	;SIGN BIT MEANS TURNED OFF AT PI LEVEL, NO TALKING TO NETWORK
 %CFSTS==200000 ;SEND STS PACKET AS SOON AS POSSIBLE (1/2 SECOND CLOCK)
 %CFCLS==100000	;HALF-CLOSED FLAG
 %CFSTY==040000 ;DIRECT-CONNECTED TO STTY FLAG
 $CFTTN==220600	;TTY NUMBER OF STTY CONNECTED TO

 %CS==,,-1
   .SEE %CSCLS	;FOR SYMBOLS FOR STATES

CHSNBF:	BLOCK NINDX		;LH LENGTH(CHSPBF), RH LENGTH(CHSIBF)
CHSNOS:	BLOCK NINDX		;NUMBER OF FREE OUTPUT SLOTS IN THE WINDOW
CHSIBF:	BLOCK NINDX		;RECEIVE BUFFER POINTERS FIRST,,LAST
CHSPBF:	BLOCK NINDX		;OUT OF ORDER RECEIVE BUFFER POINTERS FIRST,,LAST
CHSOBF:	BLOCK NINDX		;TRANSMIT BUFFER POINTERS FIRST,,LAST
CHSITM:	BLOCK NINDX		;TIME OF LAST INPUT FROM NET
CHSWIN:	BLOCK NINDX		;WINDOW SIZE RECEIVE,,TRANSMIT
CHSPKN:	BLOCK NINDX		;LAST PACKET# GIVEN TO USER,,LAST PACKET# SENT BY USER
CHSACK:	BLOCK NINDX		;LAST PACKET# ACKNOWLEDGED RECEIVE,,TRANSMIT (START OF WINDOW)
CHSLCL:	REPEAT NINDX,<.BYTE 16. ? MYCHAD ? 100000+.RPCNT>
				;BYTE (16) LOCAL HOST, LOCAL INDEX (4) 0
				;NOTE THIS SAVES THE UNIQUIZER BITS FOR THIS INDEX
CHSFRN:	BLOCK NINDX		;BYTE (16) FOREIGN HOST, FOREIGN INDEX (4) 0
;THESE FOUR ARE FOR BYTE-STREAM I/O
CHSOBP:	BLOCK NINDX		;BYTE PNTR TO OUTPUT BUFFER, 0 IF NONE
CHSOBC:	BLOCK NINDX		;BYTE COUNT, NUMBER OF BYTE SPACES LEFT IN OUTPUT BUFFER
CHSIBP:	BLOCK NINDX		;BYTE PNTR TO INPUT BUFFER, 0 IF NONE
CHSIBC:	BLOCK NINDX		;BYTE COUNT, NUMBER OF VALID BYTES REMAINING IN INPUT BUFFER

CHAOSW:	-1 ? 0	;SWITCH FOR ALLOCATING INDICES
CHALCP:	0	;LAST INDEX ALLOCATED, USED TO CIRCULARIZE ALLOCATION

CHIRFJ:	SIXBIT/CHAOS/ ? 0	;AGENT OF CHAOS
.SEE NETUSW ;NON-ZERO ENABLES RFC'S FROM HOSTS OTHER THAN SELF.

;METERS

CHNPI:	0	;NUMBER OF PACKETS INPUT (REALLY TO 10)
CHNPO:	0	;NUMBER OF PACKETS OUTPUT (ALL CAUSES)
CHNPF:	0	;NUMBER OF PACKETS FORWARDED 
CHNSTS:	0	;NUMBER OF STS PACKETS OUTPUT
CHNSNS:	0	;NUMBER OF SNS PACKETS OUTPUT
CHNRTR:	0	;NUMBER OF RETRANSMITTED PACKETS OUTPUT
CHNPFL:	0	;NUMBER OF PACKETS DISCARDED (FORWARDING LOOP)
CHNPD:	0	;NUMBER OF PACKETS DISCARDED (DUPLICATES)
CHNIPI:	0	;NUMBER OF INTERNET PACKETS IN FROM CHAOSNET
CHNIPO:	0	;NUMBER OF INTERNET FRAGMENTS OUT TO CHAOSNET

;BUFFER QUEUES.  EACH HAS A ONE-WORD HEADER, WHICH IS ZERO
;IF IT IS EMPTY, OR CONTAINS FIRST,,LAST BUFFER ADDRESS.

CHQFRE:	0	;FREE LIST
CHQRFC:	0	;PENDING RFCS
CHQLSN:	0	;PENDING LISTENS
CHCLNQ:	0 .SEE CHCLN

CHFRBF:	0	;NUMBER OF FREE BUFFERS
CHTTBF:	0	;TOTAL NUMBER OF BUFFERS
IF2 CHMXBF==50.*<1024./<%CPMXW+2>>	;MAX CORE FOR CHAOS NET 50K
CHMXTM:	0	;TIME OF LAST COMPLAINT ABOUT USING TOO MUCH CORE

IFN T11CHP,[
;VARIABLES FOR TEN-11 INTERFACE CONNECTING TO CHAOS NET

.SEE T11CHS	;EXEC ADDRESS OF PDP11 COMMUNICATION AREA
T11VER=T11CHS	;VERSION NUMBER
T11I10=T11CHS+1	;INIT 10
T11I11=T11CHS+2	;INIT 11
T11PRM=T11CHS+3	;.WORD BUFFER SIZE, # BUFFERS
		;THEN 4 SPARE DOUBLEWORDS
T11IBB:	T11CHS+8	;BEGINNING OF INPUT BUFFERS
T11IBE:	0		;END OF INPUT BUFFERS
T11IBP:	0		;POINTER TO NEXT INPUT BUFFER
T11OBB:	0		;BEGINNING OF OUTPUT BUFFERS
T11OBE:	0		;END OF OUTPUT BUFFERS
T11OBP:	0		;POINTER TO NEXT OUTPUT BUFFER
T11BSZ:	0		;BUFFER SIZE IN PDP10 WORDS
T11WIN:	0		;1 WINNING, -1 HAVE TOLD 11 TO INIT, 0 NOT WINNING
T11XMQ:	0		;QUEUED TRANSMISSION QUEUE
T11CKE:	0		;COUNT OF CHECKSUM ERRORS
;THE FIRST 32-BIT WORD OF A BUFFER IS 0 IF IDLE, OR
;NON-ZERO IF BUFFER IS TO BE SENT TO OTHER MACHINE.
;THE SECOND 32-BIT WORD IS THE CHECKSUM, WHICH IS
;COMPUTED BY ADDING ALL THE 32-BIT WORDS, IGNORING OVERFLOW,
; AND LOGICALLY SHIFTING RIGHT ONE BIT AFTER EACH ADD; BITS SHIFTED
; OUT ON THE RIGHT ARE BROUGHT BACK IN ON THE LEFT.
;IF THE NUMBER OF 16-BIT WORDS IS ODD, THE LEFT-OVER ONE BETTER BE 0.
];T11CHP

IFN DLCP,[
;VARIABLES FOR INTERFACE TO CHAOS NET ON PDP11 ON DL10
;.SEE INDICATES A VARIABLE SHARED BETWEEN 10 AND 11
;NOTE THAT THE DL10 HARDWARE LIMITS PACKET LENGTH TO 256 WORDS (1K BYTES)

.SEE DLCINI	;WHEN THE 11 SEES THIS NON-ZERO, IT KNOWS ITS HAS
		; BEEN RELOADED AND RESETS ITS PACKET POINTER TO 0
		; AND CLEARS DLCINI.
DLCSBF:	0	;CURRENT BUFFER, 10 SEND SIDE (1 OR 0)

DLCSA1:	0	;ADDRESS OF PACKET BEING SENT
DLCSA2:	0	;DITTO, SECOND BUFFER
.SEE DLCSP1	;POINTER USED BY PDP11 TO COPY PACKET (16-BIT BYTES)
.SEE DLCSP2	;DITTO, SECOND BUFFER
.SEE DLCSS1	;STATE FOR BUFFER 1, 0 IDLE, 1 SENT TO 11, 2 11 DONE
.SEE DLCSS2	;STATE FOR BUFFER 2

DLCRA1:	0	;ADDRESS OF PACKET BUFFER RECEIVING A PACKET
DLCRA2:	0	;DITTO, SECOND BUFFER
.SEE DLCRP1	;POINTER USED BY PDP11 TO COPY PACKET (16-BIT BYTES)
.SEE DLCRP2	;DITTO, SECOND BUFFER
.SEE DLCRS1	;STATE FOR BUFFER 1, 0 IDLE, 1 AWAITING 11, 2 CONTAINS A PACKET
.SEE DLCRS2	;STATE FOR BUFFER 2

DLCXMQ:	0	;TRANSMIT BUFFER LIST FOR DL10
		;NOTE THAT THIS IS NOT A REGULAR BUFFER LIST SINCE
		;IT IS THREADED THROUGH LH INSTEAD OF RH.  WE DO MAINTAIN
		;POINTERS TO FIRST,,LAST HOWEVER
];DLCP

IFN CH10P,[
;VARIABLES FOR CH10 INTERFACE ONLY

CHXCNO:	CHXREN+CHXTEN+CHXCHN	;CONO BITS CURRENTLY IN EFFECT
];CH10P

IFN CH11P,[
;VARIABLES FOR CH11 INTERFACE ONLY

CHXCSR:	%CAREN+%CATEN		;CURRENT BITS WANTED IN CSR
];CH11P

IFN CH10P+CH11P,[
;VARIABLES THAT WOULD OTHERWISE BE IN THE FRONT-END

CHXXMQ:	0	;HEAD,,TAIL OF TRANSMIT QUEUE
CHOSTA:	0	;OUTPUT STATUS: 0 IDLE, ELSE NUMBER OF TRANSMISSIONS
NCHRTR==4	;TRANSMIT UP TO 4 TIMES IN FACE OF COLLISIONS

;ROUTING STUFF
NSUBNT==122.	;122 is maximum possible
SBNRUT:	REPEAT NSUBNT, 1000,,3040	;COST,,GATEWAY ADDRESS

;EXTRA METERS
CHNABT:	0	;NUMBER OF TRANSMIT ABORTS
CHNCRC:	0	;NUMBER OF CRC ERRORS BEFORE READING PACKET
CHNCR2:	0	;NUMBER OF CRC ERRORS AFTER READING PACKET
CHNWLE:	0	;NUMBER OF WORD LENGTH ERRORS (NOT MULTIPLE OF 16 BITS)
CHNPLE:	0	;NUMBER OF PACKET LENGTH ERRORS (DISAGREES WITH LENGTH IN HEADER)
CHNLOS:	0	;NUMBER OF PACKETS LOST DUE TO RECEIVER BUSY
];CH10P+CH11P
IFN CH11P,[
CHNSPZ:	0	;NUMBER OF TIMERS BIT COUNTER SPAZZED
];CH11P

BBLK

;Get definitions of packet format

IF1,[
$INSRT CHSDEF

PKTBSZ==%CPMXW+2	;PACKET BUFFER IS 2 HEADER WORDS + MAX SIZE PACKET
IFN <PKTBSZ&<-PKTBSZ>>-PKTBSZ, .ERR PKTBSZ IS SUPPOSED TO BE A POWER OF 2

$CPKSX==$CHXRI+40000,,2	;REAL PART OF SOURCE INDEX
$CPKDX==$CHXRI+40000,,1	;REAL PART OF DESTINATION INDEX

];IF1

;;; Debugging Info

;;; This contains the last N headers received from the network
NRECHD==20
EBLK
RECHDP:	RECHDR		;POINTER TO NEXT
RECHDR:	BLOCK NRECHD*%CPKDT
BBLK

SUBTTL CHAOS NET OPEN (.CALL CHAOSO)

;.CALL CHAOSO,RCVCHN,XMTCHN,<RECEIVE,,TRANSMIT>

CHASO:	JRST OPNL12		; Say "mode not avail"
CHAOSO:	HRRZS A
	HRRZS B
	CAIGE A,20
	 CAIL B,20
	  JRST OPNL14		;BAD CHANNEL NUMBER ARGUMENT
	CAMN A,B
	 JRST OPNL33		;BOTH CHANNELS SAME IS ILLEGAL
	PUSH P,A		;SAVE ARGS, CLOSE THE SPECIFIED CHANNELS
	PUSH P,B
	PUSH P,C
	MOVE R,A
	ADDI R,IOCHNM(U)
	PUSHJ P,CCLOSE
	MOVE R,-1(P)		;B
	ADDI R,IOCHNM(U)
	PUSHJ P,CCLOSE
	POP P,C
	POP P,B
	POP P,A
	MOVE U,USER		;TO SAVE ULCERS
	HRRZM A,UUAC(U)		;REMEMBER INPUT CHNL # FOR ERRS
	PUSHJ P,SWTL		;LOCK CHAOS INDEX ASSIGNMENT SWITCH
	    CHAOSW
	MOVE I,CHALCP		;ALLOCATE AN INDEX
	SOJL I,CHASO2
CHASO1:	SKIPL CHSUSR(I)
	 SOJGE I,CHASO1
	JUMPGE I,CHASO3
CHASO2:	MOVEI I,NINDX		;REACHED BEGINNING, WRAP AROUND TO END
	CAMN I,CHALCP
	 JRST OPNL6		;ALL INDICES IN USE
	MOVEM I,CHALCP
	SOJA I,CHASO1

CHASO3:	MOVEM I,CHALCP		;SAVE SCAN POINTER FOR NEXT TIME
	PUSHJ P,CHASO4		;INIT VARIOUS STUFF
	CAILE C,MXWIND		;SET UP WINDOW SIZE
	 MOVEI C,MXWIND		;DON'T LET USER USE UP TOO MUCH WIRED CORE
	HRLZM C,CHSWIN(I)
	HRRZM U,CHSUSR(I)	;VARIABLES INITIALIZED, MAKE INDEX IN USE.
	DPB A,[$CHSUI,,CHSUSR(I)]
	DPB B,[$CHSUO,,CHSUSR(I)]
	HRLZ T,I		;SET UP USER'S IOCHNM WORDS
	HRRI T,CHAIDN
	ADDI A,IOCHNM(U)
	MOVEM T,(A)
	HRRI T,CHAODN
	ADDI B,IOCHNM(U)
	MOVEM T,(B)
	JRST LSWPJ1		;SUCCESS RETURN

;INITIALIZE CONNECTION IN I
CHASO4:	SETZM CHSNBF(I)
	SETZM CHSNOS(I)
	SETZM CHSIBF(I)
	SETZM CHSPBF(I)
	SETZM CHSOBF(I)
	SETZM CHSACK(I)
	SETZM CHSPKN(I)		;START PACKET NUMBERING AT ONE
	SETZM CHSOBP(I)
	SETZM CHSOBC(I)
	SETZM CHSIBP(I)
	SETZM CHSIBC(I)
	MOVSI T,%CFOFF .SEE %CSCLS
	MOVEM T,CHSSTA(I)
	LDB TT,[$CHXUN+40000,,CHSLCL(I)]
	CAIE TT,CHXMUN		;INCREMENT THE UNIQUIZER
	 AOSA TT
	  MOVEI TT,1		;BUT MAKE SURE IT ISN'T ZERO
	DPB TT,[$CHXUN+40000,,CHSLCL(I)]
	SETZM CHSFRN(I)
	POPJ P,

SUBTTL CHAOS NET CLOSE, FINISH, WHYINT, NETBLK, CHAOSQ

;CLOSE A CHAOS CHANNEL.
CHACLS:	HLRZ I,(R)		;GET VARIABLES INDEX
	MOVSI A,%CFCLS
	TDNN A,CHSSTA(I)	;ONLY REALLY CLOSE WHEN BOTH CHANNELS CLOSED
	 JRST CHACS7
	PUSHJ P,CHACS1		;FLUSH ALL BUFFERS OF THIS CONNECTION
	HRRZ T,CHSSTA(I)
	CAIN T,%CSOPN
	 PUSHJ P,CHABGI		;SEND A CLS IF OPEN AND MEM AVAIL
	  JRST CHACS4
	MOVE T,CHSFRN(I)
	MOVEM T,%CPKS(A)
	MOVE T,CHSLCL(I)
	MOVEM T,%CPKD(A)
	MOVEI B,[ASCIZ/Channel closed/]
	PUSHJ P,CHIRF2
CHACS4:	CONO PI,NETOFF
	SETZM (R)		;CLOSE THIS CHANNEL
	SETOM CHSUSR(I)		;RETURN INDEX
	MOVE W,CHQLSN		;FLUSH ANY PENDING LSN PACKET
	SETZM CHQLSN
CHACS5:	MOVEI Q,W		;GET NEXT PACKET OFF OLD LIST
	PUSHJ P,CHAQGF
	JUMPE A,NETONJ		;EXHAUSTED
	LDB B,[$CPKSX(A)]	;GET OWNER
	CAME B,I
	 JRST [	MOVEI Q,CHQLSN	;NOT THIS INDEX, PUT BACK
		PUSHJ P,CHAQPL
		JRST CHACS5 ]
	PUSHJ P,CHABRT		;FREE
	JRST CHACS5

CHACS7:	IORM A,CHSSTA(I) .SEE %CFCLS
	HRRZ B,(R)		;GET DIRECTION
	CAIN B,CHAIDN		;AS A BYTE POINTER TO CHANNEL NUMBER
	 SKIPA B,[$CHSUI,,CHSUSR(I)]
	  MOVE B,[$CHSUO,,CHSUSR(I)]
	MOVEI T,77		;CLOSE THAT CHANNEL
	DPB T,B
	SETZM (R)
	POPJ P,

;THIS FLUSHES ALL BUFFERS FOR CONNECTION IN I
CHACS1:	MOVSI A,%CFOFF		;INHIBIT RETRANSMISSIONS
	IORB A,CHSSTA(I)
	LDB E,[$CFTTN,,CHSSTA(I)]
	EXCH E,I
	TLNE A,%CFSTY
	 PUSHJ P,NSTYN0		;DISCONNECT FROM STY
	  JFCL
	EXCH E,I
IFN DLCP,[
	MOVEI Q,DLCXMQ		;REMOVE THIS INDEX'S BUFFERS FROM DL10 TRANSMIT LIST
	PUSHJ P,CFLXMQ
];DLCP
IFN T11CHP,[
	MOVEI Q,T11XMQ		;REMOVE THIS INDEX'S BUFFERS FROM TEN11 TRANSMIT LIST
	PUSHJ P,CFLXMQ
];T11CHP
IFN CH10P+CH11P,[
	MOVEI Q,CHXXMQ		;REMOVE THIS INDEX'S BUFFERS FROM CH10 TRANSMIT LIST
	PUSHJ P,CFLXMQ
];CH10P+CH11P
	MOVEI Q,CHSIBF(I)	;RETURN RECEIVE BUFFERS
	PUSHJ P,CHALFR
	MOVEI Q,CHSPBF(I)	;RETURN OUT OF ORDER RECEIVE BUFFERS
	PUSHJ P,CHALFR
	MOVEI Q,CHSOBF(I)	;RETURN TRANSMIT BUFFERS
	PUSHJ P,CHALFR
IFE FTRCHK,[
	SKIPE A,CHSOBP(I)	;RETURN STREAM I/O BUFFERS
	 PUSHJ P,CHBPFR
	SKIPE A,CHSIBP(I)
	 PUSHJ P,CHBPFR
];FTRCHK
IFN FTRCHK,[
	SKIPN A,CHSOBP(I)
	 JRST .+3
	  SETZM CHSOBP(I)
	  PUSHJ P,CHBPFR
	SKIPN A,CHSIBP(I)
	 JRST .+3
	  SETZM CHSIBP(I)
	  PUSHJ P,CHBPFR
];FTRCHK
	POPJ P,

;.CALL FORCE ON A CHAOS OUTPUT CHANNEL.
CHAFRC:	HLRZ I,(R)
	SKIPGE CHSSTA(I) .SEE %CFOFF
	 JRST OPNL7		;DEVICE NOT READY
	AOS (P)			;WILL TAKE SUCCESS RETURN
CHAFC1:	SKIPN A,CHSOBP(I)
	 POPJ P,		;NO BUFFERED OUTPUT TO BE FORCED
	SUBI A,1		;SIOKT LIKES TO POINT BP AT NEXT BUFFER
	ANDI A,-PKTBSZ		;GET PACKET POINTER
	ADDI A,2
	MOVSI T,(SETZ)		;DATA OPCODE
	MOVEM T,(A) .SEE $CPKOP
	MOVEI T,%CPMXC		;SET BYTE COUNT
	SUB T,CHSOBC(I)
	DPB T,[$CPKNB(A)]
	PUSHJ P,[JUMPN T,CHODT1	;IF THERE IS ANYTHING IN THE BUFFER, TRANSMIT IT
		 JRST CHABRT ]	;OTHERWISE, JUST THROW IT AWAY
	SETZM CHSOBP(I)		;NOW THERE IS NO BUFFER
	SETZM CHSOBC(I)
	POPJ P,

;.CALL FINISH ON A CHAOS OUTPUT CHANNEL.  WAIT FOR ALL BUFFERS
;ON SEND LIST TO GET SENT AND ACKNOWLEDGED.
;HANGS FOREVER IF SOCKET GETS INTO AN IMPROPER STATE, BUT YOU SHOULD GET AN INTERRUPT
CHAFIN:	HLRZ T,(R)
	PUSHJ P,[HRRZ A,CHSWIN(T)
		 CAMG A,CHSNOS(T)
		  AOS (P)
		 POPJ P, ]
	 PUSHJ P,UFLS
	JRST POPJ1

;.CALL WHYINT ON A CHAOS CHANNEL.
;RESULTS ARE:	A/ %WYCHA
;		B/ STATE
;		C/ LH NUMBER OF INPUT PACKETS AVAILABLE
;		   RH NUMBER OF OUTPUT SLOTS AVAILABLE
;		D/ WINDOW SIZE (RECEIVE,,TRANSMIT)
;		E/ INPUT CHNL#,,OUTPUT CHNL#
CHAWHY:	HLRZ I,(R)
	MOVEI A,%WYCHA
	HRRZ B,CHSSTA(I)
	HRLZ C,CHSNBF(I)	;NUMBER OF PACKETS AVAILABLE
	SKIPE CHSIBP(I)
	 ADD C,[1,,]		;ADD 1 IF PARTIALLY-READ INPUT BUFFER EXISTS
	MOVSI D,%CFSTY
	TDNE D,CHSSTA(I)
	 MOVEI C,0		;NO INPUT AVAILABLE IF DIRECT-CONNECTED
	SKIPLE CHSNOS(I)
	 HRR C,CHSNOS(I)
	MOVE D,CHSWIN(I)
	LDB E,[$CHSUO,,CHSUSR(I)]
	CAIN E,77
	 MOVEI E,-1
	LDB T,[$CHSUI,,CHSUSR(I)]
	CAIN T,77
	 TLOA E,-1
	  HRL E,T
	JRST POPJ1

;.CALL RFNAME on a CHAOS channel.  A contains index.
;Returns results analogous to RFNAME on TCP: and (almost) RFNAME on NET:.
;"FN1" is local index, "FN2" is foreign index, "SNAME" is foreign host
;number in HOSTS3 format.
CHARCH:	LDB B,[042000,,CHSLCL(A)]
	LDB C,[042000,,CHSFRN(A)]
	LDB D,[242000,,CHSFRN(A)]
	TLO D,(NW%CHS)
	POPJ P,

;IOPDL ROUTINES.  I IS 0 FOR IOPUSH, 1 FOR IOPOP.  R POINTS AT IOCHNM WORD.
;C(R) IS SET UP TO THIS DEVICE IN EITHER CASE.
CHAIOP:	HRRZ T,R		;DISCOVER CHANNEL NUMBER
	SUBI T,IOCHNM(U)
	SKIPN I
	 MOVEI T,77		;IOPUSH, USE 77
	HLRZ I,(R)		;GET CHAOS INDEX
	HRRZ B,(R)		;GET DIRECTION
	CAIN B,CHAIDN		;AS A BYTE POINTER TO CHANNEL NUMBER
	 SKIPA B,[$CHSUI,,CHSUSR(I)]
	  MOVE B,[$CHSUO,,CHSUSR(I)]
	DPB T,B			;ADJUST SAVED CHANNEL NUMBER
	POPJ P,

;.CALL NETBLK ON A CHAOS CHANNEL.
;ARG 1 - CHANNEL (COMES IN IN R)
;ARG 2 - UNDESIRED STATE
;ARG 3 - OPTIONAL TIMEOUT, WRITTEN BACK UNLESS IMMEDIATE
;VAL 1 - NEW STATE
;VAL 2 - TIME LEFT
CHANBK:	HRRZ T,(R)
	CAIL T,CHAIDN
	 CAILE T,CHAODN
IFN NCPP,  JRST ANETBL		;NOT A CHAOS CHANNEL, TRY ARPANET
IFE NCPP,  JRST OPNL34
	HLRZ I,(R)
	MOVE T,I		;SAVE INDEX IN T FOR FLSINS
	CAIGE W,3
	 JRST [	HRLOI D,377777	;NO TIME GIVEN, USE INFINITY
		JRST CHANB4 ]
	TLNE C,1000		;SKIP IF POINTER RATHER THAN IMMEDIATE
	 JRST [	HRRZ D,C	;GET IMMEDIATE TIME
		ADD D,TIME
		JRST CHANB4 ]
	XCTR XRW,[MOVES D,(C)]	;GET TIME, CHECK WRITEABILITY
	JUMPGE D,[ MOVNS D	;RELATIVE TIME, MAKE NEGATIVE ABSOLUTE
		   SUB D,TIME
		   JRST .+1 ]
	UMOVEM D,(C)		;STORE BACK ABSOLUTE TIME
	MOVNS D			;MAKE POSITIVE
CHANB4:	MOVEM D,AC0S+D(U)	;SAVE ABSOLUTE TIME TO WAIT UNTIL
	MOVEM B,AC0S+B(U)	;SAVE UNDESIRED STATE
	PUSHJ P,CHANB2		;SKIP IF STATE CHANGE OR TIMEOUT
	 PUSHJ P,UFLS
	MOVE B,D
	SUB B,TIME		;HOW MUCH USED?
	HRRZ A,CHSSTA(I)	;NEW STATE
	JRST POPJ1

CHANB2:	HRRZ A,CHSSTA(T)	;CURRENT STATE
	CAME A,AC0S+B(U)	;SKIP IF STILL MATCH
	 JRST POPJ1
	MOVE A,AC0S+D(U)	;TIMEOUT TIME
	CAMG A,TIME
	 AOS (P)
	POPJ P,

;.CALL CHAOSQ
;ARG 1 - ADDRESS OF A %CPMXW-WORD PACKET BUFFER
;FINDS THE FIRST PACKET ON THE PENDING-RFC QUEUE, COPIES IT
;INTO THE USER'S BUFFER, AND RETURNS IT TO THE QUEUE.
CHAOSQ:	MOVE C,A		;SAVE POINTER TO USER'S BUFFER
	HRL A,A			;MAKE SURE USER'S BUFFER IS SWAPPED IN
	XCTR XBRW,[BLT A,%CPMXW-1(C)]	;AND NO MAR BREAK SET
	MOVEI Q,CHQRFC		;GET FIRST PACKET ON RFC QUEUE
	PUSHJ P,CHAQGF
	JUMPE A,OPNL4		;QUEUE IS EMPTY
	PUSHJ P,CHAQPL		;PUT BACK AT END OF QUEUE
	HRL C,A			;COPY PACKET TO USER
	MOVE T,C
	XCTR XBW,[BLT T,%CPMXW-1(C)]
	JRST POPJ1

SUBTTL CHAOS NET IOT ROUTINES

;.CALL PKTIOT.  ARG1 CHANNEL, ARG2 ADDRESS OF %CPMXW-WORD BUFFER
PKTIOT:	HRRZ A,(R)
	CAIN A,CHAODN
	 JRST CHPKO
	CAIE A,CHAIDN
	 JRST OPNL34		;WRONG TYPE DEVICE
;CHAOSNET INPUT PKTIOT
;B POINTS TO %CPMXW-WORD PACKET BUFFER
CHPKI:	PUSHJ P,CHAIOS		;SET UP I, E
	HLRZ A,CHSIBF(I)	;GET FIRST RECEIVE BUFFER
	JUMPE A,[PUSHJ P,CHPKI0	;LIST EMPTY
		 JRST CHPKI ]
	HRL B,A			;COPY TO USER BEFORE REMOVING FROM LISTS
	LDB T,[$CPKNB(A)]	;GET SIZE OF PACKET
	ADDI T,4*%CPKDT+3	;HEADER PLUS ROUND-UP TO NEXT WORD BOUNDARY
	LSH T,-2		;CONVERT BYTES TO WORDS
	ADDI T,-1(B)		;ADDRESS OF LAST DESTINATION WORD
	XCTR XBW,[BLT B,(T)]
	LDB TT,[$CPKOP(A)]	;GET OPCODE
	CAIGE TT,%CODAT		;ACKNOWLEDGE IF DATA
	 CAIN TT,%COEOF		;OR EOF MARK
	  PUSHJ P,CHPKIA
	SOS CHSNBF(I)		;NOW REMOVE BUFFER FROM RECEIVE LIST
	MOVEI Q,CHSIBF(I)
	PUSHJ P,CHAQGF
	PUSHJ P,CHABRT		;AND RETURN TO FREE
	JRST POPJ1		;SUCCESS

;INPUT WITH INPUT BUFFER EMPTY.  MUSTN'T BASH B,C,E.
CHPKI0:	SKIPGE CHSSTA(I) .SEE %CFOFF
	 JRST [	HRRZ T,CHSSTA(I)
		CAIE T,%CSFRN	;CHAOSNET OR FOREIGN PROTOCOL?
		 JRST IOCR10	;IOT WITH CHANNEL IN IMPROPER STATE
		JRST .+1 ]	;WAIT BUT DON'T TRY TO TOUCH WINDOW SIZE
	;HERE CONSIDER INCREASING WINDOW SIZE
	SKIPN CHSIBF(I)		;AWAIT INPUT
	 PUSHJ P,UFLS
	POPJ P,			;RETRY

;ACKNOWLEDGE DATA PACKET IN A.  ITS OPCODE IN TT.
CHPKIA:	LDB T,[$CPKPN(A)]	;GET PACKET #
	HRLM T,CHSPKN(I)	;IT NOW NEEDS TO BE ACKNOWLEDGED
	CAIN TT,%COEOF		;ALWAYS ACKNOWLEDGE EOF RIGHT AWAY
	 JRST CHASTO
	HLRZ TT,CHSACK(I)	;GET LAST ONE REALLY ACKNOWLEDGED
	SUB T,TT		;GET NUMBER OF PACKETS AWAITING ACK
	SKIPGE T
	 ADDI T,200000
	IMULI T,3		;MORE THAN ONE THIRD THE WINDOW SIZE?
IFN FTRCHK,[
	MOVE TT,-1(A)
	CAMN TT,[ASCII/LUNCH/]
	 BUG PAUSE,[CHAOS BUFFER ADDRESS TRASHED],OCT,A
];FTRCHK
	HLRZ TT,CHSWIN(I)
	CAML T,TT
	 PUSHJ P,CHASTO		;YES, SEND ACK (CAN'T PCLSR)
	POPJ P,

;SET UP FOR CHAOS IOT
CHAIOS:	HLRZ I,(R)		;GET INDEX
	MOVE E,CHSSTA(I)
	TLNE E,%CFSTY+%CFCLS
	 JRST IOCR10		;CAN'T DO I/O WHILE DIRECT-CONNECTED OR HALF-CLOSED
	HRRZS E			;RETURN STATE IN E
	POPJ P,

;UNIT-MODE INPUT.
;1.4 IN CTLBTS IS DON'T-HANG MODE
	SKIPA T,[SIOKT]
CHAUI:	 MOVEI T,CHRKT
	PUSHJ P,CHAIOS		;SET UP I, E
	MOVE E,[440800,,4]
	JSP B,(T)
	    CHSIBP(I)
	    CHSIBC(I)
	    CHAIBG
	    CHAIBD
	    0
	    TRNA

;CHAOS INPUT BUFFER DISCARD
CHAIBD:	SKIPN A,CHSIBP(I)
	 POPJ P,
	SETZM CHSIBP(I)
	SETZM CHSIBC(I)
	JRST CHBPFR

;CHAOS INPUT BUFFER GET
CHAIBG:	HLRZ A,CHSIBF(I)	;GET FIRST RECEIVE BUFFER
	JUMPE A,CHAIB2		;NONE
	LDB TT,[$CPKOP(A)]	;IS IT NORMAL DATA?
	CAIE TT,%CODAT
	 JRST CHAIB1		;NO
	PUSHJ P,CHAIB3		;YES, ACKNOWLEDGE AND REMOVE FROM LIST
	LDB J,[$CPKNB(A)]	;SET UP FOR BYTE STREAM INPUT
	MOVEI TT,%CPKDT(A)
	JRST SIOBG1

CHAIB3:	PUSH P,B
	PUSH P,C
	PUSH P,E
	PUSHJ P,CHPKIA		;SEND ACKNOWLEDGEMENT
	POP P,E
	POP P,C
	POP P,B
	SOS CHSNBF(I)		;REMOVE BUFFER FROM RECEIVE LIST
	MOVEI Q,CHSIBF(I)
	JRST CHAQGF

CHAIB1:	CAIE TT,%COEOF
	 JRST CHAIB2
	PUSHJ P,CHAIB3		;EOF PACKET, ACKNOWLEDGE IT
	PUSHJ P,CHABRT		;RETURN IT TO FREE
	JRST POPJ2		;AND SIGNAL EOF

CHAIB2:	MOVE TT,CTLBTS(U)	;CHECK DON'T-HANG MODE
	TRNE TT,10
	 JRST POPJ2		;YES, EOF
	JUMPN A,IOCR10		;NO, ABNORMAL PACKET, BARF
	PUSHJ P,CHPKI0		;AWAIT INPUT
	JRST CHAIBG		;RETRY

;UNIT-MODE OUTPUT.
;1.4 IN CTLBTS IS DON'T-HANG MODE
	SKIPA T,[SIOKT]
CHAUO:	 MOVEI T,CHRKT
	PUSHJ P,CHAIOS		;SET UP I, E
	CAIE E,%CSOPN
	 JRST IOCR10		;NOT OPEN, ERROR
	MOVE E,[440800,,4]
	JSP B,(T)
	    SETZ CHSOBP(I)
	    CHSOBC(I)
	    CHAOBG
	    CHAOBW
	    0
	    TRNA

;GET NEW OUTPUT BUFFER
CHAOBG:	SKIPG CHSNOS(I)		;WINDOW FULL
	 PUSHJ P,[ MOVE TT,CTLBTS(U)
		   TRNN TT,10
		    JRST UFLS
		   SUB P,[1,,1]
		   JRST POPJ2 ]	;DON'T HANG MODE, RETURN "EOF"
	PUSH P,B
	PUSHJ P,CHABGT		;SET UP AN OUTPUT BUFFER
	POP P,B

	MOVEI TT,%CPKDT(A)
	MOVEI J,%CPMXC
	JRST SIOBG1

;WRITE OUTPUT BUFFER
CHAOBW:	PUSH P,B
	PUSH P,C
	PUSH P,E
	PUSHJ P,CHAFC1
	POP P,E
	JRST POPCBJ

;CHAOSNET OUTPUT PKTIOT.
;B POINTS TO %CPMXW-WORD PACKET BUFFER
CHPKO:	PUSHJ P,CHAIOS		;SET UP I, E
	UMOVE H,(B)		;GET HEADER WORD OF USER'S PACKET BUFFER
	LDB D,[$CPKNB H]	;GET BYTE COUNT
	CAIG D,%CPMXC
	 TLNE H,(.BM $CPKMV)	;WE DON'T SUPPORT MUPPETS ANY MORE
	  JRST IOCER3		;BYTE LENGTH OUT OF BOUNDS
	ADDI D,4*%CPKDT+3	;CONVERT BYTES TO WORDS, INCLUDING HEADER WDS
	LSH D,-2
	MOVSI J,1(B)		;SAVE ADDRESS+1 OF USER'S PACKET
	PUSHJ P,CHABGT		;GET A BUFFER
	PUSHJ P,LOSSET		;RETURN IT IF PCLSR
	    CHPKO2
	MOVEM H,(A)		;STORE PACKET HEADER, NOT STORED WITH BLT
	HRRI J,1(A)		; BECAUSE MIGHT HAVE CHANGED AFTER ERROR CHECK
	ADDI D,-1(A)
	XCTR XBR,[BLT J,(D)]	;COPY USER'S PACKET INTO SYSTEM
	AOS (P)			;GOING TO SUCCEED
	SKIPGE (A)		;SKIP IF CONTROL PACKET
	 JRST CHODAT		;DATA
	LDB D,[$CPKOP(A)]	;GET OPCODE
	CAIGE D,%COMAX		;DISPATCH ON IT
	 JRST @.+1(D)
	OFFSET -.
	JRST IOCER3		;OPCODE OUT OF BOUNDS
%CORFC::JRST CHORFC
%COOPN::JRST CHOOPN
%COCLS::JRST CHOCLS
%COFWD::JRST CHOFWD
%COANS::JRST CHOFWD
%COSNS::JRST IOCER3
%COSTS::JRST IOCER3
%CORUT::JRST IOCER3
%COLOS::JRST IOCER3
%COLSN::JRST CHOLSN
%COMNT::JRST IOCER3
%COEOF::JRST CHOEOF
%COUNC::JRST CHOUNC
%COBRD::JRST IOCER9		;UNTIL I IMPLEMENT IT
%COMAX::OFFSET 0

;LOSSET ROUTINE TO RETURN BUFFER A POINTS TO.
CHPKO2:	MOVE A,AC0S+A(U)
	PUSH P,Q		;MAY CLOBBER ONLY A AND T
	PUSHJ P,CHABRT
	JRST POPQJ

;SENDING %COEOF (END-FILE MARK)
CHOEOF:	CAIE E,%CSOPN		;CONNECTION MUST BE OPEN
	 JRST IOCR10
	SKIPG CHSNOS(I)
	 PUSHJ P,UFLS		;WINDOW FULL, WAIT
	JRST CHOOP1		;SEND RETRANSMITTABLE CONTROL PACKET

;SENDING REQUEST FOR CONNECTION
CHORFC:	PUSHJ P,CHORF1		;RE-INITIALIZE CONNECTION
	MOVSI B,777774		;SAVE DESTINATION HOST, CLEAR OTHER BITS
	ANDB B,%CPKD(A)
	MOVEM B,CHSFRN(I)
	MOVEI E,%CSRFS		;PUT INTO RFC-SENT STATE
	JRST CHOOP1		;GO SEND

;RE-INITIALIZE CONNECTION WHEN USER OUTPUTS RFC OR LSN
;FLUSHES ANY OLD PACKET BUFFERS, CHANGES UNIQUIZER IN INDEX#
CHORF1:	JUMPN E,IOCR10 .SEE %CSCLS	;CONNECTION MUST BE CLOSED
	PUSH P,A
	PUSH P,B
	PUSHJ P,CHACS1		;FLUSH BUFFERS FROM CONNECTION
	PUSHJ P,CHASO4		;REINITIALIZE VARIABLES
	JRST POPBAJ

;"SENDING" LISTEN
CHOLSN:	PUSHJ P,CHORF1
	PUSHJ P,LSWDEL		;GOING TO USE PACKET
	MOVEI E,%CSLSN		;PUT INTO LISTENING STATE
	HRRM E,CHSSTA(I)
	MOVEI Q,CHQRFC		;NOW SEARCH PENDING-RFC QUEUE
	CONO PI,NETOFF
	PUSHJ P,CHAQSR
	 JRST [	CONO PI,NETON	;NO MATCH, PUT ONTO LISTENING QUEUE
		MOVEI Q,CHQLSN
		MOVE T,CHSLCL(I)
		MOVEM T,%CPKS(A)
		JRST CHAQPL ]
	PUSHJ P,CHIRF0		;MATCH, JOIN INTERRUPT LEVEL CODE
	JRST NETONJ

;SENDING OPEN
CHOOPN:	CAIE E,%CSRFC		;CONNECTION MUST BE RFC-RECEIVED
	 JRST IOCR10
	MOVEI TT,4		;SET BYTE COUNT TO 4
	DPB TT,[$CPKNB(A)]
	PUSHJ P,DPBRCP		;INCLUDE RECEIPT
	HLRZ B,CHSWIN(I)	;INCLUDE WINDOW SIZE
	DPB B,[042000,,%CPKDT(A)]
	MOVEI E,%CSOPN		;MAKE IT OPEN
;HERE TO SEND A RETRANSMITTABLE CONTROL PACKET (RFC OR OPN), NEW STATE IN E
;THIS PACKET WILL GET TAKEN OFF THE CHSOBF LIST BY RECEIPT IN THE NORMAL WAY
;THIS CODE COPIED FROM CHODAT WITH SOME MODIFICATIONS
CHOOP1:	MOVE T,TIME		;UPDATE CHSITM SO WON'T THINK HOST IS DOWN
	MOVEM T,CHSITM(I)
	MOVEM E,CHSSTA(I)	;AND CLEAR %CFOFF (NO OTHER LH FLAGS CAN BE ON)
	PUSHJ P,LSWDEL		;BUFFER WILL BE USED
	HRRZ B,CHSPKN(I)	;ASSIGN PACKET NUMBER
	CAIL B,177777
	 TDZA B,B
	  ADDI B,1
	HRRM B,CHSPKN(I)
	DPB B,[$CPKPN(A)]
	HLRZ B,CHSPKN(I)	;GET PACKET NUMBER TO ACKNOWLEDGE
	HRLM B,CHSACK(I)	;REMEMBER IT HAS BEEN
	DPB B,[$CPKAN(A)]	;PIGGY-BACK THIS ACKNOWLEDGE
	MOVE B,[<.BM $CPKOP>+<.BM $CPKNB>]
	ANDM B,(A)		;CLEAR FORWARDING COUNT AND UNUSED FIELD
	MOVE B,CHSLCL(I)	;SET UP SOURCE
	MOVEM B,%CPKS(A)
	MOVE D,CHSFRN(I)	;SET UP DESTINATION
	MOVEM D,%CPKD(A)
	SETOM -2(A)		;NOTE NOT ON TRANSMIT LIST YET
	CONI PI,E		;SUPER KLUDGERY REQUIRED HERE!  FOREIGN HOST MIGHT RECEIPT
	CONO PI,NETOFF		;THIS PACKET JUST AS WE START TO TRANSMIT IT.  THIS IS A
				;VIOLATION OF PROTOCOL, BUT SHOULDN'T CRASH I.T.S. BECAUSE THE
				;PACKET ABOUT TO BE GIVEN TO CHAXMT HAS BEEN FREED ALREADY.
	MOVEI Q,CHSOBF(I)	;PUT ON END OF SEND LIST
	PUSHJ P,CHAQPL
	JRST CHAXM0		;GO TRANSMIT

;SENDING CLOSE
CHOCLS:	CAIE E,%CSOPN		;CONNECTION MUST BE OPEN
;SEND FWD OR ANS
CHOFWD:	 CAIN E,%CSRFC		; OR RFC-RECEIVED
	  TLOA E,%CFOFF		;PUT IT INTO THE CLOSED STATE
	   JRST IOCR10
	HLLZM E,CHSSTA(I) .SEE %CSCLS
	PUSHJ P,LSWDEL		;BUFFER WILL BE USED
	JRST CHODT2		;GO TRANSMIT

;Here for transmitting an UNC packet.  It could be part of a connection
;or it could be foreign-protocol mode.  In any case transmit it without
;munging the header very much.
CHOUNC:	CAIN E,%CSFRN
	 JRST CHOUN1		;Okay to transmit UNC now
	CAIN E,%CSOPN
	 JRST CHOUN2
	JUMPN E,IOCR10 .SEE %CSCLS	;Bad state
	SKIPE CHSPBF(I)		;I guess out of order packets would
	 JRST IOCR10		; cause some confusion in the NCP.
	MOVE E,[%CFOFF,,%CSFRN]	;Put into foreign-protocol state
	MOVEM E,CHSSTA(I)
CHOUN1:	MOVE D,%CPKD(A)		;Save destination
	MOVEM D,CHSFRN(I)
CHOUN3:	MOVE B,CHSLCL(I)	;Set up source
	MOVEM B,%CPKS(A)
	PUSHJ P,LSWDEL
	SETOM -2(A)
	JRST CHAXMT

CHOUN2:	MOVE D,CHSFRN(I)	;Set up destination
	MOVEM D,%CPKD(A)
	JRST CHOUN3

OVHMTR CHX

;SENDING REGULAR PACKET
CHODAT:	CAIE E,%CSOPN		;CONNECTION MUST BE OPEN
	 JRST IOCR10
	SKIPG CHSNOS(I)
	 PUSHJ P,UFLS		;WINDOW FULL, WAIT
	PUSHJ P,LSWDEL		;BUFFER WILL BE USED
CHODT1:	HRRZ B,CHSPKN(I)	;ASSIGN PACKET NUMBER
	CAIL B,177777
	 TDZA B,B
	  ADDI B,1
	HRRM B,CHSPKN(I)
	DPB B,[$CPKPN(A)]
CHODT2:	HLRZ B,CHSPKN(I)	;GET PACKET NUMBER TO ACKNOWLEDGE
	HRLM B,CHSACK(I)	;REMEMBER IT HAS BEEN
	DPB B,[$CPKAN(A)]	;PIGGY-BACK THIS ACKNOWLEDGE
	MOVE B,[<.BM $CPKOP>+<.BM $CPKNB>]
	ANDM B,(A)		;CLEAR FORWARDING COUNT AND UNUSED FIELD
	MOVE B,CHSLCL(I)	;SET UP SOURCE
	MOVEM B,%CPKS(A)
	MOVE D,CHSFRN(I)	;SET UP DESTINATION
	MOVEM D,%CPKD(A)
	SETOM -2(A)		;NOTE NOT ON TRANSMIT LIST YET
	SKIPL (A)		;SKIP IF DATA PACKET
	 JRST CHAXMT
	CONI PI,E		;SUPER KLUDGERY REQUIRED HERE!  FOREIGN HOST MIGHT RECEIPT
	CONO PI,NETOFF		;THIS PACKET JUST AS WE START TO TRANSMIT IT.  THIS IS A
				;VIOLATION OF PROTOCOL, BUT SHOULDN'T CRASH I.T.S. BECAUSE THE
				;PACKET ABOUT TO BE GIVEN TO CHAXMT HAS BEEN FREED ALREADY.
	MOVEI Q,CHSOBF(I)	;PUT ON END OF SEND LIST
	PUSHJ P,CHAQPL
	SOSA CHSNOS(I)		;USE UP WINDOW, SKIP
;SKIPS THROUGH INTO CHAXMT
;SKIPS IN
SUBTTL CHAOS NET PACKET TRANSMIT ROUTINE

;CALL WITH PACKET IN A, SMASHES B, C, D, E, T, TT, Q, J
;USES E TO SAVE THE PI STATUS, NOTHING BETTER CLOBBER THIS, OR, BOY, WILL IT EVER LOSE!
;YOU BETTER SETOM -2(A) BEFORE CALLING THIS, AND IF YOU'RE
;PUTTING IT ON A SEND LIST, DO THAT FIRST ALSO.
;THIS CODE ASSUMES THERE IS ONLY ONE INTERFACE, AND IT IS ON A
;PDP11 WHICH WILL TAKE CARE OF THE ROUTING.
;;THIS ROUTINE IS SKIPPED INTO FROM THE PREVIOUS PAGE!
CHAXMT:	 CONI PI,E		;SAVE PI STATUS BEFORE TURNING NETOFF; CALLED FROM MANY LEVELS
CHAXM0:	ANDI E,177
	AOS CHNPO
	MOVE T,TIME
	MOVEM T,-1(A)		;SET TIME OF LAST TRANSMISSION
	CONO PI,NETOFF		;ONE PROCESS AT A TIME, TO PROTECT INTERFACE VARIABLES
IFN FTRCHK,[
	HLRZ J,-2(A)		;I TOLD YOU TO SETOM -2(A)
	CAIE J,-1
	 BUG PAUSE,[CHAOS BUFFER THREAD TRASHED],OCT,A,OCT,-2(A)
];FTRCHK
IFN DLCP,[
;FOR NOW, JUST ALWAYS SHIP IT OUT THE DL10
IFN FTRCHK,[
	HLRZ J,DLCXMQ		;MAKE SURE NOT PUTTING ON LIST TWICE
	JUMPE J,.+7
	CAMN J,A
	 BUG PAUSE,[CHAOS BUFFER ALREADY ON DLCXMQ],OCT,A
	HLRZ J,-2(J)
	CAIN J,-1
	 BUG PAUSE,[DLCXMQ THREAD TRASHED]
	JUMPN J,.-5
	MOVEI J,1		;MAKE SURE NOT ACTIVE TO 11
	HRRZ T,DLCSA1(J)
	CAMN T,A
	 BUG PAUSE,[CHAOS BUFFER ALREADY ACTIVE TO 11],OCT,A
	SOJGE J,.-3
];FTRCHK
	HRRZS -2(A)		;PUT END-LIST INDICATOR IN LH (FLAGS TRANSMIT ACTIVE)
	MOVE J,DLCSBF		;SEE IF SEND BUFFER IS FREE
	SKIPE DLCSS1(J)
	 JRST CHXMD1
	PUSHJ P,DLCXMT		;YES, SEND THE PACKET NOW
	JRST CHXMD2

CHXMD1:	HRRZ B,DLCXMQ		;NO BUFFERS FREE RIGHT NOW, QUEUE
	JUMPE B,[ HRLZM A,DLCXMQ ? JRST .+2 ]
	 HRLM A,-2(B)
	HRRM A,DLCXMQ
CHXMD2:	CONO PI,PICON(E)	;RESTORE PI
	POPJ P,
];DLCP
IFN T11CHP,[
;FOR NOW, JUST ALWAYS SHIP IT OUT THE TEN11
	PUSHJ P,T11CHK		;SEE IF TEN-11 IS READY
	 JRST CHXME3		;NO
	SKIPE @T11OBP		;SEE IF HAVE AVAILABLE OUTPUT BUFFER
	 JRST CHXME1		;NO
	PUSHJ P,T11XMT		;SEND THE PACKET NOW
	JRST CHXME2

CHXME3:	HRROS T,-2(A)		;TEN11 DOWN, DISCARD PACKET
	AOJN T,CHXME2
	PUSHJ P,CHABRT
	JRST CHXME2

CHXME1:	HRRZ B,T11XMQ		;NO BUFFERS FREE RIGHT NOW, QUEUE
	JUMPE B,[ HRLZM A,T11XMQ ? JRST .+2 ]
	 HRLM A,-2(B)
	HRRM A,T11XMQ
	HRRZS -2(A)		;PUT END-LIST INDICATOR IN LH
CHXME2:	CONO PI,PICON(E)	;RESTORE PI
	POPJ P,
];T11CHP
IFN CH10P,[
;FOR NOW, JUST ALWAYS SHIP IT OUT THE CH10
	HRRZ B,CHXXMQ		;ADD TO END OF TRANSMIT QUEUE
	JUMPE B,[ HRLZM A,CHXXMQ ? JRST .+2 ]
	 HRLM A,-2(B)
	HRRM A,CHXXMQ
	HRRZS -2(A)		;PUT END-LIST INDICATOR IN LH
	MOVEI B,CHXTEN		;ENABLE TRANSMIT-DONE INTERRUPT
	IORM B,CHXCNO
	CONO CHX,@CHXCNO
	CONO PI,PICON(E)	;RESTORE PI
	POPJ P,
];CH10P
IFN CH11P,[
;FOR NOW, JUST ALWAYS SHIP IT OUT THE CH11
	HRRZ B,CHXXMQ		;ADD TO END OF TRANSMIT QUEUE
	JUMPE B,[ HRLZM A,CHXXMQ ? JRST .+2 ]
	 HRLM A,-2(B)
	HRRM A,CHXXMQ
	HRRZS -2(A)		;PUT END-LIST INDICATOR IN LH
	MOVEI B,%CATEN		;ENABLE TRANSMIT-DONE INTERRUPT
	IORB B,CHXCSR
	IOWRI B,CAICSR
	CONO PI,PICON(E)	;RESTORE PI
	POPJ P,
];CH11P

SUBTTL CHAOS NET DIRECT CONNECT TO STY

OVHMTR CHS

;CALLED AT CLOCK LEVEL FROM STYNTC WHEN A CHAOS STY IS ENCOUNTERED
;TTY NUMBER IN I & R
STYCHA:	MOVE I,STYNTI-NFSTTY(R)	;GET CHAOS INDEX
	MOVE TT,CHSSTA(I)
	TLNN TT,%CFSTY
	 JRST 4,.		;CHAOS CONNECTION CLAIMS NOT BE CONNECTED?
	JUMPL TT,STYCH9 .SEE %CFOFF	;OK TO USE?  IF NOT, DISCONNECT
	SKIPGE TTYOAC(R)	;ANY OUTPUT?
	 JRST STYCH1		;NO, CHECK FOR INPUT
	SKIPN D,CHSOBP(I)	;IF BUFFER ALLOCATED, USE IT
	 JRST [	SKIPG CHSNOS(I)	;OTHERWISE ALLOCATE ONE
		 JRST STYCH1	;WINDOW FULL, WAIT UNTIL REACTIVATED
		PUSHJ P,CHABGI
		 JRST STYCH3	;NO CORE, WAIT ONE CLOCK TICK
		MOVEI D,%CPKDT(A)
		HRLI D,440800
		MOVEM D,CHSOBP(I)
		MOVEI E,%CPMXC
		MOVEM E,CHSOBC(I)
		JRST .+3 ]
	  SKIPG E,CHSOBC(I)
	   JRST STYCH4		;BUFFER FULL, FORCE IT
	EXCH R,I		;I GETS TTY, R GETS CHAOS
	CONO PI,TTYOFF
	MOVEM D,DBBBP		;SET UP BUFFER FOR TTY OUTPUT INTERRUPT LEVEL
	MOVEM E,DBBCC
	MOVEM E,DBBCC1
	PUSH P,R
	SETOM TYPNTF
	PUSHJ P,TYP		;GENERATE OUTPUT
	SETZM TYPNTF
	POP P,R
	EXCH R,I		;I GETS CHAOS, R GETS TTY
	MOVE D,DBBBP		;ADVANCE POINTERS
	MOVEM D,CHSOBP(I)
	MOVE E,DBBCC
	SUB E,DBBCC1		;MINUS # CHARS OUTPUT GENERATED
	CONO PI,TTYON
	ADDM E,CHSOBC(I)
STYCH4:	PUSHJ P,CHAFC1		;FORCE THE BUFFER
	JRST STYCHA		;CHECK FOR MORE OUTPUT

STYCH3:	PUSHJ P,CHINTI		;REACTIVATE SO WILL COME BACK ON NEXT CLOCK TICK
STYCH1:	SOSGE CHSIBC(I)		;GET INPUT, IF ANY
	 JRST [	PUSHJ P,CHAIBD	;DISCARD EXHAUSTED INPUT BUFFER, IF ANY
		HLRZ A,CHSIBF(I)
		JUMPE A,STYNT8	;NONE, RETURN TO STYNTC
		LDB TT,[$CPKOP(A)]
		CAIE TT,%CODAT
		 JRST STYCH9	;RANDOM PACKET, DISCONNECT
		PUSHJ P,CHPKIA	;ACKNOWLEDGE GOBBLING OF THIS PACKET
		SOS CHSNBF(I)	;REMOVE BUFFER FROM RECEIVE LIST
		MOVEI Q,CHSIBF(I)
		PUSHJ P,CHAQGF
		LDB E,[$CPKNB(A)]	;SET UP FOR BYTE STREAM INPUT
		MOVEM E,CHSIBC(I)
		MOVEI D,%CPKDT(A)
		HRLI D,440800
		MOVEM D,CHSIBP(I)
		JRST STYCH1 ]
	ILDB A,CHSIBP(I)	;GET CHARACTER OF INPUT
	TRNE A,200
	 JRST [	AOS CHSIBC(I)	;WOOPS, SPECIAL CHARACTER, NEEDS USER ATTENTION
		MOVSI A,8_14	;SO PUT IT BACK AND DISCONNECT
		ADDM A,CHSIBP(I)
		JRST STYCH9 ]
	EXCH R,I		;I GETS TTY, R GETS CHAOS
	PUSH P,R
	PUSH P,I
	CONO PI,TTYOFF
	PUSHJ P,NTYI5		;GIVE CHARACTER TO TTY INPUT INTERRUPT LEVEL
	CONO PI,TTYON
	POP P,R
	POP P,I			;I GETS CHAOS, R GETS TTY ((POP IN REVERSE ORDER))
	JRST STYCH1		;TRY FOR MORE INPUT

STYCH9:	PUSH P,I
	MOVE I,R		;I GETS TTY
	PUSHJ P,NSTYN0		;DISCONNECT THE STY
	 JRST 4,.
	POP P,I			;I GETS CHAOS
	PUSHJ P,CHINTI		;WAKE UP THE TELNET SERVER
	JRST STYNT8		;GO HANDLE OTHER STYS

SUBTTL CHAOS NET CLOCK LEVEL STUFF

OVHMTR CHC

;HERE FROM 1/2 SECOND CLOCK.  DO RETRANSMISSIONS AND DELAYED STS'S
CHACLK:
IFN DLCP,[
	CONO PI,NETOFF
	PUSHJ P,DLCIBG		;GET MEMORY FOR INPUT BUFFERS IF NEEDED
	CONO PI,NETON
];DLCP
	MOVEI I,NINDX-1		;SCAN ALL INDICES
CHACL0:	SKIPL CHSUSR(I)		;SKIP THIS ONE IF NOT IN USE
	 SKIPGE CHSSTA(I) .SEE %CFOFF	;OR INHIBITED FROM PI LEVEL
	  SOJGE I,CHACL0
	JUMPL I,CPOPJ		;JUMP IF ALL INDICES DONE
	PUSHJ P,CHARTR		;RETRANSMIT IF NEEDED
	MOVSI B,%CFSTS
	TDNE B,CHSSTA(I)	;SEND STS IF NEEDED
	 PUSHJ P,CHASTO
	SOJGE I,CHACL0
	POPJ P,

;HERE EVERY 5 SECONDS, TO DO PROBES
CHA5CL:	MOVEI I,NINDX-1		;SCAN ALL INDICES
CHA5C0:	SKIPL CHSUSR(I)		;SKIP IF THIS ONE NOT IN USE
	 SKIPGE CHSSTA(I) .SEE %CFOFF ;OR INHIBITED FROM PI LEVEL
CHA5C1:	  SOJGE I,CHA5C0
	JUMPL I,CHA5C4		;JUMP IF ALL INDICES DONE
	MOVE T,TIME
	SUB T,CHSITM(I)		;TIME SINCE LAST COMMUNICATION FROM OTHER END
	CAILE T,90.*30.
	 JRST [	MOVEI W,%CSINC	;TOO LONG, CONNECTION BROKEN
		PUSHJ P,CHINT
		JRST CHA5C1 ]
	HRRZ B,CHSSTA(I)	;ONLY PROBE IF OPEN (COULD BE RFC-SENT)
	CAIE B,%CSOPN
	 JRST CHA5C1
	HRRZ B,CHSWIN(I)	;SEE IF NO TRANSMIT WINDOW (LOST STS DURING OPEN)
	JUMPE B,CHA5C2
	HRRZ B,CHSACK(I)	;SEE IF AWAITING ACK (WINDOW NOT EMPTY)
	HRRZ C,CHSPKN(I)
	CAMN B,C
	 CAIL T,60.*30.
CHA5C2:	  PUSHJ P,CHABGI	;AWAITING ACK OR IDLE FOR 1 MINUTE, PROBE
	   JRST CHA5C1		;NO PROBE, OR NO BUFFER AVAILABLE
	MOVSI T,(.DPB %COSNS,($CPKOP),0) ;SENSE PACKET, BYTE-COUNT=0
	MOVEM T,(A)
	AOS CHNSNS
	PUSHJ P,CHODT2
	JRST CHA5C1

CHA5C4:	MOVEI B,[ASCIZ/Timeout/]
	MOVEI Q,CHQRFC		;TIME-OUT FIRST RFC ON LIST
	PUSHJ P,CHAQGF
	JUMPE A,CHA5C5
	MOVE T,-1(A)
	ADDI T,60.*30.		;TIME-OUT IS ONE MINUTE
	PUSHJ P,[ CAMG T,TIME
		   JRST CHIRF2
		  JRST CHAQPF ]
CHA5C5:
IFN CH10P,[
	MOVEI T,CHXREN+CHXTEN	;WAKE UP IN CASE OF TIMING ERROR
	IORM T,CHXCNO		;IN DEALING WITH CHXCNO
	CONO CHX,@CHXCNO
	MOVSI T,-NSUBNT		;DECAY ROUTING COSTS
	CONO PI,NETOFF		;PREVENT RUT PACKET FROM COMING IN
CHA5C6:	HLRZ TT,SBNRUT(T)
	ADDI TT,1
	CAIG TT,1000
	 HRLM TT,SBNRUT(T)
	AOBJN T,CHA5C6
	CONO PI,NETON
];CH10P
IFN CH11P,[
	MOVEI T,%CAREN+%CATEN	;WAKE UP IN CASE OF TIMING ERROR
	IORB T,CHXCSR		;IN DEALING WITH CHXCSR
	IOWRI T,CAICSR
	MOVSI T,-NSUBNT		;DECAY ROUTING COSTS
	CONO PI,NETOFF		;PREVENT RUT PACKET FROM COMING IN
CHA5C6:	HLRZ TT,SBNRUT(T)
	ADDI TT,1
	CAIG TT,1000
	 HRLM TT,SBNRUT(T)
	AOBJN T,CHA5C6
	CONO PI,NETON
];CH11P
	MOVEI T,5*60.
	MOVEI C,CHA5CK
	JRST CLQREE

OVHMTR CHR

;RETRANSMIT FOR INDEX IN I
CHARTR:	CONI PI,W		;SAVE PI CHANNELS ACTIVE
	ANDI W,177		;CHAXMT BETTER NOT CLOBBER W!
	CONO PI,NETOFF		;PI BETTER BE OFF THROUGHOUT THIS ZONE
				; SO WE DON'T GET INTO CHIACK
	HLRZ A,CHSOBF(I)	;SCAN DOWN OUTPUT BUFFER LIST
	JUMPE A,CHART2		;EMPTY
CHART1:	MOVE T,-1(A)		;DON'T RETRANSMIT IF DONE TOO RECENTLY
	HLRZ TT,-2(A)		;OR IF ALREADY ON ITS WAY OUT (DON'T LINK TWICE ON XMIT LIST)
	CAME T,TIME
	 CAIE TT,-1
	  JRST CHART2		;ANYTHING AFTER THIS IS LIKELY TO LOSE ALSO
	AOS CHNRTR
	PUSHJ P,CHAXMT		;RETRANSMIT THIS
;	HRRZ A,-2(A)		;THREAD TO NEXT
;	JUMPN A,CHART1
CHART2:	CONO PI,PICON(W)
	POPJ P,

;THIS ROUTINE SENDS A STS PACKET, OR TRIES TO.  FAILURE => SLOW CLOCK WILL TRY AGAIN.
;CANNOT PCLSR NOR WAIT, CALLABLE FROM INTERRUPT LEVEL.
;INDEX IN I, CLOBBERS A,B,C,D,E,T,TT,Q,J
CHASTO:	MOVSI D,%CFSTS
	IORM D,CHSSTA(I)
	PUSHJ P,CHABGI		;GET A BUFFER, WITHOUT WAITING
	 POPJ P,		;CAN'T GET ONE, WILL RETRY AT CLOCK LEVEL
	ANDCAM D,CHSSTA(I)	;OK, A STS WILL BE SENT, CLEAR NEED-STS FLAG
	MOVE T,[.DPB %COSTS,($CPKOP),<.DPB 4,($CPKNB),0>]
	MOVEM T,(A)		;SEND A STS WITH 4 DATA BYTES
	PUSHJ P,DPBRCP		;FIRST PAIR IS RECEIPT
	HLRZ B,CHSWIN(I)	;SECOND PAIR IS WINDOW SIZE
	DPB B,[042000,,%CPKDT(A)]
	AOS CHNSTS
	JRST CHODT2		;FIRE IT OFF

DPBRCP:	HLRZ B,CHSPKN(I)
	SKIPE T,CHSIBF(I)
	 LDB B,[$CPKPN(T)]
	DPB B,[242000,,%CPKDT(A)]
	POPJ P,

SUBTTL CHAOS NET INTERRUPT-LEVEL INPUT PROCESSING

OVHMTR CHI

;PROCESS A PACKET RECEIVED AT INTERRUPT LEVEL.  BY THE TIME WE GET HERE
; A BUFFER HAS BEEN ALLOCATED AND FILLED WITH THE DATA FROM THE DEVICE.
; ITS ADDRESS IS IN A.  RETURN VIA POPJ P, WITH ALL REGISTERS CLOBBERED.
CHAPII:	MOVE B,RECHDP		;SAVE HEADER FOR DEBUGGING IN RING BUFFER
	MOVEI D,%CPKDT(B)
	HRL B,A
	BLT B,-1(D)
	CAIN D,RECHDR+<NRECHD*%CPKDT>
	 MOVEI D,RECHDR
	MOVEM D,RECHDP
	;END OF DEBUGGING CODE
	LDB D,[$CPKMV(A)]	;MUPPET?
	JUMPN D,CHABRT		;FLUSH, NOT SUPPORTED
	LDB D,[$CPKOP(A)]	;GET OPCODE
	LDB B,[$CPKDA(A)]	;CHECK DESTINATION
	CAIE B,MYCHAD		;IF FOR ME,
	 SKIPN B		;OR FOR ME BY VIRTUE OF BROADCAST
	  AOSA CHNPI		;ACCEPT IT
	   JRST CHAPFW		;NOT ME, FORWARD
	LDB C,[$CPKNB(A)]	;PASS LENGTH IN C TO OP ROUTINES
	MOVEI B,[ASCIZ/Illegal byte count/]
	CAILE C,%CPMXC
	 JRST CHALOS
	SKIPGE (A)		;TEST OPCODE
	 JRST CHIDAT		;DATA PACKET
	MOVEI B,[ASCIZ/Illegal opcode/]
	CAIGE D,%COMAX
	 JRST @.+1(D)
	OFFSET -.
	JRST CHALOS		;ILLEGAL, FLUSH
%CORFC::JRST CHIRFC
%COOPN::JRST CHIOPN
%COCLS::JRST CHICLS
%COFWD::JRST CHIANS
%COANS::JRST CHIANS
%COSNS::JRST CHISNS
%COSTS::JRST CHISTS
%CORUT::
IFE CH10P+CH11P,JRST CHABRT	;IGNORE
IFN CH10P+CH11P,JRST CHIRUT
%COLOS::JRST CHILOS
%COLSN::JRST CHALOS		;ILLEGAL, FLUSH
%COMNT::JRST CHABRT		;IGNORE
%COEOF::JRST CHIDAT
%COUNC::JRST CHIUNC
%COBRD::JRST CHIBRD
%COMAX::OFFSET 0

;FORWARDING
CHAPFW:	LDB B,[$CPKDA(A)]	;CHECK DESTINATION HOST
	TRNN B,377_8		;SUBNET 0?
	 JRST CHABRT		;FLUSH IT, XX-NETWORK-11 IS TRYING TO MAKE US CRASH
	LDB B,[$CPKFC(A)]	;INCREMENT FORWARDING COUNT
	ADDI B,1
	CAIL B,20
	 JRST [ AOS CHNPFL ? JRST CHABRT ]	;LOOP, DISCARD
	DPB B,[$CPKFC(A)]
	SETOM -2(A)		;NOT ON SEND LIST
	AOS CHNPF
	JRST CHAXMT

IFN CH10P+CH11P,[		;INCOMING ROUTING INFO
CHIRUT:	LSH C,-2		;NUMBER OF SUBNET ENTRIES
	JUMPE C,CHABRT		;COULD BE ZERO-LENGTH
	MOVEI D,%CPKDT(A)
	HRLI D,442000
	LDB E,[$CPKSA(A)]	;SOURCE HOST IS GATEWAY
CHIRU1:	ILDB T,D		;SUBNET
	ILDB TT,D		;COST
	HLRZ B,SBNRUT(T)	;COST OF EXISTING ROUTE
	CAIGE T,NSUBNT
	 CAMLE TT,B
	  JRST CHIRU2
	HRLM TT,SBNRUT(T)	;THIS IS BEST ROUTE NOW
	HRRM E,SBNRUT(T)
CHIRU2:	SOJG C,CHIRU1
	JRST CHABRT
];CH10P+CH11P

;INTERRUPT-LEVEL PROCESSING OF SNS PACKET
;NOTE THAT WE DO NOT BARF AT SNS'S TO EXISTENT NON-OPEN CONNECTIONS.  IF IT
;WAS AN RFC-SENT CONNECTION, THIS COULD BREAK IT PREMATURELY IF AN OPN WAS
;LOST AND THEN A SNS WAS NOT.
CHISNS:	MOVEI E,%CSOPN
	PUSHJ P,CHFNDX
	 JRST [	CAIE E,%CSOPN
		 JRST CHABRT	;CONNECTION EXISTS AND IS NOT OPEN, IGNORE PACKET
		JRST CHALOS ]	;CONNECTION DOES NOT EXIST, COMPLAIN
	PUSHJ P,CHABRT		;CONNECTION DOES EXIST
	CAIE E,%CSOPN
	 POPJ P,		;NOT OPEN, IGNORE
	JRST CHASTO		;REPLY WITH STS

;INTERRUPT LEVEL PROCESSING OF RECEIVED FWD OR ANS
CHIANS:	PUSHJ P,CHFNDX		;FIND CONNECTION
	 JRST CHABRT		;NOBODY AT OTHER END TO RECEIVE A LOS ANYWAY
	CAIE E,%CSRFS
	 JRST CHABRT		;NOT IN RFC-SENT STATE, LOSS
;	JRST CHICL1		;CLOSE THE CONNECTION BUT GIVE TO USER AS INPUT
	;DROPPING THROUGH WILL DO

;INTERRUPT LEVEL PROCESSING OF RECEIVED CLS PACKET
CHICLS:	PUSHJ P,CHFNDX		;FIND CONNECTION BEING CLOSED
	 JRST CHALOS		;NONE, LOSS
CHICL1:	MOVEI W,%CSCLS		;CLOSE THE CONNECTION
CHICL2:	PUSHJ P,CHINT		;SET TO STATE IN W, INTERRUPT
	PUSH P,A
	MOVEI Q,CHSPBF(I)	;DISCARD OUT-OF-ORDER PACKETS
	PUSHJ P,CHALFR
	HRRZS CHSNBF(I)
CHIC2A:	MOVEI Q,CHSOBF(I)	;DISCARD TRANSMIT PACKETS, E.G. RFC WHICH RECEIVED
	PUSHJ P,CHAQGF		;AN ANS OR FWD, DON'T WANT TO TRANSMIT AGAIN
	JUMPE A,CHIC2B
	PUSHJ P,CHABR1
	JRST CHIC2A

CHIC2B:	POP P,A
	JRST CHIDT1		;GIVE PACKET TO USER AS DATA
;INTERRUPT LEVEL PROCESSING OF RFC PACKET
CHIRFC:	MOVE T,%CPKDT(A)	;CHECK FOR STATUS REQUEST
	CAMN T,[.BYTE 8 ? "S ? "T ? "A ? "T]
	 CAIE C,6
	  JRST CHIRF7
	MOVS TT,%CPKDT+1(A)
	XORI TT,(<.BYTE 8 ? "U ? "S>)
	TRNN TT,(<.BYTE 8 ? -1 ? -1>)
	 JRST CHIRF3
CHIRF7:	MOVEI Q,CHQLSN		;SEARCH LISTENING QUEUE
	PUSHJ P,CHAQSR
	 JRST CHIRF1		;NOT FOUND, LOAD SERVER
	EXCH A,B		;A LSN, B RFC
	LDB I,[$CPKSX(A)]	;GET CORRESPONDING INDEX
	HRRZ E,CHSSTA(I)
	CAIE E,%CSLSN
	 JRST 4,.
CHIRF0:	PUSHJ P,CHABRT		;FOUND, DISCARD LISTEN PACKET
	MOVE A,B		;GET OTHER HOST'S RFC
	LDB B,[$CPKPN(A)]	;INITIALIZE RECEIVER'S PACKET NUMBER
	HRLM B,CHSPKN(I)
	MOVE B,%CPKS(A)
	MOVEM B,CHSFRN(I)	;HOOK 'EM UP
	MOVEI W,%CSRFC		;PUT INTO RFC-RECEIVED STATE
	MOVE T,TIME		;AND ENGAGE PI LEVEL
	MOVEM T,CHSITM(I)
	JRST CHICL2
	
;RFC RECEIVED AND NOT IMMEDIATELY MATCHED TO A LSN.  QUEUE AND LOAD SERVER JOB.
;BUT FIRST CHECK WHETHER THIS IS A DUPLICATE WHICH SHOULD BE DISCARDED.
CHIRF1:	MOVE C,%CPKS(A)		;SEARCH PENDING RFC QUEUE FOR RFC FROM
	HLRZ T,CHQRFC		;THE SAME SOURCE AS THIS.
	JUMPE T,CHIRD1
CHIRD0:	CAMN C,%CPKS(T)
	 JRST CHABRT		;THIS RFC IS A DUPLICATE, IGNORE IT
	HRRZ T,-2(T)
	JUMPN T,CHIRD0
CHIRD1:	MOVSI T,-NINDX		;SEARCH OPEN AND RFC-RECEIVED CONNECTIONS
CHIRD2:	SKIPL CHSUSR(T)		;FOR ONE CONNECTED TO SAME GUY AS SENT RFC
	 CAME C,CHSFRN(T)
	  AOBJN T,CHIRD2
	JUMPGE T,CHIRD3		;NO DUPLICATE OF THIS RFC, QUEUE IT
	HRRZ TT,CHSSTA(T)
	CAIE TT,%CSOPN
	 CAIN TT,%CSRFC
	  JRST CHABRT		;REALLY A DUPLICATE, DISCARD
	AOBJN T,CHIRD2
CHIRD3:	MOVEI B,[ASCIZ/System not up/]
	SKIPL SYSDBG		;REFUSE INCOMING CONNECTIONS IF LOGINS REFUSED
	 SKIPE NETUSW		;ALLOWING INCOMING NET CONNECTIONS?
	  JRST CHIRF2		;NO, REFUSE (EVEN IF FROM OURSELVES)
	HRROI T,CHIRFJ		;LOAD JOB
	CONI PI,Q		;MUST TURN UTCOFF TO CALL NUJBST
	ANDI Q,177		;SINCE THIS MAY RUN AT OTHER INT LEVELS
	CONO PI,NETOFF
	PUSHJ P,NUJBST
	 JRST [	CONO PI,PICON(Q)
		JRST CHABRT ]	;RING BUFFER FULL, IGNORE, RETRY WILL CATCH
	CONO PI,PICON(Q)
	MOVE T,TIME		;REMEMBER WHEN THIS RFC WAS QUEUED
	MOVEM T,-1(A)
	MOVEI Q,CHQRFC
	JRST CHAQPF		;PUT ON FRONT OF QUEUE

;COME HERE TO SEND A LOS PACKET IN RESPONSE TO CRUFTY INPUT IN A
;B SHOULD POINT TO AN ASCIZ STRING FOR WHY.
CHALOS:	SKIPA T,[%COLOS]
;HERE TO REFUSE AN RFC.  TURN IT INTO A CLS AND SEND IT BACK.
;B SHOULD POINT TO AN ASCIZ STRING FOR WHY.
CHIRF2:	 MOVEI T,%COCLS
	HRLI B,440700		;BP TO MESSAGE
	SETZB C,(A) .SEE $CPKFC
	DPB T,[$CPKOP(A)]
	MOVE T,%CPKS(A)		;EXCHANGE SOURCE AND DESTINATION
	EXCH T,%CPKD(A)
	MOVEM T,%CPKS(A)
	MOVE D,[440800,,%CPKDT(A)]
CHIRF4:	ILDB T,B
	JUMPE T,CHIRF5
	IDPB T,D
	AOJA C,CHIRF4

CHIRF5:	DPB C,[$CPKNB(A)]
	SETOM -2(A)		;NOT ON ANY SEND LIST
	JRST CHAXMT		;SEND IT

;HERE FOR RFC TO "STATUS" 
EXPUNGE FOO,BAR
DEFINE FOO NAME
BAR==0
.BYTE 8
IRPC CH,,NAME
"CH
BAR==BAR+1
TERMIN
IFG BAR-4, .ERR NAME MORE THAN 4 CHARACTERS
REPEAT 4-BAR, 0
.BYTE
TERMIN

CHIRF3:	MOVE B,[MNAME FOO ,,]	;NAME OF MACHINE IN 8-BIT ASCII
EXPUNGE FOO,BAR
	MOVEM B,%CPKDT(A)
	SETZM %CPKDT+1(A)
	MOVSI B,%CPKDT+1(A)
	HRRI B,%CPKDT+2(A)
	BLT B,%CPKDT+7(A)
	MOVE B,[.BYTE 8 ? MYCHAD/400 ? 1 ? 4+IFN CH10P+CH11P,[10.] ? 0 ]
	MOVEM B,%CPKDT+10(A)
	MOVEI B,%CPKDT+11(A)
	HRLI B,441000
	MOVE T,CHNPI
	PUSHJ P,CHRF3A
	MOVE T,CHNPO
	PUSHJ P,CHRF3A
IFN CH10P+CH11P,[
	MOVE T,CHNABT
	PUSHJ P,CHRF3A
	MOVE T,CHNLOS
	PUSHJ P,CHRF3A
	MOVE T,CHNCRC
	PUSHJ P,CHRF3A
	MOVE T,CHNCR2
	PUSHJ P,CHRF3A
	MOVE T,CHNPLE
	ADD T,CHNWLE
	PUSHJ P,CHRF3A
];CH10P+CH11P
	MOVEI T,%COANS
	SETZM (A) .SEE $CPKFC
	DPB T,[$CPKOP(A)]
	MOVE T,%CPKS(A)		;EXCHANGE SOURCE AND DESTINATION
	EXCH T,%CPKD(A)
	MOVEM T,%CPKS(A)
	MOVEI C,13*4+IFN CH10P+CH11P,[20.]	;BYTE COUNT
	JRST CHIRF5		;SEND

CHRF3A:	MOVEI TT,4
	IDPB T,B
	LSH T,-8
	SOJG TT,.-2
	POPJ P,

;HERE TO CONVERT A BRD INTO AN RFC

CHIBRD:	LDB T,[$CPKAN(A)]	;NUMBER OF BITMAP BYTES
	LDB TT,[$CPKNB(A)]	;NUMBER OF TOTAL DATA BYES (INCLUDES BITMAP)
	CAIG T,32.		;ACK NUMBER NO GREATER THAN 32.
	 TRNE T,3		; MUST BE MULTIPLE OF 4
	  JRST CHABRT		;  FREE THE PACKET IF NO GOOD
	CAMG TT,T		;MUST BE SOME TEXTUAL RFC DATA AS WELL
	 JRST CHABRT		; IF NOT, FREE PACKET
	MOVE C,TT		;GET NUMBER OF BYTES (CHIRFC WANTS COUNT IN C)
	SUB C,T			;WITHOUT BITMAP
	DPB C,[$CPKNB(A)]	;NEW BYTE COUNT
	LSH T,-2		;CONVERT BITMAP BYTE COUNT TO WORD COUNT
	ADDI TT,3		;CONVERT BYTE COUNT TO...
	LSH TT,-2		;... WORD COUNT
	MOVEI D,%CPKDT(A)	;GET POINTER TO BEGINNING OF DATA
	HRL D,D			;IN UPPER AND LOWER HALVES (ALMOST BLT POINTER)
	HRLZ T,T		;BITMAP WORD COUNT,,0
	ADD D,T			;RFC-STRING,,DATA-FIELD
	ADDI TT,%CPKDT-1(A)	;LAST LOCATION FOR BLT
	BLT D,(TT)
	SETZI TT,
	DPB TT,[$CPKAN(A)]	;ZERO THE ACK FIELD
	MOVE TT,MYCHAD
	DPB TT,[$CPKDA(A)]	;PRETEND IT WAS FOR ME
	JRST CHIRFC		;AND HANDLE IT AS AN RFC


;ROUTINE TO FIND INDEX PACKET CORRESPONDS TO, SKIP IF FOUND, INDEX IN I.
;ALSO RETURNS STATE IN E SINCE THAT'S OFTEN HANDY.
;ALSO SETS B FOR CHALOS
CHFNDX:	MOVEI B,[ASCIZ/Connection does not exist at this end/]
	LDB I,[$CPKDX(A)]	;GET REAL-INDEX PART OF DESTINATION INDEX
	CAIGE I,NINDX
	 SKIPGE CHSUSR(I)
	  POPJ P,		;NO MATCH
	SKIPGE CHSSTA(I) .SEE %CFOFF
	 POPJ P,		;NOT TALKING TO NETWORK
	HRRZ E,CHSSTA(I)
	MOVE TT,%CPKD(A)
	MOVE T,%CPKS(A)
	CAIN E,%CSRFS		;IF IN RFC-SENT STATE, ONLY
	 AND T,[.BYTE 16. ? -1 ? 0]	;THE SOURCE HOST HAS TO MATCH
	CAMN TT,CHSLCL(I)	;COMPARE LOCAL ADDRESS
	 CAME T,CHSFRN(I)	; AND FOREIGN ADDRESS
	  POPJ P,		;NO MATCH
	MOVE T,TIME
	MOVEM T,CHSITM(I)
	JRST POPJ1		;SUCCEED, CALLER CHECKS THE STATE

;INTERRUPT LEVEL PROCESSING OF RECEIVED OPN PACKET
CHIOPN:	PUSHJ P,CHFNDX		;FIND CONNECTION TO BE OPENED
	 JRST CHALOS
	CAIE E,%CSRFS		;NOT IN RFC-SENT STATE,
	 JRST CHABRT		; MUST BE DUPLICATE, DISCARD.
	LDB B,[$CPKPN(A)]	;GET ITS PACKET NUMBER
	HRLM B,CHSPKN(I)	;INITIALIZE PACKET NUMBERING OF RECEIVED MESSAGES
	MOVE B,%CPKS(A)
	MOVEM B,CHSFRN(I)	;HOOK 'EM UP
	PUSHJ P,CHIST1		;PROCESS AS A STS, DISCARD
	PUSHJ P,CHASTO		;RESPOND WITH A STS
	MOVEI W,%CSOPN
	;DROP INTO CHINT

;COME HERE WITH INDEX IN I AND NEW STATE IN W, TO CHANGE STATE AND INTERRUPT
CHINT:	HRRM W,CHSSTA(I)
	MOVE T,TIME
	MOVEM T,CHSITM(I)	;IN CASE GOT HERE FROM CHOLSN
	MOVSI T,%CFOFF
	CAIE W,%CSOPN
	 IORM T,CHSSTA(I)	;DISENGAGE PI LEVEL
	CAIN W,%CSOPN
	 ANDCAM T,CHSSTA(I)	;NOW OPEN, ENGAGE PI LEVEL
;COME HERE TO INTERRUPT ON THE INPUT CHANNEL.  SMASHES T,TT,W
CHINTI:	LDB T,[$CHSUI,,CHSUSR(I)]
CHINT2:	MOVE TT,CHSSTA(I)	;SIGNAL USER OR STY?
	TLNN TT,%CFSTY
	 JRST CHINT4		;USER
	LDB T,[$CFTTN,,TT]	;STY, GET TTY NUMBER
	CONO PI,PIOFF		;PROTECT LIST MODIFICATION
	SKIPL STYNTL-NFSTTY(T)	;DON'T PUT ON LIST TWICE
	 JRST PIONJ
	MOVE TT,STYNTA		;ADD TO LIST
	MOVEM TT,STYNTL-NFSTTY(T)
	MOVEM T,STYNTA
	JRST PIONJ

CHINT4:	SKIPGE TT,CHSUSR(I)
	 JRST 4,.
	MOVSI W,(SETZ)		;PCLSR THE JOB SO IT GETS AN IOC ERROR IF NEEDFUL
	IORM W,PIRQC(TT)	;EVEN IF NORMAL INTERRUPTS ARE NOT ENABLED
	CAIN T,77
	 POPJ P,		;IOPUSH'D, NO INTERRUPT
	MOVE T,CHNBIT(T)
	AND T,MSKST2(TT)
	IORM T,IFPIR(TT)
	POPJ P,

OVHMTR CHD

;INTERRUPT LEVEL PROCESSING OF RECEIVED DATA PACKET
CHIDAT:	PUSHJ P,CHFNDX		;FIND ASSOCIATED CONNECTION
	 JRST CHALOS		;NONE, LOSS
	CAIE E,%CSOPN		;STATE MUST BE OPEN
	 JRST CHALOS		;BAD, LOSS
	PUSHJ P,CHIACK		;PROCESS ACKNOWLEDGEMENT FIELD
;NOW DECIDE WHETHER IT GOES ON CHSIBF(I), OR ON CHSPBF(I), OR GETS DISCARDED.
	HLRZ B,CHSPKN(I)	;LAST PACKET NUMBER GIVEN TO USER
	LDB C,[$CPKPN(A)]	;GET PACKET NUMBER OF THE NEW PACKET
	HLRZ T,CHSWIN(I)	;RECEIVE WINDOW SIZE
	ADDI T,(B)		;HIGHEST LEGAL PACKET NUMBER
	SUB T,C
	TRNE T,100000		;SKIP IF T >= C
	 JRST CHABRT		;FOO ON YOU, OVER WINDOW SIZE
	HRRZ T,CHSIBF(I)	;COMPUTE NEXT IN-ORDER PACKET EXPECTED
	JUMPE T,CHIDT6		;BASED ON LAST IN-ORDER PACKET
	LDB TT,[$CPKOP(T)]
	CAIE TT,%COUNC
	 JRST [	LDB B,[$CPKPN(T)]
		JRST CHIDT6 ]
	HLRZ T,CHSIBF(I)	;IF IT'S AN UNC, HAVE TO GO FIND CORRECT PACKET
CHIDT5:	LDB TT,[$CPKOP(T)]
	CAIE TT,%COUNC
	 LDB B,[$CPKPN(T)]
	HRRZ T,-2(T)
	JUMPN T,CHIDT5
CHIDT6:	ADDI B,1
	ANDI B,177777		;NEXT IN-ORDER PACKET EXPECTED
	CAMN B,C
	 JRST CHIDT1		;EQUAL, IT GOES ON THE END OF CHSIBF(I) LIST.
	SUB B,C			;NOT EQUAL, COMPARE THEM MODULO 2^16.
	TRNN B,100000
	 JRST CHIDTD		;B GREATER, THIS IS AN OLD PACKET, DISCARD IT
	;PUT ON CHSPBF(I) IN PROPER ORDER
	;A IS THIS PACKET, C IS HIS NUMBER, B IS PREDECESSOR, D IS NEXT, E IS HIS #
	MOVEI B,0		;SIGNIFY AT FRONT OF LIST
	HLRZ D,CHSPBF(I)	;GET FIRST PACKET ON OUT-OF-ORDER LIST
	JUMPE D,CHIDT4		;LIST IS EMPTY
CHIDT3:	LDB E,[$CPKPN(D)]
	SUB E,C			;COMPARE PACKET NUMBERS
	JUMPE E,CHIDTD		;DUPLICATE, DISCARD
	TRNE E,100000
	 JRST [	MOVE B,D	;E IS LESS, KEEP LOOPING
		HRRZ D,-2(B)
		JUMPN D,CHIDT3
		JRST .+1 ]	;REACHED END PUT IT HERE
	SKIPE B
	 HRRM A,-2(B)		;THREAD ONTO PREVIOUS PACKET
	SKIPN D
CHIDT4:	 HRRM A,CHSPBF(I)	;THREAD ONTO BACK OF LIST
	SKIPN B
	 HRLM A,CHSPBF(I)	;THREAD ONTO FRONT OF LIST
	HRRM D,-2(A)		;THREAD IN BEFORE PACKET IN D
	MOVSI B,1
	ADDM B,CHSNBF(I)
	POPJ P,

;HERE IT GOES ON CHSIBF(I).  A HAS PACKET, C HAS ITS PACKET NUMBER.
;IF GETTING HERE FROM CHICL1, C HAS GARBAGE BUT IT WILL NEVER BE USED.
CHIDT1:	SKIPN CHSIBF(I)
	 PUSHJ P,CHINTI		;THERE WAS NO INPUT, BUT THERE IS NOW, COME AND GET IT
	AOS CHSNBF(I)
	MOVEI Q,CHSIBF(I)
	PUSHJ P,CHAQPL		;PUT ON END OF RECEIVE LIST
	HLRZ A,CHSPBF(I)	;GET FIRST OUT-OF-ORDER PACKET
	JUMPE A,CPOPJ		;NONE
	LDB B,[$CPKPN(A)]	;SEE IF THIS PACKET IS NOW IN-ORDER
	CAIL C,177777		;BY COMPARING AGAINST C+1 MODULO 2^16.
	 TDZA C,C
	  ADDI C,1
	CAME B,C
	 POPJ P,		;NO
	MOVEI Q,CHSPBF(I)
	PUSHJ P,CHAQGF		;YES, PULL PACKET OF OUT-OF-ORDER LIST
	MOVSI B,-1
	ADDM B,CHSNBF(I)
	JRST CHIDT1		;AND GO PUT ONTO IN-ORDER LIST

;HERE IF PACKET IS A DUPLICATE AND IS TO BE DISCARDED.  MUST SEND
;RECEIPT TO SHUT OFF EXCESS RETRANSMISSION.
CHIDTD:	PUSHJ P,CHABRT
	AOS CHNPD
	JRST CHASTO

;HERE FOR RECEIVING AN UNC PACKET
CHIUNC:	LDB I,[$CPKDI(A)]	;Destination index zero?
	JUMPE I,CHIUN2	
	LDB I,[$CPKDX(A)]	;GET REAL-INDEX PART OF DESTINATION INDEX
	CAIGE I,NINDX
	 SKIPGE CHSUSR(I)
	  JRST CHALOS		;NO MATCH
	MOVE TT,%CPKD(A)	;DESTINATION ADDRESS MATCHES?
	CAME TT,CHSLCL(I)
	 JRST CHALOS
	HRRZ E,CHSSTA(I)	;IN FOREIGN PROTOCOL MODE?
	CAIN E,%CSFRN
	 JRST CHIUN1
	MOVE TT,%CPKS(A)	;NORMAL PROTOCOL, SOURCE ADDRESS MUST MATCH
	CAMN TT,CHSFRN(I)
	 CAIE E,%CSOPN		;AND STATE MUST BE OPEN
	  JRST CHALOS
CHIUN1:	MOVE TT,TIME
	MOVEM TT,CHSITM(I)
	SKIPE T,CHSIBF(I)	;DISCARD PACKET IF OVER WINDOW SIZE
	 JRST [	LDB TT,[$CPKOP(T)]	; AND ALREADY HAVE AN UNC
		HRRZ T,CHSNBF(I)
		HLRZ Q,CHSWIN(I)
		CAML T,Q
		 CAIE TT,%COUNC
		  JRST .+2
		JRST CHABRT ]		
	  PUSHJ P,CHINTI	;THERE WAS NO INPUT, BUT THERE IS NOW, COME AND GET IT
	AOS CHSNBF(I)		;PUT ON END OF RECEIVE LIST.
	MOVEI Q,CHSIBF(I)	;PACKET NUMBER IS RANDOM, NOTHING LOOKS AT IT
	JRST CHAQPL

CHIUN2:
IFE INETP,JRST CHALOS		;No comprendo internet
IFN INETP,[
	LDB I,[$CPKAN(A)]	;Protocol number
	CAIE I,8_8		;DOD Internet #x0800
	 JRST CHALOS
	AOS CHNIPI		;Meter Internet packets in from Chaosnet
	MOVE J,A		;Save Chaosnet packet
	LDB A,[$CPKNB(A)]	;Compute size of Internet datagram in words
	ADDI A,3
	LSH A,-2
	MOVE C,A		;Save word count
	CALL IPGIPT		;Get buffer to copy datagram into
	 JRST CHIUN3		;No buffers available, discard packet
	MOVSI T,%CPKDT(J)	;Make BLT pointer
	HRRI T,1(B)
	ADDI B,(C)		;Address of last destination word
	BLT T,(B)
	EXCH A,J		;Free the Chaosnet packet
	CALL CHABRT
	MOVE A,J		;Datagram structure
	MOVE B,C		;Word count
	MOVEI C,0		;Offset to start of IP header
	CALRET IPRDGM		;Dispose of datagram

CHIUN3:	MOVE A,J		;Discard Chaosnet packet
	CALRET CHABRT
];INETP

OVHMTR CHJ

;INTERRUPT LEVEL PROCESSING OF LOS
CHILOS:	PUSHJ P,CHFNDX		;FIND CONNECTION TO BE BROKEN
	 JRST CHABRT		;NONE, IGNORE
	MOVEI W,%CSLOS		;PUT INTO LOST STATE
	JRST CHICL2		;GIVE PACKET TO USER AS DATA, DISENGAGE, AND INTERRUPT

;INTERRUPT LEVEL PROCESSING OF STS
CHISTS:	PUSHJ P,CHFNDX
	 JRST CHALOS
	CAIE E,%CSOPN		;CONNECTION MUST BE OPEN
	 JRST CHALOS
CHIST1:	LDB B,[042000,,%CPKDT(A)]	;GET NEW WINDOW SIZE
	CAILE B,MXWIND
	 MOVEI B,MXWIND
	HRRM B,CHSWIN(I)
	LDB B,[242000,,%CPKDT(A)]	;PROCESS RECEIPT
	PUSHJ P,CHIAK0
	PUSHJ P,CHABRT
	JRST CHARTR		;RETRANSMIT

OVHMTR CHA

;INTERRUPT LEVEL PROCESSING OF RECEIVED ACKNOWLEDGEMENT.
;REMOVE THE ACKNOWLEDGED PACKETS FROM THE INDEX'S SEND LIST AND UPDATE CHSNOS(I).
;NOTE THAT THE LIST IS ASSUMED TO BE SORTED SO WE ONLY
;REMOVE PACKETS FROM THE FRONT.  CLOBBERS B,C,D,T,TT,Q.
CHIACK:	LDB B,[$CPKAN(A)]	;PACKET NUMBER BEING RECEIPTED
CHIAK0:	LDB T,[$CPKAN(A)]	;ENTER HERE FROM CHISTS
	HRRZ D,CHSACK(I)	;GET MAX OF THIS ACKNOWLEDGE AND PREVIOUS
	SUB D,T
	TRNE D,100000
	 HRRM T,CHSACK(I)	;ACKNOWLEDGED PACKET NUMBER IS NEW START OF WINDOW
	PUSH P,A
	HLRZ A,CHSOBF(I)	;MAP DOWN SEND LIST
	JUMPE A,CHIAK2		;LIST EMPTY
CHIAK1:	LDB D,[$CPKPN(A)]
	SUBM B,D
	TRNE D,100000
	 JRST CHIAK2		;RCP# LESS THAN PKT#
	HRRZ C,-2(A)		;GET NEXT PACKET
	HLLOS D,-2(A)		;MARK NOT ON SEND LIST
	AOJE D,CHIAK3		;AND JUMP IF NOT ON TRANSMIT LIST
IFN DLCP,[
	MOVEI Q,DLCXMQ		;ON TRANSMIT LIST, TRY TO TAKE OFF
	PUSHJ P,CHIAKF
];DLCP
IFN T11CHP,[
	MOVEI Q,T11XMQ
	PUSHJ P,CHIAKF
];T11CHP
IFN CH10P+CH11P,[
	MOVEI Q,CHXXMQ
	PUSHJ P,CHIAKF
];CH10P+CH11P
	CAIA			;AND DON'T FREE IT
CHIAK3:	 PUSHJ P,CHABRT
	HRLM C,CHSOBF(I)
	SKIPE A,C
	 JRST CHIAK1
	SETZM CHSOBF(I)		;SEND LIST NOW EMPTY
CHIAK2:	MOVE D,CHSNOS(I)	;COMPUTE NEW VALUE OF CHSNOS
	HRRZ T,CHSACK(I)	;START OF WINDOW
	HRRZ C,CHSPKN(I)	;LAST PACKET SENT
	SUB T,C
	SKIPLE T
	 SUBI T,200000		;T GETS NEGATIVE AMOUNT OF WINDOW OCCUPIED
	ADD T,CHSWIN(I)		;RH(T) GETS AVAILABLE PORTION OF WINDOW
	HRREM T,CHSNOS(I)	;WHICH IS NUMBER OF OUTPUT SLOTS
	JUMPG D,POPAJ		;IF FORMERLY THERE WERE NO OUTPUT SLOTS,
	LDB T,[$CHSUO,,CHSUSR(I)]
	SKIPLE CHSNOS(I)	;AND NOW THERE ARE,
	 PUSHJ P,CHINT2		;INTERRUPT ON THE OUTPUT CHANNEL
	JRST POPAJ

;TRY TO TAKE PACKET IN A OFF OF TRANSMIT LIST IN Q.
;CLOBBER T,Q,D.  CALLED WITH INTERRUPTS OFF.
;MAY RETURN WITH A POINTING TO FREE BUT THAT IS OK AT THIS TIME.
CHIKF1:	SKIPA D,T
CHIAKF:	 MOVEI D,2(Q)		;LH[-2(D)] POINTS TO (T)
	HLRZ T,-2(D)
	JUMPE T,CPOPJ		;NOT FOUND
	CAIE T,(A)
	 JRST CHIKF1
	HLRZ T,-2(A)		;LINK OUT
	HRLM T,-2(D)
	JUMPN T,CHABRT		;JUMP IF DIDN'T DELETE LAST PACKET IN LIST
	HRRM D,(Q)		;NEW LAST PACKET IN LIST
	CAIN D,2(Q)
	 SETZM (Q)		;FOO, TRANSMIT LIST NOW EMPTY
	JRST CHABRT

SUBTTL CHAOS NET DL10 INTERRUPT ROUTINE

OVHMTR CHH

IFN DLCP,[

;COME HERE FROM EACH DL10 INTERRUPT AT TTY LEVEL.  SMASH ALL REGISTERS EXCEPT P AND 0.
DLCWAK:	CONI PI,E		;SAVE PI STATUS AND SWITCH TO NETWORK INTERRUPT LEVEL
	ANDI E,177
	PUSH P,E
	CONO PI,NETOFF
DLCWK1:	MOVEI J,1		;ALWAYS CHECK BOTH BUFFERS SO WE CAN'T GET OUT OF PHASE WITH 11
	MOVEI R,2		;CHECK FOR INPUT AVAILABLE
	CAME R,DLCRS1(J)
	 SOJGE J,.-1
	JUMPL J,DLCWK2
	MOVE A,DLCRA1(J)	;GOT INPUT, PROCESS IT
	SETZM DLCRS1(J)		;BUFFER SLOT NOT OCCUPIED NOW
IFN KS10P, CLRCSH
IFN KL10P, PUSHJ P,DLCSWP	;SWEEP CACHE IN CASE ANYONE HAPPENED TO TOUCH BUFFER
	SKIPE A			;THIS CAN HAPPEN IF PDP11 WAS JUST STUFFED
	 PUSHJ P,CHAPII		;PROCESS THE PACKET
	PUSHJ P,DLCIBG		;SUPPLY A NEW INPUT BUFFER TO 11
	JRST DLCWK1		;TRY FOR MORE INPUT

DLCWK2:	MOVEI J,1		;SCAN CHANNELS FOR OUTPUT DONE
	CAME R,DLCSS1(J)
DLCWK3:	 SOJGE J,.-1
	JUMPL J,DLCWK4
	MOVE A,DLCSA1(J)	;FOUND AN OUTPUT DONE BUFFER
	HRROS B,-2(A)		;MARK IT NOT ON TRANSMIT LIST
	AOJN B,.+2		;AND UNLESS IT IS ON SEND LIST
	 PUSHJ P,CHABRT		;RETURN IT TO FREE
	SETZM DLCSA1(J)		;IDLE THIS BUFFER
	SETZM DLCSS1(J)
	JRST DLCWK3

DLCWK4:	MOVE J,DLCSBF		;TRY TO SEND SOME OUTPUT
	SKIPE DLCSS1(J)
	 JRST DLCWK9		;BUFFER BUSY
	HLRZ A,DLCXMQ		;GET ANOTHER OFF TRANSMIT QUEUE
	JUMPE A,DLCWK9		;QUEUE EMPTY
	HLRZ T,-2(A)
IFN FTRCHK,[
	CAIN T,-1
	 BUG PAUSE,[CHAOS LIST THREAD TRASHED],OCT,A,OCT,-2(A)
];FTRCHK
	HRLM T,DLCXMQ
IFN FTRCHK,[
	JUMPN T,.+4
	  CAME A,DLCXMQ		;REACHED END OF LIST, END IN RIGHT PLACE?
	   BUG PAUSE,[DCLXMQ THREAD TRASHED]
	  SETZM DLCXMQ
];FTRCHK
IFE FTRCHK,[
	SKIPN T
	 SETZM DLCXMQ
];FTRCHK
	PUSHJ P,DLCXMT		;SEND IT ON THIS BUFFER
	JRST DLCWK4		;GO TRY TO SEND ON OTHER BUFFER

DLCWK9:	POP P,E
	CONO PI,PICON(E)	;RESTORE PI
	POPJ P,

;THIS ROUTINE SUPPLIES AN INPUT BUFFER TO THE 11 ON ALL BUFFERS THAT NEED IT
;CALL WITH INTERRUPTS OFF OR IN PROGRESS
DLCIBG:	MOVEI J,1
	SKIPE DLCRS1(J)
DLCIB1:	 SOJGE J,.-1
	JUMPL J,CPOPJ
	PUSHJ P,CHABGI		;GET A BUFFER
	 JRST [	SETZM DLCRA1(J)	;NO MEMORY, WILL TRY AGAIN AT CLOCK LEVEL
		SETZM DLCRS1(J)
		POPJ P, ]
	SETZM (A)		;CLEAR THE BUFFER SINCE THE DL10 DOESN'T TOUCH LOW 4 BITS
	HRLZ T,A
	HRRI T,1(A)
	BLT T,%CPMXW-1(A)
	MOVEM A,DLCRA1(J)	;MAKE AVAILABLE TO PDP11
	HRLI A,120000
	MOVEM A,DLCRP1(J)
	SOS DLCRP1(J)
IFN KS10P, .ERR CLRCSH not needed here?
IFN KL10P, PUSHJ P,DLCSWP	;SWEEP CACHE BEFORE SIGNALLING 11
	MOVEI T,1
	MOVEM T,DLCRS1(J)
	CONO DLC,100040+TTYCHN	;INTERRUPT 11
	JRST DLCIB1		;TRY FOR OTHER BUFFER ALSO

;THIS ROUTINE SENDS PACKET IN A TO DL10 (CALL WITH NETOFF OR IN PROGRESS)
;SWITCHES BUFFERS, LEAVES NEW ONE IN J
DLCXMT:	MOVE J,DLCSBF
	MOVEM A,DLCSA1(J)
	HRLI A,120000
	MOVEM A,DLCSP1(J)	;GIVE 11 POINTER TO NEW PACKET
	SOS DLCSP1(J)
IFN KS10P, .ERR CLRCSH not needed here?
IFN KL10P, PUSHJ P,DLCSWP	;SWEEP CACHE, PUTTING PACKET INTO CORE
	MOVEI T,1
	MOVEM T,DLCSS1(J)	;ACTIVATE PDP11
	CONO DLC,100040+TTYCHN
	XORI J,1		;NEXT BUFFER
	MOVEM J,DLCSBF
	POPJ P,

IFN KL10P,[
;THIS ROUTINE SWEEPS PACKET IN A OUT OF THE CACHE,
;CLOBBERING B, C, AND D.
IFG PKTBSZ-1000, .ERR PKTBSZ BIGGER THAN HARDWARE PAGE SIZE, CACHE SWEEP LOSES
DLCSWP:	LDB D,[111100,,A]	;SWEEP ONE PAGE OF CACHE
	SWPUO (D)		;STORING PACKET INTO CORE
	MOVE B,[CONSZ 200000]	;AWAIT COMPLETION IN ACS
	MOVE C,[JRST B]		;TO MINIMIZE CACHE INTERFERENCE
	MOVSI D,(POPJ P,)
	JRST B
];KL10P
];DLCP

SUBTTL CHAOS NET TEN-11 INTERFACE STUFF

IFN T11CHP,[
;THIS ROUTINE CHECKS FOR TEN-11 INITIALIZATION, SKIP-RETURNS IF OK TO USE
;CLOBBERS T,TT
T11CHK:	SKIPE TEN11F
	 JRST T11LUZ		;NOT SUPPOSED TO USE TEN11
	MOVE T,T11VER		;CHECK VERSION TO MAKE SURE RIGHT PROGRAM, ETC.
	CAME T,[.BYTE 8 ? "H ? "C ? 0 ? 1]
	 JRST T11LUZ		;PROBABLY TURNED OFF OR WRONG PROGRAM
	SKIPE T11I10		;SHOULD WE REINIT?
	 JRST T11CK1		;YES, GO DO SO
	SKIPLE T,T11WIN		;ARE WE WINNING?
	 JRST POPJ1		;YES, FINE
	JUMPE T,[SETOM T11WIN	;NOW THAT VERSION IS OK, TELL 11 TO INIT
		 MOVSI T,-1
		 MOVEM T,T11I11
		 JRST T11CK1 ]	;AND INIT OURSELVES
	SKIPE T11I11		;WAITING FOR 11 TO REINIT?
	 POPJ P,		;YES, WAIT
;HERE TO REINIT.  FIRST, PICK UP PARAMETERS.
T11CK1:	LDB TT,[242000,,T11PRM]	;BYTES PER PACKET BUFFER
	CAIGE TT,<%CPMXW+1>*4	;BETTER BE RIGHT SIZE
	 JRST T11LUZ		;TOO SMALL (ASSUME IF TOO BIG, PACKETS WON'T BE)
	LSH TT,-2
	MOVEM TT,T11BSZ		;SAVE BUFFER SIZE IN PDP10 WORDS
	LDB T,[042000,,T11PRM]	;NUMBER OF BUFFERS IN EACH DIRECTION
	IMULB T,TT		;NUMBER OF PDP10 WORDS IN EACH DIRECTION
	ADD TT,T11IBB
	MOVEM TT,T11IBE		;INIT POINTERS
	MOVEM TT,T11OBB
	MOVEM TT,T11OBP
	ADD TT,T
	MOVEM TT,T11OBE
	HRREI T,-T11CHS-2000(TT)
	JUMPG T,T11LUZ		;COMMUNICATION AREA LONGER THAN 1K
	MOVE T,T11IBB
	MOVEM T,T11IBP
T11CK2:	SETZM (T)		;CLEAR BUFFER HEADERS
	ADD T,T11BSZ
	CAMGE T,TT
	 JRST T11CK2
	MOVEM T,T11WIN		;WE'RE WINNING (MAKE T11WIN POSITIVE NON-ZERO)
	SETZM T11I10		;INIT DONE
	JRST POPJ1

;HERE IF PDP11 PARAMETERS DON'T MATCH WHAT WE EXPECT
T11LUZ:	SETZM T11WIN		;NOT WINNING
	POPJ P,

;HERE FROM CLOCK LEVEL TO CHECK ON TEN-11 CHAOS NET CHANNEL
T11WAK:	PUSHJ P,T11CHK		;IS EVERYTHING OK?
	 POPJ P,		;NO.
T11WK0:	MOVE C,T11IBP		;CHECK INPUT
	SKIPN (C)
	 JRST T11WK1		;NONE AVAILABLE
	MOVSI J,2(C)		;POINT TO PACKET
	LDB D,[$CPKNB+2(C)]	;GET SIZE OF PACKET
	ADDI D,4*%CPKDT+3	;CONVERT BYTES TO WORDS INCLUDING HEADER
	LSH D,-2
	CAILE D,%CPMXW		;DON'T GET FAKED OUT BY CLOBBERED COUNT
	 MOVEI D,%CPMXW
	PUSHJ P,CHABGI		;GET PLACE TO PUT IT
	 JRST T11WK1		;NONE AVAILABLE
	HRLOI E,-1(D)
	EQVI E,(A)		;AOBJN POINTER TO PACKET BUFFER
	HRRI J,(A)		;BLT POINTER TO COPY PACKET
	ADDI D,-1(A)		;LAST WORD
	BLT J,(D)		;COPY PACKET FROM 11 TO 10
	MOVEI H,0		;COMPUTE CHECKSUM
T11WK4:	ADD H,(E)
	LSH H,-1
	TRZE H,10
	 TLO H,(SETZ)
	AOBJN E,T11WK4
	MOVE TT,1(C)		;GET PDP11'S CHECKSUM
	SETZM (C)		;GIVE THE 11 BACK THE BUFFER
	ADD C,T11BSZ		;ADVANCE THE POINTER
	CAML C,T11IBE
	 MOVE C,T11IBB
	MOVEM C,T11IBP
	CAME H,TT
	 JRST [	AOS T11CKE	;COUNT CHECKSUM ERRORS
		PUSHJ P,CHABRT	;AND DISCARD PACKET
		JRST T11WK0 ]
	CONO PI,NETOFF
	PUSHJ P,CHAPII		;PROCESS THE INPUT
	CONO PI,NETON
	JRST T11WK0

T11WK1:	CONO PI,NETOFF
	SKIPE T11XMQ		;ANY OUTPUT?
	 SKIPE @T11OBP		;AND OUTPUT BUFFER SPACE AVAILABLE?
	  JRST NETONJ		;NO, RETURN FROM T11WAK
	HLRZ A,T11XMQ		;GET PACKET OFF TRANSMIT QUEUE
	HLRZ B,-2(A)		;GET NEXT AFTER THAT
	HRLM B,T11XMQ		;BECOMES NEW HEAD OF QUEUE
	SKIPN B
	 SETZM T11XMQ
	PUSHJ P,T11XMT		;COPY PACKET INTO 11
	CONO PI,NETON
	JRST T11WK1		;LOOK FOR MORE OUTPUT

;SEND PACKET A-> TO 11.  SMASHES B,C,T,TT,Q.  CALL WITH NETOFF.
T11XMT:	LDB C,[$CPKNB(A)]	;GET BYTE COUNT
	MOVE Q,C		;MUST CLEAR UNUSED BYTES AT END OF LAST WORD
	ANDI Q,3		;TO MAKE THE CHECKSUM COME OUT RIGHT
	ADDI C,4*%CPKDT+3
	LSH C,-2		;CONVERT TO WORD COUNT
	MOVE Q,(Q)[ -1		;MASK FOR BYTES TO RETAIN IN LAST WORD
		    <.BYTE 8 ? -1>
		    <.BYTE 8 ? -1 ? -1>
		    <.BYTE 8 ? -1 ? -1 ? -1> ]
	MOVEI TT,-1(C)
	ADD TT,A
	ANDM Q,(TT)		;MASK OFF LAST WORD
	HRLOI C,-1(C)
	EQVI C,(A)		;AOBJN PTR
	MOVEI TT,0		;COMPUTE XOR CHECKSUM IN TT
	SKIPA B,T11OBP		;-> CURRENT OUTPUT BUFFER IN 11
T11XM1:	 ADDI B,1
	MOVE T,(C)
	TRZ T,17		;CLEAR BITS 10-11 TREATS SPECIALLY
	ADD TT,T		;COMPUTE CHECKSUM
	LSH TT,-1
	TRZE TT,10
	 TLO TT,(SETZ)
	MOVEM T,2(B)
	AOBJN C,T11XM1
	MOVE B,T11OBP
	MOVEM TT,1(B)		;GIVE CHECKSUM TO 11
	MOVSI TT,-1
	MOVEM TT,0(B)		;GIVE PACKET TO 11
	ADD B,T11BSZ		;ADVANCE BUFFER POINTER
	CAML B,T11OBE
	 MOVE B,T11OBB
	MOVEM B,T11OBP
	HRROS T,-2(A)		;TAKE PACKET OFF TRANSMIT LIST
	AOJN T,.+2
	 PUSHJ P,CHABRT		;NOT ON SEND LIST, FREE IT
	POPJ P,
];T11CHP

SUBTTL CH-10 INTERRUPT ROUTINES

;THE GENERAL IDEA IS THAT WE INTERRUPT ON A LOW-PRIORITY INTERRUPT LEVEL,
;AND DO THE TIME-INTENSIVE PACKET COPYING AT THAT LEVEL.  THE GENERAL
;CHAOS ROUTINES ARE THEN CALLED WITH NETOFF.

IFN CH10P,[

EBLK

CHXACS:	BLOCK 20
CHXPDL:	-60,,.
	BLOCK 60

CHXBRK:	0
BBLK
	MOVEM 17,CHXACS+17
	MOVEI 17,CHXACS
	BLT 17,CHXACS+16
	MOVE P,CHXPDL
	CONSO CHX,CHXRCV	;PACKET RECEIVED?
	 JRST CHXBK5
	PUSHJ P,CHABGI		;GET PLACE TO PUT PACKET
	 JRST [	MOVEI T,CHXREN	;NONE AVAILABLE, DISABLE INTR
		ANDCAM T,CHXCNO
		CONO CHX,@CHXCNO
		JRST CHXBK5 ]
	CONSZ CHX,CHXCRC+CHXWLE	;CHECK FOR ERRORS
	 JRST [	CONSZ CHX,CHXCRC
		 AOSA CHNCRC
		  AOS CHNWLE
		JRST CHXBK4 ]	;IGNORE PACKET
	DATAI CHX,T		;FIRST DATAI YIELDS GARBAGE
	MOVEI T,CHXSWB		;DISABLE BYTE SWAPPING
	ANDCAM T,CHXCNO
	CONO CHX,@CHXCNO
	HRLI A,-%CPKDT		;READ HEADER
	DATAI CHX,(A)
	AOBJN A,.-1
	HRRZI A,-%CPKDT(A)
	PUSHJ P,CHSWAB		;ENABLE BYTE SWAPPING IF NEEDED
	LDB T,[$CPKNB(A)]	;GET SIZE OF PACKET
	CAILE T,%CPMXC		;DON'T RUN OFF END OF BUFFER
	 JRST CHXBK4
	ADDI T,3		;ROUND UP TO NEXT WORD BOUNDARY
	LSHC T,-2		;CONVERT BYTES TO WORDS, TT GETS REMAINDER
	HRLOI D,-1(T)		;MAKE AOBJN POINTER
	EQVI D,%CPKDT(A)
	JUMPGE D,.+3		;EMPTY PACKET BOUNDARY CASE
	 DATAI CHX,(D)
	 AOBJN D,.-1
	DATAI CHX,T		;NOW READ AND IGNORE HARDWARE HEADER
	TLNE T+1,400000
	 DATAI CHX,T		;THIRD HALFWORD
	CONI CHX,T		;CHECK FOR ERRORS
	TDNE T,[CHXPLE+CHXCRC+CHXOVR]
	 JRST [	TLNE T,(CHXOVR)
		 JRST CHXBKZ	;OVERRRUN CAN'T HAPPEN UNLESS HARDWARE BROKEN
		TLNE T,(CHXPLE)
		 AOSA CHNPLE
		  TRNN T,CHXCRC
		   JRST CHXBK4
		AOS CHNCR2
		JRST CHXBK4 ]
	CONO PI,NETOFF-1
	PUSHJ P,CHAPII		;PROCESS THE INPUT
	CONO PI,NETON-1
	CAIA
CHXBK4:	 PUSHJ P,CHABRT		;DIDN'T USE BUFFER AFTER ALL
	CONI CHX,T		;COUNT LOST PACKETS
	LDB T,[$CHXLC,,T]
	ADDM T,CHNLOS
	MOVEI T,CHXREN		;ENABLE RECEIVER FOR NEXT PACKET
	IORB T,CHXCNO
	CONO CHX,CHXRCV(T)
CHXBK5:	CONSO CHX,CHXXMT	;TRANSMIT DONE?
	 JRST CHXBK9
	SKIPE T,CHOSTA		;TRANSMIT IN PROGRESS?
	 CONSO CHX,CHXABT	;AND WAS ABORTED?
	  JRST CHXBK7		;NO TO EITHER, LOOK FOR MORE WORK
	AOS CHNABT		;METER TRANSMIT ABORTS
	CAIL T,NCHRTR		;ABORTED TOO MANY TIMES?
	 JRST CHXBK7		;DONE WITH PACKET
	AOS CHOSTA		;COUNT RETRANSMISSIONS
	MOVEI T,CHXTEN
	IORB T,CHXCNO
	CONO CHX,CHXXMT(T)	;RETRANSMIT PACKET
	JRST CHXBK9

CHXBK7:	SETZM CHOSTA		;TRANSMITTER IDLE, LOOK FOR NEXT PACKET
	CONO PI,PIOFF
	HLRZ A,CHXXMQ		;ANYTHING QUEUED FOR TRANSMISSION?
	JUMPE A,[ MOVEI T,CHXTEN	;DISABLE INTERRUPTS
		  ANDCAM T,CHXCNO
		  CONO CHX,@CHXCNO
		  CONO PI,PION
		  JRST CHXBK9 ]
	HLRZ B,-2(A)		;CDR TRANSMIT QUEUE
	HRLM B,CHXXMQ
	SKIPN B
	 SETZM CHXXMQ		;QUEUE EMPTY NOW
	CONO PI,PION
	AOS CHOSTA		;NOW SEND THIS PACKET
	MOVEI T,CHXHLF+CHXSWB	;CLEAR HALFWORD, BYTE-SWAP MODES
	ANDCAM T,CHXCNO
	CONO CHX,@CHXCNO
	HRLI A,-%CPKDT		;TRANSMIT HEADER
	DATAO CHX,(A)
	AOBJN A,.-1
	HRRZI A,-%CPKDT(A)
	PUSHJ P,CHSWAB		;ENABLE BYTE SWAPPING IF NEEDED
	LDB T,[$CPKNB(A)]	;GET SIZE OF PACKET
	ADDI T,1		;ROUND UP TO NEXT HALF WORD BOUNDARY
	LSHC T,-2		;CONVERT BYTES TO WORDS, T+1 GETS REMAINDER
	HRLOI D,-1(T)		;MAKE AOBJN POINTER
	EQVI D,%CPKDT(A)
	JUMPGE D,.+3		;EMPTY PACKET BOUNDARY CASE
	 DATAO CHX,(D)
	 AOBJN D,.-1
	MOVEI T,CHXHLF+CHXTEN	;SWITCH TO HALFWORD MODE, ENABLE DONE INTR
	IORM T,CHXCNO
	CONO CHX,@CHXCNO
	TLNE T+1,400000		;SEND EXTRA HALFWORD IF NEEDED
	 DATAO CHX,(D)
	MOVEI T,CHXSWB		;DISABLE SWAP BYTES MODE
	ANDCAM T,CHXCNO
	CONO CHX,@CHXCNO
	LDB T,[$CPKDN(A)]	;GET DESTINATION SUBNET
	HRRZ D,SBNRUT(T)	;GATEWAY TO THAT SUBNET
	CAIGE T,NSUBNT
	 CAIN T,MYCHAD_-8	;IF ON LOCAL CABLE
	  LDB D,[$CPKDA(A)]	;GO DIRECT
	LSH D,16.+4
	DATAO CHX,D		;STORE HARDWARE DESTINATION ADDRESS
	MOVE T,CHXCNO		;TRANSMIT PACKET
	CONO CHX,CHXXMT(T)
	CONI CHX,T
	TLNE T,(CHXOVR)		;CAN'T HAPPEN UNLESS HARDWARE BROKEN
CHXBKZ:	 BUG HALT,[CHAOS: I/O BUS OVERRUN]
	HRROS B,-2(A)		;MARK IT NOT ON TRANSMIT LIST
	AOJN B,.+2		;AND UNLESS IT IS ON SEND LIST
	 PUSHJ P,CHABRT		;RETURN IT TO FREE
CHXBK9:	MOVSI 17,CHXACS		;DISMISS INTERRUPT
	BLT 17,17
	JRST 12,@CHXBRK

CHSWAB:	LDB T,[$CPKOP(A)]	;DOES THIS PACKET NEED BYTE SWAPPING?
	TRNE T,200
	 JRST [	TRNE T,100
		 POPJ P,	;BINARY DATA
		JRST CHSWB1 ]	;CHARACTER DATA
	IDIVI T,40
	MOVE T,CHSWBT(T)
	LSH T,(T+1)
	JUMPL T,CPOPJ		;BINARY CONTROL PACKET
CHSWB1:	MOVEI T,CHXSWB		;CHARACTER, SWAP DEM BYTES
	IORM T,CHXCNO
	CONO CHX,@CHXCNO
	POPJ P,

CHSWBT:	1_<35.-%COOPN>+1_<35.-%COSTS>+1_<35.-%CORUT>
	0 ? 0 ? 0
];CH10P

SUBTTL CH-11 INTERRUPT ROUTINES

;The Unibus Chaosnet board interrupts on the same level as TTYs,
;and comes to CHXBKH via vectored interrupt.  We use a programmed
;interrupt request to drop down to a lower interrupt level for the
;slow packet-copying operation, so as not to interfere with the TTYs,
;then turn NETOFF when we call into the Chaosnet NCP.
;(We actually use NETOFF-1 and NETON-1 so as not to interfere with
;CLKOFF.  This assumes that interrupt levels between CLKCHN and
;CHXCHN are never turned off.)

IFN CH11P,[

;;; Macros that will eventually be instructions

DEFINE PACK16 AC,E		;AC,AC+1 right-aligned and zero-filled
	LSH AC,16.
	IOR AC,AC+1
	LSH AC,4
	MOVEM AC,E
TERMIN

DEFINE PACK8 AC,E		;AC: ...B2B1  AC+1: ...B4B3 zero-filled!!
	ROTC AC,-8		;B3...B2 B1...B4
	ROT AC,-16.		;B1,B2,B3 in position, B4 right-aligned
	ADDI AC+1,(AC+1)	;Shift RH(AC+1) left 4 bits
	ADDI AC+1,(AC+1)
	ADDI AC+1,(AC+1)
	ADDI AC+1,(AC+1)	;B1,B4 in position in AC+1
	IOR AC,AC+1
	MOVEM AC,E
TERMIN

DEFINE UNPK16 AC,E		;Doesn't bother masking off garbage bits
	MOVE AC,E
	MOVE AC+1,AC
	ROT AC,16.		;First halfword right-aligned
	LSH AC+1,-4		;Second halfword right-aligned
TERMIN

DEFINE UNPK8 AC,E
	MOVE AC,E		;B1B2B3B4...
	ROT AC,8		;B2B3B4...B1
	MOVE AC+1,AC
	AND AC,[377_2,,377]	;...B3...B1 zero-filled
	ROT AC+1,16.		;B4...B1B2B3
	AND AC+1,[377_12,,377_8];B4...B2... zero-filled
	IORB AC,AC+1		;B4B3...B2B1
	ROT AC+1,16.		;...B4B3, garbage in high bits
TERMIN

EBLK

CHXACS:	BLOCK 20
CHXSVH:	0
CHXPDL:	-60,,.
	BLOCK 60

CHXBKH:	0			;Hardware interrupt on TTYCHN comes here
BBLK
	CONO PI,CHXRQ		;Redirect to lower interrupt level
	MOVEM T,CHXSVH		;Clear hardware interrupt enable
	MOVEI T,%CAREN+%CATEN	; so the Chaos board will stop interrupting
	ANDCAB T,CHXCSR
	IOWRI T,CAICSR
	MOVE T,CHXSVH
	JRST 12,@CHXBKH
EBLK

CHXBRK:	0			;Software interrupt on CHXCHN comes here
BBLK
	CONO PI,020000+200_<-CHXCHN>	;BAG-BITING DEC LOSERS
	MOVEM 17,CHXACS+17
	MOVEI 17,CHXACS
	BLT 17,CHXACS+16
	MOVE P,CHXPDL
	IORDI T,CAICSR		;Check for received packet
	TRNN T,%CARDN
	 JRST CHXBK3		;No incoming packet yet
	TRNE T,%CAERR		;Check for error in received packet
	 JRST [	AOS CHNCRC
		JRST CHXBK1 ]	;Ignore packet
	IORDI R,CAIRBC		;Number of bits in packet - 1
	SUBI R,31.		;Exclude the three extra hardware words
	TRNE R,17
	 JRST [	AOS CHNWLE	;Length not a multiple of 16
		JRST CHXBK1 ]
	ASH R,-5		;32-bit word count, rounded up
	PUSHJ P,CHABGI		;Get place to put packet
	 JRST [	AOS CHNLOS	;No buffers, lose this packet
		JRST CHXBK1 ]
	HRLI A,-%CPKDT		;Copy out the packet header
CHSRC1:	IORDI B,CAIRBF
	IORDI C,CAIRBF
	PACK16 B,(A)
	AOBJN A,CHSRC1
	PUSHJ P,CHSHDR		;Decode the header
	 JRST CHSRC4		;No byte swapping
	JUMPGE D,CHSRC3
CHSRC2:	IORDI B,CAIRBF		;Read out the data, byte-swapped
	IORDI C,CAIRBF
	PACK8 B,(D)
	AOBJN D,CHSRC2
CHSRC3:	JUMPGE H,CHSRC7		;Jump if even packet length
	IORDI B,CAIRBF		;Residual halfword
	SETZ C,			;Somebody depends on zero here
	PACK8 B,(D)
	AOJA D,CHSRC7

CHSRC4:	JUMPGE D,CHSRC6
CHSRC5:	IORDI B,CAIRBF		;Read out the data, halfwords
	IORDI C,CAIRBF
	PACK16 B,(D)
	AOBJN D,CHSRC5
CHSRC6:	JUMPL H,[ IORDI B,CAIRBF	;Residual halfword
		  SETZ C,		;Somebody depends on zero here
		  PACK16 B,(D)
		  AOJA D,CHSRC7 ]
CHSRC7:	SUB D,R			;AOBJN pointer minus number of words in packet
	CAIE A,(D)
	 JRST [	AOS CHNPLE	;Packet length disagrees with hardware length
		JRST CHXBK2 ]
	IORDI T,CAIRBF		;Read the three hardware header words
	IORDI T,CAIRBF
	IORDI T,CAIRBF
	IORDI T,CAICSR
	TRNE T,%CAERR		;Make sure packet came out of RAM okay
	 JRST [	AOS CHNCR2	;Garbage, try again
		JRST CHXBK2 ]
	IORDI T,CAIRBC		;Make sure counter didn't spazz
	CAIE T,7777
	 JRST [	AOS CHNSPZ
		JRST CHXBK2 ]
	CONO PI,NETOFF-1	;Get to network interrupt level
	PUSHJ P,CHAPII		;Process the input
	CONO PI,NETON-1
CHXBK1:	IORDI T,CAICSR		;Count lost packets
	LDB TT,[$CALOS,,T]
	ADDM TT,CHNLOS
	MOVE TT,CHXCSR
	IORI TT,%CARCL		;Enable receiver for next packet
	IOWRI TT,CAICSR
CHXBK3:	TRNN T,%CATDN		;Transmit done?
	 JRST CHXBK8		;No, dismiss
	SKIPN TT,CHOSTA		;Transmit in progress?
	 JRST CHXBK7		;No, look for something to transmit
	TRNN T,%CATAB		;Yes, was it aborted?
	 JRST CHXBK5		;No, we're done with that packet
	AOS CHNABT		;Meter transmit aborts
	CAIGE TT,NCHRTR		;Aborted too many times?
	 JRST CHXBK7		;No, retransmit it
CHXBK5:	CONO PI,PIOFF		;Lock transmit list
	HLRZ A,CHXXMQ		;Get packet probably being transmitted now
	JUMPE A,[ CONO PI,PION	;It vanished?
		  JRST CHXBK6 ]
	HLRZ B,-2(A)		;CDR transmit queue
	HRLM B,CHXXMQ
	SKIPN B
	 SETZM CHXXMQ		;Queue empty now
	CONO PI,PION
	HRROS B,-2(A)		;Mark it not on transmit list
	AOJN B,CHXBK6		;And unless it is on send list
	 PUSHJ P,CHABRT		;Return it to free
CHXBK6:	SETZM CHOSTA		;Transmitter idle, look for next packet
CHXBK7:	HLRZ A,CHXXMQ		;Anything queued for transmission?
	JUMPE A,CHXBK9		;No, leave interrupts disabled
	AOS CHOSTA		;Count retransmissions
	MOVE T,CHXCSR		;Reset transmitter
	IORI T,%CATDN
	IOWRI T,CAICSR
	HRLI A,-%CPKDT		;Transmit header
CHXXM1:	UNPK16 B,(A)
	IOWRI B,CAIWBF
	IOWRI C,CAIWBF
	AOBJN A,CHXXM1
	PUSHJ P,CHSHDR		;Decode the header
	 JRST CHXXM4		;No byte swapping
	JUMPGE D,CHXXM3
CHXXM2:	UNPK8 B,(D)		;Transmit data with byte swapping
	IOWRI B,CAIWBF
	IOWRI C,CAIWBF
	AOBJN D,CHXXM2
CHXXM3:	JUMPGE H,CHXXM7		;Jump if even packet length
	UNPK8 B,(D)		;Transmit residual bytes
	IOWRI B,CAIWBF
	JRST CHXXM7

CHXXM4:	JUMPGE D,CHXXM6
CHXXM5:	UNPK16 B,(D)		;Transmit data with byte swapping
	IOWRI B,CAIWBF
	IOWRI C,CAIWBF
	AOBJN D,CHXXM5
CHXXM6:	JUMPGE H,CHXXM7		;Jump if even packet length
	UNPK16 B,(D)		;Transmit residual bytes
	IOWRI B,CAIWBF
CHXXM7:	LDB T,[$CPKDN(A)]	;Get destination subnet
	HRRZ D,SBNRUT(T)	;Gateway to that subnet
	CAIGE T,NSUBNT
	 CAIN T,MYCHAD_-8	;If on local cable,
	  LDB D,[$CPKDA(A)]	; go direct
	IOWRI D,CAIWBF		;Store hardware destination address
	IORDI T,CAIXMT		;Transmit packet
CHXBK8:	MOVEI A,%CATEN		;Enable transmit-done interrupt if xmitting
CHXBK9:	IORI A,%CAREN		;Enable receive-done interrupt always
	IORB A,CHXCSR
	IOWRI A,CAICSR
	MOVSI 17,CHXACS		;Dismiss software interrupt
	BLT 17,17
	JRST 12,@CHXBRK

CHXBK2:	PUSHJ P,CHABRT		;Packet no good, discard it
	JRST CHXBK1

;Examine packet in A, return AOBJN pointer to data in D,
; H is negative if there is an extra halfword after that.
; W gets number of full words of data (same as LH D).
; T,U get clobbered
; Returns:
;	+1  16-bit data
;	+2  8-bit data
CHSHDR:	HRRZI A,-%CPKDT(A)	;Restore packet address
	LDB W,[$CPKNB(A)]	;Get size of packet in bytes
	CAILE W,%CPMXC
	 MOVEI W,%CPMXC		;Self-defense
	ADDI W,1		;Round up to next word boundary
	LSHC W,-2		;Convert bytes to words, H gets remainder
	HRLOI D,-1(W)		;Make AOBJN pointer
	EQVI D,%CPKDT(A)
	LDB T,[$CPKOP(A)]	;Does this packet need byte swapping?
	TRNE T,200
	 JRST [	TRNN T,100
		 AOS (P)	;Character data
		POPJ P, ]	;Binary data
	IDIVI T,40
	MOVE T,CHSWBT(T)
	LSH T,(T+1)
	JUMPL T,CPOPJ		;Binary control packet
	JRST POPJ1		;Characters

CHSWBT:	1_<35.-%COOPN>+1_<35.-%COSTS>+1_<35.-%CORUT>
	0 ? 0 ? 0
];CH11P

SUBTTL CHAOS NET BUFFER LIST STUFF

OVHMTR CHL

;BUFFERS ARE PKTBSZ WORDS LONG; 2 HEADER WORDS AND %CPMXW PACKET WORDS.
;PKTBSZ IS A POWER OF 2 AND LESS THAN 1K (MEMORY PAGE SIZE).
;NOTE THAT A BUFFER ADDRESS POINTS AT THE FIRST PACKET WORD
;AND THE HEADER WORDS ARE AT NEGATIVE ADDRESSES.
;FIRST HEADER WORD:  -2(A)
;	RH LIST THREAD FOR MOST LISTS, 0=END, -1=NOT ON LIST
;	LH LIST THREAD FOR TRANSMIT LIST
;SECOND HEADER WORD: -1(A)
;	TIME RECEIVED OR TIME PUT ON TRANSMIT LIST
;	OR VALUE OF I FOR A PACKET ON THE LSN QUEUE
;	ASCII/LUNCH/ FOR A PACKET ON THE FREE LIST

;I DO IT THIS WAY (PIOFF) TO AVOID HAVING TO PUSH AND POP PI STATUS,
;CONO PI,NETOFF CAN LOSE AT INTERRUPT LEVEL (MAINLY THE NETON LOSES)

;THESE ROUTINES TURN OFF INTERRUPTS MOMENTARILY SO THAT
;LISTS MAY BE SAFELY MANIPULATED.

;Q POINTS TO THE HEADER WORD OF A QUEUE, REMOVE THE FIRST
;THING AND RETURN IN A.  (ZERO IF NONE)  CLOBBERS T
CHAQGF:	CONO PI,PIOFF
	HLRZ A,(Q)		;GET FIRST
	JUMPE A,PIONJ		;EMPTY
	HRRZ T,-2(A)		;GET SECOND
	HRLM T,(Q)		;MAKE FIRST
IFN FTRCHK,[
	JUMPN T,PIONJ
	HRRZ T,(Q)
	CAIE T,(A)
	 BUG PAUSE,[CHAOS LIST TRASHED],OCT,Q
	SETZM (Q)		;IS NOW EMPTY
];FTRCHK
IFE FTRCHK,[
	SKIPN T
	 SETZM (Q)		;IS NOW EMPTY
];FTRCHK
	CONO PI,PION
	POPJ P,

;RETURN BUFFER INTO WHICH THE BYTE POINTER IN A POINTS.  CLOBBERS A,T,Q
CHBPFR:	SUBI A,1		;SIOKT LIKES TO MAKE BP POINT AT NEXT BUFFER
	ANDI A,-PKTBSZ
	ADDI A,2
	JRST CHABRT

;RETURN BUFFER POINTED TO BY A TO FREE UNLESS ON TRANSMIT LIST.
CHABR1:	HLLOS T,-2(A)		;RH GETS -1, NO LONGER ON REGULAR LIST
	AOJN T,CPOPJ		;EXIT IF STILL ON TRANSMIT LIST
	;DROPS THROUGH
;RETURN BUFFER POINTED BY A TO FREE STORAGE.  CLOBBERS T, Q.
CHABRT:	MOVEI Q,CHQFRE
IFN FTRCHK,[
	SKIPN A
	 BUG PAUSE,[FREEING 0]
];FTRCHK
	MOVE T,[ASCII/LUNCH/]	;TANSTAAFL
	MOVEM T,-1(A)
	SETOM -2(A)		;NOT ON TRANSMIT LIST NOW (THIS IS WHAT INITS
	AOS CHFRBF		; LH[-2(A)] WHEN BUFFER FIRST CREATED)
	;JRST CHAQPL		;DROPS THROUGH

;A POINTS TO A BUFFER, Q TO A QUEUE.  PUT IT ON AS THE LAST THING.  BASHES T.
CHAQPL:	HLLZS -2(A)		;PUT ENDLIST IN RH
	CONO PI,PIOFF
	HRRZ T,(Q)		;GET LAST
	HRRM A,(Q)		;MAKE NEW LAST
	JUMPN T,[HRRM A,-2(T)	;MAKE A COME AFTER IT
		 JRST PIONJ ]
	HRLM A,(Q)		;WAS EMPTY, ALSO IS NEW FIRST
	CONO PI,PION
	POPJ P,

;A POINTS TO A BUFFER, Q TO A QUEUE.  PUT IT ON AS THE FIRST THING.  SMASHES T.
CHAQPF:	CONO PI,PIOFF
	HLRZ T,(Q)		;GET FIRST
	HRRM T,-2(A)		;MAKE SECOND
	HRLM A,(Q)		;MAKE NEW FIRST
	SKIPN T
	 HRRM A,(Q)		;WAS EMPTY, ALSO MAKE NEW LAST
	CONO PI,PION
	POPJ P,

;ALLOCATE A BUFFER AT MAIN PROGRAM LEVEL, TO A, MASHES T, TT, Q, B.
CHABG0:	PUSHJ P,UDELAY		;WAIT FOR MEMORY
CHABGT:	PUSHJ P,CHABGI
	 JRST CHABG0
	POPJ P,			;WIN
	
;ALLOCATE A BUFFER, RETURN POINTER TO IT IN A, SKIP.  BLOWS AWAY T, TT, Q.
;NON-SKIP IF NO BUFFERS AVAILABLE.  (DOESN'T MAKE NEW ONES IF FREE LIST EMPTY)
CHABAL:	MOVEI Q,CHQFRE
	PUSHJ P,CHAQGF
	JUMPE A,CPOPJ
	SETZM -1(A)		;NO LUNCH
	SOS CHFRBF
	JRST POPJ1

;ALLOCATE A BUFFER TO A, MAKE NEW IF NONE FREE.   OBLITERATES T,Q,B.
;NON-SKIP IF CAN'T GET MEMORY.  (SUITABLE FOR CALLING FROM INT LEVEL)
CHABGI:	PUSHJ P,CHABAL		;TRY TO ALLOCATE A BUFFER FROM FREE LIST
	 CAIA
	  JRST POPJ1		;WON, RETURN
	CONI PI,Q		;SAVE PI CHANNELS ON STATUS
	ANDI Q,177
	CONO PI,UTCOFF		;MAKE THE WORLD SAFE FOR IOMQ
	MOVE B,CHTTBF
	CAIL B,CHMXBF		;MAKE SURE NOT TO USE UP ALL CORE
	 JRST CHABG4
	PUSHJ P,IOMQ		;GET 1K OF MEMORY
	 JRST CHABG3		;MEM NOT AVAILABLE, FAIL
	CONO PI,PICON(Q)	;WON, RESTORE PI STATUS
	MOVEI B,MUCHA
	DPB B,[MUR,,MEMBLT(A)]
	LSH A,10.		;ADDRESS OF 1K OF ALLOCATED MEMORY
	ADD A,[-<2000/PKTBSZ>,,2]	;-BUFFERS PER 1K,,OFFSET TO HEADER
CHABG2:	PUSHJ P,CHABRT		;PUT THEM ALL ON FREE LIST
	ADDI A,PKTBSZ-1
	AOBJN A,CHABG2
	MOVEI B,<2000/PKTBSZ>	;THIS MANY MORE BUFFERS HAVE BEEN CREATED
	ADDM B,CHTTBF
	JRST CHABGI		;NOW GO ALLOCATE ONE

;HERE IF CHAOS NET TRYING TO USE UP TOO MUCH CORE
CHABG4:	MOVE B,CHMXTM	;DON'T COMPLAIN TOO OFTEN
	ADDI B,60.*30.	;JUST ONCE A MINUTE
	CAMLE B,TIME
	 JRST CHABG3
IFE CH10P, BUG CHECK,[CHAOS NET ATTEMPTING TO USE TOO MUCH CORE]
IFN CH10P,[
	CONI CHX,B
	BUG CHECK,[CHAOS NET ATTEMPTING TO USE TOO MUCH CORE, CONI=],OCT,B,[CONO=],OCT,CHXCNO,[CHOSTA=],OCT,CHOSTA
];CH10P
	MOVE B,TIME
	MOVEM B,CHMXTM
CHABG3:	CONO PI,PICON(Q)	;LOST, RESTORE PI STATUS
	POPJ P,			;AND TAKE ERROR RETURN

;FREE A WHOLE LIST OF BUFFERS, Q-> HEAD.  DESTROYS A,T
CHALFR:	PUSHJ P,CHAQGF
	JUMPE A,CPOPJ
	PUSH P,Q
	PUSHJ P,CHABR1		;FREE UNLESS STILL ON TRANSMIT LIST
	POP P,Q
	JRST CHALFR

;Q -> A TRANSMIT QUEUE, FLUSH ALL BUFFERS BELONGING TO INDEX I.
;CLOBBERS A,B,C,T
CFLXMQ:	PUSH P,Q
	CONO PI,NETOFF		;DON'T LET TRANSMIT LIST CHANGE (AT ALL)
	HLRZ A,(Q)		;HEAD OF TRANSMIT LIST
	JUMPE A,CFLXM3
	MOVEI B,2(Q)		;B PREVIOUS PACKET, A CURRENT, C NEXT
CFLXM1:	HLRZ C,-2(A)		;GET THREAD TO NEXT
IFN FTRCHK,[
	CAIN C,-1
	 JRST 4,.		;CLAIMS NOT TO BE ON LIST?
];FTRCHK
	LDB T,[$CPKSX(A)]	;GET THIS PACKET'S INDEX
	CAME T,I
	 JRST CFLXM2
	HRLM C,-2(B)		;THREAD PREVIOUS TO NEXT
	HRROS T,-2(A)		;IF THIS BUFFER IS NOT ALSO ON SEND LIST,
	AOJN T,.+2
	 PUSHJ P,CHABRT		;RETURN IT
	SKIPA Q,(P)
CFLXM2:	 MOVE B,A
	SKIPE A,C
	 JRST CFLXM1
	HRRM B,(Q)		;LAST PACKET ON LIST MAY HAVE CHANGED
	CAIN B,2(Q)
	 SETZM (Q)		;TRANSMIT QUEUE IS NOW EMPTY
CFLXM3:	POP P,Q
	JRST NETONJ

;SEARCH LIST IN Q FOR PACKET WHOSE CONTACT NAME MATCHES THAT
;OF PACKET IN A, RETURN IT IN B, SKIPPING IF WINNING.  CLOBBERS T,TT,C,D,E,H,J.
;THE PACKET RETURNED IN B IS DE-LINKED FROM THE SEARCHED QUEUE.
;HAS TO BE CALLED WITH NETOFF OR IN PROGRESS, SO LIST CAN'T GET MUNGED.
;I HOPE IT'S NOT TOO BLETCHEROUSLY SLOW.
CHAQSR:	HLRZ B,(Q)		;GET START OF LIST TO SEARCH
	JUMPE B,CPOPJ		;EMPTY, LOSE
	MOVEI J,0		;PACKET PREVIOUS TO B
CHAQS1:	LDB C,[$CPKNB(A)]	;SET UP STRING COMPARE LOOP
	LDB H,[$CPKNB(B)]	;THIS ASSUMES NO ZERO-LENGTH STRINGS
	MOVEI D,%CPKDT(A)
	HRLI D,440800
	MOVEI E,%CPKDT(B)
	HRLI E,440800
CHAQS2:	ILDB T,D
	ILDB TT,E		;DON'T IGNORE CASE, THAT WOULD JUST SLOW THIS
	CAME T,TT		;BAG-BITER DOWN EVEN MORE.  EVERYONE SHOULD
	 JRST CHAQS4		;PUT THEIR CONTACT NAMES IN UPPER-CASE.
	CAIN T,40		;TERMINATE ON SPACE
	 JRST CHAQS5
	SOJLE C,CHAQS3
	SOJG H,CHAQS2
	ILDB T,D
	CAIE T,40
	 JRST CHAQS4
CHAQS5:	HRRZ C,-2(B)		;WON, DELINK PACKET FROM LIST
	JUMPE J,[ HRLM C,(Q)
		  JUMPN C,POPJ1
	 IFN FTRCHK,[
		  HRRZ C,(Q)	;CHECK LIST ENDING IN RIGHT PLACE
		  CAIE C,(B)
		   JRST 4,.
		];FTRCHK
		  SETZM (Q)
		  JRST POPJ1 ]
	HRRM C,-2(J)
	JUMPN C,POPJ1
	HRRM J,(Q)		;TOOK LAST PACKET, STORE NEW LAST
	JRST POPJ1

CHAQS3:	SOJLE H,CHAQS5
	ILDB TT,E
	CAIN TT,40
	 JRST CHAQS5
CHAQS4:	MOVE J,B		;THIS ONE DOESN'T MATCH, TRY NEXT
	HRRZ B,-2(B)
	JUMPN B,CHAQS1
	POPJ P,			;NO MATCHES

;THIS ROUTINE RUNS IN THE CORE JOB AND CLEANS UP MEMORY USED BY CHAOS BUFFERS
;SMASHES ALL ACS
CHCLN:	SKIPE A,CHTTBF		;SEE IF 2/3 OR MORE OF BUFFERS FREE
	 SKIPN B,CHFRBF
	  POPJ P,		;NO BUFFERS OR NONE FREE, NOTHING TO DO
	SUBM A,B
	IDIV A,B		;GET RATIO OF TOTAL TO USED
	CAIGE A,3		;NOTE IF B IS ZERO A IS UNCHANGED
	 POPJ P,		; AND AT LEAST 32.
IFL TSYSM-256.,	MOVEI D,TSYSM-1	;SCAN MEMORY FOR CHAOS BUFFER PAGES
.ELSE	MOVEI D,255.
CHCLN0:	LDB A,[MUR,,MEMBLT(D)]
	CAIE A,MUCHA
CHCLN4:	 SOJGE D,CHCLN0
	JUMPL D,CPOPJ
	MOVE A,D		;QUICKLY DETERMINE IF ANY NON-FREE BUFFERS
	LSH A,10.		; ON THIS PAGE
	HRLI A,-<2000/PKTBSZ>
	MOVE T,[ASCII/LUNCH/]
CHCLN5:	CAME T,1(A)
	 JRST CHCLN4		;NOT FREE, DON'T BOTHER WITH SLOW STUFF
	ADDI A,PKTBSZ-1
	AOBJN A,CHCLN5
	SETZB C,CHCLNQ		;COLLECT ALL FREE BUFFERS THAT ARE ON THIS PAGE
	MOVE E,CHFRBF		;LOOP ABOUT AS MANY TIMES AS THERE ARE FREE BUFFERS
CHCLN1:	PUSHJ P,CHABAL		;GET NEXT FREE BUFFER
	JUMPE A,CHCLN2
	LDB B,[121000,,A]
	CAMN B,D
	 JRST [ MOVEI Q,CHCLNQ	;THIS ONE'S ON THE PAGE, SAVE IT
		PUSHJ P,CHAQPL
		AOJA C,.+2 ]	;COUNT THEM
	  PUSHJ P,CHABRT	;NOT ON THE PAGE, PUT BACK
	SOJG E,CHCLN1
CHCLN2:	CAIE C,<2000/PKTBSZ>	;DID WE GET THE WHOLE PAGE?
	 JRST [	MOVEI Q,CHCLNQ ? PUSHJ P,CHALFR ? JRST CHCLN4 ]
	MOVNS C			;YES, GET RID OF THESE BUFFERS
	ADDM C,CHTTBF
	MOVE A,D
	PUSHJ P,MEMR
	JRST CHCLN

OVHMTR CHZ
