Trailing-Edge
-
PDP-10 Archives
-
BB-R598A-RM_1983
-
swskit-v3/nvt/nrtsrv-10.mac
There is 1 other file named nrtsrv-10.mac in the archive. Click here to see a list.
title nrtsrv - Program to service NVTHAC links
.text "/symseg:low/locals"
search glxmac ;get galaxy's symbols
prolog (nrtsrv)
TOPS20< PRINTX ? Wrong.
END>
sall ;pretty(er) listings
;version information
nrsver==1
nrsmin==0
nrsedt==5
nrswho==0
%%nrs==vrsn.(nrs) ;make the version obvious
glob %%nrs
loc 137 ;<.jbver>
exp %%nrs
reloc
;revisions
; 3-Sept-80 Edit #4
; Don't let NRTSRV run if it is a [1,2] job.
;
; 21-Oct-80 Edit #5
; Restrict the number of chars in an output message (to tops-20)
; to 40. decimal. This is because of murphy's set-host hack
;
;register definitions
l=.a13 ;pointer to the link block
;Helper to define symbols
define $def(name,size<1>)<name==%%%loc
%%%loc==%%%loc+size>
subttl Symbols - helpful definitions
uu.dmr==uu.bjp ;Task Disable Message Reassembly
uu.fsp==1b1 ;Full Scnser Pty
dc.dar==2 ;data with end of record
nd tibfsz,10 ;task input buffer size
nd pobfsz,10 ;pty output buffer size
nd pibfsz,10 ;pty input buffer size
nd tobfsz,10 ;task output buffer size
nd adtime,10 ;do an AUDIT every 10 seconds.
nd sltime,adtime*^D1000 ;sleep between audits
nd lnkmax,50 ;maximum number of links
nd pdllen,70 ;stack length
subttl LBLOCK - link block definitions
%%%loc==0 ;init the $def macro
$def l$link ;contains the link number (ordinal)
;pty control locations
$def p$chan ;channel the pty is open on
$def p$trmn ;number of terminal pty controls
$def p$ibuf,pibfsz+3+3 ;Pty input buffer
$def p$obuf,pobfsz+3+3 ;Pty output buffer
$def p$isr,2 ;interrupt service routine for pty
$def p$svac,2 ;AC save area for ptyisr
;tsk control locations
$def t$stat ;status for the TSK device
$def t$chan ;TSK channel number
$def t$ibuf,tibfsz+3+3 ;TSK input buffer
$def t$obuf,tobfsz+3+3 ;TSK output buffer
$def t$isr,2 ;TSK interrupt service routine
$def t$svac,2 ;AC save area
$def l$size,0 ;size of the link block
subttl INIT - Code to initialize nrtsrv
go: jfcl ;ignore CCL entry
move s1,[xwd firzer,firzer+1]
setzm -1(s1)
blt s1,lstzer ;clear out the data base
move p,[iowd pdllen,pdl] ;set up the stack
reset ; and close all the channels
;now get the GLXLIB high segment.
setz s1, ;a zero length IB
$call i%init ;get the galaxy high-seg
setzm .jbpfh ;keep stupid glxlib from trying
; to page out the entire program.
setom newlok ;clear the "newlnk" interlock
;now see if we are already logged in as [1,2], if so, halt.
; This prevents stupid operators from compromising the system's
; security
getppn s1, ;get our ppn
camn s1,[xwd 1,2] ;operator?
$stop (CRO,NRTSRV may NOT be run as an operator job.)
;now log us in as [2,5] (So users don't get logged in for free)
move s1,[xwd -4,t1] ;arg block is 4 wds long
move t1,[xwd 2,5] ;ppn
seto t2, ;privs
dmove t3,[sixbit | NRT-Server |] ;name
login s1, ;log us in (so we can open TSK)
;now detach us from FRCLIN
movsi s1,-1 ;get a -1 in the LH
attach s1, ; and detach us
$stop (DTF,Detach failed.)
;set up the PSI system
movei s1,vector ;get the address of the interrupt vector
piini. s1, ;init the PSI system
$STOP (CIP,<Couldn't init the PSI system.>)
movx s1,ps.fon ;turn the system on
pisys. s1, ;turn it on
$call s..cip ;?
; jrst loop ;go run the main code
subttl LOOP - Main driver for nrtsrv
loop: movx s1,%cndtm ;gettab for the universal
gettab s1, ; date/time
$stop (UDF,<Gettab for Universal Date/Time failed.>)
movem s1,time ;remember the time
caml s1,audtim ;if it's time, go
$call audit ; make a through check of things.
;now loop over each link looking for ones that "want service"
sloop: movsi p1,-lnkmax ;aobjn pointer for LNKTBL
skipl l,lnktbl(p1) ;look at the next link entry
aobjn p1,.-1 ; if not requesting service, go on.
jumpge p1,sleep ;if aobjn is done, so are we.
hrrzs lnktbl(p1) ;clear the "request bit"
$call service ;go service the request
jrst sloop ; and re-start the scan
; This gives better service to low
; links, but it probably doesn't matter
;nothing more to do. Give up the CPU for a while
sleep: movx t1,<xwd 0,sltime> ;get length of time to sleep
hiber t1, ;zzz.
$stop (HDS,<Hiber uuo failed.>)
jrst loop ;do it till we get it wrong.
subttl SERVICE - routine to service requests
servic: skipn t$chan(l) ;if no task is assigned
jrst tskep ; then "NEWLNK" want's one
srvdsp: move t1,t$stat(l) ;get the task state
cail t1,.tksid ; range check
caile t1,.tksok ; the state
$stop (ITS,<Illegal task state - ^O/t1/.>)
jrst @.+1(t1) ;dispatch on the state
jrst died ;.tksid - link down
jrst wait ;.tksci - waiting for a connect
$call s..its ;.tkscc - we don't send connects
jrst copy ;.tksok - running ok
;here if we are the PASSIVE task waiting for some one to connect
wait: $call tskgst ;recompute the TSK state
CAIN S1,.TKSOK ;We just got a connect
$CALL SNDCFG ;Send config so RSTS or VAX know who we are
caie s1,.tksci ;if we've left CI state
jrst srvdsp ; go see what state we're in now
$warn (<Un-explained interrupt on passive tsk ^O/t$chan(l)/.>)
$rett ;return with that warning
;here if the TSK channel died
died: $call ptycls ;stop the job, close the pty
$call tskcls ;free the TSK channel
move s1,l$link(l) ;get the channel number
setzm lnktbl(s1) ; and free the link number
movx s1,l$size ;get the size
hrrz s2,l ; and address of this channel block
$call m%rmem ;return the block to the free pool
$call audit ;make sure there is a passive link
$rett ; and we're done
subttl COPY - Routines to actually push the data.
copy: skipn p$chan(l) ;if we haven't assigned a pty yet
$call ptyopn ; then go do so.
t2p: skipg p$obuf+.bfctr(l) ;see if there is room in the buffer
$call dopout ;if not, try to get some
skipg p$obuf+.bfctr(l) ;see if there is some now
jrst p2t ;if not, let the tsk back up
$call dotin ;do an "in" (only if necessary)
skipg t$ibuf+.bfctr(l);see if there is input data
jrst p2t ;if not, go look at the other side
move s2,p$obuf+.bfctr(l);get the minimum of the
caml s2,t$ibuf+.bfctr(l); of the two buffer
move s2,t$ibuf+.bfctr(l); counts
movn s1,s2 ;get the negative of that value
addm s1,t$ibuf+.bfctr(l); and fixup the counts
addm s1,p$obuf+.bfctr(l); for both buffers
t2pcpy: ildb s1,t$ibuf+.bfptr(l);get and
idpb s1,p$obuf+.bfptr(l); put the byte
sojg s2,t2pcpy ;loop over all bytes
jrst t2p ;go back and try to find more work
p2t: skipg t$obuf+.bfctr(l);see if the output buffer is available
$call dotout ; if not, try to do an "out"
skipg t$obuf+.bfctr(l);see if it's ok now
jrst cpydon ; if not, then we're done for now
$call dopin ;try to get pty data
skipg p$ibuf+.bfctr(l);see if we got any
jrst cpydon ;if not, we're done
move s2,p$ibuf+.bfctr(l);calculate the
caml s2,t$obuf+.bfctr(l); minimum of the two
move s2,t$obuf+.bfctr(l); counts
movn s1,s2 ;and
addm s1,p$ibuf+.bfctr(l); update the counts
addm s1,t$obuf+.bfctr(l); by what we're about to copy
p2tcpy: ildb s1,p$ibuf+.bfptr(l);get a byte
idpb s1,t$obuf+.bfptr(l); and send it
sojg s2,p2tcpy ;loop over all
jrst p2t ;go look for more work
cpydon: $call dopout ;send any pty data
$call dotout ; task data as well
$rett ;done.
subttl AUDIT - Routine to check things out...
audit: $save <p1> ;conventions.
movx t1,adtime*3 ;get audit increment
add t1,time ; and calculate time to do next audit
movem t1,audtim ;remember it.
;first scan to make sure we have a passive channel
movsi p1,-lnkmax ;aobjn pointer
audit1: skipn l,lnktbl(p1) ;see if this channel is in use
jrst audit2 ; if not, go check the next one
skipn t$chan(l) ;make sure there is a TSK assigned
jrst audit2 ; if not, just skip over the link
$call tskgst ;get the status
cain s1,.tksci ;if we are in CI
jrst audit3 ; then we found our passive tsk
audit2: aobjn p1,audit1 ;loop over them all (if necessary)
$call newlnk ;if none, make one.
audit3: $rett
subttl ISRs - Interrupt service routines.
;isr's are called from the appropriate location in the link block
; s1/ location +1 of the call to the isr
tskisr: subi s1,t$isr+2 ;get the location of the block
move s2,l$link(s1) ;get the link number in s2
xor s1,lnktbl(s2) ;compare the two addresses
trne s1,-1 ; and if they aren't equal
$stop (IWA,Interrupt to wrong address.)
movsi s1,(1b0) ;get the "service me" bit
iorb s1,lnktbl(s2) ;set it and get our block addr back
dmove s1,t$svac(s1) ;reload the ac's
debrk. ; and we're done
ptyisr: subi s1,p$isr+2 ;get the location of the block
move s2,l$link(s1) ;get the link number in s2
xor s1,lnktbl(s2) ;compare the two addresses
trne s1,-1 ; and if they aren't equal
$call s..iwa ;interrupt to wrong address
movsi s1,(1b0) ;get the "service me" bit
iorb s1,lnktbl(s2) ;set it and get our block addr back
dmove s1,p$svac(s1) ;reload the ac's
debrk. ; and we're done
subttl NEWLNK - Routine to allocate storage for a new link.
newlnk: aose newlok ;we only want one level in here at once
$rett ;return if some one else is here
;first find a free slot in LNKTBL
movsi t1,-lnkmax ;aobjn pointer to lnktbl
skipe lnktbl(t1) ;start looking
aobjn t1,.-1 ; keep looking
jumpge t1,[setom newlok;if no free links, release the lock
$rett] ; and return (will try again next audit)
movx s1,l$size ;get the size of a link block
$call m%gmem ;allocate a new link block
hrli s2,(1b0) ;get the "want's service" bit
movem s2,lnktbl(t1) ;mark the link as in use and wanting
hrrzm t1,l$link(s2) ;remember the link number
setom newlok ;free the interlock
$rett ; and return
subttl TSKEP - Routine to assign a new task channel
;first open the TSK device
tskep: move s1,[xwd 4,t1] ;filop open argument list
movx t1,fo.asc+.focre;open a new channel, assign chan
movx t2,uu.aio+uu.dmr+.iobyt ;byte mode, non-blocking
movx t3,<sixbit |TSK|>;device name
hrli t4,t$obuf(l) ;output buffer
hrri t4,t$ibuf(l) ; input buffer too
filop. s1, ;open the TSK
$stop (OTF,Open of the TSK channel failed.)
ldb s1,[pointr (t1,fo.chn)] ;get the assigned channel number
movem s1,t$chan(l) ; and remember it
;set up buffer fings
movei s1,t$obuf+3+1(l);address of link word in the buffer
hrli s1,(1b0) ;magic flag that says "virgin"
movsi s2,(point 8,0) ;byte size
dmovem s1,t$obuf(l) ;set up pointer to buffer ring
setz s1, ;zero initial status
hrri s2,t$obuf+3+1(l);address of next buffer in ring (first)
hrli s2,tobfsz+1 ;size of this buffer
dmovem s1,t$obuf+3(l) ;init the header of the single buffer
;input too...
movei s1,t$ibuf+3+1(l);address of link to buffer ring
hrli s1,(1b0) ;virgin bit
movsi s2,(point 8,0) ;byte size
dmovem s1,t$ibuf(l) ;set up buffer control block
setz s1, ;init status
hrri s2,t$ibuf+3+1(l);link to next (aka first) buffer
hrli s2,tibfsz+1 ;task input buffer size
dmovem s1,t$ibuf+3(l) ;init the buffer header
;now attach the TSK to the interrupt system
dmove s1,[dmovem s1,0 ;isr first save's s1, s2
jsp s1,tskisr] ;then call's the isr
hrri s1,t$svac(l) ;fixup the addr of the save routine
dmovem s1,t$isr(l) ; and init it for this task
;calculate the vector offset for this device
move s2,l$link(l) ;get our link
addi s2,(s2) ;tsk uses the even slots
lsh s2,2 ;multiply by 4 to get offset
;now fill in the vector information
movei s1,t$isr(l) ;get the address of the ISR
movem s1,vector+.psvnp(s2) ;and save it as the "new pc"
movx s1,ps.vto ;get the appropriate "flags"
movem s1,vector+.psvfl(s2) ;and save the "flags"
;now connect the device
movx s1,ps.fac+t1 ;function is "add device"
move t1,t$chan(l) ;this is the channel
hrl t2,s2 ;this is the vector offset
hrri t2,ps.rid+ps.rod+ps.rol ;the enabled conditions
setz t3, ;clear the reserved word
pisys. s1, ;add the tsk device
$stop (PAT,Pisys uuo to add the TSK device failed.)
;now put the TSK in the passive state
move s1,[xwd 4,t1] ;argument block length and address
movx t1,.tkfep ;function is "enter passive"
move t2,t$chan(l) ;get the channel
move t3,srcnpd ;the remote NPD
move t4,rmtnpd ;the local descriptor
tsk. s1, ;enter passive state
$stop (EPF,Enter passive state TSK uuo failed.)
; pjrst tskgst ;set up the status and return
subttl TSKGST - routine to get the status of a TSK channel
tskgst: move s1,[xwd 3,t1] ;address of the TSK. arg block
movx t1,.tkfrs ;function is return status
move t2,t$chan(l) ;channel number
setz t3, ;status goes here
tsk. s1, ;do the uuo
$stop (RSF,Read status TSK. uuo failed.)
movem t3,t$stat(l) ;save the status
move s1,t3 ;also return it in s1
$rett ; and we're done
subttl TSKIO - Routines to do in/out uuo's to the TSK device
dotin: skiple t$ibuf+.bfctr(l);if there is already data there
$rett ; then don't clobber it
move s1,[xwd 3,t1] ;arg list
movx t1,.tkfin ;in uuo function
move t2,t$chan(l) ;channel
setz t3, ;eor notification
tsk. s1, ;do the uuo.
caia ;skip if something is worng
$rett ;return if ok
cain s1,tkils% ;if it's "illegal in this state"
jrst tsklwd ; then the link went down
caie s1,tkudw% ;if it's an unknown error
jrst tskerr ; go to common code to look at it
txne t1,io.err+io.eof;if the link wen't down
jrst tsklwd ;go set flags to clean up.
$rett ;let loop catch the problems.
dotout: move s1,t$obuf+.bfctr(l) ;get the number of free chars
caxl s1,tobfsz*4 ;if all the chars are free
$rett ; then don't do the out
move s1,[xwd 3,t1] ;arg list address
movx t1,.tkfot ;output uuo
move t2,t$chan(l) ;channel
movx t3,dc.dar ;data with end of record
tsk. s1, ;do the output uuo
caia ; skip if an error
$rett ;return if not.
cain s1,tkils% ;if it's "illegal in this state"
jrst tsklwd ; then the link went down
caie s1,tkudw% ;was the error "didn't work"
jrst tskerr ;go describe the error
txnn t1,io.eof+io.err;if it's just async i/o
jrst [setzm t$obuf+.bfctr(l) ;say the buffer is full
$rett] ;and return (tskser remembers the size)
tskerr: $warn (<TSK I/O error ^O/s1/, DEVIOS = ^O/t3/.>)
tsklwd: $call tskgst ;if link is down, recompute the state
move s1,l$link(l) ;get the link number
movsi s2,(1b0) ;get the "want service" flag
iorm s2,lnktbl(s1) ;set it so some one will notice
$rett ; and let loop clean up
SNDCFG: PUSHJ P,DOTOUT ;Make dummy out happen
MOVEI T1,CFGMSG ;Send configuration msg
PJRST SNDMSG
EXP 10
CFGMSG: BYTE(8) 1,1,0,0,11,0,10,0
; Config--' ^ ^ ^ ^ ^ ^ ^
; ? ? ? | ? | ?
; System=TOPS10----' |
; Protocol=TOPS20-------'
SNDMSG:
MOVE T2,-1(T1)
HRLI T1,441000 ;Set up byte pointer
SNDMS0: ILDB T3,T1 ;GET BYTE
IDPB T3,T$OBUF+.BFPTR(L) ;Put it in the buffer
SOJG T2,SNDMS0 ;back for more
SETZM T$OBUF+.BFCTR(L);no more bytes in here
PJRST dotout ;Send it
subttl PTYOPN - Routine to init the PTY side of a link.
;first open the PTY device
ptyopn: move s1,[xwd 4,t1] ;filop arg block
movx t1,fo.asc+.focre ;assign channel and open it
movx t2,uu.aio+uu.fsp ;full scnser control
movx t3,<sixbit |PTY|>;device name
hrli t4,p$obuf(l) ;output buffer address
hrri t4,p$ibuf(l) ;input buffer address
filop. s1, ;open the devic
$stop (OPF,<Open of the PTY device failed - ^O/s1/.>)
ldb s1,[pointr (t1,fo.chn)];get the assigned channel
movem s1,p$chan(l) ; and remember it for later.
;set up the buffer rings
movei s1,p$obuf+3+1(l);address of link word in the buffer
hrli s1,(1b0) ;magic flag that says "virgin"
movsi s2,(point 7,0) ;byte size
dmovem s1,p$obuf(l) ;set up pointer to buffer ring
setz s1, ;zero initial status
hrri s2,p$obuf+3+1(l);address of next buffer in ring (first)
hrli s2,pobfsz+1 ;size of this buffer
dmovem s1,p$obuf+3(l) ;init the header of the single buffer
;input too...
movei s1,p$ibuf+3+1(l);address of link to buffer ring
hrli s1,(1b0) ;virgin bit
movsi s2,(point 7,0) ;byte size
dmovem s1,p$ibuf(l) ;set up buffer control block
setz s1, ;init status
hrri s2,p$ibuf+3+1(l);link to next (aka first) buffer
hrli s2,pibfsz+1 ;task input buffer size
dmovem s1,p$ibuf+3(l) ;init the buffer header
;now attach the PTY to the interrupt system
dmove s1,[dmovem s1,0 ;isr fisrt saves the ac's
jsp s1,ptyisr] ;then to common code
hrri s1,p$svac(l) ;relocate to the correct save area
dmovem s1,p$isr(l) ; and init it for this pty
;calculate the vector offset for this device
move s2,l$link(l) ;get our link
addi s2,1(s2) ;pty uses the odd slots
lsh s2,2 ;multiply by 4 to get offset
;now fill in the vector information
movei s1,p$isr(l) ;get the address of the ISR
movem s1,vector+.psvnp(s2) ;and save it as the "new pc"
movx s1,ps.vto ;get the appropriate "flags"
movem s1,vector+.psvfl(s2) ;and save the "flags"
;now connect the device
movx s1,ps.fac+t1 ;function is "add device"
move t1,p$chan(l) ;this is the channel
hrl t2,s2 ;this is the vector offset
hrri t2,ps.rid+ps.rod+ps.rol ;the enabled conditions
setz t3, ;clear the reserved word
pisys. s1, ;add the pty device
$stop (PAP,Pisys uuo to add the PTY device failed.)
;now force initia on the new line
move s1,p$chan(l) ;get the pty channel
iondx. s1, ; and get the PTY udx
$stop (CFI,Error while trying to force INITIA on line.)
andi s1,777 ;get just the PTY number
movx s2,%cnpty ;get the offset of the
gettab s2, ; first pty
$call s..cfi ;?
movx t1,<sixbit |INITIA|> ;command to force
hlrz t2,s2 ;tty number of first PYT
addi t2,.uxtrm(s1) ;tty UDX of controled terminal
movem t2,p$trmn(l) ;save it for posteity
move s1,[xwd 2,t1] ;arglist for frcuuo
frcuuo s1, ;force initia
jfcl ;we tried. (Really should work...)
$rett ;done
subttl PTYIO - Routines to do in/out uuo's to the PTY
dopin: skiple p$ibuf+.bfctr(l);if there is already data there
$rett ; then don't write over it
move s1,p$chan(l) ;get the channel
movx s2,.foinp ;the filop in function
dpb s1,[pointr (s2,fo.chn)] ;set the channel
move s1,[xwd 1,s2] ;arglist descriptor
filop. s1, ;do the output
$warn (<PTY input error = ^O/s1/.>)
$rett ;done.
dopout: move s1,p$obuf+.bfctr(l);see if the output buffer
caxl s1,pobfsz*5 ; is empty. if so,
$rett ; don't do an output on it
move s1,p$chan(l) ;get the channel
movx s2,.foout ;get the output fucntion
dpb s1,[pointr (s2,fo.chn)] ;set the channel
move s1,[xwd 1,s2] ;arglist descriptor
filop. s1, ;do the output
jfcl ;pty's suck.
; $warn (<PTY output error = ^O/s1/.>)
$rett
subttl PTYCLS - Routine to close a PTY
ptycls: skipn s1,p$chan(l) ;first make sure there is a PTY
$rett ; if none, we're done.
jobsts s1, ;see if we are controlling anyone
$stop (JUF,Jobsts UUO failed.)
ldb t2,[pointr (s1,jb.ujn)] ;get the job number
jumpe t2,ptycl1 ;if none, just go free the pty
;stop the job on the PTY
move s1,[xwd 2,t1] ;frcuuo arg list is 2 wds long
move t1,[sixbit |.halt|] ;just a gentle
frcuuo s1, ; whack!
jfcl ;this doesn't work
; $stop (FUS,<Frcuuo to stop job ^O/t2/ failed.>)
;now get rid of the PTY. First remove it from the PI system
ptycl1: movx s1,ps.frc+t1 ;remove function, arg blk in t1
move t1,p$chan(l) ;pty channel
move t2,l$link(l) ;get the link number
addi t2,1(t2) ; pty's are the odd vector blocks
lsh t2,^D18+2 ;shift half words (and multiply by 4)
setz t3 ;clear the "reserved word"
pisys. s1, ;remove the PTY
$stop (RPF,Pisys to remove the PTY channel failed.)
;now release the PTY
movx s2,.forel ;filop release function
move s1,p$chan(l) ;get the channel
dpb s1,[pointr (s2,fo.chn)] ;store the channel number
move s1,[xwd 1,s2] ;length - arg list address
filop. s1, ;release the PTY
$stop (FRP,Filop to release the PTY failed.)
setzm p$chan(l) ;indicate the PTY is no longer assigned
$rett ; and we're done
subttl TSKCLS - Routine to close the TSK channel
tskcls: skipn t$chan(l) ;make sure the task is assigned
$stop (TNA,TSKCLS was called with no channel assigned.)
;first disconnect the TSK from the PI system
movx s1,ps.frc+t1 ;function "remove" arglist in t1-t3
move t1,t$chan(l) ;get the channel
move t2,l$link(l) ;get the link number
addi t2,(t2) ;we use the even offsets
lsh t2,^D18+2 ;multiply by 4 and put in the LH(t2)
setz t3, ;clear the "reserved word"
pisys. s1, ;remove the TSK
$stop (TRF,Pisys to remove the TSK channel failed.)
;now release the channel
movx s2,.forel ;filop release function
move s1,t$chan(l) ;the channel number
dpb s1,[pointr (s2,fo.chn)] ;put it where filop likes it
move s1,[xwd 1,s2] ;arg-list length and address
filop. s1, ;do the release
$stop (FTR,Filop to release the TSK channel failed.)
setzm t$chan(l) ;say the TSK is gone
$rett ; and we're done
subttl DATA - Data area
firzer: ;start zeroing here on a restart
time: block 1 ;current time
audtim: block 1 ;time of next audit
pdl: block pdllen ;stack
vector: block lnkmax*2*4 ;interrupt vector block
lnktbl: block lnkmax ;table of pointers to link blocks
; sign bit means "want's serivce"
newlok: block 1 ;interlock for creating links
lstzer: block 1 ;last word to zero
srcnpd: xwd 4,.+1 ;our name
exp 0 ;ignore the node
exp 10 ;10 characters
ascii |ANF-NRTsrv| ;our name
rmtnpd: xwd 4,.+1 ;address
exp -1 ;any node
exp 4 ;4 char pattern
byte (7) 0, "2", "7", "*" ;match any object 23
exp 0
end go