Google
 

Trailing-Edge - PDP-10 Archives - BB-D868C-BM - language-sources/qsrnet.mac
There are 36 other files named qsrnet.mac in the archive. Click here to see a list.
	TITLE	QSRNET - NETWORK DATA BASE MANAGER

;
;
;                COPYRIGHT (c) 1975,1976,1977,1978,1979
;                    DIGITAL EQUIPMENT CORPORATION
;
;     THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED
;     AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE
;     AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE.   THIS
;     SOFTWARE  OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR
;     OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON.  NO  TITLE  TO
;     AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED.
;
;     THE INFORMATION  IN  THIS  SOFTWARE  IS  SUBJECT  TO  CHANGE
;     WITHOUT  NOTICE  AND SHOULD NOT BE CONSTRUED AS A COMMITMENT
;     BY DIGITAL EQUIPMENT CORPORATION.
;
;     DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY
;     OF  ITS  SOFTWARE  ON  EQUIPMENT  WHICH  IS  NOT SUPPLIED BY
;     DIGITAL.

	SEARCH	QSRMAC,ORNMAC,GLXMAC
	PROLOG	(QSRNET)
	SUBTTL	LOCAL STORAGE

NETPAG:	BLOCK	1		;SAVE AREA FOR THE NODE UUO/JSYS DATA PAGE

NETADR:	BLOCK	1		;SAVE AREA FOR THE ADDR OF THE NODE BLK ADDRESS

NETDUP:	BLOCK	1		;FLAG FOR DUPLICATE NODE DB ENTRIES


NWAMSG:	$BUILD	.OHDRS+ARG.DA+OBJ.SZ
	 $SET(.MSTYP,MS.CNT,.OHDRS+ARG.DA+OBJ.SZ)
	 $SET(.MSTYP,MS.TYP,.QONWA)
	 $SET(.OARGC,,1)
	 $SET(.OHDRS+ARG.HD,AR.LEN,OBJ.SZ+1)
	 $SET(.OHDRS+ARG.HD,AR.TYP,.OROBJ)
	$EOB


MSGPDB:	$BUILD	IPCHSZ
	 $SET(.IPCFP,LHMASK,.OHDRS+ARG.DA+OBJ.SZ)
	 $SET(.IPCFP,RHMASK,NWAMSG)
	$EOB

ONOFF:	[ASCIZ/Online /]
	[ASCIZ/Offline /]

	INTERN	N$INIT		;NETWORK INITIALIZATION
	INTERN	N$NODE		;CHECK FOR NODE ONLINE/OFFLINE STATUS
	INTERN	N$INTR		;ADD A NODE TO THE DATA BASE
	INTERN	N$INT		;NETWORK CHANGE INTERRUPT PROCESSOR.
	INTERN	N$NRTE		;NETWORK ROUTING ROUTINE
	INTERN	N$CSTN		;PERFORM STATION RE-ROUTING
	INTERN	N$LOCL		;VALIDATE A LOCAL NODE NAME/NUMBER
	INTERN	N$MTCH		;SEE IF 2 NODE NAME/NUMBERS ARE EQUIVALENT
	INTERN	N$NONL		;IBM NODE ONLINE PROCESSOR
	INTERN	N$NOFF		;IBM NODE OFFLINE PROCESSOR
SUBTTL	N$INIT - ROUTINE TO INITIALIZE THE NETWORK DATA BASE MANAGER.

N$INIT:	MOVEI	H,HDRNET##		;GET ADDR OF NETWORK DB HEADER
	PUSHJ	P,M$GFRE##		;GET A FREE CELL
	PUSHJ	P,I%HOST		;GET THE HOST IDS
	MOVEM	S1,G$LNAM##		;SAVE THE LOCAL NODE NAME
	MOVEM	S2,G$LNBR##		;SAVE THE LOCAL NODE NUMBER
	MOVEM	S1,NETNAM(AP)		;SAVE THE NAME
	MOVEM	S2,NETNBR(AP)		;SAVE THE NUMBER
	MOVX	S1,NETNSV+NETONL	;GET VALID STATUS+ONLINE
	MOVEM	S1,NETSTS(AP)		;SAVE IT
	$TEXT	(<-1,,NETASC(AP)>,<^N/NETCOL(AP)/^0>) ;GEN NAME(NBR)
	PUSHJ	P,M$FLNK##		;LINK IT IN AT THE BEGINNING.
	PUSHJ	P,I$NINT##		;GO SETUP FOR NETWORK INTERRUPTS
	SETOM	G$CNET##		;FAKE A NETWORK CHANGE INTERRUPT
	$RETT				;RETURN
SUBTTL	N$INT - ROUTINE TO PROCESS NETWORK TOPOLOGY CHANGES

N$INT: $BGINT	1,
	SETOM	G$CNET##		;INDICATE A NETWORK CHANGE OCCURED
	$DEBRK				;LEAVE INTERRUPT LEVEL
	SUBTTL	N$INTR - ROUTINE TO ANALYZE THE NETWORK CHANGES

	;CALL:	PUSHJ P,N$INTR
	;	TRUE ALWAYS

N$INTR:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	SETZM	G$CNET##		;CLEAR THE INTERRUPT FLAG
	DOSCHD				;FORCE A SCHEDULING PASS ON NETWORK INTERRUPTS
	MOVEI	H,HDRNET##		;GET THE NETWORK DB HEADER ADDRESS
	LOAD	AP,.QHLNK(H),QH.PTF	;GET THE FIRST ENTRY
	LOAD	AP,.QELNK(AP),QE.PTN	;SKIP THE CENTRAL SITE
	MOVX	S1,NETNSV		;GET THE NETWORK-STATUS-VALID BITS

	;CLEAR THE NETWORK-STATUS-VALID BITS FOR ALL NETWORK ENTRIES

INTR.1:	JUMPE	AP,INTR.2		;NO MORE,,CONTINUE PROCESSING
	ANDCAM	S1,NETSTS(AP)		;CLEAR THE STATUS BIT
	LOAD	AP,.QELNK(AP),QE.PTN	;GET THE NEXT ENTRY ADDRESS
	JRST	INTR.1			;AND GO PROCESS IT

	;DO NECESSARY PROCESSING FOR ON-LINE NODES

INTR.2:	PUSHJ	P,GET.NETWORK.TOPOLOGY	;READ THE NETWORK TOPOLOGY
	JUMPF	INTR.3			;NO MORE,,GO PROCESS OFF-LINE NODES
	PUSHJ	P,FINDNODE		;FIND THE NODE IN OUR DATA BASE
	MOVE	S1,NETSTS(AP)		;PICK UP THE NODE STATUS
	TXNN	S1,NETONL+NETADD	;WAS IT ONLINE or JUST ADDED ???
	PUSHJ	P,PURGE.DUP.OBJS	;NO,,THE SCAN OBJ QUEUE FOR DUP OBJS
	MOVE	S1,NETSTS(AP)		;PICK UP THE NODE'S STATUS BITS
	TXZE	S1,NETADD		;IF IT WAS JUST ADDED,,GEN THE NODE NAME
	$TEXT	(<-1,,NETASC(AP)>,<^N/NETCOL(AP)/^0>) ;GEN THE NAME
	TXNN	S1,NETONL		;IS IT WAS OFFLINE,,THEN TELL THE OPR
	$WTO	(< Network Node ^T/NETASC(AP)/ is Online >,,,$WTFLG(WT.SJI))
	TXO	S1,NETNSV+NETONL	;ADD VALID STATUS+ONLINE
	MOVEM	S1,NETSTS(AP)		;SAVE IT
	JRST	INTR.2			;AND GO GET ANOTHER NODE

	;NOW DO SOME PROCESSING FOR THE OFF-LINE NODES

INTR.3:	LOAD	AP,.QHLNK(H),QH.PTF	;GET THE FIRST DB ENTRY
	SKIPA				;SKIP THE FIRST TIME THROUGH
INTR.4:	LOAD	AP,.QELNK(AP),QE.PTN	;GET THE NEXT NODE DB ENTRY
	JUMPE	AP,.RETT		;NO MORE,,WE ARE FINALLY DONE
	MOVE	S1,NETSTS(AP)		;GET THIS NODES STATUS BITS
	TXC	S1,NETONL		;FLIP THE ONLINE BIT
	TXNE	S1,NETNSV+NETONL+NETIBM;MUST BE STATUS INVALID+ONLINE+NOT IBM
	JRST	INTR.4			;NO,,GET THE NEXT ENTRY
	MOVX	S1,NETONL		;GET THE ONLINE BIT
	ANDCAM	S1,NETSTS(AP)		;TURN IT OFF (MAKE IT OFFLINE)
	$WTO	(< Network Node ^T/NETASC(AP)/ is Offline >,,,$WTFLG(WT.SJI)) 
	MOVE	S1,NETCOL(AP)		;GET THE NODE NAME/NUMBER
	MOVEM	S1,NWAMSG+.OHDRS+ARG.DA+OBJ.ND ;SAVE THE NODE NAME/NUMBER
	PUSH	P,AP			;SAVE THIS ADDR SINCE IT GETS TRASHED


	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;LOOP THROUGH THE OBJECT QUEUE LOOKING FOR OBJECTS STARTED AND
	;SETUP FOR THE NODE WHICH WENT DOWN

	LOAD	P1,HDROBJ##+.QHLNK,QH.PTF ;GET THE FIRST ENTRY
	SKIPA				;SKIP THE FIRST TIME THROUGH
INTR.5:	LOAD	P1,.QELNK(P1),QE.PTN	;POINT TO THE NEXT OBJECT
	MOVE	S1,NWAMSG+.OHDRS+ARG.DA+OBJ.ND ;RESTORE THE NODE NAME/NUMBER
	JUMPE	P1,INTR.6		;NO MORE,,FINISH UP
	CAME	S1,OBJNOD(P1)		;IS THIS A REMOTE OBJECT ???
	JRST	INTR.5			;NO,,SKIP THIS
	LOAD	S1,OBJSCH(P1)		;GET THE SCHEDULING BITS
	TXC	S1,OBSSTA+OBSSUP	;MUST BE STARTED+SETUP !!!
	TXNE	S1,OBSSTA+OBSSUP	;IS IT ???
	JRST	INTR.5			;NO,,SKIP THIS
	HRLI	S1,OBJTYP(P1)		;GET THE SOURCE OBJECT ADDRESS
	HRRI	S1,NWAMSG+.OHDRS+ARG.DA+OBJ.TY ;GET THE DESTINATION ADDRESS
	BLT	S1,NWAMSG+.OHDRS+ARG.DA+OBJ.SZ-1 ;COPY IT OVER
	MOVE	S1,OBJPID(P1)		;GET THE PID TO SEND TO.
	MOVEM	S1,MSGPDB+.IPCFR	;SAVE AS THE RECIEVERS PID
	MOVEI	AP,MSGPDB		;GET THE PDB ADDRESS
	PUSHJ	P,C$SEND##		;SEND THE MESSAGE OFF
	JRST	INTR.5			;AND GO SEE IF THERE ARE ANY MORE

INTR.6:	POP	P,AP			;RESTORE AP
	PUSHJ	P,SNDORN		;SEND THE MESSAGE OFF TO ORION
	JRST	INTR.4			;AND GO CHECK THE NEXT NODE
SUBTTL	N$NODE	- ROUTINE TO VERIFY THAT THE NODE IS ONLINE.

	;CALL: 	S1/A SIXBIT NODE NAME OR A NODE NUMBER
	;
	;RET:	TRUE IF ONLINE, FALSE IF OFFLINE.
	;	S1/	THE NODE NBR(-10), NODE NAME(-20)
	;	S2/	THE ENTRY ADDRESS

N$NODE:	$SAVE	AP			;SAVE AP FOR A MINUTE
	LOAD	AP,HDRNET##+.QHLNK,QH.PTF ;GET THE FIRST LINK
NODE.1:	JUMPE	AP,NODE.2		;NONE THERE,,ADD IT TO THE LIST.
	CAME	S1,NETNBR(AP)		;DO WE MATCH AS A NUMBER ???
	CAMN	S1,NETNAM(AP)		;OR DO WE MATCH AS NAMES ???
	JRST	NODE.3			;YES TO EITHER,,CONTINUE ON.
	LOAD	AP,.QELNK(AP),QE.PTN	;GET THE POINTER TO THE NEXT NODE.
	JRST	NODE.1			;AND TRY IT.
NODE.2:	PUSHJ	P,N$ANET		;ADD THIS NODE TO THE DATA BASE
NODE.3:	MOVE	S1,NETCOL(AP)		;GET THE NODE ID IN S1
	MOVE	S2,AP			;GET THE ENTRY ADDRESS
	MOVE	AP,NETSTS(AP)		;GET THE STATUS BITS
	TXNE	AP,NETONL		;IS IT ONLINE ???
	$RETT				;ONLINE !!
	$RETF				;OFFLINE !!!
	SUBTTL	N$ANET - ROUTINE TO ADD A NODE TO THE DATA BASE.

	;CALL:	S1/ THE NODE NAME OR NUMBER TO ADD
	;
	;RET:	TRUE ALWAYS

N$ANET:	$SAVE	H			;ALSO H
	MOVEI	H,HDRNET##		;GET OUR HEADER ADDRESS
	PUSH	P,S1			;SAVE S1 FOR A MINUTE
	PUSHJ	P,M$GFRE##		;GET A FREE CELL
	POP	P,S1			;RESTORE S1.
	MOVEM	S1,NETNAM(AP)		;SAVE THE NODE NAME
	MOVEM	S1,NETNBR(AP)		;SAVE THE NODE NUMBER
	$TEXT	(<-1,,NETASC(AP)>,<^N/NETCOL(AP)/^0>) ;GEN THE NAME STRING
	PUSHJ	P,M$ELNK##		;LINK IT IN AT THE END
	$RETT				;AND RETURN

	
	SUBTTL	N$NRTE - ROUTINE TO PERFORM NETWORK ROUTING

	;CALL: 	S1/SOURCE NODE NAME OR NUMBER
	;	S2/DESTINATION NAME OR NUMBER
	;
	;RET:	TRUE ALWAYS

N$NRTE:	PUSHJ	P,.SAVE2		;SAVE P1, P2
	DMOVE	P1,S1			;SAVE SOURCE, DESTINATION NODES
	PUSHJ	P,N$NODE		;FIND THE SOURCE NODE
	MOVEM	P2,NETRTE(S2)		;ROUTE SOURCE TO DESTINATION
	MOVE	S1,P2			;GET THE DESTINATION NODE
	MOVE	P2,S2			;SAVE THE SOURCE ENTRY ADDRESS
	PUSHJ	P,N$NODE		;FIND THE DESTINATION
	$ACK (<Node ^T/NETASC(P2)/ Routed to ^T/NETASC(S2)/>,,,.MSCOD(M))
	CAMN	S2,P2			;IS THE NODE THE SAME ???
	SETZM	NETRTE(S2)		;YES,,RESET IT TO ZERO
	$RETT				;RETURN
	SUBTTL	N$CSTN - ROUTINE TO PERFORM STARTION RE-ROUTING

	;CALL:	S1/NODE WE WANT TO CHECK
	;
	;RET:	S1/THE NODE NBR(-10), THE NODE NAME(-20)
	;	S2/THE ENTRY ADDRESS

N$CSTN:	PUSHJ	P,N$NODE		;FIND THE NODE
	SKIPN	NETRTE(S2)		;GET ITS ROUTING NODE
	$RETT				;NONE THERE,,RETURN
	MOVE	S1,NETRTE(S2)		;GET THE NODE ITS ROUTED TO.
	PUSHJ	P,N$NODE		;FIND IT.....
	$RETT				;AND RETURN
	SUBTTL	N$LOCL - ROUTINE TO VERIFY THAT A NODE NAME/NUMBER IS LOCAL

	;CALL:	S1/NODE NAME or NODE NUMBER
	;
	;RET:	TRUE if S1 contains a local node name or number
	;	FALSE if s1 is not local

N$LOCL:	CAME	S1,G$LNAM##		;IS IT THE LOCAL NODE NAME ???
	CAMN	S1,G$LNBR##		;OR IS IT THE LOCAL NODE NUMBER ???
	$RETT				;YES TO EITHER,,RETURN TRUE
	$RETF				;ELSE RETURN FALSE
	SUBTTL	N$MTCH - SEE IF 2 REMOTE STATION ID'S ARE EQUIVALENT

	;CALL:	S1/ First node name/number
	;	S2/ Second node name/number
	;
	;RET:	True if they match
	;	False otherwise

N$MTCH:	CAMN	S1,S2			;YOU NEVER KNOW,,WE MIGHT GET LUCKY !!
	$RETT				;THEY'RE EQUAL,,WE WIN BIG !!!
	PUSH	P,S2			;SAVE THIS NODE NAME FOR A MINUTE
	PUSHJ	P,N$NODE		;FIND THE FIRST NAME IN OUR DATA BASE
	POP	P,S1			;RESTORE SECOND NODE NAME TO S1
	CAME	S1,NETNAM(S2)		;S2 POINTS TO FIRST NAME'S DB ENTRY
	CAMN	S1,NETNBR(S2)		;DO WE MATCH EITHER THE NODE NAME
	$RETT				;OR THE NODE NUMBER .. IF SO WE WIN !!
	$RETF				;ELSE NO MATCH .
	SUBTTL	N$NONL / N$NOFF - IBM ONLINE/OFFLINE PROCESSING ROUTINES

	;CALL:	S1/ The Node DB Entry Address
	;	S2/ The Object Block Address
	;
	;RET:	True Always

N$NONL:	TDZA	TF,TF			;INDICATE 'ONLINE' ENTRY POINT
N$NOFF:	MOVEI	TF,1			;INDICATE 'OFFLINE' ENTRY POINT
	MOVE	S2,OBJTYP(S2)		;GET THE OBJECT TYPE
	CAXE	S2,.OTRDR		;IS IT THE CARD READER
	CAXN	S2,.OTBAT		;   OR IS IT THE EMULATION SPOOLER ???
	SKIPA				;YES,,CONTINUE
	$RETT				;NO,,RETURN NOW
	MOVE	S2,TF			;SAVE THE ENTRY POINT INDICATOR
	MOVX	TF,NETONL		;GET THE NODE ONLINE BIT
	JUMPN	S2,NOFF.1		;OFFLINE,,GO PROCESS IT

	;Here if we are Online

	TDNE	TF,NETSTS(S1)		;ARE WE ONLINE ALREADY ???
	$RETT				;YES,,JUST RETURN
	IORM	TF,NETSTS(S1)		;NO,,LITE THE NODE ONLINE BIT
	JRST	NOFF.2			;MEET AT THE PASS

	;Here if we are Offline

NOFF.1:	TDNN	TF,NETSTS(S1)		;ARE WE ALREADY OFFLINE ???
	$RETT				;YES,,JUST RETURN
	ANDCAM	TF,NETSTS(S1)		;NO,,CLEAR NODE ONLINE BIT

	;Here we tell the OPR whats happening and tell ORION also.

NOFF.2:	$WTO(< Network Node ^T/NETASC(S1)/ is ^T/@ONOFF(S2)/>,,,<$WTFLG(WT.SJI)>)
	LOAD	TF,NETSTS(S1),NT.MOD	;GET THE NODES MODE OF OPERATION
	CAXE	TF,DF.TRM		;IS IT TERMINATION ???
	$RETT				;NO,,JUST RETURN
	MOVE	TF,NETPTL(S1)		;YES,,GET THE NODES PORT,,LINE NUMBER
	MOVEM	TF,NWAMSG+.OFLAG	;SAVE IT IN THE MESSAGE
	MOVX	TF,%ONLINE		;DEFAULT TO NODE ONLINE
	SKIPN	S2			;UNLESS ITS OFFLINE
	MOVEM	TF,NWAMSG+.MSFLG	;ONLINE,,LITE THE NODE ONLINE BIT
	MOVE	TF,NETCOL(S1)		;GET THE NODES NAME/NUMBER
	MOVEM	TF,NWAMSG+.OHDRS+ARG.DA+OBJ.ND ;SAVE IT IN THE MESSAGE
	PUSHJ	P,SNDORN		;SEND THE MSG OFF TO ORION
	SETZM	NWAMSG+.MSFLG		;DONE,,CLEAR THE FLAG WORD
	SETZM	NWAMSG+.OFLAG		;   AND THIS ONE TOO
	$RETT				;RETURN
	SUBTTL	SNDORN - ROUTINE TO SEND A NODE WENT AWAY MSG OFF TO ORION


SNDORN:	$SAVE	AP			;SAVE AP ACROSS THE CALL
	MOVE	S1,G$OPR##		;GET ORION'S PID
	MOVEM	S1,MSGPDB+.IPCFR	;SAVE AS THE RECIEVERS PID
	MOVX	S1,.OTOPR		;GET THE OPR OBJECT TYPE
	STORE	S1,NWAMSG+.OHDRS+ARG.DA+OBJ.TY ;SAVE IT
	SETZM	NWAMSG+.OHDRS+ARG.DA+OBJ.UN ;ZAP ANY UNIT NUMBER
	MOVEI	AP,MSGPDB		;GET THE MESSAGE PDB ADDRESS
	PUSHJ	P,C$SEND##		;SEND IT OFF
	$RETT				;AND RETURN
	SUBTTL	GET.NETWORK.TOPOLOGY - ROUTINE TO GET THE NETWORK TOPOLOGY

	;CALL:	PUSHJ	P,GET.NETWORK.TOPOLOGY
	;
	;RET:	S1/SIXBIT NODE NAME
	;	S2/NODE NUMBER OR NODE NAME IF -20  
	;	T1/-1 IF ONLINE, 0 IF OFFLINE
	;	FALSE IF NO MORE NODES IN THE SYSTEM DATA BASE

GET.NETWORK.TOPOLOGY:

TOPS20 <
	SKIPE	S1,NETPAG		;HAVE WE READ THE TOPOLOGY YET ???
	JRST	GET.1			;YES,,GET NEXT AND RETURN
	PUSHJ	P,M%GPAG		;GET A PAGE FOR THE DATA
	MOVEM	S1,NETPAG		;SAVE THE PAGE ADDRESS
	MOVEI	S2,776			;GET THE BLOCK LENGTH
	MOVEM	S2,.NDNND(S1)		;SAVE IT IN THE DATA BLOCK
	MOVX	S1,.NDGNT		;GET NETWRK TOPOLOGY INFO FUNCTION
	MOVE	S2,NETPAG		;GET THE ARGUMENT BLOCK ADDRESS IN S2
	NODE				;GET THE NETWORK TOPOLOGY
	 ERJMP	GET.2			;NO GOOD,,RELEASE THE PAGE & RETURN
	MOVE	S1,NETPAG		;GET THE DATA ADDRESS
	HLRZ	S2,.NDNND(S1)		;GET THE NODE COUNT
	JUMPE	S2,GET.2		;NONE THERE,,RELEASE DATA PAGE & RETURN
	MOVEM	S2,.NDNND(S1)		;SAVE THE TOTAL COUNT 
	MOVEI	S2,.NDBK1-1(S1)		;POINT TO THE FIRST NODE BLK POINTER
	MOVEM	S2,NETADR		;SAVE THE ADDRESS FOR LATER

GET.1:	SOSGE	.NDNND(S1)		;SUBTRACT 1 FRON NODE COUNT
	JRST	GET.2			;IF NO MORE,,RELEASE THE DATA PAGE
	AOS	S2,NETADR		;POINT TO THE NEXT NODE BLK ADDRESS
	MOVE	S1,0(S2)		;GET THE POINTER TO THE NODE BLOCK
	MOVE	S1,.NDNAM(S1)		;GET THE BYTE PTR TO THE NODE NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVE	S1,S2			;GET THE NODE NAME IN S1
	$RETT				;RETURN

GET.2:	MOVE	S1,NETPAG		;GET THE DATA PAGE
	PUSHJ	P,M%RPAG		;RELEASE IT
	SETZM	NETPAG			;CLEAR THE DATA PAGE FLAG
	$RETF				;AND RETRUN
>  ;END TOPS20 CONDITIONAL
TOPS10 <
	SKIPE	S1,NETPAG		;HAVE WE READ THE TOPOLOGY YET ???
	JRST	GET.1			;YES,,GET NEXT AND RETURN
	PUSHJ	P,M%GPAG		;GET A PAGE FOR THE DATA
	MOVEM	S1,NETPAG		;SAVE THE PAGE ADDRESS
	MOVEM	S1,NETADR		;SAVE THE DATA ADDRESS
	MOVEI	S2,776			;GET THE DATA BLOCK LENGTH
	MOVEM	S2,0(S1)		;SAVE THE NODE. PARAMETER
	HRLI	S1,12			;GET THE NODE. TOPOLOGY FUNCTION
	NODE.	S1,			;GET THE NETWORK TOPOLOGY
	 JRST	GET.4			;CANT DO IT,,NO NETWORK HERE
	MOVEM	S1,@NETPAG		;SAVE THE NODE COUNT
	MOVE	S1,NETPAG		;GET THE NODE. BLOCK ADDRESS

GET.1:	SOSGE	0(S1)			;COUNT DOWN THE NODE COUNT
	JRST	GET.4			;NO MORE,,FINISH UP AND RETURN
	AOS	S2,NETADR		;BUMP DATA ARG COUNT BY 1
	MOVE	S2,0(S2)		;GET A NODE NUMBER
	LOAD	AP,HDRNET##+.QHLNK,QH.PTF ;POINT TO THE FIRST NETWORK ENTRY
	SKIPA				;SKIP THE FIRST TIME THROUGH

GET.2:	LOAD	AP,.QELNK(AP),QE.PTN	;GET THE NEXT NETWORK ENTRY
	JUMPE	AP,GET.3		;NOT THERE,,GET THE NAME
	CAME	S2,NETNBR(AP)		;HAVE WE FOUND IT ???
	JRST	GET.2			;NO,,TRY NEXT ENTRY
	MOVE	S1,NETNAM(AP)		;GET THE NODE NAME
	MOVE	AP,NETSTS(AP)		;GET THE NETWORK STATUS
	TXNE	AP,NETONL		;WAS IT ALREADY ONLINE ???
	$RETT				;YES,,JUST RETURN

GET.3:	MOVEI	S1,2			;BLOCK LENGTH OF 2
	MOVE	TF,[2,,1]		;GET PARAMETER LIST (WANT NODE NAME)
	NODE. 	TF,			;GET THE NODE NAME (GIVEN NODE NBR)
	 MOVE	TF,S2			;SHOULD NOT HAPPEN !!!
	MOVE	S1,TF			;GET THE NODE NAME IN S1
	$RETT				;AND RETURN

GET.4:	MOVE	S1,NETPAG		;GET THE DATA PAGE ADDRESS
	PUSHJ	P,M%RPAG		;RELEASE THE PAGE
	SETZM	NETPAG			;CLEAR THE DATA PAGE FLAG
	$RETF				;AND RETURN
>  ;END TOPS10 CONDITIONAL
	SUBTTL	FINDNODE - ROUTINE TO FIND A NODE IN OUR DATA BASE

	;CALL:	S1/ The Sixbit Node Name 
	;	S2/ The Node Number
	;
	;RET:	AP/ The DB Entry Address

FINDNOD: DMOVE	P1,S1			;SAVE THE NODE NAME AND NUMBER
	LOAD	AP,HDRNET##+.QHLNK,QH.PTF ;GET THE FIRST ENTRY IN THE NODE DB
	SKIPA				;SKIP THE FIRST TIME THROUGH
FIND.1:	LOAD	AP,.QELNK(AP),QE.PTN	;GET THE NEXT ENTRY IN THE DATA BASE
	JUMPE	AP,FIND.4		;NOT FOUND,,ADD IT
	CAME	P1,NETNAM(AP)		;DO THE NAMES MATCH ???
	CAMN	P2,NETNBR(AP)		;OR THE NUMBERS ???
	SKIPA				;YES,,CONTINUE
	JRST	FIND.1			;NO,,GO CHECK THE NEXT ENTRY
	MOVEM	P1,NETNAM(AP)		;SAVE THE NAME
	MOVEM	P2,NETNBR(AP)		;SAVE THE NUMBER
	PUSH	P,AP			;SAVE AP FOR A MINUTE

FIND.2:	LOAD	AP,.QELNK(AP),QE.PTN	;GET THE NEXT ENTRY ADDRESS
	JUMPE	AP,FIND.3		;NO MORE,,JUST RETURN
	CAME	P1,NETNAM(AP)		;DO THE NAMES MATCH ???
	CAMN	P2,NETNBR(AP)		;OR THE NUMBERS ???
	SKIPA				;YES,,DELETE THE DUPLICATE ENTRY
	JRST	FIND.2			;NO,,GO CHECK THE NEXT ENTRY
	PUSHJ	P,M$DLNK##		;DE-LINK THIS ENTRY
FIND.3:	POP	P,AP			;RESTORE THE OLD ENTRY ADDRESS
	$RETT				;AND RETURN

FIND.4:	PUSHJ	P,M$GFRE##		;GET A FREE CELL FOR THE ENTRY
	MOVEM	P1,NETNAM(AP)		;SAVE THE NODE NAME
	MOVEM	P2,NETNBR(AP)		;SAVE THE NODE NUMBER
	MOVX	S1,NETADD		;GET THE ADDED BITS
	MOVEM	S1,NETSTS(AP)		;SET IT (AVOID THE OBJ QUEUE SEARCH)
	PUSHJ	P,M$ELNK##		;LINK IT IN
	$RETT				;AND RETURN
	SUBTTL	PURGE.DUP.OBJS - ROUTINE TO PURGE DUPLICATE OBJECTS

	;This routine is called because it is possible to start the same
	;device at the same node using both the node name and node number.
	;This works only if the node is offline, since QUASAR cannot
	;validate the Node. For example, if an operator said:
	;Start Pr 0/Node:MUMBLE and Start Pr 0/Node:10 and node MUMBLE
	;and node 10 are the same node, then you have a problem when
	;the node comes online. This routine is called when a node comes
	;online and it schedules a shutdown for the duplicate node.

	;CALL:	AP/ Node DB Address of Node which came online
	;
	;RET:	True Always

PURGE.D: LOAD	T1,HDROBJ##+.QHLNK,QH.PTF ;GET THE FIRST OBJECT ADDRESS
	SKIPA				;SKIP THE FIRST TIME THROUGH
PURG.1:	LOAD	T1,.QELNK(T1),QE.PTN	;GET THE NEXT OBJECT ENTRY ADDRESS
	JUMPE	T1,.RETT		;DONE,,COMPLETE NODE ONLINE PROCESSING
	MOVE	S1,OBJNOD(T1)		;GET THE OBJECTS NODE NAME/NUMBER
	CAME	S1,NETNAM(AP)		;LETS SEE IF WE MATCH
	CAMN	S1,NETNBR(AP)		;MUST TRY BOTH VALUES
	SKIPA				;YES,,CONTINUE ON
	JRST	PURG.1			;NO,,TRY NEXT OBJECT
	MOVE	S1,NETCOL(AP)		;SYSTEM'IZE THE NODE FIELD
	MOVEM	S1,OBJNOD(T1)		;   OF THE OBJECT BLOCK
	MOVX	S1,OBSIGN		;GET THE IGNORE BIT
	ANDCAM	S1,OBJSCH(T1)		;CLEAR IT UNCONDITIONALLY
	MOVE	T2,T1			;GET THE OBJECT ADDRESS

	;HAVING FOUND 1 OBJECT STARTED FOR THIS NODE,,ARE THERE ANY MORE ???

PURG.2:	LOAD	T2,.QELNK(T2),QE.PTN	;POINT TO THE NEXT OBJECT ENTRY
	JUMPE	T2,PURG.1		;NO MORE,,CONTINUE ON
	MOVE	S1,OBJNOD(T2)		;GET THIS OBJECTS NAME/NUMBER
	CAME	S1,NETNAM(AP)		;DO WE MATCH BY NAME
	CAMN	S1,NETNBR(AP)		;OR BY NUMBER ???
	SKIPA				;YES,,CHECK REST OF BLOCK
	JRST	PURG.2			;NO,,GO CHECK THE NEXT OBJECT BLOCK

	;WE FOUND ANOTHER OBJECT STARTED FOR THIS NODE,,ARE THEY FOR 
	;THE SAME DEVICE ??? IF SO, THATS A NO-NO

	MOVE	S1,OBJTYP(T1)		;GET THE FIRST OBJ'S TYPE
	CAME	S1,OBJTYP(T2)		;DO WE MATCH ???
	JRST	PURG.2			;NO,,WE'RE OK SO FAR
	MOVE	S1,OBJUNI(T1)		;GET THE FIRST OBJ'S UNIT
	CAME	S1,OBJUNI(T2)		;DO WE MATCH ???
	JRST	PURG.2			;NO,,THATS OK TOO !!!
	MOVE	S1,T2			;GET THE DUPLICATES ADDRESS
	PUSH	P,AP			;SAVE THE NODE ENTRY ADDRESS
	PUSHJ	P,S$SHUT##		;GO SHUT IT DOWN
	POP	P,AP			;RESTORE NODE ENTRY ADDRESS
	$RETT				;CANT HAVE MORE THEN 2 DUPLICATE OBJECTS
					;SO JUST RETURN NOW !!!
	END