Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_1_19910112 - 6-1-monitor/ipcidv.mac
There are 5 other files named ipcidv.mac in the archive. Click here to see a list.
; Patch to CIPRST to retry if IP layer not yet initialized
;
; UPD ID= 2086, SNARK:<6.1.MONITOR>IPCIDV.MAC.12,   3-Jun-85 14:45:13 by MCCOLLUM
;TCO 6.1.1406  - Update copyright notice.
; UPD ID= 1748, SNARK:<6.1.MONITOR>IPCIDV.MAC.11,  12-Apr-85 11:30:30 by PAETZOLD
;TCO 6.1.1319 - Fix intitialization problem
; UPD ID= 1599, SNARK:<6.1.MONITOR>IPCIDV.MAC.10,   7-Mar-85 15:40:56 by PAETZOLD
;Document BUGxxx's
; UPD ID= 1574, SNARK:<6.1.MONITOR>IPCIDV.MAC.9,  26-Feb-85 17:18:42 by PAETZOLD
;Document BUGxxx's
; UPD ID= 1452, SNARK:<6.1.MONITOR>IPCIDV.MAC.8,   1-Feb-85 14:19:47 by LOMARTIRE
;Add new symbols to describe the priority used by SC.SDG
; UPD ID= 1417, SNARK:<6.1.MONITOR>IPCIDV.MAC.7,  29-Jan-85 11:37:14 by PAETZOLD
;TCO 6.1.1158 - Decrease scheduler latency when requesting INTFRK from interrupt context.
;More TCO 6.1.1100 - Reset NETON if NTLADR uninitialized.
; UPD ID= 1250, SNARK:<6.1.MONITOR>IPCIDV.MAC.6,   1-Jan-85 14:29:57 by PAETZOLD
;TCO 6.1.1100 - Verify local host number on initialization and enforce compliance.
; UPD ID= 1100, SNARK:<6.1.MONITOR>IPCIDV.MAC.5,  19-Nov-84 15:34:17 by GLINDELL
;Fix race in connection algorithm
;Do not 'CIPDNS' if connection to remote is not open
; UPD ID= 1062, SNARK:<6.1.MONITOR>IPCIDV.MAC.4,  13-Nov-84 09:07:21 by LOMARTIRE
;Use new sending priority symbols in SC.SDG calls
; UPD ID= 1034, SNARK:<6.1.MONITOR>IPCIDV.MAC.3,  12-Nov-84 15:23:58 by PAETZOLD
;TCO 6.1041 - Move ARPANET to XCDSEC
; UPD ID= 1011, SNARK:<6.1.MONITOR>IPCIDV.MAC.2,   9-Nov-84 08:41:30 by PRATT
;TCO 6.1.1030 - Interface Multinet to SCA


;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED
;OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT  (C)  DIGITAL  EQUIPMENT  CORPORATION  1976, 1985.
;ALL RIGHTS RESERVED.


	SEARCH ANAUNV,PROLOG,SCAPAR,NIPAR,PHYPAR
	SALL
	.DIRECTIVE FLBLST

	TTITLE (IPCIDV,IPCIDV,< - Internet CI Interface>)
	SUBTTL SCA Connection algorithm

COMMENT \

There is a IPCIDV connection state associated with each of the 16 ports
on the CI. The states are:

OFF		TCP/CI has not been enabled, i.e. CIOPEN has not been called.

DOWN		The remote port is known to be down.

CONNECT		The remote port is known to be up, and we have initiated an
		active connect.

LISTEN		The remote port is known to be up, and we are listening for
		an incoming connect request.

ACCEPT		We have accepted an incoming connect request, and we are now
		waiting for an 'OK to send data' message before going to RUN
		state.

RUN		A connection is established with the remote port, and data
		transfer is allowed.

There  is always a listener outstanding. It listens to incoming connect
requests from all remote ports.

The NODINI will initiate a connection to a remote node. It is called in
three different cases:

(i)	by CIOPEN when TCP/CI is enabled.

(ii)	by 'remote port came online' callback.  SCA will issue this callback
	when a remote port becomes available after having been unreachable
	(DOWN).

(iii)	when the remote initiated a disconnect of a connection.

NODINI  assumes  the  port  state  to  be  down.  If the remote port is
available, it issues an active connect request and moves the  state  to
CONNECT. From now on, SCA callbacks take over.

We will get a "connect request response" to the CONNECT we sent out. If
the remote port accepted, we can move our port state to RUN.

Now  look  at  the other port: it receives an incoming connect request.
This translates into a "connect to listen" callback.  The  remote  port
will  accept and move its state to ACCEPT. Soon after, another callback
from SCA will inform the remote IPCIDV that "it is ok  to  send  data",
and the remote can go to RUN. The connection is established.

The  complication  is that it is likely for both ends to try to connect
to each other at the same time. Two active connect requests can  be  in
transition  at  the  same  time.  One of the two connections need to be
disconnected. The backoff code is in the "connect to  listen"  callback
routine.  If  we  already  are  in  CONNECT  state  (i.e.  we  have  an
outstanding  connect  request)  then we will reject a connection if the
remotes port number is lower than our own.

\
	SUBTTL Definitions

;Special AC definitions

	CID==Q1			;CID holds connect ID
	PT==Q2		 	;PT keeps port number
	SRV==Q3			;type of service
	NCT==P1			;address of our nct
	RID==P3			;request id (buffer address)

;Internal error codes for debugging

	CI.NKL==620001		;No KLIPA present in system
	CI.NLP==620002		;Not allowed to transmit to Local Port
	CI.NRE==620003		;No resources
	CI.SDG==620004		;SCA Send datagram failed
	CI.NRU==620005		;Port not in RUN state
	CI.NBA==620007		;CIGRBF couldn't get a buffer
	CI.BTL==620010		;Buffer too long on transmit

;Miscellaneous definitions

	CI.HOP==.NBLD1		;Routing adress is kept in the leader
	DEFSTR CINOD,CI.HOP,35,4 ;CI node # is built into the internet adr
	NDGBUF==4		;# of SCA buffers to post (4 is a guess)

	XSWAPCD
SCANAM:	ASCI8(<TCP$IPCI        >) ;SCA process name
	SUBTTL Local storage

;The PRT BEGSTR contains information about each port

	BEGSTR PT
		FIELD OWN,1	;Set if this is local port
		FIELD HOS,1	;Set if this port is hostile, i.e. not TOPS-20
		FILLER 1
		HWORD STA	;Port state (DOWN,CONNECT,LISTEN,ACCEPT,RUN)
	ENDSTR
	IFN <PT.LEN - 1>,<PRINTX ?BEGSTR PT is not 1 word long>

;Storage

	RS(PRTTAB,C%SBLL)	;Each word is in form of PT BEGSTR
	RS(CIDTBL,C%SBLL)	;Each word keeps the connect ID (CID)
	RS(KLPON,1)		;Non-zero if KLIPA interface is present
	RS(OURPRT,1)		;Our KLIPA port number
	SUBTTL Port States and Macros

;These are the port states (stored in PTSTA in PRTTAB)

	.PSOFF==0		;Closed (or not OPENed)
	.PSDOWN==1		;Remote port not available
	.PSCONNECT==2		;Connect outstanding to remote
	.PSLISTEN==3		;Listen outstanding
	.PSACCEPT==4		;Accept, waiting for SCA .SCOSD callback
	.PSRUN==5		;Run, data may be transmitted

;The GETSTATE macro loads the port connect state into the AC argument

	DEFINE GETSTATE (A) <
		LOAD A,PTSTA,+PRTTAB(PT)
	>

;The CHKSTATE macro skips if the port connect state is equal to the
; state given as argument

	DEFINE CHKSTATE (A) <
		LOAD CX,PTSTA,+PRTTAB(PT)
		CAIE CX,.PS'A
	>

;The NEWSTATE macro sets the port connect state to a new value

	DEFINE NEWSTATE (A) <
		MOVX CX,.PS'A
		STOR CX,PTSTA,+PRTTAB(PT)
	>
	SUBTTL SCA Callback Dispatch

;SCA callbacks

XXXSEC==<XCDSEC,,0>

	XRESCD
SCADSP:	TABBEG .SSDGR,.SSDMA,<XXXSEC!SCAUC> ;Unknown callbacks bugchk
	  TABENT .SSDGR,<XXXSEC!SCADGR> ;Datagram received
	  TABENT .SSPBC,<XXXSEC!SCAPBC> ;Port broke connection
	  TABENT .SSCTL,<XXXSEC!SCACTL> ;Connection to listen
	  TABENT .SSCRA,<XXXSEC!SCACRA> ;Connection response available
	  TABENT .SSMSC,<XXXSEC!SCAMSC> ;Datagram/message send complete
	  TABENT .SSDDG,<XXXSEC!R>      ;Datagram dropped
	  TABENT .SSLCL,<XXXSEC!R>      ;Little credit left
	  TABENT .SSNCO,<XXXSEC!SCANCO> ;Node came online
	  TABENT .SSOSD,<XXXSEC!SCAOSD> ;Ok to send data
	  TABENT .SSRID,<XXXSEC!SCARID> ;Remote initiated disconnect
	  TABENT .SSCIA,<XXXSEC!R>      ;Credit is available
	TABEND
	SUBTTL Initialization and Background Service

;CIPINI - INITIALIZATION 
;
; Called from MNTINI when initializing all of the networks known
; to  Multinet. 
;
; NCT/ NCT address 
;
; Returns + 1 always 

	XSWAPCD

CIPINI::MOVEM NCT,CIPNCT	;SAVE OUR NCT FOR THE CALLBACK ROUTINE
	SETZM HSTGDM(NCT)	;CANCEL GOING DOWN MESSAGES
 	RET

;CIPSRV - BACKGROUND SERVICE FOR IPCI
;
; Called by the Internet fork to provide background processing
; for IPCIDV. 
;
; Returns + 1 always

CIPSRV::SKIPE INTON		;CAN'T DO ANYTHING UNTIL INTERNET INIT'D
	SKIPN CIPON		;OR UNTIL WE'RE INIT'D
	RET
	CALL CIPGIB		;GET SOME BUFFERS IF NEEDED
	RET
	SUBTTL Multinet Restart Service

;CIPRST - RESTART
;
; Call here when we want to open the Internet comm over the CI.
;
; NCT/ NCT address
;
; Returns + 1 always

	XSWAPCD

CIPRST::SKIPN INTON		;HAS INTERNET BEEN INITIALIZED ?
	 RET			;NO. NOT READY YET.
	SKIPG T1,NTLADR(NCT)	;SEE IF WE HAVE HOST NUMBER YET
	RET			;NO. NOT READY YEST.
	TXZ T1,<^-<377>>	;TURN OFF UNWANTED BITS
	SKIPN T2,CHNTAB+KLPRH2	;GET THE CDB ADDRESS
	 JRST CIPRSE		;NO CDB
	JE <CS.CIP>,CDBSTS(T2),CIPRSE ;IF NOT A CI WE ARE ALL DONE
	MOVE T2,CDBNOD(T2)	;GET OUR CI NODE NUMBER
	CAME T1,T2		;LOW ORDER HOST NUMBER SAME AS CI NODE NUMBER?
	 JRST CIPRSE		;NO
	SETZM NTTOUT(NCT)	;CLEAR OUTPUT HUNG TIMEOUT
	CALL CIPGIB		;GET A BUNCH OF BUFFERS
	CALL CIOPEN		;GO DO THE OPEN
	 JRST CRSTER		;COULDN'T
	SETOM CIPON		;INTERFACE IS READY
	AOS NTSTCH(NCT)		;CAUSE CHANGE IN STATE TO BE NOTED
	GTAD
	MOVEM T1,NTXUPP(NCT)	;SAVE TIME WHEN IT CAME UP
	SETOM NTRDY(NCT)	;INDICATE FULLY UP
	SETOM NTORDY(NCT)	;ALLOW OUTPUT
	CALL INTUP		;INTERFACE IS UP
	CALL CIPSTO		;START OUTPUT IF NEEDED
	AOS JB0FLG		;NOTE NETWORK CHANGE
	RET

;Here to handle errors during restart

CRSTER:	MOVEM T1,CIPERR		;SAVE THE ERROR
	CALL CIPHNG		;HANDLE IT
	RET

CIPRSE:				;HERE WHEN NO CI OR ADR DOES NOT EXIST
	BUG.(INF,CIPBAD,IPCIDV,SOFT,<IP Host number conflicts with CI Node Number.>,<<T1,HOST>,<T2,QODE>>,<

Cause:	The low order octet of the local internet host address for the CI
	interface (from the SYSTEM:INTERNET.ADDRESS file) disagrees with the
	systems CI node number.

Action: Fix the SYSTEM:INTERNET.ADDRESS file.

>)
CIPRSX:
	SETZM NETON(P1)		;MAKE SURE WE DO NOT TRY TO START AGAIN
	RET			;AND RETURN
	SUBTTL Multinet Status Checking and Header Building

;CIPSTA - STATUS CHECK 
;
; This  routine  is  called from Multinet to check the status of
; the KLIPA.
;
; NCT/ NCT address
;
; Returns + 1 on error
;	  + 2 on success

	XSWAPCD

CIPSTA::CALL CISTS		;GO GET THE STATUS
	 SKIPA			;ERROR DETECTED
	  RETSKP		
CIPHNG:	SETOM NTERRF(NCT)	;YES, FLAG AN ERROR
	SETZM NTRDY(NCT)	;MAKE THE NETWORK NOT READY
	MOVE T1,TODCLK		;GET TIME NOW
	ADDI T1,^D60*^D1000	;TIMEOUT IN ONE MINUTE
	MOVEM T1,NTTOUT(NCT)	;SET INTERFACE HUNG TIMEOUT
	RET


;CIPHDR - BUILD HEADER 
;
; Called from Multinet to build a header for the local transport
; layer. In our case, the only essential information is the host
; number of the next node which can route the packet.
;
; T1/  local address to send to
; T2/  address of buffer
; NCT/  NCT address
;
; Returns + 1 always

	XSWAPCD

CIPHDR::MOVEM T1,CI.HOP(T2)	;STORE DESTINATION ADDRESS
	RET
	SUBTTL Multinet Output Service

;CIPSTO - START OUTPUT
;
; Called to send an output buffer.
;
; NCT/ NCT address 
; NTIOBO/ pointer to the list of internet buffers to send 
; NTIOBI/ tail end of the list
;
; Returns +1 always

	XRESCD 

CIPSTO::SAVEAC <RID>		
CIPOS1:	SKIPN RID,NTIOBO(NCT)	;ANY INTERNET OUTPUT WAITING?
	RET                 	;NO
	NOSKED			;NO INTERRUPTIONS FROM OTHER FORKS
	LOAD T2,NBQUE,(RID)	;GET ITS SUCCESSOR
	JUMPN T2,CIPOS2		;JUMP IF NOT LAST ONE
	SETZM NTIOBI(NCT)	;YES.  MAKE QUEUE NULL
	SKIPA
CIPOS2:	SETSEC T2,INTSEC	;PLACE IN PROPER SECTION
	MOVEM T2,NTIOBO(NCT)	;UPDATE OUTPUT POINTER
	SETZRO NBQUE,(RID)	;DEQUEUE BUFFER FROM ITS OLD CHAIN
 	OKSKED			;ALLOW INTERRUPTS AGAIN
	CALL CISNDP		;NO. SEND TO SCA
	 RETBAD                 ;ERROR
	SETZM NTTOUT(NCT)	;CLEAR OUTPUT HUNG TIMEOUT
	JRST CIPOS1		;TRY FOR MORE

;CISNDP - SEND PACKET VIA SCA
;
; NCT/ NCT address
; RID/ address of buffer
;
; Returns + 1 on error
;	  + 2 on success

	XSWAPCD

CISNDP:	XMOVEI T2,-LCLPKT(RID)	;POINT TO RIGHT LOCATION TO PICK UP PIDH
	LOAD T3,PIDH,(T2)	;GET THE DESTINATION HOST #
	CAMN T3,NTLADR(NCT)   	;DESTINED FOR US ?
	JRST CILCAL		;YES
	LOAD T1,CINOD,(RID)	;GET THE ROUTING ADDRESS
	XMOVEI T2,MAXLDR(RID)	;POINT AT DATA PORTION OF BUFFER
	XMOVEI T3,-LCLPKT(RID)	;POINT TO RIGHT LOCATION TO PICK UP LENGTH
	LOAD T3,PIPL,(T3)	;GET PACKET LENGTH 
	CALL CISEND		;GO SEND IT
	 JRST CISND1		;GO HANDLE ERROR
	CALLRET CIRELB		;GO RELEASE BUFFER
	SUBTTL Local Loopback Service

;CILCAL - LOCAL LOOPBACK
;
; Called  from CISNDP to handle a message to ourself. We reserve
; a input buffer and copy the IP packet into it, queue  it,  and
; release  the  old  packet.  This routine is needed because the
; SCA does not allow us to send to ourself.
;
; RID/ address of the outgoing IP packet
; NCT/ address of the NCT
;
; Returns via CIRELB

	XSWAPCD

CILCAL:	STKVAR <BFA>
	CALL CIGRBF		;GET A BUFFER TO USE
	 JRST CISND1		;DIDN'T GET A BUFFER
	MOVEM T2,BFA   		;SAVE THE NEW BUFFER ADDRESS
	XMOVEI T2,-LCLPKT(RID)	;POINT AT PACKET HEADER BEGINNING
	LOAD T1,PIPL,(T2)	;HEADER LENGTH IN BYTES
	ADDI T1,3+PKTELI*4	;PACKET SIZE IN BYTES, ROUNDED UP
	ASH T1,-2		;PACKET SIZE IN FULL WORDS
	XMOVEI T2,MAXLDR(RID)	;POINT TO BEGINNING OF BUFFER
 	MOVE T3,BFA        	;DESTINATION IS THE POSTED RCV BUFFER'S
	ADDI T3,MAXLDR		; DATA AREA
	CALL XBLTA		;COPY IP HEADERS
	MOVE T2,BFA       	;POINT AT RCV BUFFER
	CALL CIDGRC		;GIVE THE BUFFER TO INTERNET
	CALLRET CIRELB		;RELEASE OLD BUFFER 

	ENDSV.


;Here to release the current output buffer

	XSWAPCD

CISND1:	SKIPA T3,T1		;WANT THE ERROR STATUS
CIRELB:	SETZ T3,		;DON'T WANT ANY ERROR STATUS
	MOVE T1,RID        	;GET BUFFER ADDRESS 
	MOVE T2,T1		;COPY FOR INDEXING
	PIOFF
	EXCH T1,INTNFB		;PUT ON FREE LIST
	STOR T1,NBQUE,(T2)	;HANG OLD LIST OFF OF THIS NEW HEAD
	PION
	AOS INTFLG		;GET INTERNET GATEWAY TO NOTICE IT
	SKIPN T1,T3          	;NO, GET THE CHANNEL STATUS
	RETSKP			;NO ERRORS DETECTED  
CDSERR:	AOS CIOCNT		;BUMP THE OUTPUT ERROR COUNT
	CAIE T1,CI.NRU		;If 'not in RUN state' then dont bugcheck
	BUG.(INF,CIPDNS,IPCIDV,SOFT,<Datagram not sent>,<<T1,ERROR>>,<

Cause:	The internet SCA interface attempted to queue a buffer to SCA
	and the buffer was refused.

>)
	MOVEM T1,CIPERR
	RETBAD
	SUBTTL Shutdown and Error Routines

;CIPKIL - SHUTDOWN 
;
; Called from MNETDV to shut down both Internet and ARP 
; communications with SCA.
;
; NCT/ NCT address 
;
; Returns + 1 always  (T1 IS PRESERVED)

	XSWAPCD

CIPKIL::MOVE T1,NTRDY(NCT)	;RECORD IF ANYTHING CHANGED
	IOR T1,NTORDY(NCT)
	SETZM NTTOUT(NCT)	;CLEAR OUTPUT HUNG TIMEOUT
	JUMPE T1,CIPKLD		;NOTHING CHANGED SO EXIT QUIETLY
	SETZM NTRDY(NCT)	;CI OFF
	SETZM NTORDY(NCT)	;OUTPUT OFF
 	AOS NTSTCH(NCT)		;JUST CHANGED STATE
	AOS JB0FLG		;NOTE THE NETWORK CHANGE
	CALL CICLS		;CLOSE THE CI 
	SETZM CIPON		;INTERNET NOT ON ANYMORE
CIPKLD:	RET
	SUBTTL Buffer Management

;CIPGIB - GET INPUT BUFFERS.
;
; Called  from the Internet fork to get a bunch of input buffers
; to be used for incoming IP packets over the CI.
;
; Returns + 1 always

	XRESCD

CIPGIB:	MOVE T1,CIPNFI		;NUMBER OF FREE INPUT BUFFERS
CIPGB1: CAML T1,CIPNIB		;BELOW DESIRED LEVEL?
	 RET			;NO - DO NOTHING
	MOVE T1,MAXWPM		;GET ENOUGH ROOM
	CALL GETNIB		;GET A BUFFER
	JUMPE T1,CIPGB3   	;ZERO ADDRESS, NONE AVAILABLE
	SETZRO PKTFLG,(T1)	;CLEAR ALL INTERNAL CONTROL FLAGS
	SETONE PFSIZ,(T1)	;INDICATE IT'S A FULL SIZE PACKET
	XMOVEI T2,LCLPKT(T1)	;GET POINTER TO LOCAL HEADERS
	MOVE T3,MAXWPM		;MAX WORDS
	STOR T3,NBBSZ,(T2)	;SAVE AS BUFFER SIZE
	SETZRO NBQUE,(T2)
        CALL INTLKB		;MAKE SURE BUFFER IS RESIDENT
	MOVE T1,T2
 	PIOFF
	EXCH T2,CIPFRI		;ADD TO LIST OF FREE INPUT BUFFERS
	STOR T2,NBQUE,(T1)	;OLD LIST IS SUCCESSOR OF THIS BUF
	AOS T1,CIPNFI		;BUMP THE COUNT TO MATCH
	PION
	JRST CIPGB1		;SEE IF ENOUGH

CIPGB3:				;HERE WHEN NO BUFFERS AVAILABLE
	MOVE T1,CIPNFI		;GET NUMBER OF BUFFERS AVAILABLE
	CAIGE T1,NCIPTH		;BELOW THE THRESHOLD LEVEL ?
	BUG.(CHK,CIPNBA,IPCIDV,SOFT,<No IPCI input buffers available.>,<<T1,BFRCNT>>,<

Cause:	The internet SCA interface was unable to assign any buffers from
	the internet free space manager.  This should be a temporary condition.

>)
	RET
	SUBTTL Receive Buffer Handling

;CIGRBF - get receive buffer
;
;CI driver will call this routine when it has received a SCA datagram
; and needs an IP buffer to copy the message to.
;
;Call:	<no arguments>
;	CALL CIGRBF
;	 +1 return/ no buffers available
;	+2 return/ T2/ address of resident buffer (need not be physically
;		       contiguous)
;		   T3/ # of bytes in buffer
;Context: Interrupt (SCA)

	XRESCD

CIGRBF:	PIOFF
	SOSL T1,CIPNFI		;COUNT DOWN NUMBER OF FREE INTERNET BUFS
	 SKIPN T2,CIPFRI	;GET POINTER TO BUFFER TO USE
	 IFNSK.
	  AOS CIPNFI		;DON'T HAVE BUFFERS. DON'T LET IT GO NEGATIVE
	  PION
	  MOVE T2,CIPFRI	;MAKE SURE WE GET POINTER 
	  BUG.(CHK,CIPBLP,IPCIDV,SOFT,<IPCIDV input buffer list problem>,<<T1,CNT>,<T2,BFR>>,<

Cause:	The internet SCA interface requested a buffer for an incoming datagram 
	and none were available.

>)
	  RETBAD <CI.NBA>	;SET THE ERROR CODE AND RETURN
	 ENDIF.
	LOAD T1,NBQUE,(T2)	;NEXT INTERNET FREE BUFFER
        SETSEC T1,INTSEC	;YES SO SET THE SECTION NUMBER
	SETZRO NBQUE,(T2)	;CLEAR LIST POINTER
	MOVEM T1,CIPFRI		;BECOMES HEAD OF LIST
	PION
	ADDI T2,MAXLDR		;POINT PAST HEADER AREA
	MOVE T3,INTXPB		;GET SIZE OF INTERNET PACKET
	ADDI T3,4		;ADD IN CRC 
	RETSKP
	SUBTTL SCA Datagram Received Service

;CIDGRC - receive datagram
;
;CI driver will call this routine when it has received a message and copied
; it into an IP buffer
;
;Call:	T1/ node # (of source)
;	T2/ buffer address
;	T3/ # of bytes
;	CALL CIDGRC
;	+1 return always
;Context: Interrupt (SCA)

	XRESCD

CIDGRC:	PIOFF			;DON'T ALLOW US TO BE INTERRUPTED
	SUBI T2,MAXLDR		;POINT AT HEADER AREA
	MOVE T3,INTIBI		;QUEUE FOR INTERNET GATEWAY
	JUMPN T3,CBDRQ1
	MOVEM T2,INTIBO		;ONLY THIS ITEM
	SKIPA
CBDRQ1:	 STOR T2,NBQUE,(T3)
	MOVEM T2,INTIBI		;NEW POINTER
	AOS INTFLG		;CAUSE INTERNET TO NOTICE IT.
	AOS PSKD1		;AND CAUSE THE SCHED TO NOTICE IF SYSTEM IDLE
	PION
	RET
	SUBTTL CISTS - Check status of CI

;CISTS - Check status of CI
;
;Call:	<no arguments>
;	CALL CISTS
;	 +1 error return with CI.NKL (No KLIPA present) in T1
;	+2 success return: CI interface is available

	EXTERN SC.PRT
CISTS=SC.PRT			;SC.PRT does exactly this
	SUBTTL CIOPEN - Open CI for traffic

;CIOPEN - Open CI for Internet traffic
;
;Call:	<no arguments>
;	CALL CIOPEN
;	 +1 error return with error code in T1
;	+2 success return


	XSWAPCD
CIOPEN:	SKIPE KLPON		;ALREADY ON ?
	 RET
	SAVEAC <P1,CID,PT>
	SETZ PT,		;Initialize the port table
	DO.
	  SETZM PRTTAB(PT)	;Clear port table entry
	  NEWSTATE DOWN		;Set initial state to "DOWN"
	  CAIGE PT,<C%SBLL-1>	;Done all ports yet?
	  AOJA PT,TOP.		; -no, initialize next
	ENDDO.
	CALL SC.PRT		;Get local port number
	 RETBAD (CI.NKL)	; -no KLIPA, return error
	MOVEM T1,OURPRT		;Save our port number
	SETONE PTOWN,+PRTTAB(T1) ;Flag "own" flag for this port
				;Now post a promiscuous listen
	CALL DOLIS		;Post a listener
	 RETBAD (CI.NRE)	; -return "no resources"

;Set online address so we get notified if new nodes come online

	BLCAL. (<@[MSEC1,,SC.SOA]>,<[XADDR. SCACBK]>) ;Set callback address
	 RETBAD (CI.NRE)

;Loop over all nodes, and see if we should try to connect

	SETZ PT,		;PT is node index
	DO.
	  CALL NODINI		;Initialize this node
	  CAIGE PT,<C%SBLL-1>	;Done all nodes?
	  AOJA PT,TOP.		; -no, go to the next
	ENDDO.
	SETOM KLPON		;Flag CI present
	RETSKP
	SUBTTL SCA Remote Node Connection Initialization

	XRESCD

NODINI:				;(try to) initialize a remote node
	STKVAR <CBADR>
	MOVE T1,[XWD .RESP1,.RDLEN] ;Priority,,length
	MOVEI T2,.RESGP		;Pool
	CALL ASGRES		;Assign space
	RET			; -failed
	MOVEM T1,CBADR		;Save address of block
	BLCAL. (<@[MSEC1,,SC.RCD]>,<PT,T1>)	;Read configuration
	IFNSK.			; -not there
	  MOVE T1,CBADR		;  Get address of block
	  CALLRET RELRES	;   and return deallocating it
	ENDIF.
	MOVE T1,CBADR		;Get address of block
	CALL NODIN1		;Call coroutine to do the work
	MOVE T1,CBADR		;Retrieve configuration block address
	CALLRET RELRES		; and return the block and return
	ENDSV.

NODIN1:	LOAD T2,RDVCST,(T1)	;Get VC state
	LDB T3,[POINT PKSID,.RDPCH(T1),PKPID]	;Get remote system ID
	CAIN T3,ID.KL		;Is it a friendly system?
	IFSKP.			; -no,
	  SETONE PTHOS,+PRTTAB(PT) ;  Set the hostile bit
	  RET			;      and return
	ENDIF.

;Coming here we want to try to connect if the remote is available

	CAIE T2,VC.OPN		;Is VC state OPEN?
	RET
	CALLRET DOCONN		; and do the connect

;DOLIS - post a promiscuous listen

	XRESCD
DOLIS:	BLCAL. (<@[MSEC1,,SC.LIS]>,<[XADDR. SCANAM],[XADDR. SCANAM],[-1],[XADDR. SCACBK],[0],[0],[0]>)
	 RET
	RETSKP

;DOCONN - do an active connect
	XRESCD
DOCONN:	CIOFF			;Protect from state changes
	CHKSTATE DOWN		;Verify that we believe remote is down
	JRST DOCON1		; -no, go do CION and RET
	BLCAL. (<@[MSEC1,,SC.CON]>,<[XADDR. SCANAM],[XADDR. SCANAM],PT,[0],[0],[XADDR. SCACBK],[0],[0],[0],[NDGBUF]>)
	IFSKP.			;Success
	  NEWSTATE CONNECT	; so new state is CONNECT
	ELSE.			;On error return
	  CAIE T1,KLPX9		; VC closed
	  CAIN T1,SCSISB	;  or remote not available?
	  IFNSK.
	    NEWSTATE DOWN	;  -yes, move state to DOWN
	  ELSE.
	    NEWSTATE LISTEN	;  -no, move state to LISTEN
	  ENDIF.
	ENDIF.
DOCON1:	CION			;Done with sensitive code
	RET
	SUBTTL CISEND - Send datagram

;CISEND - send datagram
;
;Call:	T1/ node #
;	T2/ buffer address
;	T3/ # of bytes to transmit
;	CALL CISEND
;	 +1 return on error with error code in T1
;	+2 return on success

	XSWAPCD
CISEND:	SKIPN KLPON		;Make sure KLIPA is on
	RETBAD (CI.NKL)		; -return 'no KLIPA'
	SAVEAC <P1,P2,CID,PT>
	MOVE PT,T1		;Port number to PT
	CHKSTATE RUN		;Is it RUN state?
	RETBAD (CI.NRU)		; -no, return error
	CAXLE T3,<C%BYTD-C%OVHD> ;Make sure supplied buffer isnt too large
	RETBAD (CI.BTL)		;  -it was, return error
	MOVE CID,CIDTBL(PT)	;Get CID for connection
	DMOVE P1,T2		;Move T2,T3 to P1,P2
	MOVX T1,1		;Get one buffer
	CALL SC.ALD		; from SCA pool
	 RETBAD (CI.NRE)	;  -return "no resources"
				;Copy the IP buffer into the SCA buffer
	MOVE T2,P1		;Move IP buffer address into T2
	MOVE P1,T1		;And save SCA buffer address in P1
	MOVEI T1,3(P2)		;Get # of bytes to transmit + 3
	ASH T1,-2		; to make into words
	XMOVEI T3,.MHUDA(P1)	;And SCA buffer address to T3
	EXTEND T1,[XBLT]	;XBLT into the buffer
				;Send the datagram
	BLCAL. (<@[MSEC1,,SC.SDG]>,<CID,[F.RTB],P2,P1,[IPCPRI],[0]>)
	 RETBAD (CI.SDG)
	RETSKP
	SUBTTL CICLS - Close CI

;CICLS - close CI
;
;Call:	<no arguments>
;	CALL CICLS
;	 +1 return on error with error code in T1
;	+2 return on success

	XRESCD
CICLS:	SAVEAC <CID,PT>
	
;Step through all ports and disconnect any connections

	SETZ PT,		;PT is port number
	DO.
	  CIOFF			;Protect from callbacks that may move state to
				; RUN
	  GETSTATE T1		;Get current state into T1
	  NEWSTATE OFF		; and move state to OFF
	  CION			;Let in interrupts again
	  CAIE T1,.PSRUN	;Was this port in RUN
	  CAIN T1,.PSACC	; or in ACCEPT state?
	  IFNSK.
	    BLCAL. (<@[MSEC1,,SC.DIS]>,<CIDTBL(PT),[0]>) ;Disconnect
	    JFCL
	  ENDIF.
	  CAIGE PT,<C%SBLL-1>	;Done all ports?
	  AOJA PT,TOP.		; -no, go to next one
	ENDDO.
	SETZM KLPON		;CLEAR THE ON FLAG
	RETSKP			;Return success
	SUBTTL SCACBK - SCA Callback Entry Point

	XRESCD
SCACBK:				;Called on SCA callbacks
	SAVEAC <CID,PT>		;Save preserved ACs
	CALL @SCADSP(T1)	;Call service routine
	RET			;Always single return

CID2PN:				;Convert CID to port number
	MOVE T1,CID
	CALL SC.NOD		;Call SCA to do this
	MOVE PT,T2		;Node # is returned in T1
	RET

SCAUC:				;Unexpected callback
	BUG. (CHK,IPSCBV,IPCIDV,SOFT,<SCA passed an illegal callback function>,<<T1,CODE>,<T2,ARG1>,<T3,ARG2>>,<

Cause:	SCA gave the internet SCA interface a callback with an unknown function
	code.

>)
	RET
	SUBTTL SCADGR - Datagram Received Callback

;Call:	T2/ address of datagram buffer
;	T3/ CID
;	T4/ flags
;	CALL SCADGR
;	+1 return always

;Ac usage:
; P1/ SCA buffer address
; P2/ SCA packet length
; P4/ flags
; P5/ IP buffer address

	XRESCD
SCADGR:	SAVEP
	MOVE P1,T3		;SCA buffer address
	MOVE P2,.MHPKL(P1)	;SCA packet length
	SUBI P2,C%OVHD		; minus overhead bytes
	MOVE P4,T4		;Flags
	MOVE CID,T2		;Get CID
	CALL CID2PN		;CID =) port #
				;is port in RUN state?
	CHKSTATE RUN		;RUN?
	 CALLRET RDGBUF		; -no, return SCA buffer and return
	TXNN P4,F.SPM		;Industry compatible mode?
	CALL CIGRBF		; -yes, get IP buffer
	 CALLRET RDGBUF		;  -no to any or both, return buffer
	MOVE P5,T2		;Save IP buffer address
	CAMGE T3,P2		;IP buffer big enough?
	CALLRET RDGBUF		; -no, (should probably bugcheck)
				;Copy SCA buffer to IP buffer
	MOVEI T1,3(P2)		;Get # of SCA bytes + 3
	ASH T1,-2		; and make into words
	XMOVEI T2,.MHUDA(P1)	;Get SCA buffer address
	MOVE T3,P5		; and IP buffer address
	EXTEND T1,[XBLT]	;  and move the data
	CALL RDGBUF		;Return the SCA buffer
				;Call IP to process incoming packet
	MOVE T1,PT		;Port #
	MOVE T2,P5		;IP buffer address
	MOVE T3,P2		;# of bytes
	CALL CIDGRC		;Call "received datagram"
	RET			;Return to SCA

RDGBUF:				;Put a SCA buffer back on free queue
	BLCAL. (<@[MSEC1,,SC.RDG]>,<CID,[0],P1>) ;Recycle buffer to free queue
	BUG. (CHK,IPNFRB,IPCIDV,SOFT,<Failed to recycle buffer>,,<

Cause:	The internet SCA interface attempted to return a buffer to SCA and
	the buffer was refused.

>)
	RET
	SUBTTL SCAPBC - Port broke connection

;Call:	T2/ CID
;	CALL SCAPBC
;	+1 return always

	XRESCD
SCAPBC:	SKIPL CID,T2		;Get CID and test for unsolicited (T2 eq -1)
	IFSKP.			; -unsolicited
	  MOVE PT,T3		;  so get port # from T3
	ELSE.			; -real pbc
	  CALL CID2PN		;  so get port number from CID
	ENDIF.
	NEWSTATE DOWN		;Move state to DOWN in all cases
	RET
	SUBTTL SCACTL - Connect to listen

;Call:	T2/ CID
;	T3/ address of connetion data
;	CALL SCACTL
;	+1 return always

	XRESCD
SCACTL:	MOVE CID,T2		;Move CID into place
	CALL CID2PN		; and make port number
	CALL DOLIS		;Post a new listener since the old one is gone
	  JFCL			;  -too bad...
	CHKSTATE LISTEN		;In LISTEN state
	SKIPA			; -no,
	JRST DOACC		;-yes, do accept
	CHKSTATE CONNECT	;In CONNECT state
	  JRST DOREJ		;  -no, go reject
	CAML PT,OURPRT		;-yes, remotes port number lower than ours?
	JRST DOREJ		; -no, reject

DOACC:				;All set, accept
	BLCAL.(<@[MSEC1,,SC.ACC]>,<CID,[0],[0],[NDGBUF]>)
	IFNSK.
	  BUG. (CHK,IPACFA,IPCIDV,SOFT,<SCA ACCEPT failed>,,<

Cause:	The internet SCA interface attempted to accept a connection and
	failed.

>)
	ELSE.
	  NEWSTATE ACCEPT	;Move state to ACCEPT
	ENDIF.
	RET			;All sone

DOREJ:	BLCAL.(<@[MSEC1,,SC.REJ]>,<CID,[0]>)
	 JFCL
	RET
	SUBTTL SCACRA - Connection response available

;Call:	T2/ CID
;	T3/ -1 if accepted, 0 if rejected
;	CALL SCACRA
;	+1 return always

	XRESCD
SCACRA:	MOVE CID,T2		;Get connect ID
	CALL CID2PN		; and get port #
	CHKSTATE CONNECT	;Are we in CONNECT state?
	IFNSK.			; -no,
	  SKIPN T3		;  Were we accepted?
	  IFSKP.		;  -yes,
	    BLCAL.(<@[MSEC1,,SC.DIS]>,<CID,[0]>) ; disconnect connection
	    JFCL
	  ENDIF.
	ELSE.			; -yes, port in CONNECT state
	  SKIPN T3		;  Were we accepted?
	  IFSKP.		;  -yes, good news
	    MOVEM CID,CIDTBL(PT) ;Save CID
	    NEWSTATE RUN
	  ELSE.
	    NEWSTATE LISTEN	;  -no, bad news
	  ENDIF.
	ENDIF.
	RET
	SUBTTL Misc. SCA callbacks.

;Call:	T2/ CID
;	T3/ address of buffer
;	CALL SCAMSC
;	+1 return always

	XRESCD
SCAMSC:	MOVE T1,T3		;Get buffer
	CALLRET SC.RLD		; and return it to SCA

;Call:	T2/ # of node that just came online
;	CALL SCANCO
;	+1 return always

SCANCO:	MOVE PT,T2		;NODINI expects node in PT
	CALLRET NODINI		;Try to iniitializa node that came online

;Call:	T2/ CID
;	CALL SCAOSD
;	+1 return always

SCAOSD:	MOVE CID,T2		;Get connect ID
	CALL CID2PN		; and make port number of it
	CHKSTATE ACCEPT		;ACCEPT state?
	IFSKP.
	  MOVEM CID,CIDTBL(PT)  ;Save CID
	  NEWSTATE RUN		; -yes, then move to RUN
	ELSE.
	  BLCAL.(<@[MSEC1,,SC.DIS]>,<CID,[0]>) ; -no, then disconnect
	  JFCL
	ENDIF.
	RET

;Call:	T2/ CID
;	CALL SCARID
;	+1 return always

SCARID:	MOVE CID,T2		;Get connect ID
	CALL CID2PN		; and get port number
	GETSTATE T1		;Get port state
	CAIE T1,.PSRUN		;RUN or
	CAIN T1,.PSACCEPT	; ACCEPT?
	IFNSK.			;  -yes,
	  BLCAL.(<@[MSEC1,,SC.DIS]>,<CID,[0]>) ; disconnect
	  JFCL
	ENDIF.
	NEWSTATE DOWN		;Reset state
	CALL NODINI		;Reinitialize connection with remote
	RET
	SUBTTL End of Module

	TNXEND
	END