Google
 

Trailing-Edge - PDP-10 Archives - TOPS-20_V6.1_DECnetSrc_7-23-85 - mcb/nmx/nmx.bli
There is 1 other file named nmx.bli in the archive. Click here to see a list.
module NMX (					! Network Management External Interface
            ident = 'X01270'
            ) =
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: MCB Network Management
!
! ABSTRACT:
!
!     NMX supplies an interface between the Network Management Layer
!     process running as an RSX task and the MCB processes supplying
!     NM interfaces.
!
! ENVIRONMENT: MCB V3.x
!
! AUTHOR: Scott G. Robinson	CREATION DATE: 9-SEP-80
!
! MODIFIED BY:
!
! 01 - Modifications to NMXCKT, NMXLIN, NMXMOD for Error Handling
! 02 - Fix RETURN Functions to use MTBF$S correctly
! 03 - Add ERROR_CODE support in Control-Complete Processing
! 04 - Update NMX for MCB V3.1 fixes
! 05 - Update NMXxxx for MCB V3.2 and setup for NMXINI Initialization
! 06 - Continue edit 05 for MCB V3.2
! 07 - Update NMXxxx for new N$Sxxx, N$Fxxx, N$Ixxx nomenclature
!      Fix RETURN_DSR functions to new formats
! 10 - Add routine to NMXINI to allow interrogation of Entity Data
!      bases. Add different buffer checking routines.
! 11 - Fix CLEAR ALL processing in NMXNOD, NMXCKT, NMXLIN, NMXMOD
! 12 - Add routine $NMGID to NMXINI for data base interrogation
! 13 - Fix returned buffer length bug in NMXxxx show functions
! 14 - Fix various calls and things in NMXINI and NMXUTL
! 15 - Fix missing conditional in NMXLIN
! 16 - Add Event Logging Support
! 17 - Add Direct Line Access Support
! 18 - Add Receive Timeout Code for Direct Line Access
!       Alan D. Peckham, 11-Jan-82
! 19 - Add support for returning completion time into time block
!      supplied in parameter #6
!       Alan D. Peckham, 14-Apr-82
! 20 - Complete rework of NM support.
!      Code compressed and NME process eliminated.
! 21 - Fix buffer length bug in NMXEVE.
! 22 - Fix unrecognized component bug in NMXCCE.
! 23 - Disallow SERVICE state in NMXCCE.
! 24 - Fix DSR return bug in NMXDLE.
!      Check string lengths in NMXINE.
!      Range check entity type in NMX$MAP_ENTITY_ID_TO_DB.
! 25 - Change protocol for events in NMXEVE.
!      Maintain EVENTS_PROCESSED in NMXEVE.
!      Add NMLMCB access control support in NMXEVE.
! 26 - Add code in TIMPIN to get the EXECUTOR ADDRESS/NAME from high core.
! 27 - Fix for system specific parameter in NMXCCE.
!--

!
! INCLUDE FILES:
!

library 'XPORTX';

library 'MCBLIB';

library 'NMXPAR';

library 'NMXLIB';

require 'DLXPAR';

!
! TABLE OF CONTENTS:
!

linkage
    NMX_LKG_NAM = jsr (register = 0);

forward routine
    QIODSP : RSX_UCB_SCB_IOP novalue,   ! QIO Function Dispatch
    QIONOP : RSX_UCB novalue,           ! Driver Function No operation
    DLXNM : MCB_DB_CCB novalue,         ! FM_NM processor
    DSPTIM : MCB_DB_MOD novalue,        ! FC_TIM processor
    DSPCCP : MCB_DB_CCB_MOD novalue,    ! FC_CCP dispatcher
    BADCCB : MCB_DB_CCB_MOD novalue,    ! Invalid CCB Parameters
    TIMLTM : MCB_DB novalue,            ! FM_LTM Long timer processor
    TIMPIN : MCB_DB novalue,            ! FM_PIN Process initialization
    GET_PIX : NMX_LKG_NAM,              ! Get process index
    NMX$GET_NMX_CCB : NMX$LKG_DB_IOP,   ! Convert IOP to CCB for NMX
    NMX$MAP_ENTITY_ID_TO_DB : NMX$LKG_TYP_ENT,
    NMX$MAP_NMXID_TO_DB : NMX$LKG_NMXID,
    NMX$RETURN_NMX_CCB : NMX$LKG_CCB novalue;   ! Return NMX CCB/NMPAR

!
! RSX Related Items for NMX
!

global bind
    $NMTBL =                        ! RSX Driver Dispatch Table
	uplit (QIODSP,              !     I/O Initiator Dispatcher
              QIONOP,               !     I/O Cancellation
              QIONOP,               !     I/O Timeout
              QIONOP);              !     Power Failure Notification

!

external
    $HEADR : ref block field (HDR_FIELDS),	! Current Task Header
    $TTNS : vector;				! RSX Uptime Vector

!
! NMX related items
!

external routine
    BADREQ : MCB_DB_CCB novalue,        ! IE_BAD parameter processor
    CKTCCP : MCB_DB_CCB novalue,        ! Process FC.CCP for CIRCUIT Entities
    CKTREQ : MCB_DB_CCB novalue,        ! Process IOP for CIRCUIT Entities
    DLXAST : MCB_DB_CCB_MOD novalue,    ! Process FC.AST for all items
    DLXCCP : MCB_DB_CCB novalue,        ! Process FC.CCP for DLX functions
    DLXCON : NMX$LKG_UCB_IOP novalue,   ! Process IOP Connect
    DLXCTL : MCB_DB_CCB_MOD novalue,    ! Process FC.CTL for DLX functions
    DLXDSC : NMX$LKG_UCB_IOP novalue,   ! Process IOP Disconnect
    DLXRCP : MCB_DB_CCB_MOD novalue,    ! Process FC.RCP for all items
    DLXRCV : NMX$LKG_UCB_IOP novalue,   ! Process IOP Receive
    DLXXCP : MCB_DB_CCB_MOD novalue,    ! Process FC.XCP for all items
    DLXXMT : NMX$LKG_UCB_IOP novalue,   ! Process IOP Transmit
    EVPRLB : NMX$LKG_UCB_IOP novalue,   ! Process Read Event Queue
    EVPWAT : MCB_DB_CCB novalue,        ! Process Event Filter Setup
    LINCCP : MCB_DB_CCB novalue,        ! Process FC.CCP for LINE Entities
    LINREQ : MCB_DB_CCB novalue,        ! Process IOP for LINE Entities
    MODCCP : MCB_DB_CCB novalue,        ! Process FC.CCP for MODULE Entities
    MODREQ : MCB_DB_CCB novalue,        ! Process IOP for MODULE Entities
    NODCCP : MCB_DB_CCB novalue,        ! Process FC.CCP for NODE Entities
    NODREQ : MCB_DB_CCB novalue;        ! Process IOP for NODE Entities

!
! MCB Process Header and related items for NMX
!

external routine
    $DSPCR : novalue;				! Invalid function crash routine in CEX

!
$MCB_PROCESS (					! Define the NMX MCB Process
    NAME = NMX,
    LLC_DISPATCH = TABLE$ ($DSPCR, FC_CCP, (FC_AST, DLXAST), 	! Asynchronous Events
	(FC_TIM, DSPTIM), 			! Time Interval Complete/Process init
	(FC_CTL, DLXCTL), 			! Control Enable
	(FC_XCP, DLXXCP), 			! Transmit Complete
	(FC_RCP, DLXRCP), 			! Receive Complete
	(FC_CCP, DSPCCP)), 			! Control Complete
    RSX_DISPATCH = $NMTBL);
!

external
    MCB$GAW_PROCESS_DATA_BASE : vector [2];
routine QIODSP (UCB, SCB, IOP) : RSX_UCB_SCB_IOP novalue = 	!QIO Function Processor

!++
! FUNCTIONAL DESCRIPTION:
!
!      QIODSP processes the receipt of an I/O Packet from RSX. It handles the
!      validation and processing of IO$xxx functions from the NM: device.
!
! FORMAL PARAMETERS:
!
!	UCB - the Unit Control Block for NM:
!       SCB - the Status Control Block for NM:
!       IOP - the I/O Packet
!
! IMPLICIT INPUTS:
!
!	UCB, SCB, IOP contents
!       NMX Process Data Base Items
!
! IMPLICIT OUTPUTS:
!
!	IOP - could be immediately completed via $IOFIN
!
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!
!       IOP completion could be delayed until MCB processing is complete.
!
!--

    begin

    map
	IOP : ref NMX_IOP_BLOCK,
	UCB : ref block field (UCB_FIELDS),
	SCB : ref block field (SCB_FIELDS);

!
! Reformat IOP into internal format, this is essentially a specially
! setup RSX Transfer Function IOP.
!

    begin

    macro
        IOP_MOVE (FLD_S, FLD_D) =
            %if %fieldexpand (FLD_S, 0) gtr %fieldexpand (FLD_D, 0)
            %then %warn ('Overlap exists: reorder the fields to move')
            %else
                %if %fieldexpand (FLD_S, 0) lss %fieldexpand (FLD_D, 0)
                %then IOP [FLD_D] = .IOP [FLD_S]
                %fi
            %fi %;

    IOP_MOVE (I_PRM6, I_NMX_TIME);
    IOP_MOVE (I_PRM5, I_NMX_QUALIFIER);
    IOP_MOVE (I_PRM4, I_NMX_ENTITY);
    IOP_MOVE (I_PRM3, I_NMX_TYPE);
    IOP_MOVE (I_PRM2, I_NMX_CNT);

    if .IOP [I_PRM2] eql 0
    then
	begin					! Count = 0 so ignore user buffer
	IOP [I_NMX_ADDR] = %o'160001';
	IOP [I_NMX_BIAS] = 0;
	end
    else
	begin					! Count <> 0 so map user buffer

	if not ACHKB$ (.IOP [I_PRM1], .IOP [I_PRM2])	! Check Buffer address first
	then
	    begin
	    $RSX_FINISH_IOP (.UCB, .IOP, $NM$ERR_MPE, 0);
	    return;
	    end;

	RELOC$ (.IOP [I_PRM1], IOP [I_NMX_BIAS], IOP [I_NMX_ADDR]);
	end;

    end;

!
! Split Processing based upon Function Code and Entity
!

    selectone .IOP [I_FCN]^-8 of
	set
	[IOP_CTL] :
	    begin

	    local
                CCB : ref NMX_CCB_BLOCK,
		NMXDB : ref NMXDB_BLOCK;

	    bind routine
		DISPATCH = (case .IOP [I_NM_ENTITY] from NMX$ENT_lo to NMX$ENT_hi of
			set
			[NMX$ENT_mod] : MODREQ;
			[NMX$ENT_nod] : NODREQ;
			[NMX$ENT_ckt] : CKTREQ;
			[NMX$ENT_lin] : LINREQ;
			[inrange, outrange] : BADREQ;
			tes) : MCB_DB_CCB novalue;

	    $MCB_RSX_TO_MCB (.UCB, NMXDB);

            if $NMX_GET_NMX_CCB (.IOP, CCB)
            then
	        DISPATCH (NMXDB [NMX_BASE], .CCB);

            $MCB_MCB_TO_RSX (NMXDB [NMX_BASE]);
	    end;
	[IOP_WAT] :
            begin

	    local
                CCB : ref block field (C_FIELDS),
		NMXDB : ref NMXDB_BLOCK;

	    bind routine
		DISPATCH = EVPWAT : MCB_DB_CCB novalue;

	    $MCB_RSX_TO_MCB (.UCB, NMXDB);

            if $NMX_GET_NMX_CCB (.IOP, CCB)
            then
                DISPATCH (NMXDB [NMX_BASE], .CCB);

            $MCB_MCB_TO_RSX (NMXDB [NMX_BASE]);
	    end;
	[IOP_RLB] :
	    EVPRLB (.UCB, .IOP);
	[IOP_CON] :
	    DLXCON (.UCB, .IOP);
        [IOP_DSC] :
	    DLXDSC (.UCB, .IOP);
        [IOP_RCV] :
	    DLXRCV (.UCB, .IOP);
        [IOP_XMT] :
	    DLXXMT (.UCB, .IOP);
	[otherwise] :
	    $RSX_FINISH_IOP (.UCB, .IOP, $NM$ERR_UFO, 0);
	tes;

    end;					!End of QIODSP
routine QIONOP (UCB) : RSX_UCB novalue = 	!Non-Operation Driver Dispatch

!++
! FUNCTIONAL DESCRIPTION:
!
!     This routine just returns to the caller.
!
! FORMAL PARAMETERS:
!	UCB - Unit Control Block (unused)
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    return
    end;					!End of QIONOP
routine DLXNM (NMXDB, CCB) : MCB_DB_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!    This routine dispatches completed NM requests to the lower layers
!
! FORMAL PARAMETERS:
!
!	NMXDB - NMX's Data Base
!
! IMPLICIT INPUTS:
!
!	None
!
! IMPLICIT OUTPUTS:
!
!	None
!
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	The data base items associated with system specific functions
!       are initialized.
!--

    begin

    map
        CCB : ref NMX_CCB_BLOCK,
	NMXDB : ref NMXDB_BLOCK;

    MCB_DB_CCB ((case .CCB [C_NM_ENTITY] from NMX$ENT_lo to NMX$ENT_hi of
	set
	[NMX$ENT_mod] : MODCCP;
	[NMX$ENT_nod] : NODCCP;
	[NMX$ENT_ckt] : CKTCCP;
	[NMX$ENT_lin] : LINCCP;
	[inrange, outrange] : BADCCB;
	tes), NMXDB [NMX_BASE], .CCB);
    end;					! End of TIMPIN
routine DSPTIM (NMXDB, FCM) : MCB_DB_MOD novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!    DSPTIM handles NMX process initialization.
!
! FORMAL PARAMETERS:
!
!	NMXDB - NMX's Data Base
!       FCM - FC_MOD of FC_TIM
!
! IMPLICIT INPUTS:
!
!	None
!
! IMPLICIT OUTPUTS:
!
!	None
!
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	The data base items associated with system specific functions
!       are initialized.
!--

    begin

    map
	NMXDB : ref NMXDB_BLOCK;

    DISPATCH$ (
	.FCM,
	TABLE$ ($DSPCR, FD_TIM,		! Timer dispatch table:
	    (FM_PIN, TIMPIN),		!  Process initialization
	    (FM_LTM, TIMLTM)),		!  Long timer
	(NMXDB [NMX_BASE]),
	MCB_DB);
    end;					! End of DSPTIM
routine DSPCCP (NMXDB, CCB, FCM) : MCB_DB_CCB_MOD novalue = 	!Dispatch on Control Complete

!++
! FUNCTIONAL DESCRIPTION:
!
!    Dispatch to appropriate service routine for Control Complete CCB.
!
! FORMAL PARAMETERS:
!
!    NMXDB - the NMX process data base
!    CCB   - the CCP Communication Control Block
!    FCM   - the Function Modified in the CCB
!
!
! IMPLICIT INPUTS:
!
!    Misc Items from NMXDB
!
! IMPLICIT OUTPUTS:
!
!	None
!
! ROUTINE VALUE:
!
!	None
!
! SIDE EFFECTS:
!
!	None
!--

    begin

    map
	NMXDB : ref NMXDB_BLOCK,
	CCB : ref NMX_CCB_BLOCK;

    DISPATCH$ (.FCM,
	TABLE$ (DLXCCP, FD_CTL,		! Control complete dispatch table:
	    (FM_NM, DLXNM)),		!  NM request complete
	(NMXDB [NMX_BASE], .CCB),
	MCB_DB_CCB);
    end;
global routine BADCCB (NMXDB, CCB, FCM) : MCB_DB_CCB_MOD novalue = 	! Crash on bad CCB

!++
! FUNCTIONAL DESCRIPTION:
!
!    Signal Stop for Bad CCB parameter area
!
! FORMAL PARAMETERS:
!
!    NMXDB - NMX data base
!    CCB - the offending CCB
!    FCM - the Function Modifier
!
! IMPLICIT INPUTS:
!
!	None
!
! IMPLICIT OUTPUTS:
!
!       None
!
! COMPLETION CODES:
!
!	None
!
! SIDE EFFECTS:
!
!    Crashes the system
!--

    begin

    map
	NMXDB : ref NMXDB_BLOCK,
	CCB : ref block field (C_FIELDS);

!
    SIGNAL_STOP (NMX$_ICP);
    end;
routine TIMLTM (NMXDB) : MCB_DB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!    TIMLTM handles the long timer dispatches
!
! FORMAL PARAMETERS:
!
!	NMXDB - NMX's Data Base
!
! IMPLICIT INPUTS:
!
!	None
!
! IMPLICIT OUTPUTS:
!
!	None
!
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	The data base items associated with system specific functions
!       are initialized.
!--

    begin

    map
	NMXDB : ref NMXDB_BLOCK;

    local
        LUNBLK : ref DLX_LUN_BLOCK;

    NMXDB [NMX_TIMER_COUNT] = .NMXDB [NMX_TIMER_COUNT] + 1;
    LUNBLK = NMXDB [NMX_LUN_QUEUE];

    while (LUNBLK = .LUNBLK [LUN_LINK]) neq 0 do
        begin

        local
            IOP : ref NMX_IOP_BLOCK;

        bind
            RCVQ = LUNBLK [LUN_RCVS] : vector;

        if (IOP = .RCVQ [0]) neq 0
        then

            selectone true of
                set
                [.IOP [I_NMX_ENTITY] eql 0] :
                    begin       ! Timeout has Occurred
                    $NMX_DEQUEUE (RCVQ, IOP);
                    $NMX_RETURN_RSX_IOP (.IOP, IE$TMO, 0);
                    end;
                [.IOP [I_NMX_ENTITY] gtr 0] :
                    IOP [I_NMX_ENTITY] = .IOP [I_NMX_ENTITY] - 1;
                [otherwise] :
                    ;
                tes;

        end;

    end;					! End of TIMLTM
routine TIMPIN (NMXDB) : MCB_DB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!    TIMPIN handles process initialization
!
! FORMAL PARAMETERS:
!
!	NMXDB - NMX's Data Base
!
! IMPLICIT INPUTS:
!
!	None
!
! IMPLICIT OUTPUTS:
!
!	None
!
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	The data base items associated with system specific functions
!       are initialized.
!--

    begin

    map
	NMXDB : ref NMXDB_BLOCK;

    local
	ENABLE_VECTOR : VECTOR [3];

    external routine
	$NMEVT : novalue;

    bind
	NMX = rad50'NMX',
	SC = rad50'SC ',
	NSP = rad50'NSP',
	XPT = rad50'XPT';

    NMXDB [NMX_NMX_PIX] = GET_PIX (NMX);
    NMXDB [NMX_SC_PIX] = GET_PIX (SC);
    NMXDB [NMX_NSP_PIX] = GET_PIX (NSP);
    NMXDB [NMX_XPT_PIX] = GET_PIX (XPT);
!
! Get the EXE ADR and NAM from high core
!
    begin

    external
        $SYSIZ : block [3];

    if .$SYSIZ [2, 0, 16, 1] eql -1 and .$SYSIZ [1, 8, 8, 1] eql -1
    then
        begin

        bind
            PASSED_NUMBER = %o'140000',
            PASSED_NAME = %o'140002';

        MAP$ (.$SYSIZ [0, 0, 16, 0] - 1);

        if .PASSED_NUMBER neq 0
        then
            NMXDB [NMX_EXECUTOR_NUMBER] = .PASSED_NUMBER;

        if ch$rchar (ch$ptr (PASSED_NAME,, 8)) neq %c' '
        then
            begin

            local
                LEN;

            LEN = ch$find_ch (6, ch$ptr (PASSED_NAME,, 8), %c' ');

            if ch$fail (.LEN)
            then
                LEN = 6
            else
                LEN = ch$diff (.LEN, ch$ptr (PASSED_NAME,, 8));

            NMXDB [NMX_EXECUTOR_NAME_LENGTH] = .LEN;
            ch$move (.LEN, ch$ptr (PASSED_NAME,, 8),ch$ptr (NMXDB [NMX_EXECUTOR_NAME], 1, 8));
            end;

        end;

    end;
!
! Setup the Exception Handler for Event Logging
!
    ENABLE_VECTOR [0] = $NMEVT;
    ENABLE_VECTOR [1] = .NMXDB [NMX_NMX_PIX];
    ENABLE_VECTOR [2] = NMXDB [NMX_BASE];
    $MCB_EXCEPTION (1, ENABLE_VECTOR, );
    $MCB_ENABLE_LONG_TIMER ();
    NMXDB [NMX_TIMER_COUNT] = 1;
    begin

    bind
        EVTDB = NMXDB[NMX_EVENT_QUEUE] : NMX_EVENT_BLOCK;

    local
        CCB : ref block field (C_FIELDS);

    if $MCB_GET_CCB (CCB)
    then
        begin
        CCB [C_BIAS] = 0;
        CCB [C_ADDR] = .NMXDB [NMX_NMLINI_ADDR];
        CCB [C_CNT] = .NMXDB [NMX_NMLINI_CNT];
        CCB [C_PRM1] = 0;
        CCB [C_PRM5] = 0;
        $MCB_QUEUE_CCB (EVTDB [EVENT_QUEUE], .CCB);
        end;

    end;
    begin

    bind
        NMLMCB = uplit (%rad50_11 'NMLMCB');

    local
        TCB;

    if $RSX_GET_TCB (NMLMCB, TCB)
    then
        $RSX_REQUEST_TASK (.TCB);

    end;
    end;					! End of TIMPIN
routine GET_PIX (NAME) : NMX_LKG_NAM =

!++
! FUNCTIONAL DESCRIPTION:
!
!    GET_PIX gets the process index for the given process name.
!
! FORMAL PARAMETERS:
!
!    NAME - Rad50 process name
!
! IMPLICIT INPUTS:
!
!	None
!
! IMPLICIT OUTPUTS:
!
!	None
!
! ROUTINE VALUE:
!
!       0 if no such process,
!       process index otherwise.
!
! SIDE EFFECTS:
!
!       None
!--

    begin

    local
        PIX;

    PIX = 0;
    $MCB_GET_PROCESS_HANDLE (.NAME, PIX);
    .PIX
    end;					!of GET_PIX
global routine NMX$GET_NMX_CCB (NMXDB, IOP) : NMX$LKG_DB_IOP =

!++
! FUNCTIONAL DESCRIPTION:
!
!    Convert from IOP format to CCB format the
!    requested function.
!
! FORMAL PARAMETERS:
!
!    NMXDB - address of the NMX process data base
!    IOP - the I/O Packet to be converted
!
! IMPLICIT INPUTS:
!
!	None
!
! IMPLICIT OUTPUTS:
!
!    Various CCB fields will be setup
!
! ROUTINE VALUE:
!
!    CCB address - if successful
!    0 - if failure
!
! SIDE EFFECTS:
!
!	None
!--

    begin

    map
	IOP : ref NMX_IOP_BLOCK,
	NMXDB : ref NMXDB_BLOCK;

    local
	CCB : ref NMX_CCB_BLOCK,
	NMPAR : ref NMX_NMPAR_BLOCK;

!
! Allocate the CCB and NMPAR blocks. If resourse failure then return 0.
!

    if not $MCB_GET_CCB (CCB)
    then
	begin
	$NMX_RETURN_RSX_IOP (.IOP, $NM$ERR_REE, 0);
	return 0		    ! CCB Allocation Failure
	end;

    if not $MCB_GET_DSR (NMX_NMPAR_ALLOCATION, NMPAR)
    then
	begin                       ! NMPAR Allocation Failure
	$NMX_RETURN_RSX_IOP (.IOP, $NM$ERR_REE, 0);
	return 0		    ! Tell user
	end;

    begin
    map NMPAR : ref vector;
    NMPAR [0] = 0;
    NMPAR [1] = 0;
    NMPAR [2] = 0;
    NMPAR [3] = 0;
    end;

!
! We now have a CCB and the NMPAR block allocated; fill them in from the
! IOP.
!
    CCB [C_NM_NMPAR] = .NMPAR;      ! Point to NMPAR
    CCB [C_CNT] = 0;

    if (CCB [C_NMX_IOP] = .IOP) neqa 0
    then
	begin
	CCB [C_BIAS] = .IOP [I_NMX_BIAS];   ! Copy Buffer Descriptor
	CCB [C_ADDR] = .IOP [I_NMX_ADDR];
	CCB [C_CNT] = .IOP [I_NMX_CNT];
	CCB [C_NMX_TYPE] = .IOP [I_NMX_TYPE];       ! and type field
!
! Process Qualifier if specified otherwise flag no qualifier
!
	CCB [C_NM_QUAL] = 0;

	if .IOP [I_NMX_QUALIFIER] neq 0
	then
	    begin
	    CCB [C_NM_QUAL] = 1;
	    $RSX_CONVERT_TO_BIAS_ADDRESS (
		.IOP [I_NMX_QUALIFIER],
		NMPAR [NMX_NMPAR_AX0_BIAS],
		NMPAR [NMX_NMPAR_AX0_ADDR]);
	    end;

!
! Process Entity and store it in NMPAR is specified.
!

	if (.IOP [I_NMX_ENTITY] neq 0)
	then
	    begin

	    local
		ID_ADDRESS,
		ID_BIAS;

	    $RSX_CONVERT_TO_BIAS_ADDRESS (
		.IOP [I_NMX_ENTITY], ID_BIAS, ID_ADDRESS);
	    MAP$ (.ID_BIAS);

	    if (.CCB [C_NM_ENTITY] eql NMX$ENT_nod)
	    then
		begin

                bind
                    NODE_ENTITY = NMPAR [NMX_NMPAR_ENTITY] : block field (NODE_ENTITY_ID);

		NODE_ENTITY [NODE_ADDRESS] = (ch$rchar (.ID_ADDRESS) + (ch$rchar (ch$plus (.ID_ADDRESS, 1)
		)^8));
		NODE_ENTITY [NAME_LENGTH] = minu((ch$rchar (ch$plus (.ID_ADDRESS, 2))),6);

		if .NODE_ENTITY [NAME_LENGTH] neq 0
		then
		    CH$MOVE (.NODE_ENTITY [NAME_LENGTH],
		        ch$plus (.ID_ADDRESS, 3), byt$ptr (NODE_ENTITY [NAME_ITSELF]));

		end
	    else
		begin

                bind
                    OTHER_ENTITY = NMPAR [NMX_NMPAR_ENTITY] : block field (OTHER_ENTITY_ID);

		OTHER_ENTITY [OTHER_LENGTH] = minu((ch$rchar (.ID_ADDRESS)),16);

		if .OTHER_ENTITY [OTHER_LENGTH] neq 0
		then
		    CH$MOVE (.OTHER_ENTITY [OTHER_LENGTH],
		        ch$plus (.ID_ADDRESS, 1), byt$ptr (OTHER_ENTITY [OTHER_ITSELF]));

		end;

	    end;

        if .CCB [C_NM_FUNC] eql NMX$FNC_ret
        then
            NMPAR [NMX_NMPAR_RETURN_CNT] = 0;

	end;

    CCB [C_NMX_CNT] = 0;            ! Store initial buffer count
    CCB [C_NMX_STATE] = ST$INI;	    ! State is DEFAULT
    CCB [C_FNC] = FC_CTL;           ! Control Function
    CCB [C_MOD] = FM_NM;            !  for Network Management
    .CCB
    end;					! of NMX$GET_NMX_CCB
global routine NMX$MAP_ENTITY_ID_TO_DB (TYPE, ENTID_PTR) : NMX$LKG_TYP_ENT =

!++
! FUNCTIONAL DESCRIPTION:
!
!    GET_ENTITY searches for a data base that matches ENTID
!    and returns its' address in ENTBLK.
!
! FORMAL PARAMETERS:
!
!    ENTBLK - set to the address of a ENTITY_BLOCK
!    ENTID - points at string for ENTITY_ID
!
! IMPLICIT INPUTS:
!
!	None
!
! IMPLICIT OUTPUTS:
!
!	None
!
! ROUTINE VALUE:
!
!    true - if ENTITY found
!    false - otherwise
!
! SIDE EFFECTS:
!
!    Mapping register APR6 is modified  to map in the ENTITY_BLOCK.
!--

    begin

    bind
	NMXDB = .MCB$GAW_PROCESS_DATA_BASE [1] : NMXDB_BLOCK;

    local
	ENTADR : ref NMX_GENERAL_BLOCK,
	ENTCNT,
        ENTLEN : ref vector;

    case .TYPE from NMX$ENT_lo to NMX$ENT_hi of
        set
        [NMX$ENT_lin] :
            ENTLEN = NMXDB [NMX_LINES];
        [NMX$ENT_ckt] :
            ENTLEN = NMXDB [NMX_CIRCUITS];
        [NMX$ENT_mod] :
            ENTLEN = NMXDB [NMX_MODULES];
        [inrange, outrange] :
            return 0;
        tes;

    MAP$ (.ENTLEN [0]);
    ENTLEN = ENTLEN [1];	%(to force auto-increment)%
    ENTADR = .ENTLEN [0];
    ENTLEN = ENTLEN [1];	%(to force auto-increment)%
    if .ENTADR eqla 0 then return 0;
    ENTCNT = .ENTLEN [0];
    ENTLEN = ENTLEN [1];	%(to force auto-increment)%
    if .ENTCNT eql 0 then return 0;
    ENTLEN = .ENTLEN [0];
!
! Search through Entity BLOCKs looking for a matching one.
!
    do
	begin

        if ch$eql (.ENTADR [GENERAL_NAME_LENGTH] + 1,
                   byt$ptr (ENTADR [GENERAL_NAME]),
                   .ENTADR [GENERAL_NAME_LENGTH] + 1,
                   .ENTID_PTR)
        then return .ENTADR;

	ENTADR = .ENTADR + .ENTLEN;
	end
    while (ENTCNT = .ENTCNT - 1) neq 0;

    return 0
    end;					!of NMX$MAP_ENTITY_ID_TO_DB
global routine NMX$MAP_NMXID_TO_DB (NMXID) : NMX$LKG_NMXID =

!++
! FUNCTIONAL DESCRIPTION:
!
!    This routine checks for an existing entity data base
!
! FORMAL PARAMETERS:
!
!    .NMXID - A NMX id word
!
! IMPLICIT INPUTS:
!
!	NMXDB items pointing to database entries
!
! IMPLICIT OUTPUTS:
!
!       NMXDB items created
!
! ROUTINE VALUE:
!
!	0 = No such entity
!	adr = Data base found
!
! SIDE EFFECTS:
!
!	None
!--

    begin

    bind
	NMXDB = .MCB$GAW_PROCESS_DATA_BASE [1] : NMXDB_BLOCK;

    local
	ENTBLK : ref NMX_GENERAL_BLOCK;

    case .NMXID <8, 8> from NMX$ENT_lo to NMX$ENT_hi of
	set
	[NMX$ENT_lin] : ENTBLK = NMXDB [NMX_LINES];
	[NMX$ENT_ckt] : ENTBLK = NMXDB [NMX_CIRCUITS];
	[NMX$ENT_mod] : ENTBLK = NMXDB [NMX_MODULES];
	[inrange, outrange] :
	    return 0;
	tes;

    begin

    map
	ENTBLK : ref NMX_ENTITY_BLOCK;

    if .NMXID<0, 8, 0> gequ .ENTBLK [NMX_ENTITY_BLOCK_ENTRIES]
    then
	return 0;

    MAP$ (.ENTBLK [NMX_ENTITY_BLOCK_BIAS]);
    ENTBLK = .ENTBLK [NMX_ENTITY_BLOCK_ADDRESS] +
	.NMXID<0, 8, 0>*.ENTBLK [NMX_ENTITY_BLOCK_LENGTH];
    end;

    if .ENTBLK [GENERAL_NAME_LENGTH] eqlu 0
    then return 0;

    if (.ENTBLK [GENERAL_ID] nequ .NMXID) then return 0;

    return .ENTBLK
    end;			    ! of NMX$MAP_NMXID_TO_DB
global routine NMX$RETURN_NMX_CCB (CCB) : NMX$LKG_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!    Return the given CCB and NMPAR DSR.
!
! FORMAL PARAMETERS:
!
!    CCB - Address of CCB to be returned
!
! IMPLICIT INPUTS:
!
!	None
!
! IMPLICIT OUTPUTS:
!
!       None
!
! ROUTINE VALUE:
!
!       None
!
! SIDE EFFECTS:
!
!	None
!--

    begin

    map
	CCB : ref NMX_CCB_BLOCK;

    begin

    local
	NMPAR;

    if (NMPAR = .CCB [C_NM_NMPAR]) neqa 0
    then
	$MCB_RETURN_DSR (NMX_NMPAR_ALLOCATION, .NMPAR);

    end;
    begin

    local
        AMOUNT,
        ERROR_CODE,
	IOP : ref NMX_IOP_BLOCK;

    if (IOP = .CCB [C_NMX_IOP]) neqa 0
    then
	begin
        ERROR_CODE = .CCB [C_STS];
	AMOUNT = .CCB [C_NMX_CNT];
	end;

    $MCB_RETURN_CCB (.CCB);

    if .IOP neqa 0
    then
        $NMX_RETURN_RSX_IOP (.IOP, .ERROR_CODE, .AMOUNT);

    end;
    end;					! of NMX$RETURN_NMX_CCB

end

eludom
! Local Modes:
! Comment Column:36
! Comment Start:!
! Mode:BLISS
! Auto Save Mode:2
! End: