Google
 

Trailing-Edge - PDP-10 Archives - BB-P363B-SM_1985 - mcb/nml/nmunet.b16
There are no other files named nmunet.b16 in the archive.
! <BRANDT.DEVELOPMENT>NMUNET.B16.1 21-Oct-82 14:39:37, Edit by BRANDT
!
!   Ident 09.
!     Rework code in ASSIGN_A_LUN to compress code size.
!
! <BRANDT.DEVELOPMENT>NMUNET.B16.1 21-Oct-82 9:00:17, Edit by BRANDT
!
!   Ident 08.
!     In NMU$NETWORK_OPEN, for source_links having no node name, convert
!     the node number to an ASCII string and use that for the name.
!     Remove code from ident 5.
!     And finally some simple code compression so we can task build.
!
! <BRANDT.DEVELOPMENT>NMUNET.B16.1 14-Sep-82 14:22:34, Edit by BRANDT
!
!   Ident 07.
!     In NMU$NETWORK_OPEN set the error detail field of a response
!     message for RSX error codes other than IE$NRJ.  Thus "rejected
!     by object" will no longer be a catch all error.
!
! <BRANDT.DEVELOPMENT>NMUNET.B16.1 9-Sep-82 17:00:17, Edit by BRANDT
!
!   Ident 06.
!     Change FAIL_TYPE mappings for reject codes 0 and 5.
!
! <BRANDT.DEVELOPMENT>NMUNET.B16.1 9-Sep-82 15:30:17, Edit by BRANDT
!
!   Ident 05.
!     In NMU$NETWORK_OPEN make a check for source_links to verify that
!     a node name is supplied.
!
!NET:<PECKHAM.DEVELOPMENT>NMUNET.B16.3 25-Jun-82 19:39:37, Edit by PECKHAM
!
! Ident 04.
! Add global symbols UN$USER, UN$PASSWORD, UN$ACCOUNT for access control
! (they are filled in by NMLEVT with data from NMX).
! In NMU$NETWORK_VALIDATE, check the connect accounting data
! against the strings supplied in the above.
!
!NET:<PECKHAM.DEVELOPMENT>NMUNET.B16.3 23-Mar-82 08:25:40, Edit by PECKHAM
!
! Ident 03.
! Make response pointers optional in NMU$NETWORK_OPEN.
!
!NET:<PECKHAM.DEVELOPMENT>NMUNET.B16.3  3-Mar-82 08:37:38, Edit by PECKHAM
!
! Ident 02.
! Revise to accomodate fix in SCX X1(42).
! After receiving NT$DSC/ABO/ABT, insure that an ABO is done.
!
!NET:<PECKHAM.DEVELOPMENT>NMUNET.B16.2 23-Jan-82 20:47:26, Edit by PECKHAM
!
! Ident 01.
! Fix call to NMU$SCHED_WAIT to include timeout value.
!
module NMUNET (					! Task to task network communications
		ident = 'X01.09'
		) =
begin
!
!                    COPYRIGHT (c) 1980, 1981, 1982
!                    DIGITAL EQUIPMENT CORPORATION
!                        Maynard, Massachusetts
!
!     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.
!

!++
! Facility: LSG DECnet Network Management
!
! Abstract: This module provides a "generic" interface to DECnet
!	    task to task communications.
!
!	    As perceived by  the user of  these interfaces, there  are
!	    two types of link ends: TARGET and SOURCE.  A TARGET  task
!	    (sometimes known as  a SERVER) waits  for another task  to
!	    issue a connect to it.  A SOURCE task issues a connect  to
!	    the task it  wishes to communicate  with.  Thus the  major
!	    difference  between  the  ends  of  a  link  is  the  link
!	    connection operation.
!
! Environment: TOPS10/TOPS20 user mode, MCB RSX task level
!
! Author: Scott G. Robinson, Creation Date: 26-JAN-81
!
!	From NMUNET.B36 by Steven M. Jenness
!
! Modified by:
!
! 02 - Fix Maximum Logical Links and Error Detail on Server Rejects
! 03 - Install Limit Protection code on ch$copy and ch$moves
! 04 - Remove Synchronization Race Condition on LSB_CONNECTED
! 05 - Ensure no conflicts on simultaneous Transmits and Receives
! 06 - Prevent Queue Interlocks from deadlocking non-Interrupt processing
! 07 - Conform to Node_ID format in CONN_BLK
! 08 - Support Assignment of DLX Luns
! 09 - Have NETWORK_OPEN build a response message on error.
! 10 - Add a response code -2 to NETWORK_OPEN, to mean "don't retry".
!
!--

!<BLF/SYNONYM $FIELD=FIELD>
!<BLF/SYNONYM %unquote =>
!<BLF/PAGE>
!
! Include files
!

library 'NMULIB';				! All required definitions

!
! Global routines
!

forward routine
    NMU$NETWORK_UTILITIES;			! Define global entry points

!
! Local routines
!

forward routine
    DECLARE_NETWORK_EVENT : novalue,		! Declare a Network Event
    GND_AST : VANILLA_INTERRUPT_LINKAGE,	! Network Mailbox Interrupt Service
    PROCESS_MAILBOX_ENTRY : novalue,		! Process a Mailbox Entry
    IQ_SCAN,					! Scanning routine for info queue
    ASSIGN_A_LUN;				! Assign a LUN for Network Usage

!
! Global Items
!

global literal 					!These are used in the NML
    LUN$NM = NMU$_NM_DEVICE_LUN,
    EFN$NM = NMU$_NM_DEVICE_FLAG,
    LUN$NS = NMU$_NETWORK_LUN,
    EFN$NS = NMU$_NETWORK_FLAG;

!
! Own variables
!

literal
    NODE_ID_LENGTH = 9;

bind
    FAIL_TYPE = uplit

!	Failure code			Reject/object code
!	------------			------------------

	(      10,			!       0
		4,			!       1
		2,			!       2
	       11,			!       3
		7,			!       4
		6,			!       5
		9,			!       6
	       12,			!       7
	       15,			!       8
	       14,			!       9
    rep 22 of (15),			!   10-31
		4,			!      32
		9,			!      33
		8,			!      34
	       15,			!      35
		8,			!      36
	       15,			!      37
	       10,			!      38
		3,			!      39
	       15,			!      40
	       15,			!      41
	       15,			!      42
		8): vector;		!      43

bind
    RETRY_CODE = uplit

!	Return code			Reject/object code
!	-----------			------------------

	(	-2,			!	0
		-1,			!	1
		-2,			!	2
		-2,			!	3
		-2,			!	4
		-2,			!	5
		-1,			!	6
		-2,			!	7
		-1,			!	8
		-2,			!	9
    rep 22 of (-2),			!   10-31
		-1,			!      32
		-1,			!      33
		-2,			!      34
		-2,			!      35
		-2,			!      36
		-2,			!      37
		-1,			!      38
		-2,			!      39
		-2,			!      40
		-2,			!      41
		-2,			!      42
		-2): vector;		!      43
own
    LOCAL_NODE : block [ch$allocation (NODE_ID_LENGTH, 8)],	! Local node id
    NEXT_LINK_ID,				! Link identification sequence
    INFO_QUEUE : Q_HEADER,			! Queue of all link info blocks
    NETWORK_LUNS : VECTOR [NMU$_NETWORK_MAX_LUNS];	! LUN Assignment Vector

global
    UN$USER : block [ch$allocation (1 + 16, 8)],
    UN$PASSWORD : block [ch$allocation (1 + 8, 8)],
    UN$ACCOUNT : block [ch$allocation (1 + 16, 8)];

!
! Structures
!
! 	All contained in NMUNTS
!
! Local Macros
!

macro
    WAIT_FOR_NETWORK (LNKINFO, WHILE_COND) =
	begin

	bind
	    LNKSTS = LNKINFO[LINK_STATUS] : LINK_STATUS_BLOCK;

	while (WHILE_COND) do
	    NMU$SCHED_WAIT(LNKINFO[LINK_EVENT], 0)
	end %;

!
! External routines
!

external routine
    NMU$QUEUE_MANAGER,				! Queue management routines
    NMU$MEMORY_MANAGER,				! Memory management routines
    NMU$SCHED_MANAGER;				! Scheduler interface
global routine %unquote NMU$NETWORK_INITIALIZE : novalue =

!++
! Functional description:
!
!	This routine initializes the network system interface.
!
! Formal parameters: none
!
! Routine value: none
! Side effects:
!
!	The local node id is retrieved for NMU$NETWORK_LOCAL.
!
!--

    begin

    own
	NETWORK_STATUS : $NETWORK_STATUS_BLOCK,
	OPN_DIR : OPNW$ (NMU$_NETWORK_LUN, NMU$_NETWORK_FLAG, NETWORK_STATUS,, <NMU$_NETWORK_MAX_LUNS>),
	GLN_DIR : GLNW$ (NMU$_NETWORK_LUN, NMU$_NETWORK_FLAG, NETWORK_STATUS,,
		<LOCAL_NODE, NODE_ID_LENGTH, 1>);

!
! Interrupt Service Routine for SPA$ Initialization
!
    routine SPA_AST NETWORK_INTERRUPT_ROUTINE =
	begin

	map
	    NETWORK_STATUS_BLOCK : ref $NETWORK_STATUS_BLOCK;

	bind
	    NUMBER_OF_ENTRIES = NETWORK_STATUS_BLOCK [NETSB$IO_COUNT];

!
! See if we were successful and if so process a few entries
! from the mailbox.
!

	if .NETWORK_STATUS_BLOCK [NETSB$ERR] eql IS$SUC
	then

	    until .NUMBER_OF_ENTRIES eql 0 do
		begin
		PROCESS_MAILBOX_ENTRY ();
		NUMBER_OF_ENTRIES = .NUMBER_OF_ENTRIES - 1;
		end;

!
	end;					!of SPA_AST
!
! Reset Network queues
!
    NMU$QUEUE_RESET (INFO_QUEUE);
!
! Reset Internal Link IDs
!
    NEXT_LINK_ID = 1;
!
! Assign the network LUNS and make them available for assignment
!

    INCR LUN_NUMBER from NMU$_NETWORK_LUN to NMU$_NETWORK_LUN + NMU$_NETWORK_MAX_LUNS do
	begin
	ALUN$S (.LUN_NUMBER, %ASCII'NS', 0);
	NETWORK_LUNS [.LUN_NUMBER - NMU$_NETWORK_LUN] = 0;
	end;

!
! Assign the NM: device to its' LUN
!
    ALUN$S (NMU$_NM_DEVICE_LUN, %ASCII'NM', 0);
!
! Assign the NM: DLX device to its' LUNS
!
    ALUN$S (NMU$_DL0_DEVICE_LUN, %ASCII'NM', 0);
    ALUN$S (NMU$_DL1_DEVICE_LUN, %ASCII'NM', 0);
!
! Identify us to the network
!
    dir$ (OPN_DIR);
!
! We are now known to the network; Get local node information and
! construct local node information.
!
    dir$ (GLN_DIR);
!
! Startup Mailbox Interrupt Service
!
    SPA$S (NMU$_NETWORK_LUN,, NETWORK_STATUS, SPA_AST, <GND_AST>);
!
    end;					! End of NMU$NETWORK_INITIALIZE
global routine %unquote NMU$NETWORK_OPEN (TYPE, CONN_BLK, RESPONSE_PTR,
			  RESPONSE_LEN, RESPONSE_CODE) =

!++
! Functional description:
!
!	This routine opens a logical link.  It blocks the running
!	task until a successful connect is made or the link connection
!	is aborted for some explicit reason.
!
!	TARGET_LINK:	When this routine returns it will have filled
!			in the connect block fields: OPTIONAL_DATA,
!			USER, ACCOUNT and PASSWORD.  The link must
!			still be accepted or rejected.
!
!	SOURCE_LINK:	When this routine returns it will have filled
!			in the connect block fields: OPTIONAL_DATA,
!			REJECT_REASON.
!
! Formal parameters:
!
!	.TYPE	   	Link type to open (SOURCE_LINK, TARGET_LINK).
!	.CONN_BLK  	Address of a link connect block.
!	.RESPONSE_PTR	Pointer to a response buffer
!			if 0, no response is built.
!	.RESPONSE_LEN	Address of a value which on input contains the
!			maximum length of the response buffer, and on
!			output contains the actual length (if any).
!	.RESPONSE_CODE	NICE error code to put into response message
!			(usually LCF or MCF).
!
! Routine value:
!
!	gtr 0	Link id to be used in all future link references.
!	lss 0	DECnet link failure indication.
!
! Side effects: none
!
!--

    begin

    map
	CONN_BLK : ref CONNECT_BLOCK;

    local
	LINK_INFO : ref LINK_INFO_BLOCK,
	TEMP_PTR;

!
! The interrupt service routine for SOURCE_LINK connects.
!
    routine CON_AST NETWORK_INTERRUPT_ROUTINE =
	begin

	map
	    NETWORK_STATUS_BLOCK : ref $NETWORK_STATUS_BLOCK;

	local
	    LINK_INFO : ref LINK_INFO_BLOCK;

!
! Find our LINK_INFO block
!

	if (LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .NETWORK_STATUS_BLOCK [NETSB$LINK_ID], IQ_SCAN)) neq 0
	then
!
! Update status to reflect connect complete
!
	    begin

	    bind
		LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

	    if .NETWORK_STATUS_BLOCK [NETSB$ERR] eql IS$SUC
	    then
		begin
		LNKSTS [LSB_CONNECTED] = 1;
		LNKSTS [LSB_CLOSED] = 0;
		end;

	    LNKSTS [LSB_CCWAIT] = 0;
!
! Startup waiting process
!
	    DECLARE_NETWORK_EVENT (.LINK_INFO);
	    end;

	end;					! of CON_AST
!
! Main OPEN Processing
!
    LINK_INFO = NMU$MEMORY_GET (LINK_INFO_BLOCK_ALLOCATION);
    LINK_INFO [LINK_ID] = (NEXT_LINK_ID = .NEXT_LINK_ID + 1);

    if .NEXT_LINK_ID lss 0 then NEXT_LINK_ID = 1;

    NMU$SCHED_EVENT (LINK_INFO [LINK_EVENT], $true);
    LINK_INFO [LINK_TYPE] = .TYPE;
!
! All LINK_INFO_BLOCKs go into the INFO_QUEUE.
!
    NMU$QUEUE_INSERT (INFO_QUEUE, LINK_INFO [LINK_QUEUE]);
    begin

    bind
	LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK,
	CONB = LINK_INFO [LINK_CONB] : RSX$_CONB_BLOCK,
	GNDB = LINK_INFO [LINK_GNDB] : RSX$_GNDB_BLOCK,
	LNKSB = LINK_INFO [LINK_LINK_SB] : $NETWORK_STATUS_BLOCK,
	INSB = LINK_INFO [LINK_IN_SB] : $NETWORK_STATUS_BLOCK,
	OUTSB = LINK_INFO [LINK_OUT_SB] : $NETWORK_STATUS_BLOCK;

!
! Setup other LINK_IDs for AST Routines
!
    LNKSB [NETSB$LINK_ID] = .LINK_INFO [LINK_ID];
    INSB [NETSB$LINK_ID] = .LINK_INFO [LINK_ID];
    OUTSB [NETSB$LINK_ID] = .LINK_INFO [LINK_ID];
!
! Format appropriate blocks for SOURCE and TARGET Links.
!
    LNKSTS [LSB_CONNECTED] = 0;

    if .TYPE eql TARGET_LINK
    then
	begin					! TARGET_LINK Open
!
! Construct GNDB from CONN_BLK information. The GNDB is used to
! match incoming connects in PROCESS_MAILBOX_ENTRY.
!
	GNDB [GNDB_DEST_OBJECT] = .CONN_BLK [CB_OBJECT];
	GNDB [GNDB_DEST_FORMAT] = 0;		!Format 0 Descriptor

	if .CONN_BLK [CB_DESCRIPTOR_LENGTH] GTR 0
	then
	    begin				!Format 1 Descriptor
	    GNDB [GNDB_DEST_FORMAT] = 1;
	    GNDB [GNDB_D1_LENGTH] = .CONN_BLK [CB_DESCRIPTOR_LENGTH];
	    ch$move (.CONN_BLK [CB_DESCRIPTOR_LENGTH], .CONN_BLK [CB_DESCRIPTOR],
		ch$ptr (GNDB [GNDB_D1_TASK_NAME]));
	    end;

!
! Flag we are waiting for a connect and that we are a server.
! We then wait for the incoming connect to happen.
!
	LNKSTS [LSB_SERVER] = 1;
	LNKSTS [LSB_CIWAIT] = 1;
	LNKSTS [LSB_CCWAIT] = 0;
	end
    else
	begin					! SOURCE Open
	ch$copy (minu (ch$rchar (ch$plus (.CONN_BLK [CB_HOST], 2)), 6), ch$plus (.CONN_BLK [CB_HOST], 3),
	    %C' ', 6, ch$ptr (CONB [CONB_NODE_NAME]));
	if (ch$rchar (ch$plus (.CONN_BLK [CB_HOST], 2)) eql 0)
	then					! If no node name,
	    begin				!  use node number as name
            linkage CBDSG = JSR (register=0,register=1,register=2;
                                 register=0) : nopreserve (1,2);
            external routine $CBDSG : CBDSG novalue;
	    local TEMP_PTR;

	    TEMP_PTR = .CONN_BLK [CB_HOST];	! Pointer to node number
            $CBDSG (CONB [CONB_NODE_NAME],	! ASCII output to here
		    GETW(TEMP_PTR),		! Value to convert
                    0;				! Zero suppress
		    TEMP_PTR);			! For updated pointer
            end;
	CONB [CONB_FORMAT] = 0;
	CONB [CONB_OBJECT] = .CONN_BLK [CB_OBJECT];

	if .CONN_BLK [CB_DESCRIPTOR_LENGTH] gtr 0
	then
	    begin				!Descriptor Format 1
	    CONB [CONB_FORMAT] = 1;
	    CONB [CONB_1_LENGTH] = .CONN_BLK [CB_DESCRIPTOR_LENGTH];
	    ch$move (.CONB [CONB_1_LENGTH], .CONN_BLK [CB_DESCRIPTOR], ch$ptr (CONB [CONB_1_TASK_NAME]));
	    end;

	CONB [CONB_USER_LENGTH] = .CONN_BLK [CB_USERID_LENGTH];
	ch$move (.CONB [CONB_USER_LENGTH], .CONN_BLK [CB_USERID], ch$ptr (CONB [CONB_USER_ID]));
	CONB [CONB_PASSWORD_LENGTH] = .CONN_BLK [CB_PASSWORD_LENGTH];
	ch$move (.CONB [CONB_PASSWORD_LENGTH], .CONN_BLK [CB_PASSWORD], ch$ptr (CONB [CONB_PASSWORD]));
	CONB [CONB_ACCOUNT_LENGTH] = .CONN_BLK [CB_ACCOUNT_LENGTH];
	ch$move (.CONB [CONB_ACCOUNT_LENGTH], .CONN_BLK [CB_ACCOUNT], ch$ptr (CONB [CONB_ACCOUNT]));

	if ASSIGN_A_LUN (.LINK_INFO) lss 0
	then
	    return $false
	else
	    begin
	    LNKSTS [LSB_CCWAIT] = 1;
	    LNKSTS [LSB_CIWAIT] = 0;
	    LNKSTS [LSB_SERVER] = 0;
	    TEMP_PTR = .CONN_BLK [CB_DATA];
	    CONN_BLK [CB_DATA] = ch$ptr (CONN_BLK [CB_DATA_BUFFER]);
	    CON$S (.LINK_INFO [LINK_LUN],, LINK_INFO [LINK_LINK_SB], CON_AST,
		<LINK_INFO [LINK_CONB],
		    RSX$_CONB_ALLOCATION, (if .CONN_BLK [CB_DATA_LENGTH] eql 0 then 0 else .TEMP_PTR),
		    .CONN_BLK [CB_DATA_LENGTH], .CONN_BLK [CB_DATA], 16>);
	    end;

	end;

!
! Wait for the link to become valid or an error is detected
!
    WAIT_FOR_NETWORK (LINK_INFO, (.LNKSTS [LSB_CIWAIT] or .LNKSTS [LSB_CCWAIT]));
!
! We have had some activity on the logical link which has removed us from
! waiting.
!
    begin

    bind
	NETSTS = LINK_INFO [LINK_LINK_SB] : $NETWORK_STATUS_BLOCK;

    if .NETSTS [NETSB$ERR] eql IS$SUC
    then
	begin
	CONN_BLK [CB_DATA_LENGTH] = .NETSTS [NETSB$CNT]; !SOURCE_LINK
	if .LINK_INFO [LINK_TYPE] eql TARGET_LINK
	then
	    begin				!TARGET_LINK Processing

	    bind
		LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK,
		GNDB = LINK_INFO [LINK_GNDB] : RSX$_GNDB_BLOCK;

	    local
		TEMP_PTR,
		TEMP_PTR1,
		TEMP_LEN;

	    LNKSTS [LSB_CCWAIT] = 1;
	    CONN_BLK [CB_HOST] = ch$ptr (CONN_BLK [CB_HOST_BUFFER]);
	    TEMP_PTR1 = .CONN_BLK [CB_HOST];
	    PUTB (0, TEMP_PTR1);
	    PUTB (0, TEMP_PTR1);
	    TEMP_PTR = ch$find_ch (6, ch$ptr (GNDB [GNDB_SOURCE_NODE_NAME]), %c' ');
	    TEMP_LEN = (if ch$fail (.TEMP_PTR) then 6 else ch$diff (.TEMP_PTR,
		    ch$ptr (GNDB [GNDB_SOURCE_NODE_NAME])));
	    CONN_BLK [CB_HOST_LENGTH] = minu (.TEMP_LEN, 6) + 3;
	    PUTB (.TEMP_LEN, TEMP_PTR1);
	    ch$copy (minu (.TEMP_LEN, 6), ch$ptr (GNDB [GNDB_SOURCE_NODE_NAME]), 0, 6, .TEMP_PTR1);
	    CONN_BLK [CB_TASK] = ch$ptr (CONN_BLK [CB_TASK_BUFFER]);

	    case .GNDB [GNDB_SOURCE_FORMAT] from 0 to 2 of
		set

		[0] : 				!Format 0 Descriptor
		    begin
		    CONN_BLK [CB_TASK_LENGTH] = 0;
		    end;

		[1] : 				!Format 1 Descriptor
		    begin
		    CONN_BLK [CB_TASK_LENGTH] = .GNDB [GNDB_S1_LENGTH];
		    ch$copy (minu (.GNDB [GNDB_S1_LENGTH], 16), ch$ptr (GNDB [GNDB_S1_TASK_NAME]), 0, 17,
			.CONN_BLK [CB_TASK]);
		    end;

		[2] : 				!Format 2 Descriptor
		    begin
		    CONN_BLK [CB_TASK_LENGTH] = .GNDB [GNDB_S2_LENGTH];
		    ch$copy (minu (.GNDB [GNDB_S2_LENGTH], 16), ch$ptr (GNDB [GNDB_S2_TASK_NAME]), 0, 17,
			.CONN_BLK [CB_TASK]);
		    end;
		tes;

	    CONN_BLK [CB_USERID] = ch$ptr (CONN_BLK [CB_USERID_BUFFER]);
	    CONN_BLK [CB_USERID_LENGTH] = .GNDB [GNDB_SOURCE_TASK_LENGTH];
	    ch$copy (minu (.GNDB [GNDB_SOURCE_TASK_LENGTH], 16), ch$ptr (GNDB [GNDB_SOURCE_TASK_ID]), 0, 17,
		.CONN_BLK [CB_USERID]);
	    CONN_BLK [CB_PASSWORD] = ch$ptr (CONN_BLK [CB_PASSWORD_BUFFER]);
	    CONN_BLK [CB_PASSWORD_LENGTH] = .GNDB [GNDB_SOURCE_PASSWORD_LENGTH];
	    ch$copy (minu (.GNDB [GNDB_SOURCE_PASSWORD_LENGTH], 8), ch$ptr (GNDB [GNDB_SOURCE_PASSWORD]), 0,
		9, .CONN_BLK [CB_PASSWORD]);
	    CONN_BLK [CB_ACCOUNT] = ch$ptr (CONN_BLK [CB_ACCOUNT_BUFFER]);
	    CONN_BLK [CB_ACCOUNT_LENGTH] = .GNDB [GNDB_SOURCE_ACCOUNT_LENGTH];
	    ch$copy (minu (.GNDB [GNDB_SOURCE_ACCOUNT_LENGTH], 16), ch$ptr (GNDB [GNDB_SOURCE_ACCOUNT]), 0,
		17, .CONN_BLK [CB_ACCOUNT]);
	    CONN_BLK [CB_DATA] = ch$ptr (CONN_BLK [CB_DATA_BUFFER]);
	    CONN_BLK [CB_DATA_LENGTH] = .GNDB [GNDB_OPTIONAL_LENGTH];
	    ch$copy (minu (.GNDB [GNDB_OPTIONAL_LENGTH], 16), ch$ptr (GNDB [GNDB_OPTIONAL_DATA]), 0, 17,
		.CONN_BLK [CB_DATA]);
	    end;

	.LINK_INFO [LINK_ID]
	end
    else
	begin					!Link Connect Unsuccessful
!
! Source links can still return optional data so ensure count is correct.
!

	CONN_BLK [CB_REJECT_CODE] = 0;
	if .LINK_INFO [LINK_TYPE] eql SOURCE_LINK
	then
	    begin
	    CONN_BLK [CB_DATA_LENGTH] = .NETSTS [NETSB$CNT];
	    if .NETSTS [NETSB$ERR] eql IE$NRJ
	    then
		begin
		CONN_BLK [CB_REJECT_CODE] = .NETSTS [NETSB$CNT];
		CONN_BLK [CB_DATA_LENGTH] = 0;
		end
	    end;

!
!	Build a response message
!

	if .RESPONSE_PTR neq 0
	then
	    .RESPONSE_LEN = $RESPONSE (.RESPONSE_PTR, .RESPONSE_CODE,
		(selectone .NETSTS [NETSB$ERR] of  ! Error detail
		     set
		     [IE$ABO]:	15;	! Abort by management
		     [IE$URJ]:	5;	! Rejected by object
		     [IE$BAD]:	8;	! Access Control Rejected
		     [IE$SPC,
		      IE$RSU]:	4;	! Network resources
		     [IE$NNT]:	3;	! Node unreachable
		     [IS$DAO]:	9;	! Object too busy
		     [IE$NRJ]:	.FAIL_TYPE [.CONN_BLK[CB_REJECT_CODE]];
		     [otherwise]: 10;	! No response from object
		     tes));

!
!	Return LINK_INFO Resources
!
	NETWORK_LUNS [.LINK_INFO [LINK_LUN] - NMU$_NETWORK_LUN] = 0;
	NMU$QUEUE_EXTRACT (INFO_QUEUE, .LINK_INFO);
	NMU$MEMORY_RELEASE (.LINK_INFO, LINK_INFO_BLOCK_ALLOCATION);
	-1
	end

    end
    end
    end;					! End of NMU$NETWORK_OPEN
global routine %unquote NMU$NETWORK_ACCEPT (LINK_IDENTIFIER, DATA_LEN, DATA_PTR) =

!++
! Functional description:
!
!	This routine accepts the connection to a TARGET link
!	end.  The link was initially opened by a call to the
!	NMU$NETWORK_TARGET routine.
!
! Formal parameters: none
!
!	.LINK_IDENTIFIER    Link id for the target link end.
!	.DATA_LEN	    Length of optional accept data
!	.DATA_PTR	    Pointer to optional accept data
!
! Routine value:
!
!	$true - Accept Done
!	$false - Accept Not Done
!
! Side effects: none
!
!--

    begin

    local
	LINK_INFO : ref LINK_INFO_BLOCK;

!
! Routine to process ACC$ ASTs
!
    routine ACC_AST NETWORK_INTERRUPT_ROUTINE =
	begin

	map
	    NETWORK_STATUS_BLOCK : ref $NETWORK_STATUS_BLOCK;

	local
	    LINK_INFO : ref LINK_INFO_BLOCK;

!
! Find our LINK_INFO block
!

	if (LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .NETWORK_STATUS_BLOCK [NETSB$LINK_ID], IQ_SCAN)) neq 0
	then
!
! Update status to reflect connect complete
!
	    begin

	    bind
		LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

	    if .NETWORK_STATUS_BLOCK [NETSB$ERR] eql IS$SUC
	    then
		begin
		LNKSTS [LSB_CONNECTED] = 1;
		LNKSTS [LSB_CLOSED] = 0;
		end;

	    LNKSTS [LSB_CCWAIT] = 0;
!
! Startup waiting process
!
	    DECLARE_NETWORK_EVENT (.LINK_INFO);
	    end;

	end;					! of ACC_AST
!
! Main Accept Processing
!

    if (INTERRUPT_OFF; LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .LINK_IDENTIFIER, IQ_SCAN); INTERRUPT_ON;
	.LINK_INFO) neq 0
    then
	begin

	bind
	    LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK,
	    NETSTS = LINK_INFO [LINK_LINK_SB] : $NETWORK_STATUS_BLOCK;

	ACC$S (.LINK_INFO [LINK_LUN],, LINK_INFO [LINK_LINK_SB], ACC_AST,
	    <LINK_INFO [LINK_GNDB],
		RSX$_GNDB_ALLOCATION, (if .DATA_LEN eql 0 then 0 else .DATA_PTR), .DATA_LEN>);
	WAIT_FOR_NETWORK (LINK_INFO, (.LNKSTS [LSB_CCWAIT]));

	if (.LNKSTS [LSB_CONNECTED])
	then
	    $true
	else
	    begin

	    if .NETSTS [NETSB$ERR] neq IS$SUC then NMU$NETWORK_REJECT (.LINK_IDENTIFIER, 0, 0);

	    $false
	    end

	end
    else
	$false
!
    end;					! End of NMU$NETWORK_ACCEPT
global routine %unquote NMU$NETWORK_REJECT (LINK_IDENTIFIER, REASON, DATA_LEN, DATA_PTR) =

!++
! Functional description:
!
!	This routine rejects the connection to a TARGET link
!	end.  The link was initially opened by a call to the
!	NMU$NETWORK_TARGET routine.
!
! Formal parameters: none
!
!	.LINK_IDENTIFIER    Link id for the target link end.
!	.REASON		    Reason code for rejection
!	.DATA_LEN	    Length of optional reject data
!	.DATA_PTR	    Pointer to optional reject data
!
! Routine value:
!
!	$true - Reject Done
!	$false - Reject Not Done
!
! Side effects: none
!
!--

    begin

    local
	LINK_INFO : ref LINK_INFO_BLOCK;

!
! Routine to process REJ$ ASTs
!
    routine REJ_AST NETWORK_INTERRUPT_ROUTINE =
	begin

	map
	    NETWORK_STATUS_BLOCK : ref $NETWORK_STATUS_BLOCK;

	local
	    LINK_INFO : ref LINK_INFO_BLOCK;

!
! Find our LINK_INFO block
!

	if (LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .NETWORK_STATUS_BLOCK [NETSB$LINK_ID], IQ_SCAN)) neq 0
	then
!
! Update status to reflect connect complete
!
	    begin

	    bind
		LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

	    LNKSTS [LSB_CLOSED] = 1;
	    LNKSTS [LSB_CONNECTED] = 0;
	    LNKSTS [LSB_CCWAIT] = 0;
!
! Startup waiting process
!
	    DECLARE_NETWORK_EVENT (.LINK_INFO);
	    end;

	end;					! of REJ_AST
!
! Main Reject Processing
!

    if (INTERRUPT_OFF; LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .LINK_IDENTIFIER, IQ_SCAN); INTERRUPT_ON;
	.LINK_INFO) neq 0
    then
	begin
	REJ$S (NMU$_NETWORK_LUN,, LINK_INFO [LINK_LINK_SB], REJ_AST,
	    <LINK_INFO [LINK_GNDB],
		RSX$_GNDB_ALLOCATION, (if .DATA_LEN eql 0 then 0 else .DATA_PTR), .DATA_LEN>);
	WAIT_FOR_NETWORK (LINK_INFO, (.LNKSTS [LSB_CCWAIT]));
	$true
	end
    else
	$false
!
    end;					! End of NMU$NETWORK_REJECT
global routine %unquote NMU$NETWORK_READ (LINK_IDENTIFIER, BUFFER_SIZE, BUFFER) =

!++
! Functional description:
!
!	This routine reads data from the specified logical link into
!	the supplied buffer.  This calls blocks until either data is
!	available or the link is disco<<nnected.
!
! Formal parameters:
!
!	.LINK_IDENTIFIER Link identifier.
!	.BUFFER		Address of buffer to read data into.
!	.BUFFER_SIZE	Number of 8 bit bytes available in buffer.
!
! Routine value:
!
!	Number of bytes read in (0 = link error)
!
! Side effects: none
!
!--

    begin

    local
	LINK_INFO : ref LINK_INFO_BLOCK;

!
! Interrupt Service Routine for Receives
!
    routine REC_AST NETWORK_INTERRUPT_ROUTINE =
	begin

	map
	    NETWORK_STATUS_BLOCK : ref $NETWORK_STATUS_BLOCK;

	local
	    LINK_INFO : ref LINK_INFO_BLOCK;

!
! Find our LINK_INFO block
!

	if (LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .NETWORK_STATUS_BLOCK [NETSB$LINK_ID], IQ_SCAN)) neq 0
	then
!
! Update status to reflect receive complete
!
	    begin
	    LINK_INFO [LINK_INPUT_IN_PROGRESS] = 0;
!
! Startup waiting process
!
	    DECLARE_NETWORK_EVENT (.LINK_INFO);
	    end;

	end;					! of REC_AST
!
! Main Receive Processing
!

    if (INTERRUPT_OFF; LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .LINK_IDENTIFIER, IQ_SCAN); INTERRUPT_ON;
	.LINK_INFO) neq 0
    then
	begin

	bind
	    LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

	if not .LNKSTS [LSB_CONNECTED]
	then
	    0
	else
	    begin
	    LINK_INFO [LINK_INPUT_IN_PROGRESS] = 1;
	    REC$S (.LINK_INFO [LINK_LUN],, LINK_INFO [LINK_IN_SB], REC_AST, <.BUFFER, .BUFFER_SIZE>);
!
! Wait for data buffer to be received
!
	    WAIT_FOR_NETWORK (LINK_INFO, (.LINK_INFO [LINK_INPUT_IN_PROGRESS]));
!
! Return Error Indication if any
!
	    begin

	    bind
		LNKIOSB = LINK_INFO [LINK_IN_SB] : $NETWORK_STATUS_BLOCK;

	    if .LNKIOSB [NETSB$ERR] neq IS$SUC then 0 else .LNKIOSB [NETSB$IO_COUNT]

	    end
	    end

	end
    else
	0

    end;					! End of NMU$NETWORK_READ
global routine %unquote NMU$NETWORK_WRITE (LINK_IDENTIFIER, EOM_FLAG, BUFFER_SIZE, BUFFER) =

!++
! Functional description:
!
!	This routine writes data to the specified logical link from
!	the supplied buffer.
!
! Formal parameters:
!
!	.LINK_IDENTIFIER Link identifier.
!	.EOM_FLAG	Flag to indicate end of message.
!	.BUFFER		Address of buffer to write data from.
!	.BUFFER_SIZE	Number of 8 bit bytes of data in buffer.
!
! Routine value:
!
!	$true	Write succeeded
!	$false	Write failed, link disconnected.
!
! Side effects: none
!
!--

    begin

    local
	LINK_INFO : ref LINK_INFO_BLOCK;

!
! Interrupt Service Routine for Transmits
!
    routine SND_AST NETWORK_INTERRUPT_ROUTINE =
	begin

	map
	    NETWORK_STATUS_BLOCK : ref $NETWORK_STATUS_BLOCK;

	local
	    LINK_INFO : ref LINK_INFO_BLOCK;

!
! Find our LINK_INFO block
!

	if (LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .NETWORK_STATUS_BLOCK [NETSB$LINK_ID], IQ_SCAN)) neq 0
	then
!
! Update status to reflect transmit complete
!
	    begin
	    LINK_INFO [LINK_OUTPUT_IN_PROGRESS] = 0;
!
! Startup waiting process
!
	    DECLARE_NETWORK_EVENT (.LINK_INFO);
	    end;

	end;					! of SND_AST
!
! Main Send Processing
!

    if (INTERRUPT_OFF; LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .LINK_IDENTIFIER, IQ_SCAN); INTERRUPT_ON;
	.LINK_INFO) neq 0
    then
	begin

	bind
	    LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

	if not .LNKSTS [LSB_CONNECTED]
	then
	    $false
	else
	    begin

	    if not .EOM_FLAG
	    then
		return $false
	    else
		begin

		bind
		    NETSTS = LINK_INFO [LINK_OUT_SB] : $NETWORK_STATUS_BLOCK;

		LINK_INFO [LINK_OUTPUT_IN_PROGRESS] = 1;
		SND$S (.LINK_INFO [LINK_LUN],, LINK_INFO [LINK_OUT_SB], SND_AST, <.BUFFER, .BUFFER_SIZE>);
!
! Wait for data buffer to be transmitted
!
		WAIT_FOR_NETWORK (LINK_INFO, (.LINK_INFO [LINK_OUTPUT_IN_PROGRESS]));

		if .NETSTS [NETSB$ERR] neq IS$SUC then $false else $true

		end

	    end

	end
    else
	$false

    end;					! End of NMU$NETWORK_WRITE
global routine %unquote NMU$NETWORK_ABORT (LINK_IDENTIFIER, REASON, DATA_LEN, DATA_PTR) =

!++
! Functional description:
!
!
! Formal parameters:
!
!	.LINK_IDENTIFIER    Identifier of link to abort
!	.REASON		    Reason code to aborting link
!	.DATA_LEN	    Length of optional abort data
!	.DATA_PTR	    Pointer to optional abort data
!
! Routine value:
!
!	$true - Abort has been done
!	$false - Abort could not be done
!
! Side effects: none
!
!--

    begin

    local
	LINK_INFO : ref LINK_INFO_BLOCK;

!
! Interrupt Service Routine for Aborts
!
    routine ABT_AST NETWORK_INTERRUPT_ROUTINE =
	begin

	map
	    NETWORK_STATUS_BLOCK : ref $NETWORK_STATUS_BLOCK;

	local
	    LINK_INFO : ref LINK_INFO_BLOCK;

!
! Find our LINK_INFO block
!

	if (LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .NETWORK_STATUS_BLOCK [NETSB$LINK_ID], IQ_SCAN)) neq 0
	then
!
! Update status to reflect disconnect complete
!
	    begin

	    bind
		LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

	    LNKSTS [LSB_ABORTED] = 1;
	    LNKSTS [LSB_CLOSED] = 1;
	    LNKSTS [LSB_CCWAIT] = 0;
	    LNKSTS [LSB_CIWAIT] = 0;
	    LNKSTS [LSB_CONNECTED] = 0;
!
! Startup waiting process
!
	    DECLARE_NETWORK_EVENT (.LINK_INFO);
	    end;

	end;					! of ABT_AST
!
! Main Processing for Aborts
!

    if (INTERRUPT_OFF; LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .LINK_IDENTIFIER, IQ_SCAN); INTERRUPT_ON;
	.LINK_INFO) neq 0
    then
	begin

	bind
	    LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

	if not .LNKSTS [LSB_CLOSED]
	then
	    begin
	    ABT$S (.LINK_INFO [LINK_LUN],, LINK_INFO [LINK_LINK_SB], ABT_AST,
		<(if .DATA_LEN eql 0 then 0 else .DATA_PTR), .DATA_LEN>);
	    WAIT_FOR_NETWORK (LINK_INFO, ( not .LNKSTS [LSB_ABORTED]));
	    end;

	NETWORK_LUNS [.LINK_INFO [LINK_LUN] - NMU$_NETWORK_LUN] = 0;
	NMU$QUEUE_EXTRACT (INFO_QUEUE, .LINK_INFO);
	NMU$MEMORY_RELEASE (.LINK_INFO, LINK_INFO_BLOCK_ALLOCATION);
	$true
	end
    else
	$false

    end;					! End of NMU$NETWORK_ABORT
global routine %unquote NMU$NETWORK_CLOSE (LINK_IDENTIFIER, DATA_LEN, DATA_PTR) =

!++
! Functional description:
!
!
! Formal parameters:
!
!	.LINK_IDENTIFIER    Identifier of link to close
!	.DATA_LEN	    Length of optional close data
!	.DATA_PTR	    Pointer to optional close data
!
! Routine value:
!
!	$true - Close Completed
!	$false - Close could not be done
!
! Side effects: none
!
!--

    begin

    local
	LINK_INFO : ref LINK_INFO_BLOCK;

!
! Interrupt Service Routine for Disconnects
!
    routine DSC_AST NETWORK_INTERRUPT_ROUTINE =
	begin

	map
	    NETWORK_STATUS_BLOCK : ref $NETWORK_STATUS_BLOCK;

	local
	    LINK_INFO : ref LINK_INFO_BLOCK;

!
! Find our LINK_INFO block
!

	if (LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .NETWORK_STATUS_BLOCK [NETSB$LINK_ID], IQ_SCAN)) neq 0
	then
!
! Update status to reflect disconnect complete
!
	    begin

	    bind
		LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

	    LNKSTS [LSB_CLOSED] = 1;
	    LNKSTS [LSB_CCWAIT] = 0;
	    LNKSTS [LSB_CIWAIT] = 0;
	    LNKSTS [LSB_CONNECTED] = 0;
!
! Startup waiting process
!
	    DECLARE_NETWORK_EVENT (.LINK_INFO);
	    end;

	end;					! of DSC_AST
!
! Main Processing for Disconnects
!

    if (INTERRUPT_OFF; LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .LINK_IDENTIFIER, IQ_SCAN); INTERRUPT_ON;
	.LINK_INFO) neq 0
    then
	begin

	bind
	    LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

	if not .LNKSTS [LSB_CLOSED]
	then
	    begin
	    DSC$S (.LINK_INFO [LINK_LUN],, LINK_INFO [LINK_LINK_SB], DSC_AST,
		<(if .DATA_LEN eql 0 then 0 else .DATA_PTR), .DATA_LEN>);
	    WAIT_FOR_NETWORK (LINK_INFO, ( not .LNKSTS [LSB_CLOSED]));
	    end;

	NETWORK_LUNS [.LINK_INFO [LINK_LUN] - NMU$_NETWORK_LUN] = 0;
	NMU$QUEUE_EXTRACT (INFO_QUEUE, .LINK_INFO);
	NMU$MEMORY_RELEASE (.LINK_INFO, LINK_INFO_BLOCK_ALLOCATION);
	$true
	end
    else
	$false

    end;					! End of NMU$NETWORK_CLOSE
global routine %unquote NMU$NETWORK_STATUS (LINK_IDENTIFIER, STS_BLK) =

!++
! Functional description:
!
!	This routine supplies the status of a logical link.
!
! Formal parameters:
!
!	.LINK_IDENTIFIER   Link identifier.
!	.STS_BLK	   Address of status block.
!
! Routine value:
!
!	$true - Link Status Available
!	$false - Link Status Unavailable
!
! Side effects: none
!
!--

    begin

    local
	LINK_INFO : ref LINK_INFO_BLOCK;

    if (INTERRUPT_OFF; LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .LINK_IDENTIFIER, IQ_SCAN); INTERRUPT_ON;
	.LINK_INFO) neq 0
    then
	begin

	bind
	    LNKSTS = LINK_INFO [LINK_STATUS] : vector [1];

	.STS_BLK = .LNKSTS [0];
	$true
	end
    else
	$false

    end;					! End of NMU$NETWORK_STATUS
global routine %unquote NMU$NETWORK_VALIDATE (CONN_BLK) =

!++
! Functional description:
!
!
! Formal parameters:
!
!	.CONN_BLK  	Address of a link connect block.
!
! Routine value:
!
!	 0 - Unprivledged user
!	 1 - Privledged user
!
! Side effects: none
!
!--

    begin

    map
	CONN_BLK : ref CONNECT_BLOCK;

    local
	CNT,
	PTR;

    PTR = ch$ptr (UN$USER,, 8);

    if (CNT = ch$rchar_a (PTR)) neq 0
    then
	begin

	if .CONN_BLK [CB_USERID_LENGTH] neq .CNT then return 0;

	if ch$neq (.CNT, .CONN_BLK [CB_USERID], .CNT, .PTR, 0) then return 0;

	end;

    PTR = ch$ptr (UN$PASSWORD,, 8);

    if (CNT = ch$rchar_a (PTR)) neq 0
    then
	begin

	if .CONN_BLK [CB_PASSWORD_LENGTH] neq .CNT then return 0;

	if ch$neq (.CNT, .CONN_BLK [CB_PASSWORD], .CNT, .PTR, 0) then return 0;

	end;

    PTR = ch$ptr (UN$ACCOUNT,, 8);

    if (CNT = ch$rchar_a (PTR)) neq 0
    then
	begin

	if .CONN_BLK [CB_ACCOUNT_LENGTH] neq .CNT then return 0;

	if ch$neq (.CNT, .CONN_BLK [CB_ACCOUNT], .CNT, .PTR, 0) then return 0;

	end;

    1
    end;					! End of NMU$NETWORK_VALIDATE
global routine %unquote NMU$NETWORK_LOCAL =

!++
! Functional description:
!
!	This routine returns a pointer to the local node
!	name string.
!
! Formal parameters: none
!
! Routine value:
!
!	Byte pointer to node name string.
!
! Side effects: none
!
!--

    begin
    ch$ptr (LOCAL_NODE,, 8)
    end;					! End of NMU$NETWORK_LOCAL

!<BLF/PAGE>
routine DECLARE_NETWORK_EVENT (LINK_INFO) : novalue =

!++
! Functional description:
!
!	This routine flags a network event and wakes up the scheduler.
!
! Formal parameters:
!
!	.LINK_INFO is the LINK_INFO_BLOCK for this event
!
! Routine value: none
!
! Side effects: none
!
!--

    begin

    map
	LINK_INFO : ref LINK_INFO_BLOCK;

    NMU$SCHED_FLAG (LINK_INFO [LINK_EVENT]);
    PROCESS_WAKE;
    end;					! of DECLARE_NETWORK_EVENT
!<BLF/PAGE>
!++
!	routine GND_AST VANILLA_INTERRUPT_ROUTINE
!	routine PROCESS_MAILBOX_ENTRY
!
! Functional description:
!
!	These routines process various asynchronous network events signaled
!	via the "Network Mailbox".
!	GND_AST is entered when asynchronous events are available.
!	PROCESS_MAILBOX_ENTRY is the main processing code for the events.
!
! Formal parameters:
!
!     $RSX_AST_PARAMETERS - Not Touched
!
! Routine value: none
!
! Side effects: none
!
!--
routine GND_AST VANILLA_INTERRUPT_ROUTINE =
    begin
    PROCESS_MAILBOX_ENTRY ();
    end;					!of GND_AST
routine PROCESS_MAILBOX_ENTRY : novalue =

!++
! Functional description:
!
!
! Formal parameters:
!
!
! Routine value: none
!
! Side effects: none
!
!--

    begin

    own
	GND_SB : $NETWORK_STATUS_BLOCK,
	REJ_BUF : vector [3, byte] initial (byte (-21, 9, 0)),
	GND_BUF : RSX$_GNDB_BLOCK,
	GND_DIR : GNDW$ (NMU$_NETWORK_LUN, NMU$_NETWORK_FLAG, GND_SB,, <GND_BUF, RSX$_GNDB_ALLOCATION>),
	REJ_DIR : REJW$ (NMU$_NETWORK_LUN, NMU$_NETWORK_FLAG, GND_SB,,
		<GND_BUF, RSX$_GNDB_ALLOCATION,
		    REJ_BUF, 3>);

    local
	LINK_INFO : ref LINK_INFO_BLOCK;

!
! Routine to find Target Links which match connections
!
    routine TQ_SCAN (LINK_INFO, CURRENT_GNDB) =
	begin

	map
	    CURRENT_GNDB : ref RSX$_GNDB_BLOCK,
	    LINK_INFO : ref LINK_INFO_BLOCK;

	bind
	    GNDB = LINK_INFO [LINK_GNDB] : RSX$_GNDB_BLOCK,
	    LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

!
! Ensure this link is a waiting target.
!

	if (.LNKSTS [LSB_SERVER] and .LNKSTS [LSB_CIWAIT])
	then
!
! Compare objects and determine matching characteristics
!

	    case .GNDB [GNDB_DEST_FORMAT] from 0 to 2 of
		set

		[0] : 				! Format 0 Descriptor
		    begin

		    if .CURRENT_GNDB [GNDB_DEST_FORMAT] neq 0 then return 0;

		    if .CURRENT_GNDB [GNDB_DEST_OBJECT] eql .GNDB [GNDB_DEST_OBJECT]
		    then
			return .LINK_INFO
		    else
			return 0;

		    end;

		[1] : 				! Format 1 Descriptor
		    begin

		    if .CURRENT_GNDB [GNDB_DEST_FORMAT] neq 1 then return 0;

		    if .CURRENT_GNDB [GNDB_DEST_OBJECT] neq .GNDB [GNDB_DEST_OBJECT] then return 0;

		    if ch$eql (.CURRENT_GNDB [GNDB_D1_LENGTH], ch$ptr (CURRENT_GNDB [GNDB_D1_TASK_NAME]),
			    .GNDB [GNDB_D1_LENGTH], ch$ptr (GNDB [GNDB_D1_TASK_NAME]), 0)
		    then
			return .LINK_INFO
		    else
			return 0;

		    end;

		[2] : 				! Format 2 Descriptor
		    return 0;
		tes

	else
	    0

	end;					! of TQ_SCAN
!
! Routine to find LINK_INFO block via LUN
!
    routine IQ_LUN_SCAN (LINK_INFO, LUN) =
	begin

	map
	    LINK_INFO : ref LINK_INFO_BLOCK;

	if .LINK_INFO [LINK_LUN] eql .LUN then .LINK_INFO else 0

	end;					! of IQ_LUN_SCAN
!
! Main processing of Mailbox Entries
! Get the mailbox entry
!
    dir$ (GND_DIR);

    if .GND_SB [NETSB$ERR] neq IS$SUC then return;

!
! Classify request into Connects, Disconnects, and Interrupt Messages. Then
! process accordingly.
!

    case .GND_SB [NETSB$ERR1] from NT$CON to NT$ABO of
	set

	[NT$CON] : 				!Connect Received
	    begin

	    if (LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, GND_BUF, TQ_SCAN)) eql 0
	    then
		begin				! No waiting TARGET found, Reject Connection
		dir$ (REJ_DIR);
		end
	    else
		begin				! We have a waiting TARGET

		if ASSIGN_A_LUN (.LINK_INFO) lss 0
		then
		    dir$ (REJ_DIR)
		else
		    begin

		    bind
			LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK,
			NETSTS = LINK_INFO [LINK_LINK_SB] : $NETWORK_STATUS_BLOCK;

		    NETSTS [NETSB$ERROR] = IS$SUC;
		    ch$copy (minu (.GND_SB [NETSB$CNT], RSX$_GNDB_ALLOCATION), ch$ptr (GND_BUF), 0,
			RSX$_GNDB_ALLOCATION, ch$ptr (LINK_INFO [LINK_GNDB]));
		    LNKSTS [LSB_CIWAIT] = 0;
		    DECLARE_NETWORK_EVENT (.LINK_INFO);
		    end;

		end;

	    end;

	[NT$INT] : 				!Interrupt Message Received
	    return;				!Ignore for now

	[NT$DSC, NT$ABT] : 			!Disconnect or Abort Received
	    begin

	    if (LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .GND_SB [NETSB$CNT1], IQ_LUN_SCAN)) eql 0
	    then
		return
	    else
		begin

		bind
		    LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

		LINK_INFO [LINK_OPTI_LENGTH] = .GND_SB [NETSB$CNT];
		ch$copy (minu (.GND_SB [NETSB$CNT], 16), ch$ptr (GND_BUF), 0, 16,
		    ch$ptr (LINK_INFO [LINK_OPTI_DATA]));
		LNKSTS [LSB_CONNECTED] = 0;
		DECLARE_NETWORK_EVENT (.LINK_INFO);
		end;

	    end;

	[NT$ABO] :
	    begin

	    if (LINK_INFO = NMU$QUEUE_SCAN (INFO_QUEUE, .GND_SB [NETSB$CNT1], IQ_LUN_SCAN)) eql 0
	    then
		return
	    else
		begin

		bind
		    LNKSTS = LINK_INFO [LINK_STATUS] : LINK_STATUS_BLOCK;

		LNKSTS [LSB_REASON] = .GND_SB [NETSB$CNT];
		LINK_INFO [LINK_OPTI_LENGTH] = 0;
		LNKSTS [LSB_CONNECTED] = 0;
		DECLARE_NETWORK_EVENT (.LINK_INFO);
		end;

	    end;

	[INRANGE, OUTRANGE] : 			!Erroneous code
	    return;
	tes;

!
    end;					! of PROCESS_MAILBOX_ENTRY
routine IQ_SCAN (LINK_INFO, LINK_IDENTIFIER) =

!++
! Functional description:
!
!	This routine is called when scanning the INFO_QUEUE by
!	NMU$QUEUE_SCAN to find the entry associated with a
!	particular link identifier.
!
! Formal parameters:
!
!	.LINK_INFO	  address of current entry on the info queue.
!	.LINK_IDENTIFIER  identifier of link to find data base for.
!
! Routine value:
!
!	Address of link info block if matched (0 otherwise).
!
! Side effects: none
!
!--

    begin

    map
	LINK_INFO : ref LINK_INFO_BLOCK;

    if .LINK_INFO [LINK_ID] eql .LINK_IDENTIFIER then .LINK_INFO else 0

    end;					! End of IQ_SCAN
routine ASSIGN_A_LUN (LINK_INFO) =

!++
! Functional description:
!
!	This routine assigns a LUN for usage by a link. It assigns the
!	LUN based upon the TYPE or LINK (e.g. SOURCE_LINK or TARGET_LINK).
!
! Formal parameters:
!
!	LINK_INFO = LINK_INFO_BLOCK for this link
!
! Routine value:
!
!	gtr 0 - the LUN number assigned
!	lss 0 - No LUN available
!
! Side effects:
!
!	*******Warning*******
!	SOURCE_LINK LUNs are assigned at non-interrupt level
!	TARGET_LINK LUNs are assigned at interrupt level
!
!--

    begin

    map
	LINK_INFO : ref LINK_INFO_BLOCK;

    local
	LUN_ADR : ref vector,
	LUN_CNT,
	LUN_NUMBER;

!
! Determine search algorithm based upon type
!

    LUN_NUMBER = NMU$_NETWORK_LUN + 1;
    LUN_CNT = NMU$_NETWORK_MAX_INCOMING;
    LUN_ADR = NETWORK_LUNS [1];

    if .LINK_INFO [LINK_TYPE] eql SOURCE_LINK
    then
	begin
        LUN_NUMBER = NMU$_NETWORK_LUN + NMU$_NETWORK_MAX_INCOMING + 1;
        LUN_CNT = NMU$_NETWORK_MAX_LUNS - NMU$_NETWORK_MAX_INCOMING;
        LUN_ADR = NETWORK_LUNS [NMU$_NETWORK_MAX_INCOMING + 1];
        end;

    do
        begin

        if
            begin
            local VAL;
            VAL = .LUN_ADR [0];
            LUN_ADR = LUN_ADR [1];  %(force auto-increment)%
            .VAL
            end eql 0
        then
            begin
            LUN_ADR = LUN_ADR [-1];  %(force auto-decrement)%
            LUN_ADR [0] = .LINK_INFO;
            LINK_INFO [LINK_LUN] = .LUN_NUMBER;
            LINK_INFO [LINK_FLAG] = .LUN_NUMBER;
            return .LUN_NUMBER;
            end;

	LUN_NUMBER = .LUN_NUMBER + 1;
	end
    while (LUN_CNT = .LUN_CNT - 1) neq 0;

    LUN_NUMBER = -1;
    return .LUN_NUMBER
    end;					! of ASSIGN_A_LUN
end						! End of module NMUNET

eludom
! Local Modes:
! Mode:Fundamental
! Comment Start:!
! Comment Column:40
! Comment Rounding:+1
! Auto Save Mode:2
! End: