.TITLE MONLAT .IDENT /V1.1/ ; This program will listen for LAT multicast messages and display information ; from the messages it finds. ; Author = David Gagne .LIBRARY "SYS$LIBRARY:LIB.MLB" $IODEF ;Define I/O functions and modifiers $NMADEF ;Define Network Management parameters $LNMDEF ;Define logical name parameters ; Modification history ; ; 1.1 David Gagne ; 01 Modify the specific node display ; QIO data structures for the LAT channel. ; Setmode parameter buffer SETPARM: .WORD NMA$C_PCLI_PTY ; Protocol type .LONG ^X0460 .WORD NMA$C_PCLI_BFN ; Number of buffers to save .LONG 4 .WORD NMA$C_PCLI_BUS ; Max. receivable buffer size .LONG 1500 .WORD NMA$C_PCLI_PAD ; Padding .LONG NMA$C_STATE_OFF .WORD NMA$C_PCLI_MCA ; Multicast address .WORD 8 .WORD NMA$C_LINMC_SET .BYTE 09,00,^X2B,00,00,^X0F SETPARMLEN = .-SETPARM SETPARMDSC: .LONG SETPARMLEN .ADDRESS SETPARM ; Read buffer for LAT multicast messages RCVBUF: .BLKB 1504 RCVBUFLEN = .-RCVBUF ; Place to store incoming P5 buffer RCVP5: RCVDA: .BLKB 6 RCVSA: .BLKB 6 RCVPTY: .BLKB 2 ; QIO data structures for the MOP (SYSTEM ID) channel. ; P2 parameter buffer for finding devices of other nodes. SIDPARM: .WORD NMA$C_PCLI_PTY ; Protocol Type .LONG ^X0260 SIDPARMLEN = .-SIDPARM SIDPARMDSC: .LONG SIDPARMLEN .ADDRESS SIDPARM ; P2 transmit data buffer for sending request SYSID messages. XMTP2BUF: .BYTE 05 ; SYSTEM ID request code .BYTE 00 ; Reserved XMTP2RCT: .WORD 4242 ; Receipt number (to be returned) XMTP2LEN = .-XMTP2BUF ; Address of the node whose Device ID we would like to find. SIDADDR: .BLKB 6 ; Read buffer for receiving System IDs RCVBUF2: .BLKB 1504 RCVBUFLEN2 = .-RCVBUF2 ; Place to store incoming P5 buffer RCVP52: RCVDA2: .BLKB 6 RCVSA2: .BLKB 6 RCVPT2: .BLKB 2 ; Message structures ; General message buffer FAODESC: FAOLEN: .LONG 80 .ADDRESS FAOBUF FAOBUF: .BLKB 80 HDRMSG1: .ASCID "MONLAT - Ethernet LAT monitoring program. Version 1.1" INPMSG1: .ASCID "Monitor requests available:" INPMSG2: .ASCID " 1) Monitor service announcements from all nodes" INPMSG3: .ASCID " 2) Monitor service announcements for a specific group code" INPMSG4: .ASCID " 3) Monitor service announcement from a specific node" INPMSG5: .ASCID " any other input will stop the program" IOMSG: .ASCID "!/The contents of the 2nd longword in the IOSB is !XL" NDMSG: .ASCID "No device found. Please define ETH appropriately." DNEMSG: .ASCID "MONLAT complete. Thank you for your continued support." BLNKMSG: .ASCID "" ; Output strings for monitoring service announcements from all nodes M1ALL1: .ASCID "Address: AA-00-04-00-!XB-!XB; Controller !2UB=!AS; DECnet node: !2UB.!UW" M1ALL2: .ASCID "Address: !XB-!XB-!XB-!XB-!XB-!XB; Controller !2UB=!AS" M1MASK: .ASCID " Group code bit mask:" M1BIT1: .ASCID " (063-000) !XB !XB !XB !XB !XB !XB !XB !XB" M1BIT2: .ASCID " (127-064) !XB !XB !XB !XB !XB !XB !XB !XB" M1BIT3: .ASCID " (191-128) !XB !XB !XB !XB !XB !XB !XB !XB" M1BIT4: .ASCID " (255-192) !XB !XB !XB !XB !XB !XB !XB !XB" M1NONE: .ASCID "No service announcement messages were found" ; Output strings for monitoring service announcements for a specific group M2HDR0: .ASCID "Group Code #!3UB" M2ALL1: .ASCID " Address: AA-00-04-00-!XB-!XB; Controller !2UB=!AS; DECnet node !2UB.!UW" M2ALL2: .ASCID " Address: !XB-!XB-!XB-!XB-!XB-!XB; Controller !2UB=!AS" M2NONE: .ASCID "No service announcement messages were found using Group Code #!3UB" ; Output strings for monitoring service announcements from a specific node M3ADDR: .ASCID "Address: !XB-!XB-!XB-!XB-!XB-!XB" M3NODE: .ASCID " DECnet node: !2UB.!UW" M3CONT: .ASCID " Controller: !UB = !AS" M3IDN1: .ASCID " Node name: !AD" M3IDN2: .ASCID " Node desc: !AD" M3IDN3: .ASCID " Service name: !AD" M3IDN4: .ASCID " Service desc: !AD" M3HDR1: .ASCID " Group Codes Set:" M3GCOD: .ASCID " !3UW" M3NONE: .ASCID "No service announcement message found from !XB-!XB-!XB-!XB-!XB-!XB" ; Strings for various device names DEV01: .ASCID "DEUNA" ; Strings for various devices DEV05: .ASCID "DEQNA" DEV11: .ASCID "DELUA" DEV17: .ASCID "LANCE" DEV23: .ASCID "DEBNA" DEV33: .ASCID "DS200" DEV35: .ASCID "DS500" DEV37: .ASCID "DELQA" DEV39: .ASCID "DESVA" DEV65: .ASCID "DEBNI" DEVNR: .ASCID "Noans" DEVUK: .ASCID "Unkwn" DEVMS: .ASCID "Misng" DEVDSC: .BLKQ ; General device name descriptor DEVID: .BLKB ; Device ID from SYSID response ; Buffers, variables, and strings for the time control of the program HOURS: .BLKB 1 ; Storage of requested input MINUTES:.BLKB 1 SECONDS:.BLKB 1 ; The following variable are for reading input from the user after prompting. INPSTRDSC: ; Input buffer descriptor .LONG 0 .ADDRESS INPSTR INPSTR: .BLKB 18 ; Input buffer INPSIZ: .BLKL 1 ; The prompts are defined next. RPRMT: .ASCID "Which monitor request would you like to make: " HPRMT: .ASCID "How many hours would you like to monitor: " MPRMT: .ASCID "How many minutes would you like to monitor: " SPRMT: .ASCID "How many seconds would you like to monitor: " GPRMT: .ASCID "Which group code would you like to monitor: " APRMT: .ASCID "Enter the address of the node (ex: AA-00-04-00-75-4C): " ; Input variables from prompts DSTADR: .BLKB 6 ; Address to look for GCODE: .BYTE 1 ; Group code to look for ENDTIM: .BLKQ 1 ; Time to end test TIME: .BLKQ 1 ; Temporary time buffer DTIME: .ASCID /0 !2ZB:!2ZB:!2ZB.00/ ; String for calculating delta time ; Miscellaneous variables GCBITS: .BLKB 32 ; Used for examining group codes RCVTRY: .BLKL 1 ; Counter for receive attempts IOSB: .BLKQ 1 ; I/O status block ; Device names DEVDSC1:.ASCID 'ETH' ; Units to use for test DEVDSC2:.ASCID 'ESA0' DEVDSC3:.ASCID 'XQA0' DEVDSC4:.ASCID 'ETA0' DEVDSC5:.ASCID 'XEA0' DEVDSC6:.ASCID 'EXA0' DEVDSC7:.ASCID 'EZA0' ; Table of pointers to device names DEVADR: .ADDRESS DEVDSC1 .ADDRESS DEVDSC2 .ADDRESS DEVDSC3 .ADDRESS DEVDSC4 .ADDRESS DEVDSC5 .ADDRESS DEVDSC6 .ADDRESS DEVDSC7 .LONG 0 ; Channels - one for LAT and one for Remote Console CHNLAT: .BLKL 1 CHNRMC: .BLKL 1 .ENTRY START,^M<> ; Assign both channels to the first device found which is available CLRL R5 ; Check each channel name to see if one 10$: TSTL DEVADR(R5) ; is available until one is found: the BEQL 30$ ; first name checked is "ETH", a dummy MOVL DEVADR(R5),R4 ; name which can be defined to the $ASSIGN_S- ; device desired if either: DEVNAM=(R4),- ; 1) An unregistered device is used CHAN=CHNLAT ; or 2) One device is prefered BLBS R0,20$ ; If success, assign the 2nd channel ADDL #4,R5 ; Skip to next device name CMPW R0,#SS$_NOSUCHDEV ; Was the error "no such device"? BEQL 10$ ; If yes, try next device name BRW ERROR ; Else, exit with error 20$: $ASSIGN_S- ; Assign the 2nd channel to the same DEVNAM=(R4),- ; device name CHAN=CHNRMC BLBS R0,ASSIGN_OK ; If success, continue BRW ERROR ; Else, exit with an error ; No device was found. 30$: BSBW BLANK ; No device was found, so say so and PUSHAB NDMSG ; then exit. CALLS #1,G^LIB$PUT_OUTPUT BRW EXIT ASSIGN_OK: ; Start up the first channel for examining LAV packets. $QIOW_S FUNC=#,- CHAN=CHNLAT,- IOSB=IOSB,- P2=#SETPARMDSC BLBS R0,START_REQ_OK1 BRW ERROR START_REQ_OK1: MOVZWL IOSB,R0 BLBS R0,START_IO_OK1 BRW ERROR START_IO_OK1: ; Start up the second channel for getting the device ID and name. $QIOW_S FUNC=#,- CHAN=CHNRMC,- IOSB=IOSB,- P2=#SIDPARMDSC BLBS R0,START_REQ_OK2 BRW ERROR START_REQ_OK2: MOVL IOSB,R0 BLBS R0,START_IO_OK2 BRW ERROR START_IO_OK2: ; Print program header BSBW BLANK PUSHAB HDRMSG1 CALLS #1,G^LIB$PUT_OUTPUT GET_TEST: ; Print the prompt that requests which monitor request the user wants. This ; is also the top of the loop that allows the user to make multiple monitor ; requests. BSBW BLANK PUSHAB INPMSG1 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG2 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG3 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG4 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG5 CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK ; Read the user's input to our prompt for the number of the test to run. MOVL #2,INPSTRDSC ; Set number of bytes to read PUSHAB INPSIZ ; Push input size parameter PUSHAB RPRMT ; Push prompt string parameter PUSHAB INPSTRDSC ; Push String descriptor parameter CALLS #3,G^LIB$GET_INPUT ; Read the user's input ; Convert the input to a test number. CLRL R1 ; Start with zero in test number CLRL R2 ; Clear # of input characters done 10$: CMPW R2,INPSIZ ; Have we processed all the input? BGEQU 20$ ; If EQL, yes MOVZBL INPSTR(R2),R0 ; Get an input character SUBL2 #^A/0/,R0 ; Convert to a digit MULL2 #^D10,R1 ; Shift current decimal digits ADDL2 R0,R1 ; Add new digit INCL R2 ; Bump # of input characters done BRB 10$ ; Check next character ; Clear the per-test global variables. 20$: CLRL DECCNT CLRL OTHCNT CLRB HOURS CLRB MINUTES CLRB SECONDS ; Now perform the appropriate test based on the test number. CMPL R1,#1 ; Check if test #1 BNEQ 30$ ; If NEQ, no BSBW TEST_1 ; Do test BRW GET_TEST ; Check for another test to run 30$: CMPL R1,#2 ; Check if test #2 BNEQ 40$ ; If NEQ, no BSBW TEST_2 ; Do test BRW GET_TEST ; Check for another test to run 40$: CMPL R1,#3 ; Check if test #3 BNEQ 50$ ; If NEQ, no BSBW TEST_3 ; Do test BRW GET_TEST ; Check for another test to run ; Not a supported test, so exit. 50$: BRW EXIT ; Not any of above, so exit ; Test #1 ; ; This test receives all LAT packets coming into the node where the program ; is run for a length of time requested by the user. The packets are ; examined, and if the address is the first occurance thereof, the packet ; is stored. After the set time is over, all packets stored (along with ; other information) are displayed. TEST_1: BSBW GET_TIME BSBW SET_TIME RCV_T1: BSBW RCV_LAT ; Get a message BLBS R0,10$ ; If we have a message, process it BRW PRINT_T1 ; Else time ran out, so print results ; Check/store the message based on whether it's a DECnet address or not. 10$: MOVZBL RCVBUF+12,R1 ; First store the group codes MOVC5 R1,RCVBUF+13,#0,- #^X20,GCBITS CMPL RCVSA,#^X000400AA ; Is this a DECnet address? BNEQ OTHER_T1 ; If NEQ, no, goto OTHER BRW DECNET_T1 ; Else goto DECNET ; Process packets from non-DECnet addresses. OTHER_T1: ; Check to see if the source address is already in the OTHER table. If so, ; throw it away and read another one. CLRL R1 ; Start counter at zero 10$: CMPL R1,OTHCNT ; Have we looked at all entries? BEQL 40$ ; If EQL, yes, so add to table MULL3 #^D38,R1,R2 ; Calc entry to check CMPL RCVSA,OTHTBL(R2) ; Source address match? BNEQ 20$ ; If NEQ, no, so check next entry CMPW RCVSA+4,OTHTBL+4(R2) ; Source address match? BEQL 30$ ; If EQL, yes, so ignore message 20$: INCL R1 ; Increment counter BRB 10$ ; Check next entry in table 30$: BRW RCV_T1 ; Get another message ; The address was not in the table, so add it if there's room. 40$: CMPL OTHCNT,#^D100 ; Is there room? BEQL 50$ ; If EQL, no, so ignore message MULL3 #^D38,OTHCNT,R2 ; Calc where to store entry MOVL RCVSA,OTHTBL(R2) ; Store SA MOVW RCVSA+4,OTHTBL+4(R2) ; Store SA MOVO GCBITS+00,OTHTBL+06(R2) ; Store group code mask MOVO GCBITS+08,OTHTBL+14(R2) ; Store group code mask MOVO GCBITS+16,OTHTBL+22(R2) ; Store group code mask MOVO GCBITS+24,OTHTBL+30(R2) ; Store group code mask INCL OTHCNT ; Bump number of used entries 50$: BRW RCV_T1 ; Process packets from DECnet addresses. DECNET_T1: ; Check to see if the source address is already in the DECNET table. If so, ; throw it away and read another one. CLRL R1 ; Start counter at zero 10$: CMPL R1,DECCNT ; Have we looked at all entries? BEQL 40$ ; If EQL, yes, so add to table MULL3 #^D34,R1,R2 ; Calc entry to check CMPL RCVSA,DECTBL(R2) ; Source address match? BNEQ 20$ ; If NEQ, no, so check next entry CMPW RCVSA+4,DECTBL+4(R2) ; Source address match? BEQL 30$ ; If EQL, yes, so ignore message 20$: INCL R1 ; Increment counter BRB 10$ ; Check next entry in table 30$: BRW RCV_T1 ; Get another message ; The address was not in the table, so add it if there's room. 40$: CMPL DECCNT,#^D1000 ; Is there room? BEQL 50$ ; If EQL, no, so ignore message MULL3 #^D34,DECCNT,R2 ; Calc where to store entry MOVW RCVSA+4,DECTBL(R2) ; Store SA MOVO GCBITS+00,DECTBL+02(R2) ; Store group code mask MOVO GCBITS+08,DECTBL+10(R2) ; Store group code mask MOVO GCBITS+16,DECTBL+18(R2) ; Store group code mask MOVO GCBITS+24,DECTBL+26(R2) ; Store group code mask INCL DECCNT ; Bump number of used entries 50$: BRW RCV_T1 PRINT_T1: ; If we have no data, then print appropriate message. TSTL DECCNT ; Anything in DECNET table? BNEQ PRINT_DEC_T1 ; If NEQ, yes, so print them TSTL OTHCNT ; Anything in OTHER table? BNEQ PRINT_DEC_T1 ; If NEQ, yes, so print them ; Print "no messages found" message. BSBW BLANK PUSHAB M1NONE CALLS #1,G^LIB$PUT_OUTPUT RSB PRINT_DEC_T1: ; First print out all nodes in the DECnet table DECL DECCNT 10$: MULL3 #^D34,DECCNT,R2 TSTL DECCNT BGEQ 20$ BRW PRINT_OTH_T1 20$: DECL DECCNT BSBW BLANK MOVL #^X000400AA,SIDADDR MOVW DECTBL(R2),SIDADDR+4 BSBW GET_DEVID MOVW DECTBL(R2),R0 BICW #^XFC00,R0 MOVZBL DECTBL+1(R2),R1 ASHL #-2,R1,R3 MOVL #80,FAOLEN $FAO_S CTRSTR=M1ALL1,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DECTBL(R2),- P2=DECTBL+1(R2),- P3=DEVID,- P4=#DEVDSC,- P5=R3,- P6=R0 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M1MASK CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M1BIT1,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DECTBL+9(R2),- P2=DECTBL+8(R2),- P3=DECTBL+7(R2),- P4=DECTBL+6(R2),- P5=DECTBL+5(R2),- P6=DECTBL+4(R2),- P7=DECTBL+3(R2),- P8=DECTBL+2(R2) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M1BIT2,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DECTBL+17(R2),- P2=DECTBL+16(R2),- P3=DECTBL+15(R2),- P4=DECTBL+14(R2),- P5=DECTBL+13(R2),- P6=DECTBL+12(R2),- P7=DECTBL+11(R2),- P8=DECTBL+10(R2) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M1BIT3,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DECTBL+25(R2),- P2=DECTBL+24(R2),- P3=DECTBL+23(R2),- P4=DECTBL+22(R2),- P5=DECTBL+21(R2),- P6=DECTBL+20(R2),- P7=DECTBL+19(R2),- P8=DECTBL+18(R2) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M1BIT4,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DECTBL+33(R2),- P2=DECTBL+32(R2),- P3=DECTBL+31(R2),- P4=DECTBL+30(R2),- P5=DECTBL+29(R2),- P6=DECTBL+28(R2),- P7=DECTBL+27(R2),- P8=DECTBL+26(R2) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT BRW 10$ ; Now print out the data for any non-DECnet nodes PRINT_OTH_T1: DECL OTHCNT 10$: MULL3 #^D38,OTHCNT,R2 TSTL OTHCNT BGEQ 20$ RSB 20$: DECL OTHCNT BSBW BLANK MOVL OTHTBL(R2),SIDADDR MOVW OTHTBL+4(R2),SIDADDR+4 BSBW GET_DEVID MOVL #80,FAOLEN $FAO_S CTRSTR=M1ALL2,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=OTHTBL(R2),- P2=OTHTBL+1(R2),- P3=OTHTBL+2(R2),- P4=OTHTBL+3(R2),- P5=OTHTBL+4(R2),- P6=OTHTBL+5(R2),- P7=DEVID,- P8=#DEVDSC PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M1MASK CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M1BIT1,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=OTHTBL+13(R2),- P2=OTHTBL+12(R2),- P3=OTHTBL+11(R2),- P4=OTHTBL+10(R2),- P5=OTHTBL+9(R2),- P6=OTHTBL+8(R2),- P7=OTHTBL+7(R2),- P8=OTHTBL+6(R2) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M1BIT2,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=OTHTBL+21(R2),- P2=OTHTBL+20(R2),- P3=OTHTBL+19(R2),- P4=OTHTBL+18(R2),- P5=OTHTBL+17(R2),- P6=OTHTBL+16(R2),- P7=OTHTBL+15(R2),- P8=OTHTBL+14(R2) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M1BIT3,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=OTHTBL+29(R2),- P2=OTHTBL+28(R2),- P3=OTHTBL+27(R2),- P4=OTHTBL+26(R2),- P5=OTHTBL+25(R2),- P6=OTHTBL+24(R2),- P7=OTHTBL+23(R2),- P8=OTHTBL+22(R2) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M1BIT4,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=OTHTBL+37(R2),- P2=OTHTBL+36(R2),- P3=OTHTBL+35(R2),- P4=OTHTBL+34(R2),- P5=OTHTBL+33(R2),- P6=OTHTBL+32(R2),- P7=OTHTBL+31(R2),- P8=OTHTBL+30(R2) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT BRW 10$ ; Test #2 ; ; This test asks the user for both a length of time to run the test for and ; a group code to watch for. Once the end time has been reached, the addresses ; of all nodes received with the specific group code enabled are printed. TEST_2: BSBW GET_TIME BSBW BLANK BSBW GET_GCODE BSBW SET_TIME RCV_T2: BSBW RCV_LAT ; Get a message BLBS R0,10$ ; If we have a message, process it BRW PRINT_T2 ; Else time ran out, so print results ; First check if the appropriate group code is set in this message. 10$: MOVZBL RCVBUF+12,R1 ; Get group code length MOVC5 R1,RCVBUF+13,#0,- ; Copy (with zero extend) into #^X20,GCBITS ; a fixed place MOVZBL GCODE,R1 ; Get requested group code CLRL R0 ; To calc group code bit number, CLRL R2 ; start with 0 in R0 and R2 EDIV #8,R1,R0,R2 ; R0=byte to check in the bit mask ; R2=bit to check in that byte BBS R2,GCBITS(R0),20$ ; If group code enabled, continue BRW RCV_T2 ; Else, ignore message ; Store the message based on whether it's a DECnet address or not. 20$: CMPL RCVSA,#^X000400AA ; Is this a DECnet address? BNEQ OTHER_T2 ; If NEQ, no, goto OTHER BRW DECNET_T2 ; Else goto DECNET ; Process packets from non-DECnet addresses. OTHER_T2: ; Check to see if the source address is already in the OTHER table. If so, ; throw it away and read another one. CLRL R1 ; Start counter at zero 10$: CMPL R1,OTHCNT ; Have we looked at all entries? BEQL 40$ ; If EQL, yes, so add to table MULL3 #6,R1,R2 ; Calc entry to check CMPL RCVSA,OTHTBL(R2) ; Source address match? BNEQ 20$ ; If NEQ, no, so check next entry CMPW RCVSA+4,OTHTBL+4(R2) ; Source address match? BEQL 30$ ; If EQL, yes, so ignore message 20$: INCL R1 ; Increment counter BRB 10$ ; Check next entry in table 30$: BRW RCV_T2 ; Get another message ; The address was not in the table, so add it if there's room. 40$: CMPL OTHCNT,#^D633 ; Is there room? BEQL 50$ ; If EQL, no, so ignore message MULL3 #6,OTHCNT,R2 ; Calc where to store entry MOVL RCVSA,OTHTBL(R2) ; Store SA MOVW RCVSA+4,OTHTBL+4(R2) ; Store SA INCL OTHCNT ; Bump number of used entries 50$: BRW RCV_T2 ; Process packets from DECnet addresses. DECNET_T2: ; Check to see if the source address is already in the DECNET table. If so, ; throw it away and read another one. CLRL R1 ; Start counter at zero 10$: CMPL R1,DECCNT ; Have we looked at all entries? BEQL 40$ ; If EQL, yes, so add to table MULL3 #2,R1,R2 ; Calc entry to check CMPW RCVSA+4,DECTBL(R2) ; Source address match (2 bytes)? BEQL 30$ ; If EQL, yes, so ignore message 20$: INCL R1 ; Increment counter BRB 10$ ; Check next entry in table 30$: BRW RCV_T2 ; Get another message ; The address was not in the table, so add it if there's room. 40$: CMPL DECCNT,#^D17000 ; Is there room? BEQL 50$ ; If EQL, no, so ignore message MULL3 #2,DECCNT,R2 ; Calc where to store entry MOVW RCVSA+4,DECTBL(R2) ; Store SA INCL DECCNT ; Bump number of used entries 50$: BRW RCV_T2 PRINT_T2: ; If we have no data, then print appropriate message. TSTL DECCNT ; Anything in DECNET table? BNEQ 10$ ; If NEQ, yes, so print them TSTL OTHCNT ; Anything in OTHER table? BNEQ 10$ ; If NEQ, yes, so print them ; Print "no messages found" message. BSBW BLANK MOVL #80,FAOLEN $FAO_S CTRSTR=M2NONE,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=GCODE PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT RSB ; Some nodes were found, print the header. 10$: BSBW BLANK MOVL #80,FAOLEN $FAO_S CTRSTR=M2HDR0,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=GCODE PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT PRINT_DEC_T2: MOVZWL DECCNT,R10 ; Save original node count 10$: TSTL DECCNT BGTR 20$ BRW PRINT_OTH_T2 ; Find the smallest node. We will print this list in order. 20$: MOVAL DECTBL,R2 ; Assume the first entry is smallest MOVAL DECTBL+2,R9 ; This is the first place to compare SUBL3 #1,R10,R8 ; Number of slots to compare 30$: TSTL R8 ; Any left to compare? BEQL 70$ ; Br if not TSTW (R9) ; Is there an address here? BEQL 60$ ; Br if not TSTW (R2) ; Do we have an address yet? BEQL 50$ ; Br if not CMPW (R9),(R2) ; Is the new one smaller? BGEQU 60$ ; Br if not, else ... 50$: MOVL R9,R2 ; Copy current entry into R2 and ; continue the search 60$: ADDL #2,R9 ; Skip to next address DECL R8 ; One less address to compare BRB 30$ ; Check next entry 70$: MOVL #^X000400AA,SIDADDR MOVW (R2),SIDADDR+4 BSBW GET_DEVID MOVW (R2),R0 BICW #^XFC00,R0 MOVZBL 1(R2),R1 ASHL #-2,R1,R3 MOVL #80,FAOLEN $FAO_S CTRSTR=M2ALL1,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=(R2),- P2=1(R2),- P3=DEVID,- P4=#DEVDSC,- P5=R3,- P6=R0 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT DECL DECCNT CLRW (R2) BRW 10$ ; Now print out the data for any other nodes found. PRINT_OTH_T2: DECL OTHCNT 10$: MULL3 #6,OTHCNT,R2 TSTL OTHCNT BGEQ 20$ RSB 20$: DECL OTHCNT MOVL OTHTBL(R2),SIDADDR MOVW OTHTBL+4(R2),SIDADDR+4 BSBW GET_DEVID MOVL #80,FAOLEN $FAO_S CTRSTR=M2ALL2,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=OTHTBL(R2),- P2=OTHTBL+1(R2),- P3=OTHTBL+2(R2),- P4=OTHTBL+3(R2),- P5=OTHTBL+4(R2),- P6=OTHTBL+5(R2),- P7=DEVID,- P8=#DEVDSC PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT BRB 10$ ; Test #3 ; ; This test asks the user for one address, and waits for a message from that ; address. Once a message from that address is found, a listing of all group ; codes enabled is given. TEST_3: ; Start the test; continue until the end time is reached. BSBW GET_TIME BSBW BLANK BSBW GET_ADDR BSBW SET_TIME RCV_T3: BSBW RCV_LAT ; Get a message BLBS R0,10$ ; If we have a message, process it ; Print "no messages found" message. BSBW BLANK MOVL #80,FAOLEN $FAO_S CTRSTR=M3NONE,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DSTADR,- P2=DSTADR+1,- P3=DSTADR+2,- P4=DSTADR+3,- P5=DSTADR+4,- P6=DSTADR+5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT RSB ; Check if the source address is the desired one. 10$: MOVZBL RCVBUF+12,R1 MOVC5 R1,RCVBUF+13,#0,#^X20,GCBITS CMPC3 #6,RCVSA,DSTADR BNEQ RCV_T3 ; The address was the desired one, so print the results PRINT_T3: ; Print the address. BSBW BLANK MOVL #80,FAOLEN $FAO_S CTRSTR=M3ADDR,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=RCVSA,- P2=RCVSA+1,- P3=RCVSA+2,- P4=RCVSA+3,- P5=RCVSA+4,- P6=RCVSA+5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print the DECnet node if this is a DECnet address CMPL #^X000400AA,RCVSA ; Is this a DECnet address? BNEQ 1$ ; If NEQ, no MOVW RCVSA+4,R0 BICW #^XFC00,R0 MOVZBL RCVSA+5,R3 ASHL #-2,R3,R3 MOVL #80,FAOLEN $FAO_S CTRSTR=M3NODE,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R3,- P2=R0 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print the device ID and device name. 1$: MOVL DSTADR,SIDADDR MOVW DSTADR+4,SIDADDR+4 BSBW GET_DEVID MOVL #80,FAOLEN $FAO_S CTRSTR=M3CONT,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DEVID,- P2=#DEVDSC PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print the node name if there is one. MOVZBL RCVBUF+12,R1 ; Get size of group code bits ADDL3 #^D13,R1,R4 ; Offset to node name size MOVAL RCVBUF+1,R5 ; Calc address of string ADDL R4,R5 ; Address of string MOVZBL RCVBUF(R4),R3 ; Get size BEQL 10$ ; If EQL, none to print MOVL #80,FAOLEN $FAO_S CTRSTR=M3IDN1,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R3,- P2=R5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print the node descriptor if there is one. 10$: ADDL R3,R5 ; Address of size MOVZBL (R5)+,R3 ; Get size BEQL 20$ ; If EQL, none to print MOVL #80,FAOLEN $FAO_S CTRSTR=M3IDN2,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R3,- P2=R5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print each service set. 20$: ADDL R3,R5 ; Address of number of sets MOVZBL (R5)+,R6 ; Get number of sets BEQL 60$ ; Branch if none CLRL R3 ; Nothing to skip right now ; Print the service name if there is one. 30$: INCL R5 ; Skip service rating ADDL R3,R5 ; Address of size MOVZBL (R5)+,R3 ; Get size BEQL 40$ ; If EQL, none to print MOVL #80,FAOLEN $FAO_S CTRSTR=M3IDN3,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R3,- P2=R5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print the service descriptor if there is one. 40$: ADDL R3,R5 ; Address of size MOVZBL (R5)+,R3 ; Get size BEQL 50$ ; If EQL, none to print MOVL #80,FAOLEN $FAO_S CTRSTR=M3IDN4,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R3,- P2=R5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; If more service sets, print them. 50$: SOBGTR R6,30$ ; Print the group code header. 60$: PUSHAB M3HDR1 CALLS #1,G^LIB$PUT_OUTPUT ; Print all the enabled group code's. CLRL R1 70$: CLRL R0 CLRL R2 EDIV #8,R1,R0,R2 BBC R2,GCBITS(R0),80$ PUSHL R1 MOVL #80,FAOLEN $FAO_S CTRSTR=M3GCOD,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R1 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT POPL R1 80$: INCL R1 CMPL R1,#^D256 BLSS 70$ RSB RCV_LAT: ; Read a LAT multicast service announcement frame. Return if time has run ; out (R0=0) or if a frame was received successfully (R0=1). ; First check if time has run out. $GETTIM_S- ; Get current time TIMADR=TIME CMPL TIME+4,ENDTIM+4 ; Did we look long enough? BEQL 10$ ; If equal, need to check low longword BLSSU 30$ ; If LSSU, continue BRB 20$ ; Else end search for the node 10$: CMPL TIME,ENDTIM ; Check low longword BLSSU 30$ ; If LSSU, continue 20$: CLRL R0 ; Say that time ran out RSB 30$: $QIOW_S FUNC=#IO$_READVBLK!IO$M_NOW,- CHAN=CHNLAT,- IOSB=IOSB,- P1=RCVBUF,- P2=#RCVBUFLEN,- P5=#RCVP5 BLBS R0,RCV_REQ_OK BRW ERROR RCV_REQ_OK: MOVZWL IOSB,R0 BLBS R0,RCV_IO_OK CMPW R0,#SS$_ENDOFFILE BEQL RCV_LAT BRW ERROR RCV_IO_OK: ; Check if this is a multicast message. If not, throw it away and look for ; another message. BLBC RCVDA,RCV_LAT ; Ignore packet if sent to physical ; Make sure this is a service announcement message. If not, throw it away ; and look for another message. CMPB #^X28,RCVBUF ; Is this a service announcement? BNEQ RCV_LAT ; If NEQ, no, try again ; The message is good, return success MOVZBL #1,R0 RSB GET_DEVID: ; Get the node's device ID and device name. This is done by requesting a ; SYSID message from the node. The response (if any) contains the device ; ID. From the device ID, we will select the correct device name. Upon ; completion of this routine, DEVID (a byte) will have the device ID and ; DEVDSC will point to the device name. ; Transmit the request ID message to the node we want to find out about. $QIOW_S FUNC=#IO$_WRITEVBLK,- CHAN=CHNRMC,- IOSB=IOSB,- P1=XMTP2BUF,- P2=#XMTP2LEN,- P5=#SIDADDR BLBS R0,DXMT_REQ_OK BRW ERROR DXMT_REQ_OK: MOVL IOSB,R0 BLBS R0,DXMT_IO_OK BRW ERROR DXMT_IO_OK: ; Receive the SYSID response. If there is no data ready to receive, then the ; Ethernet driver will return immediately with SS$_ENDOFFILE. CLRL RCVTRY ; Clear the number of read attempts DRCV: $QIOW_S FUNC=#IO$_READVBLK!IO$M_NOW,- CHAN=CHNRMC,- IOSB=IOSB,- P1=RCVBUF2,- P2=#RCVBUFLEN2,- P5=#RCVP52 BLBS R0,DRCV_REQ_OK BRW ERROR DRCV_REQ_OK: MOVL IOSB,R0 BLBS R0,DRCV_IO_OK CMPW IOSB,#SS$_ENDOFFILE BEQL DRCV_TRY BRW ERROR DRCV_TRY: CMPL RCVTRY,#4000 ; Have we tried enough times? BGTR 20$ ; If GTR, yes, so message is lost INCL RCVTRY ; Count this attempt BRB DRCV ; Try again 20$: CLRB DEVID ; Clear the Device ID number MOVQ DEVNR,DEVDSC ; Set the device name to no response RSB ; Return to caller DRCV_IO_OK: ; Check that this is a SYSTEM ID message from the correct node. CMPB RCVBUF2,#7 ; Is this a SYSTEM ID message? BNEQ DRCV_TRY ; If NEQ, no, try again CMPL RCVSA2,SIDADDR ; Correct node? BNEQ DRCV_TRY ; If NEQ, no CMPW RCVSA2+4,SIDADDR+4 ; Correct node? BNEQ DRCV_TRY ; If NEQ, no ; We received a message from the remote node. Look for the Device ID entry ; in this SYSID message. MOVL #4,R3 ; Skip over SYSID header ; Loop through the entries in the SYSID looking for the Device ID entry. 10$: CMPW R3,IOSB+2 ; Any buffer left to look at? BLSSU 20$ ; If LSSU, yes, so look for more BRW 130$ ; Else report Device ID missing 20$: CMPW RCVBUF2(R3),#^D100 ; Is this the device ID entry? BEQL 30$ ; If EQL, yes MOVZBL RCVBUF2+2(R3),R1 ; Get size of this entry ADDL #3,R3 ; Skip over entry type and size ADDL R1,R3 ; Skip over entry value BRW 10$ ; Check next entry ; The Device ID was found. Store the Device ID and select a device name. 30$: ADDL #3,R3 ; Skip over Device ID header MOVB RCVBUF2(R3),DEVID ; Store the Device ID CMPB DEVID,#^D01 ; Is this Device 1? BNEQ 40$ ; Branch if not MOVQ DEV01,DEVDSC ; Store Device Name for ID 1 BRW 140$ ; Exit 40$: CMPB DEVID,#^D05 BNEQ 50$ MOVQ DEV05,DEVDSC BRW 140$ 50$: CMPB DEVID,#^D11 BNEQ 60$ MOVQ DEV11,DEVDSC BRW 140$ 60$: CMPB DEVID,#^D17 BNEQ 70$ MOVQ DEV17,DEVDSC BRB 140$ 70$: CMPB DEVID,#^D23 BNEQ 80$ MOVQ DEV23,DEVDSC BRB 140$ 80$: CMPB DEVID,#^D39 BNEQ 90$ MOVQ DEV39,DEVDSC BRB 140$ 90$: CMPB DEVID,#^D33 BNEQ 100$ MOVQ DEV33,DEVDSC BRB 140$ 100$: CMPB DEVID,#^D35 BNEQ 110$ MOVQ DEV35,DEVDSC BRB 140$ 110$: CMPB DEVID,#^D37 BNEQ 115$ MOVQ DEV37,DEVDSC BRB 140$ 115$: CMPB DEVID,#^D65 BNEQ 120$ MOVQ DEV65,DEVDSC BRB 140$ 120$: MOVQ DEVUK,DEVDSC ; This is an unknown device BRB 140$ 130$: CLRB DEVID ; No Device ID was found MOVQ DEVMS,DEVDSC ; Device ID is missing 140$: RSB GET_GCODE: ; Get group code to watch for MOVL #18,INPSTRDSC PUSHAB INPSIZ PUSHAB GPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert group code CLRL R1 CLRW R2 10$: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS 10$ MOVB R1,GCODE RSB GET_ADDR: ; Get the address to look for from the user. MOVL #18,INPSTRDSC ; Maximum input size is 18 bytes PUSHAB INPSIZ ; Place to store # of bytes entered PUSHAB APRMT ; Prompt to display PUSHAB INPSTRDSC ; Place to store input string CALLS #3,G^LIB$GET_INPUT CLRL R1 ; Index to next input character CLRL R3 ; Index to next address byte ; Get the first digit of the next address byte. 10$: MOVZBL INPSTR(R1),R0 ; Get next input character INCL R1 ; Bump input character index CMPB R0,#^A/A/ ; Is this a letter or greater? BGEQU 20$ ; If GEQU, yes, so branch SUBL3 #^A/0/,R0,R2 ; Convert digit character to digit BRB 30$ ; Get the next input character 20$: SUBL2 #^A/A/,R0 ; Convert letter character to digit ADDL3 #^D10,R0,R2 ; Add ten to have correct digit ; Get the second digit of the next address byte. 30$: MULL2 #^D16,R2 ; Put the first digit into its place MOVZBL INPSTR(R1),R0 ; Get next input character INCL R1 ; Bump input character index CMPB R0,#^A/A/ ; Is this a letter or greater? BGEQU 40$ ; If GEQU, yes, so branch SUBL2 #^A/0/,R0 ; Convert digit character to digit BRB 50$ ; Go to add the second digit 40$: SUBL2 #^A/A/,R0 ; Convert letter character to digit ADDL2 #^D10,R0 ; Add ten to have correct digit 50$: ADDL R0,R2 ; Add lower digit to address ; Store this address byte and see if we need to do more. MOVB R2,DSTADR(R3) ; Store this address byte INCL R3 ; Bump to next address byte CMPL R3,#^D06 ; Have we processed 6 bytes? BLSS 60$ ; Branch if not, more to do RSB ; Else return to caller 60$: INCL R1 ; Skip over "-" in input string BRW 10$ ; Do next address byte GET_TIME: ; Get number of hours to run test for GET_HOUR: BSBW BLANK MOVL #6,INPSTRDSC PUSHAB INPSIZ PUSHAB HPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert number of hours CLRL R1 CLRW R2 NUM_LOOP2: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS NUM_LOOP2 CMPL R1,#^D23 BGTR GET_HOUR MOVL R1,HOURS ; Get number of minutes to run test for GET_MINUTE: MOVL #6,INPSTRDSC PUSHAB INPSIZ PUSHAB MPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert number of minutes CLRL R1 CLRW R2 NUM_LOOP3: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS NUM_LOOP3 CMPL R1,#^D59 BGTR GET_MINUTE MOVL R1,MINUTES ; Get number of seconds to run test for GET_SECOND: MOVL #6,INPSTRDSC PUSHAB INPSIZ PUSHAB SPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert number of seconds CLRL R1 CLRW R2 NUM_LOOP4: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS NUM_LOOP4 CMPL R1,#^D59 BGTR GET_SECOND MOVL R1,SECONDS RSB SET_TIME: ; Determine the time to stop the test ; Now put the total time into one string MOVL #80,FAOLEN $FAO_S CTRSTR=DTIME,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=HOURS,- P2=MINUTES,- P3=SECONDS ; Change the ASCII string for the time to a quadword value. $BINTIM_S- TIMBUF=FAODESC,- TIMADR=TIME MNEGL TIME+4,TIME+4 MNEGL TIME,TIME SBWC #0,TIME+4 ; Now get the present time and add the test time to get the end time. $GETTIM_S- TIMADR=ENDTIM ADDL TIME,ENDTIM ADWC TIME+4,ENDTIM+4 RSB EXIT: BSBW BLANK PUSHAB DNEMSG CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK $DASSGN_S- CHAN=CHNLAT $DASSGN_S- CHAN=CHNRMC $EXIT_S BLANK: ; Print blank line PUSHAB BLNKMSG CALLS #1,G^LIB$PUT_OUTPUT RSB ; An error has occured, so print R0 value and 2nd longword of IOSB. ERROR: PUSHL R0 ; Pass R0 error code CALLS #1,RBL$ERCODE ; Print error code ; Print IOSB 2nd longword value in hex MOVL #80,FAOLEN $FAO_S CTRSTR=IOMSG,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=IOSB+4 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT BRW EXIT ; Now exit normally .PAGE ; RBL$ERCODE ; ; This subroutine accepts a VMS error code in binary ; and print the message on the terminal. ; ; INPUT: 4(AP) = Error Code ; ; OUTPUT: all registers saved except R0 and R1 ; ; CALLING SEQ: PUSHx error code ; CALL_S #1,RBL$ERCODE ; .ENTRY RBL$ERCODE,^M MOVL 4(AP),R3 ; Get error code $GETMSG_S- ; Convert error code to message MSGID=R3,- MSGLEN=ERRMSG_LEN,- BUFADR=ERRMSG_BUF_DESC PUSHAB ERRMSG_BUF_DESC CALLS #1,G^LIB$PUT_OUTPUT RET ; Return to caller ; Structures used to build error message from error code ERRMSG_BUF_DESC: ERRMSG_LEN: .LONG 256 .ADDRESS- ERRMSG_BUF ERRMSG_BUF: .BLKB 256 ; Tables for addresses already found OTHCNT: .LONG 0 OTHTBL: .BLKB 100*38 ; Maximum of 100 DECnet nodes DECCNT: .LONG 0 DECTBL: .BLKB 1000*34 ; Maximum of 1000 DECnet nodes .END START