.title latwatch .ident "X5-005" ;+ ; Version: X5-005 ; ; Facility: Diagnostic Utilities. ; ; Abstract: This is similar to ETHERWATCH but will only process LAT ; protocol messages. ; ; Environment: PHY_IO privilege is needed. ; ; The following is the CLD used in LATWATCH: ; ; module latwatch_cld ; ; define verb latwatch ; noparameters ; qualifier debug ; qualifier device, value (required) ; qualifier display, default, value (type = display_options) ; qualifier both ; qualifier from, default, value (default = "*") ; qualifier to, default, value (default = "*") ; qualifier message_type, default, value (list, type = message_options) ; qualifier nonames ; qualifier begin, value (required, type = $datetime) ; qualifier end, value (required, type = $datetime) ; qualifier count, value (required, type = $number) ; qualifier output, ; value (type = $outfile, default = "LATWATCH.LOG") ; qualifier record, ; value (type = $outfile, default = "LATWATCH.RECORD") ; qualifier playback, ; value (type = $infile, default = "LATWATCH.RECORD") ; ; disallow (end and count) ; disallow (record and playback) ; disallow (playback and (begin or end)) ; ; define type display_options ; keyword all ; keyword both ; keyword none ; keyword ascii, default ; keyword text ; keyword hexadecimal ; keyword fast ; ; define type message_options ; keyword all, default ; keyword run_message ; keyword type0 ; keyword start_message ; keyword type1 ; keyword stop_message ; keyword type2 ; keyword type3 ; keyword type4 ; keyword type5 ; keyword type6 ; keyword type7 ; keyword type8 ; keyword type9 ; keyword command_message ; keyword type10 ; keyword type11 ; keyword status_message ; keyword type12 ; keyword service_info ; keyword type13 ; keyword solicit_info ; keyword type14 ; keyword response_info ; keyword type15 ; keyword unknown ; ; History: ; ; 02-Apr-1990, DBS; Version X1-001 ; 001 - Original version. Based on ETHUTIL by Mark Myers of the University ; of Melbourne. ; 02-Apr-1990, DBS; Version X1-002 ; 002 - Added code to handle /both, /from and /to. ; 03-Apr-1990, DBS; Version X1-003 ; 003 - Added code for the /unkown qualifier and changed the code that matches ; the addresses to nodenames. ; 09-Apr-1990, DBS; Version X1-004 ; 004 - Fix to pick up the value returned in the iosb when starting up the ; device. ; 11-Apr-1990, DBS; Version X1-005 ; 005 - Use for_signal/stop to handle errors. ; 23-May-1990, DBS; Version X1-006 ; 006 - Added code to unpack LAT messages. ; 05-Jun-1990, DBS; Version X1-007 ; 007 - Modified to always do the LAT format on LAT messages. ; 06-Jun-1990, DBS; Version X1-008 ; 008 - Added more specific lat packet processing. ; ; 07-Jun-1990, DBS; Version X2-001 ; 001 - Major rehash for lat processing. ; Became LATWATCH about this time... ; 15-Jun-1990, DBS; Version X2-002 ; 002 - Changed the format of the ascii/hex displays. ; 15-Jun-1990, DBS; Version X2-003 ; 003 - Cleanup time... ; ; 27-Jun-1990, DBS; Version X3-001 ; 001 - Added wildcard matching on addresses and protocols. ; 09-Jul-1990, DBS; Version X3-002 ; 002 - Added a control C trap so we can exit cleanly. ; 20-Nov-1991, DBS; Version X3-003 ; 003 - Added call to sys_find_ether_device to establish default. ; 17-Jan-1992, DBS; Version X3-004 ; 004 - Added software expiry check. ; ; 08-Jan-1993, DBS; Version X4-001 ; 001 - Major rehash to change the qualifiers so source and destination ; addresses can be specified. ; 08-Oct-1993, DBS; Version X4-002 ; 002 - Added reason descriptions for stop messages. ; 11-Oct-1993, DBS; Version X4-003 ; 003 - Fixed bug with header size and first six bytes of packet data being ; overwritten. ; 11-Oct-1993, DBS; Version X4-004 ; 004 - Added /message_type qualifier. ; ; 01-Aug-1994, DBS; Version X5-001 ; 001 - Major rewrite in Macro (this one stolen from ETHERWATCH and the LAT ; stuff put in). ; 03-Aug-1994, DBS; Version X5-002 ; 002 - Fixed a bug with the CLD specifications. ; 15-Aug-1994, DBS; Version X5-003 ; 003 - Added /BEGIN and /END to specify run times and /COUNT to allow ; termination after processing a specified number of LAT packets. ; Added /RECORD qualifier to dump raw data to a file for later playback ; and of course /PLAYBACK to look at the recorded data. ; Added /OUTPUT qualifier (long overdue). ; 23-Aug-1994, DBS; Version X5-004 ; 004 - Made /RECORD imply /NONAMES - waste of time while recording. ; 21-Oct-1994, DBS; Version X5-005 ; 005 - Fixed bug that reported the buffer size incorrectly on /PLAYBACK. ;- .subtitle Psect definitions, external definitions .library "SYS$LIBRARY:LIB.MLB" .library "SYS$LIBRARY:STARLET.MLB" .library "DBSLIBRARY:SYS_MACROS.MLB" .link "SYS$SYSTEM:SYS.STB" /selective_search .disable global .external cli$dcl_parse .external cli$get_value .external cli$present .external lan_format_header .external lan_startup_prm .external latwatch_cld .external lib$free_vm .external lib$get_foreign .external lib$get_vm .external lib$init_timer .external lib$lookup_key .external lib$show_timer .external lib$show_vm .external lib$signal .external lib$stop .external lib_cvt_t_l .external lib_output_seg_t .external lib_output_seg_tzb .external lib_output_seg_zb .external str$match_wild .external str_collapse .external str_len .external str_uppercase .external sys_find_ether_device .external sys_trap_controlc enb_long ; for structured macro stuff _landef _lanhdrdef $clidef $climsgdef $fabdef $iodef $latdef $lnmdef $psldef $rabdef $rmsdef $ssdef $stsdef def_psect _util_data, type=DATA, alignment=LONG def_psect _util_code, type=CODE, alignment=LONG .subtitle Local macros ; .macro IF_PRESENT ; All we do here is set bits in cli_defaulted and cli_present to indicate ; which qualifiers were used and whether or not they used the default. ; This information is used later for matching packet information against ; what the user wants to see. .macro if_present item call cli$present cli_'item if then bisl #m_'item, cli_defaulted else if then bisl #m_'item, cli_supplied endif endif .endm if_present .macro vector location, value .address location .long value .endm vector .macro pad location bicl3 #^XFFFFFFFE, location, r0 addl2 r0, location .endm pad .macro init_item location movab location, r3 .endm init_item .macro item description movab description, r2 call display_desc_ascic .endm item .subtitle Impure data areas set_psect _util_data program_id: .ascid "LATWATCH X5-005" loaded_fao: .ascid "!UL names and addresses were loaded" intro_line1: .ascid "Starting a watch on device !AS" intro_line2: .ascid "LAT packets from !AS [!AS] to !AS [!AS]!/"- "Message type is !AS, Display option is !AS" playing_back: .ascid "Reading recorded data from !AS" display_header: .ascid "!78*-!/From !AS [!AC] to !AS [!AC]"- "!/ !4UW byte buffer at !%D" virt_circ_hdr: .ascid "!28AC Dest !XW, Source !XW, !UB slot!%S,"- " Seq/Ack !UB/!UB!/!AC, !AC" start_message: .ascid " Protocol Version V!UB.!UB, Product !UB V!UB, "- "Facility !XW, Circuit Timer !UBms!/"- " Keep Alive Timer !UB, MinRcvDGsize !UW, "- "MaxSimSlots !UB, DataLinkBuffs !UB" stop_message: .ascid " Circuit disconnect (!XB)" command_message:.ascid "Command Message !30<!> "- "Command type !UB, modifier !UB!/"- " Protocol format !UB, Current protocol V!UB.!UB"- ", High version !UB, Low version !UB!/"- " Datalink receive frame size !UW, Request ID !UW"- ", Entry ID !UW" status_message:.ascid "Status Message, Protocol format !UB, "- "Current protocol V!UB.!UB, High V!UB, Low V!UB!/"- " Datalink receive frame size !UW, "- "Retransmit Timer !UW"- ", Entry count !UW" solicit_message:.ascid "Solicit Information, Protocol format !UB, "- "Current protocol V!UB.!UB, High V!UB, Low V!UB!/"- " Datalink receive frame size !UW, "- "Solicit identifier !UW"- ", Response timer !UW" response_message:.ascid "Response Information, Protocol format !UB, "- "Current protocol V!UB.!UB, High V!UB, Low V!UB!/"- " Datalink receive frame size !UW, "- "Solicit identifier !UW!/"- " Response status !XW, Source status !XW!/"- " Source node address !XB-!XB-!XB-!XB-!XB-!XB, "- "Multicast timer !UW" service_message:.ascid "Service Announcement, Circ Timer !UBms, "- "Current protocol V!UB.!UB, High V!UB, Low V!UB!/"- " Datalink receive frame size !UW, "- "Multicast timer !UW, Node status !XB" service_entries:.ascid " !UB Service!%S" service_number: .ascid " Service !UL" service_status: .ascid " Service status !/ Service rating " status_entries: .ascid " !UB Status entr!1%Cy!%Eies!%F" unknown_message:.ascid "Unknown message type !UB" slot_header: .ascid " Slot !3UB !20<!> (!XB), Dest !XB, Source !XB"- ", !3UB Byte!%S, !UB Credit!%S" start_slot: .ascid " Service Class !UB, Min Attn Size !UB, Data Size !UB" stop_slot: .ascid " Stop reason (!XB) " item_format: .ascid " !AC " entry_header: .ascid " Entry status !XB, Error !XB, Req ID !XW, "- "Entry ID !XW!/"- " Queue elapsed time !UWmins, Min position !UW, "- "Max position !UW" wildcard: .ascid "*" null_ascic: .ascic "" bad_item: .ascic "**bad packet data**" vm_allocated: .ascid "LIB$GET_VM allocated !UL bytes at !XL" tally: .ascid "Of the !UL LAT packets read "- "(!UL total), !UL packets were !AS" displayed: .ascid "displayed" recorded: .ascid "recorded" faol_prmlst: .blkl 40 .long ^XFFBADBAD dst_node_name: .ascic "Destination node" dst_srvc_name: .ascic "Requested service" location_text: .ascic "Location" master_node_name: .ascic "Master node" node_name: .ascic "Node name" node_desc: .ascic "Desc'n" obj_node_name: .ascic "Destination node" obj_port_name: .ascic "Destination port" obj_srvc_name: .ascic "Destination service" reason_given: .ascic "Reason" slave_node_name: .ascic "Slave node" src_node_name: .ascic "Source node" src_node_desc: .ascic "Desc'n" srvc_class: .ascic "Service class" srvc_name: .ascic "Service name" srvc_desc: .ascic "Desc'n" subj_group: .ascic "Subject group" subj_node_name: .ascic "Soliciting node" subj_port_name: .ascic "Soliciting port" subj_dscr: .ascic "Source service" alloc_string _faobuf, 2048 ; used for all output - needs to ; be big enough to hold an ethernet ; packet (in case /disp=fast is used) alloc_string command, 256 ; Here we have to fudge the command line by loading the verb and then ; tacking on whatever the user specifies to the end of it. This we can ; then pass on the the cli routines. command_buffer: .long command_buffer_extra-command_buffer_t .address command_buffer_t command_buffer_t: .ascii "LATWATCH" command_buffer_extra: .blkb <8+256> ; Some general bits and pieces lat_protocol = ^X0460 iosb: .word 0 iosb_xfr_size: .word 0 iosb_unused1: .byte 0 iosb_status: .byte 0 iosb_error_summary: .byte 0 iosb_unused2: .byte 0 log_channel: .long 0 packets_read: .long 0 ; used for some stats on the way lat_packets_read: .long 0 ; out... packets_displayed: .long 0 ; ... stats_context: .long 0 ; used by lib$init/show_timer slot_type: .long 0 ; These next bits are used to convert decnet node numbers in the format ; area.node to aa type addresses area_number: .long 0 node_number: .long 0 area_number_s: .long 0 area_number_addr: .long 0 node_number_s: .long 0 node_number_addr: .long 0 aa_format: .ascid "AA-00-04-00-!XB-!XB" ; The following definitions specifiy the sizes of the text representations ; of the various fields that are used. s_address = 17 ; xx-xx-xx-xx-xx-xx s_name = 32 ; maximum allowed name size s_sap = 23 s_protocol = 5 ; The next bits are used to set up some virtual memory to contain the ; name and address lists (for use by lib$lookup_key) and pointers to the ; lists and data area. vm_bytecount: .long 0 ; used by lib$get_vm/lib$free_vm vm_base_address: .long 0 address_vector_size: .long 0 ; filled in later name_vector_size: .long 0 data_area_size: .long 0 max_nodecount = 30000 ; we won't load any more than this ; many nodes from the nodelist user_nodecount: .long 0 ; this is from reading nodelist node_count: .long 0 ; this is how many real nodes we got address_vector: .long 0 ; these will contain pointers to name_vector: .long 0 ; the memory allocated by lib$get_vm name_address_data: .long 0 ; These are some dummy headers that we need for various routines to point ; to the header and data buffers. packet_header_ds: .long lanhdr_s_lanhdrdef packet_header_addr: .address packet_header packet_data_ds: .long lan_s_ethernet packet_data_addr: .address packet_data ; This is the buffer where the header and data are returned by $qio packet_length: .long 0 ; length of received packet record_buffer: rec_type: .byte 0 rec_time: .quad 0 rec_hdrsize = .-record_buffer packet_buffer: packet_header: .blkb lanhdr_s_lanhdrdef packet_data: .blkb lan_s_ethernet rec_rsize = .-record_buffer rec_ascii = 1 rec_binary = 2 ; Here we define some descriptors that will be used to check the details ; of the incoming packet. We basically have three strings, the source and ; destination address and the sap details (returned by LAN_FORMAT_HEADER). ; We then use "fake" descriptors to address sub-fields within the sap details. ; The strings are those returned by lan_format_header and are therefore ; fixed length and a known format. ; pkt_destination and pkt_source will look like "XX-XX-XX-XX-XX-XX". ; pkt_sap will look like "XX-XX XX XX-XX-XX-XX-XX", where "XX-XX" is the ; protocol (also DSAP plus SSAP), the "XX" is the control byte and the rest ; is the PID consisting of COPID and IPID fields. pkt_destination: .long s_address .address pkt_destination_t pkt_destination_t: .blkb s_address pkt_source: .long s_address .address pkt_source_t pkt_source_t: .blkb s_address pkt_sap: .long s_sap .address pkt_sap_t pkt_sap_t: .blkb s_sap pkt_protocol: .long s_protocol .address pkt_sap_t+0 pkt_message_type: .long ; extracted... ; The following areas are used to store the items returned from the command ; line. The sizes here should give enough room for valid addresses etc. ; and also allow for the use of keywords on those items that allow keywords. alloc_string from, 64 alloc_string to, 64 alloc_string device, 64 alloc_string display, 32 alloc_string message_type, 32 alloc_string begin, 64 alloc_string end, 64 alloc_string count, 32 alloc_string output, 255 alloc_string record, 255 alloc_string from_name, s_name ; filled in if available from the alloc_string to_name, s_name ; nodelist entries from_ascic: .long 0 to_ascic: .long 0 message_value: .long 0 ; filled in by lib$lookup_key if the ; /message value is a keyword selected_messages: .long 0 ; bit mask of selected message types default_end: .ascid "0 00:30:00.00" begin_time: .quad 0 end_time: .quad 0 count_l: .long 0 ; use time limit lnm_tabnam: .ascid "LNM$PROCESS_TABLE" lnm_lognam: .ascid "SYS$OUTPUT" lnm_acmode: .long psl$c_user lnm_itmlst: .word 0 ; buffer length - filled in later .word lnm$_string .long 0 ; buffer address - filled in later .long 0 ; return address - not used .long 0 ; to end the list m_run_msg = 1 m_start_msg = 2 m_stop_msg = 4 m_service_msg = 1024 m_command_msg = 4096 m_status_msg = 8192 m_solicit_msg = 16384 m_response_msg = 32768 m_all_msg = ^XFFFFFFFF m_msg_type0 = 1 m_msg_type1 = 2 m_msg_type2 = 4 m_msg_type3 = 8 m_msg_type4 = 16 m_msg_type5 = 32 m_msg_type6 = 64 m_msg_type7 = 128 m_msg_type8 = 256 m_msg_type9 = 512 m_msg_type10 = 1024 m_msg_type11 = 2048 m_msg_type12 = 4096 m_msg_type13 = 8192 m_msg_type14 = 16384 m_msg_type15 = 32768 m_unknown_msg = alloc_string message_choice, 16 ; filled in later destination_ascic: .address null_ascic ; filled in by lookup_name when source_ascic: .address null_ascic ; processing a packet display_option: .long display_c_ascii ; the default display_c_all = 1 display_c_none = 2 display_c_ascii = 3 display_c_hex = 4 display_c_fast = 5 alloc_string display_choice, 16 ; filled in by lib$lookup_key to ; be the full keyword all_segment_size: .long 16 hex_segment_size: .long 20 ascii_segment_size: .long 64 fast_format: .ascid "!AF" ; minimum formatting required ; Here are the valid command line qualifiers. cli_debug: .ascid "DEBUG" cli_device: .ascid "DEVICE" cli_both: .ascid "BOTH" cli_display: .ascid "DISPLAY" cli_from: .ascid "FROM" cli_to: .ascid "TO" cli_message_type: .ascid "MESSAGE_TYPE" cli_nonames: .ascid "NONAMES" cli_count: .ascid "COUNT" cli_end: .ascid "END" cli_begin: .ascid "BEGIN" cli_output: .ascid "OUTPUT" cli_record: .ascid "RECORD" cli_playback: .ascid "PLAYBACK" ; The following definitions are used for checking whether a command line ; item was defaulted or not. This is used in an attempt to increase the speed ; with which we determine whether or not we display a particular packet. ; The flags are set by the command parsing routine. flag1: .long 0 ; this is a general flag area but uses ; the stuff defined below... cli_supplied: .long 0 ; to keep track of what was given cli_defaulted: .long 0 ; and what was defaulted m_from = 1 v_from = 0 m_to = 2 v_to = 1 m_both = 512 v_both = 9 m_unknown = 1024 v_unknown = 10 m_from_unknown = 2048 v_from_unknown = 11 m_to_unknown = 4096 v_to_unknown = 12 m_device = 8192 v_device = 13 m_display = 16384 v_display = 14 m_source_unknown = 32768 v_source_unknown = 15 m_dest_unknown = 65536 v_dest_unknown = 16 m_nonames = 131072 v_nonames = 17 m_debug = 262144 v_debug = 18 m_message_type = 524288 v_message_type = 19 m_count = 1048576 v_count = 20 m_end = 2097152 v_end = 21 m_begin = 4194304 v_begin = 22 m_output = 8388608 v_output = 23 m_record = 16777216 v_record = 24 m_playback = 33554432 v_playback = 25 ; The following keyword table (for lib$lookup_key) is used to check the ; single entry UNKNOWN to be used in /from and /to choices. unknown_vector: .long 1*2 ; only one keyword .address unknown_keyword .long m_unknown ; value to return unknown_keyword: .ascic "UNKNOWN" unknown_ascid: .ascid "UNKNOWN" ; not part of the table, but used ; The following keyword table (for lib$lookup_key) contains the valid options ; available on the /display qualifier. display_vector: .long 7*2 ; seven choices available vector ascii_keyword, display_c_ascii vector text_keyword, display_c_ascii vector all_keyword, display_c_all vector both_keyword, display_c_all vector none_keyword, display_c_none vector hex_keyword, display_c_hex vector fast_keyword, display_c_fast all_keyword: .ascic "ALL" both_keyword: .ascic "BOTH" none_keyword: .ascic "NONE" ascii_keyword: .ascic "ASCII" text_keyword: .ascic "TEXT" hex_keyword: .ascic "HEXADECIMAL" fast_keyword: .ascic "FAST" ; The following keyword table (used by lib$lookup_key) contains valid options ; for the /message_type qualifier message_vector: .long 26*2 ; 26 choices vector all_types_keyword, m_all_msg vector unknown_types_keyword, m_unknown_msg vector run_keyword, m_run_msg vector start_keyword, m_start_msg vector stop_keyword, m_stop_msg vector service_keyword, m_service_msg vector command_keyword, m_command_msg vector status_keyword, m_status_msg vector solicit_keyword, m_solicit_msg vector response_keyword, m_response_msg vector type0_keyword, m_msg_type0 vector type1_keyword, m_msg_type1 vector type2_keyword, m_msg_type2 vector type3_keyword, m_msg_type3 vector type4_keyword, m_msg_type4 vector type5_keyword, m_msg_type5 vector type6_keyword, m_msg_type6 vector type7_keyword, m_msg_type7 vector type8_keyword, m_msg_type8 vector type9_keyword, m_msg_type9 vector type10_keyword, m_msg_type10 vector type11_keyword, m_msg_type11 vector type12_keyword, m_msg_type12 vector type13_keyword, m_msg_type13 vector type14_keyword, m_msg_type14 vector type15_keyword, m_msg_type15 all_types_keyword: .ascic "ALL" unknown_types_keyword: .ascic "UNKNOWN" run_keyword: .ascic "RUN_MESSAGE" start_keyword: .ascic "START_MESSAGE" stop_keyword: .ascic "STOP_MESSAGE" service_keyword: .ascic "SERVICE_INFO" command_keyword: .ascic "COMMAND_MESSAGE" status_keyword: .ascic "STATUS_MESSAGE" solicit_keyword: .ascic "SOLICIT_INFO" response_keyword: .ascic "RESPONSE_INFO" type0_keyword: .ascic "TYPE0" type1_keyword: .ascic "TYPE1" type2_keyword: .ascic "TYPE2" type3_keyword: .ascic "TYPE3" type4_keyword: .ascic "TYPE4" type5_keyword: .ascic "TYPE5" type6_keyword: .ascic "TYPE6" type7_keyword: .ascic "TYPE7" type8_keyword: .ascic "TYPE8" type9_keyword: .ascic "TYPE9" type10_keyword: .ascic "TYPE10" type11_keyword: .ascic "TYPE11" type12_keyword: .ascic "TYPE12" type13_keyword: .ascic "TYPE13" type14_keyword: .ascic "TYPE14" type15_keyword: .ascic "TYPE15" ; The next bits are the message type display texts message_display: .address 10$ .address 11$ .address 12$ .address 13$ .address 14$ .address 15$ .address 16$ .address 17$ .address 18$ .address 19$ .address 20$ .address 21$ .address 22$ .address 23$ .address 24$ .address 25$ .address 26$ 10$: .ascic "Run Message" 11$: .ascic "Start Message" 12$: .ascic "Stop Message" 13$: .ascic "Message Type 3" 14$: .ascic "Message Type 4" 15$: .ascic "Message Type 5" 16$: .ascic "Message Type 6" 17$: .ascic "Message Type 7" 18$: .ascic "Message Type 8" 19$: .ascic "Message Type 9" 20$: .ascic "Service Info" 21$: .ascic "Message Type 11" 22$: .ascic "Command Message" 23$: .ascic "Status Message" 24$: .ascic "Solicit Info" 25$: .ascic "Response Info" 26$: .ascic "Unknown Message Type" ; The next bits are the slot type display texts slot_display: .address 10$ .address 11$ .address 12$ .address 13$ .address 14$ .address 15$ .address 16$ .address 17$ .address 18$ .address 19$ .address 20$ .address 21$ .address 22$ .address 23$ .address 24$ .address 25$ 10$: .ascic "Data-A-Slot" 11$: .ascic "SlotType_1" 12$: .ascic "SlotType_2" 13$: .ascic "SlotType_3" 14$: .ascic "SlotType_4" 15$: .ascic "SlotType_5" 16$: .ascic "SlotType_6" 17$: .ascic "SlotType_7" 18$: .ascic "SlotType_8" 19$: .ascic "Start-Slot" 20$: .ascic "Data-B-Slot" 21$: .ascic "Attention-Slot" 22$: .ascic "Reject-Slot" 23$: .ascic "Stop-Slot" 24$: .ascic "SlotType_14" 25$: .ascic "SlotType_15" ; The next bits are the display texts for the stop reasons stop_display: .address 10$ .address 11$ .address 12$ .address 13$ .address 14$ .address 15$ .address 16$ .address 17$ .address 18$ .address 19$ .address 20$ .address 21$ 10$: .ascic "Reason is unknown" 11$: .ascic "No slots connected on VC" 12$: .ascic "Illegal message or slot received" 13$: .ascic "User requested disconnect" 14$: .ascic "No progress is being made" 15$: .ascic "Time limit expired" 16$: .ascic "LAT message retry limit reached" 17$: .ascic "Insufficient resources" 18$: .ascic "Server circuit timer out of range" 19$: .ascic "Number of VCs is exceeded" 20$: .ascic "Incompatible protocol version" 21$: .ascic "**Reason outside known range**" ; The next bits are the display texts for the slot stop reasons slot_stop_display: .address 10$ .address 11$ .address 12$ .address 13$ .address 14$ .address 15$ .address 16$ .address 17$ .address 18$ .address 19$ .address 20$ .address 21$ .address 22$ .address 23$ .address 24$ .address 25$ 10$: .ascic "Reason is unknown" 11$: .ascic "User requested disconnect" 12$: .ascic "System shutdown in progress" 13$: .ascic "Invalid slot received" 14$: .ascic "Invalid service class" 15$: .ascic "Insufficient resources" 16$: .ascic "Service in use" 17$: .ascic "No such service" 18$: .ascic "Service is disabled" 19$: .ascic "Service not offered by port" 20$: .ascic "Port name is unknown" 21$: .ascic "Invalid password" 22$: .ascic "Entry is not in queue" 23$: .ascic "Immediate access rejected" 24$: .ascic "Access denied" 25$: .ascic "Corrupted solict request" ; The next two bits relate tp the message originator who_display: .address 10$ .address 11$ 10$: .ascic "Slave" 11$: .ascic "Master" answer_display: .address 10$ .address 11$ 10$: .ascic "No Response Required" 11$: .ascic "Response Required" command_display: .address 17$ .address 11$ .address 12$ .address 13$ .address 14$ .address 15$ .address 16$ .address 17$ 11$: .ascic "Solicit non-queued access" 12$: .ascic "Solicit queued access" 13$: .ascic "Cancel queue entry" 14$: .ascic "Send status of entry" 15$: .ascic "Send status of queue" 16$: .ascic "Send status of multiple entries" 17$: .ascic "**Unknown command type**" lat_c_service_msg = 10 lat_c_command_msg = 12 lat_c_max_valid_stop = 10 lat_c_unknown_stop = 11 lat_c_min_valid_command = 1 lat_c_max_valid_command = 6 lat_c_unknown_command = 7 lat_c_min_valid_message = 0 lat_c_max_valid_message = 15 lat_c_unknown_message = 16 lat_c_min_slot_type = 0 lat_c_max_slot_type = 15 ; offsets for virtual circuit header info lat_r_vc_header = 0 lat_s_vc_header = 8 lat_b_msg_type = 0 lat_m_rrf = 1 lat_v_rrf = 0 lat_m_master = 2 lat_v_master = 1 lat_s_msg_type = 6 lat_v_msg_type = 2 lat_b_nbr_slots = 1 lat_w_dst_cir_id = 2 lat_w_src_cir_id = 4 lat_b_msg_seq_nbr = 6 lat_b_msg_ack_nbr = 7 ; offsets for start messages at end of virtual circuit header lat_w_min_rcv_datagram_size = 8 lat_b_prtcl_ver = 10 lat_b_prtcl_eco = 11 lat_b_max_sim_slots = 12 lat_b_nbr_dl_bufs = 13 lat_b_srv_circt_tmr = 14 lat_b_keep_alive_timer = 15 lat_w_facility_number = 16 lat_b_prod_type_code = 18 lat_b_prod_vers_numb = 19 lat_r_start_data = 20 ; offsets for stop messages lat_b_stop_reason = 8 lat_t_stop_reason = 9 ; offsets for command messges map over the virtual circuit header lat_b_prtcl_fmt = 1 lat_b_high_prtcl_ver = 2 lat_b_low_prtcl_ver = 3 lat_b_curr_prtcl_ver = 4 lat_b_curr_prtcl_eco = 5 lat_w_dl_rcv_frame_size = 6 lat_w_req_id = 8 lat_w_entry_id = 10 lat_b_cmd_type = 12 lat_b_cmd_modifier = 13 lat_r_cmd_data = 14 ; offsets for status messages same as command in first 8 bytes lat_w_status_retrans_timer = 8 lat_b_entries_counter = 10 lat_r_status_data = 11 ; offsets for solicit messages same as command in first 8 bytes lat_w_solicit_id = 8 lat_w_response_timer = 10 lat_r_solicit_data = 12 ; offsets for response messages same as solicit in first 10 bytes lat_w_response_status = 10 lat_w_src_node_status = 12 lat_r_source_node_addr = 14 lat_w_node_mc_timer = 20 lat_r_response_data = 22 ; offsets for service announcements lat_b_srv_circt_tmr = 1 lat_b_msg_incarnation = 6 lat_b_change_flags = 7 lat_w_dl_rcv_frame_size2 = 8 lat_b_node_multi_timr = 10 lat_b_node_status = 11 lat_r_service_data = 12 ; offsets for slot header fields slot_c_slot_header = 8 ; offset to first slot header slot_b_dst_slot_id = 0 slot_b_src_slot_id = 1 slot_b_slot_byte_count = 2 slot_b_status_byte_count = 2 slot_b_credits = 3 slot_s_credits = 4 slot_v_credits = 0 slot_s_slot_type = 4 slot_v_slot_type = 4 slot_c_header_size = 4 ; offset to start of slot data a & b type slots slot_t_slot_data = 4 ; offsets for start slot slot_b_service_class = 4 slot_b_min_attn_slot_size = 5 slot_b_min_data_slot_size = 6 slot_r_start_slot = 7 ; offsets for stop slot slot_b_reason = 3 ; is the same as the credits field slot_s_reason = 4 slot_v_reason = 0 ; offets for entries within status messages entry_b_length = 0 entry_b_status = 1 entry_b_error = 2 entry_b_fill_1 = 3 entry_w_request_id = 4 entry_w_entry_id = 6 entry_w_elapsed_queue_time = 8 entry_w_min_queue_position = 10 entry_w_max_queue_position = 12 entry_r_entry_data = 14 reset_psect .subtitle Work areas for reading of the nodelist file set_psect _util_data _rsize = 256 ; not really but should be plenty _record: .blkb _rsize ; buffer for the record _record_ds: .long _rsize ; descriptor to point to the buffer _record_addr: .address _record alloc_string play_thing, _rsize ; used for juggling the record alloc_string play_thing2, _rsize _mbc = 127 _mbf = 16 _rtv = 255 .align long _fab: $fab fac=, - fnm=, - dnm=, - fop=, - rtv=_rtv, - shr= _rab: $rab fab=_fab, - mbc=_mbc, - mbf=_mbf, - rac=, - rop=, - ubf=_record, - usz=_rsize reset_psect .subtitle Work areas for recording/playback file set_psect _util_data rec_alq = 2400 ; initial allocation rec_deq = 2400 ; default extension quantity rec_mbc = 127 ; multi block count rec_mbf = 16 ; multi buffer count rec_mrs = rec_rsize ; maximum record size rec_rtv = 255 ; retreival pointers .align long rec_fab: $fab alq=rec_alq, - deq=rec_deq, - dnm=, - fop=, - mrs=rec_mrs, - org=, - rat=, - rfm=, - rtv=rec_rtv, - shr= rec_rab: $rab fab=rec_fab, - mbc=rec_mbc, - mbf=rec_mbf, - rac=, - rbf=record_buffer, - rop=, - ubf=record_buffer, - usz=rec_rsize reset_psect .subtitle Mainline set_psect _util_code .entry - latwatch, ^m<> call lib$init_timer - ; initialize stats in case we stats_context ; want to look at them call sys_trap_controlc - ; so we can exit gracefully process_controlc, - ; ... (hopefully) iosb call read_nodelist ; need some of this info when ; parsing the command... call parse_command ; get all the gory details call startup_device ; fire up the controller $hiber_s ; ...and wait 90$: ret .subtitle Read the nodelist file .entry - read_nodelist, ^m ;++ ; Functional Description: ; The first thing we do is a quick scan of the nodelist file to see ; how much memory we need to allocate for the names and addresses. ; Here we open the nodelist file, read each record in the file and ; pass it on to the process_nodelist_entry routine to validate it ; and store it in the appropriate tables. When complete we just ; close the file. If we don't find the file, we don't generate any ; errors, we just continue but don't have any names and addresses in ; the tables so every address is UNKNOWN when we display the packet ; details. ; ; Calling Sequence: ; call read_nodelist ; ; Formal Argument(s): ; None. ; ; Implicit Inputs: ; None. ; ; Implicit Outputs: ; None. ; ; Completion Codes: ; None ; ; Side Effects: ; None ;-- call scan_nodelist ; to see how many are there clrl node_count ; we use this for counting movl address_vector, r2 ; we will use this later addl #4, r2 ; skip the count movl name_vector, r3 ; we need this also addl #4, r3 ; skip the count movl name_address_data, r4 ; we need this as well $open fab=_fab ; open the nodelist blbc r0, close $connect rab=_rab ; connect to it blbc r0, close 10$: $get rab=_rab ; grab a record blbc r0, close movzwl _rab+rab$w_rsz, r5 ; these get passed on to the movl _rab+rab$l_rbf, r6 ; processing routine call process_nodelist_entry cmpl node_count, - ; how many have we done so far user_nodecount blss 10$ ; still got room, try again close: $close fab=_fab mull3 #2, node_count, - ; setup the vector count to be the @address_vector ; number of longwords (2 per node) movl @address_vector, - ; should be the same number of entries @name_vector ; in each list ret .subtitle Routine to scan the nodelist and allocate virtual memory .entry - scan_nodelist, ^m<> ;+ ; Here we do a quick scan of the nodelist file to see how many entries are ; in it. We assume each line is valid so that if there are comments and ; blank lines we will over allocate the real space that we need. (I can live ; with that). ;- clrl user_nodecount $open fab=_fab ; open the nodelist blbc r0, 90$ $connect rab=_rab ; connect to it blbc r0, 90$ 10$: $get rab=_rab ; grab a record blbc r0, 90$ incl user_nodecount brb 10$ 90$: $close fab=_fab if then movl #max_nodecount, user_nodecount endif if then ; if the file is missing, or empty movl #1, user_nodecount ; allocate space for 1 node to bisl #m_nonames, cli_supplied; prevent accvio's, and set /nonames endif mull3 #8, user_nodecount, - ; that's how many bytes in the vector address_vector_size addl2 #4, address_vector_size ; allow for the vector count movl address_vector_size, - ; they will be the same size name_vector_size addl3 #s_address, #s_name, - ; that's the size of each entry data_area_size addl2 #2, data_area_size ; plus byte count overhead mull2 user_nodecount, - ; and this is how much we really need data_area_size ; for the data portion mull3 #2, address_vector_size, - vm_bytecount addl2 data_area_size, - ; this is the total allocation we vm_bytecount ; need call lib$get_vm - ; now try to allocate it vm_bytecount, - vm_base_address if then ; and signal any problems signal code=r0 endif movl vm_base_address, - ; that's the pointer to the address address_vector ; vector addl3 address_vector_size, - ; this is the pointer to the name address_vector, - ; vector name_vector addl3 name_vector_size, - ; and the pointer to the data area name_vector, - name_address_data clrl @address_vector ; in case we have no entries clrl @name_vector ret .subtitle Process a nodelist entry .entry - process_nodelist_entry, ^m<> ;++ ; Functional Description: ; This routine will verify (in a limited way) the record from the ; nodelist file. Blank lines are allowed, comments can begin with ; either "!" or ";" and can really be any line without an equals sign ; in it. ; The expected format of the record is ; xx-xx-xx-xx-xx-xx = nodename ; Where the xx-xx... stuff is the address of the node with name ; nodename. All characters are converted to uppercase. ; Once we get a "valid" record, we load it into the address and name ; tables, sort out the cross referencing between the two and that's ; that. ; ; Calling Sequence: ; call process_nodelist_entry ; ; Formal Argument(s): ; None. ; ; Implicit Inputs: ; R2 pointer to next longword entry in address vector ; R3 pointer to next longword entry in name vector ; R4 pointer to next byte in name/address data ; R5 size of record ; R6 address of record buffer ; ; Implicit Outputs: ; R5 and R6 are trashed to reflect the size of the record after we ; have done an str_collapse. ; ; Completion Codes: ; None ; ; Side Effects: ; None ;-- movl r5, _record_ds ; load up a descriptor for us to movl r6, _record_addr ; use call str_uppercase - ; convert the record to uppercase play_thing_ds, - _record_ds call str_collapse - ; get rid of spaces etc... play_thing2_ds, - play_thing_ds call str_len - ; and get the real length play_thing2_ds, - play_thing2 movq play_thing2, r5 ; now point to the real data tstl r5 ; anything there? beql 90$ ; nope, so go away cmpb #^A/!/, (r6) ; is this a comment beql 90$ ; yep, so ignore it cmpb #^A/;/, (r6) ; allow ";" as a comment as well beql 90$ ; yep, so ignore it cmpb #^A/=/, (r6) ; see if address is null beql 90$ ; yep, so ignore it locc #^A/=/, r5, (r6) ; look for an "=" cmpl r0, #1 ; how many characters left? bleq 90$ ; not enough, so skip it subl3 r6, r1, r7 ; R7 = address length movl r4, (r2)+ ; pointer to address in address vector movb r7, (r4)+ ; move the address byte count to the ; data area 10$: movb (r6)+, (r4)+ ; now move the address sobgtr r7, 10$ ; until we have it all movl r4, (r2)+ ; pointer to name in address table decl r0 ; this skips the "=" by reducing the ; length by one incl r6 ; and upping the address by one cmpl r0, #s_name ; check that the name is not too long bleq 15$ ; it's ok, so keep going movl #s_name, r0 ; force it to our maximum length 15$: movb r0, (r4)+ ; move the name byte count to the ; data area 20$: movb (r6)+, (r4)+ ; now move the name sobgtr r0, 20$ ; until it's all done movl -4(r2), (r3)+ ; pointer to name in name vector movl -8(r2), (r3)+ ; pointer to address in name vector incl node_count ; keep track of how many we have 90$: ret .subtitle Parse the command .entry - parse_command, ^m<> ;++ ; Functional Description: ; Here we validate the command and extract everything we can and ; validate any qualifier values that were suppplied. ; ; Calling Sequence: ; call parse_command ; ; Formal Argument(s): ; None ; ; Implicit Inputs: ; None. ; ; Implicit Outputs: ; None. ; ; Completion Codes: ; None ; ; Side Effects: ; None ;-- pushaw command ; here we get the command they pushl #0 ; used to invoke us - we don't pushaq command_ds ; prompt even if they didn't give calls #3, g^lib$get_foreign ; any options pushr #^m movc3 command, - ; tack the foreign command command_t, - ; onto the primed buffer command_buffer_extra popr #^m addl2 command, command_buffer ; and fixup the length call cli$dcl_parse - ; see if the cli routines think command_buffer, - ; the command is ok latwatch_cld if then ; if it didn't work bisl #sts$m_inhib_msg, r0 ; then don't signal when we exit pushl r0 ; cli$... has already done that calls #1, g^lib$stop ; bail out endif ; then if_present from ; here we check all the possible if_present to ; qualifiers and set bits in if_present device ; the cli_supplied and _defaulted if_present display ; flags to say what was what if_present message_type if_present both if_present nonames if_present debug if_present count if_present end if_present output if_present record if_present playback ; get the output details if any if then call cli$get_value cli_output, output_ds, output movw output, lnm_itmlst movab output_t, lnm_itmlst+4 $crelnm_s - tabnam=lnm_tabnam, - lognam=lnm_lognam, - acmode=lnm_acmode, - itmlst=lnm_itmlst if then signal code=r0 endif endif ; now see if we are recording or playing back if then call cli$get_value cli_record, record_ds, record call create_record_file bisl #m_nonames, cli_supplied ; prevent name processing endif if then call cli$get_value cli_playback, record_ds, record endif display program_id ; say who we are $fao_s ctrstr=loaded_fao, - ; say how many names/addresses we outbuf=_faobuf_ds, - ; loaded outlen=_faobuf, - p1=node_count display _faobuf ; Now we get the values they supplied, if any if then call cli$get_value - ; they supplied a device, so use it cli_device, device_ds, device else call sys_find_ether_device - ; else see what's on the system device_ds ; and use that one if then ; if any problems at this point pushl r0 calls #1, g^lib$stop ; bail out endif ; then call str_len - ; we got one, now fix up the device_ds, - ; string device endif ; then ; ...now get all the other values, there should be no errors since all these ; have defaults i.e. there should not be any cli$_absent returned call cli$get_value cli_from, from_ds, from call cli$get_value cli_to, to_ds, to call cli$get_value cli_display, display_ds, display if then bisl #m_all_msg, selected_messages movzbl all_keyword, message_choice pushr #^m movc3 message_choice, - all_keyword+1, - message_choice_t popr #^m else 10$: call cli$get_value cli_message_type, message_type_ds, message_type if then call lib$lookup_key - ; see if the value is a keyword message_type, - message_vector, - message_value, - message_choice_ds, - message_choice bisl message_value, selected_messages brb 10$ endif endif call check_display_option if then ; if /from not defaulted call check_from_option ; check what they gave us else clrl from_name endif if then ; if /to not defaulted call check_to_option ; check what they gave us else clrl to_name endif if then $fao_s ctrstr=vm_allocated, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=vm_bytecount, - p2=vm_base_address display _faobuf call lib$show_vm endif if then call cli$get_value cli_begin, begin_ds, begin $bintim_s - timbuf=begin, - timadr=begin_time $setimr_s - efn=#0, - daytim=begin_time $wfland_s - efn=#0, - mask=#1 endif if then call cli$get_value cli_count, count_ds, count call lib_cvt_t_l count, count_l endif if then ; if it's zero decl count_l ; make it -l i.e. use time to end endif bbs #v_count, cli_supplied, - ; if /count specified, then exit_parse ; don't use the timer to exit if then call cli$get_value cli_end, end_ds, end $bintim_s - timbuf=end, - timadr=end_time else $bintim_s - timbuf=default_end, - timadr=end_time endif $setimr_s - daytim=end_time, - astadr=process_controlc exit_parse: ret .subtitle Routines to check the command line qualifier values .entry - check_display_option, ^m<> ;+ ; Here we take what was given and return the full keyword for display ; purposes. There should be no errors since the cli parsing would have ; picked them up and we wouldn't have got this far. ;- call lib$lookup_key - display, - ; this is what they said display_vector, - ; ...the table of valid keywords display_option, - ; ...the coded value display_choice_ds, - ; ...the full keyword display_choice ; ...and the keyword length ret ;+ ; The check_from_option and check_to_option routines do the same work but ; just use different strings as the source. ; The strategy is as follows: ; 1. See if the keyword UNKNOWN was used. If so then set the appropriate ; flag for later... that's all we need to do. ; 2. Now check to see if the string is in the form area.node i.e. a DECnet ; address. If it is, then we convert it into a string of the form ; AA-00-04-00-XX-XX and make it look like the user typed it. ; 3. Assume the string is a name that will be found in the nodename list. ; 4. If we find the name in the nodename list then use the associated address ; as our address used for matching against packets and use the given ; name to display in the header. At this point we have finished. ; 5. If the name is not in the nodename list, assume it is an address in the ; address list. ; 6. If we find it in the address list then use the address for matching ; purposes and use the associated name to display in the header. ; At this point we have finished. ; 7. At this point the given value is neither a known name nor a known ; address therefore just use what we were given as it is probably an ; address that is not currently in the list or contains wildcards. ;- .entry - check_from_option, ^m<> call lib$lookup_key from, unknown_vector if then ; if they said /from=unknown bisl #m_from_unknown, flag1 ; set the flag movq wildcard, from movq unknown_ascid, from_name else pushr #^m movaq from_ds, r10 ; check for a DECnet address movaq from, r11 call convert_decnet_to_aa popr #^m call lib$lookup_key from, @name_vector, from_ascic, from_ds, from if then ; if it is a name pushr #^m movc3 from, @from+4, - ; copy "from" into "from_name" @from_name+4 movl from, from_name ; and fix the length movl from_ascic, r0 ; just to play with movzbl (r0)+, from ; that's the address length movc3 from, (r0), @from+4 ; copy the address to the "from" field popr #^m else ; wasn't a name... call lib$lookup_key from, @address_vector, from_ascic if then ; if it is an address pushr #^m movl from_ascic, r0 movzbl (r0)+, from_name movc3 from_name, (r0), - ; copy the ascic stuff to the ascid @from_name+4 ; area popr #^m else ; wasn't name or address - use as is clrl from_name ; nothing to display endif ; then endif ; then endif ; then ret .entry - check_to_option, ^m<> call lib$lookup_key to, unknown_vector if then ; if they said /to=unknown bisl #m_to_unknown, flag1 ; set the flag movq wildcard, to movq unknown_ascid, to_name else pushr #^m movaq to_ds, r10 ; see if it is a DECnet address movaq to, r11 call convert_decnet_to_aa popr #^m call lib$lookup_key to, @name_vector, to_ascic, to_ds, to if then ; if it is a name pushr #^m movc3 to, @to+4, @to_name+4 ; copy "to" into "to_name" movl to, to_name ; and fix the length movl to_ascic, r0 ; just to play with movzbl (r0)+, to ; that's the address length movc3 to, (r0), @to+4 ; copy the address to the "to" field popr #^m else ; wasn't a name... call lib$lookup_key to, @address_vector, to_ascic if then ; if it is an address pushr #^m movl to_ascic, r0 movzbl (r0)+, to_name movc3 to_name, (r0), - ; copy the ascic stuff to the ascid @to_name+4 ; area popr #^m else ; wasn't name or address - use as is clrl to_name ; nothing to display endif ; then endif ; then endif ; then ret .entry - convert_decnet_to_aa, ^m<> ;+ ; Here we check to see if the specified address is a possible decnet type ; address in the form area.node. If it is then we convert it to the format ; AA-00-04-00-XX-XX and set this up to look like the user supplied this value. ; ; Inputs: ; R10 Address of the output buffer descriptor ; R11 Address of the input buffer descriptor ;- pushr #^m movq (r11), r8 ; grab the input buffer descriptor locc #^A/./, r8, (r9) ; try to find a dot tstl r0 ; is there one? bneq 10$ ; yes, so play with it brw 90$ ; no, bail out 10$: movq (r11), area_number_s ; load the area number descriptor subl2 r0, area_number_s ; and fix up the length decl r0 ; shorten length by one incl r1 ; and increase address by one ; to skip the dot movq r0, node_number_s ; load the node number descriptor call lib_cvt_t_l area_number_s, area_number blbc r0, 90$ ; bail out if no good call lib_cvt_t_l node_number_s, node_number blbc r0, 90$ ; bail out if no good mull3 #1024, area_number, r0 ; now convert the two numbers into addl2 node_number, r0 ; a single word value movl r0, r1 ; we need a copy to split it bicl #^XFFFFFF00, r0 ; now do the jiggery pokery to bicl #^XFFFF00FF, r1 ; get the bytes swapped and divl2 #^X100, r1 ; cleaned up for the aa format $fao_s ctrstr=aa_format, - outbuf=(r10), - outlen=(r11), - p1=r0, - p2=r1 90$: popr #^m ret .subtitle Startup the ethernet device in promiscuous mode .entry - startup_device, ^m<> ;++ ; Functional Description: ; This routine attempts to startup the ethernet device, set it up so ; we can see everything then queue the first read request to it. ; It also displays some informational messages along the way. ; ; Calling Sequence: ; call startup_device ; ; Formal Argument(s): ; None ; ; Implicit Inputs: ; None. ; ; Implicit Outputs: ; None. ; ; Completion Codes: ; None ; ; Side Effects: ; None ;-- if then $fao_s ctrstr=playing_back, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=#record display _faobuf call open_record_file 10$: $get rab=rec_rab blbc r0, 20$ call process_packet brb 10$ 20$: call process_controlc else $fao_s ctrstr=intro_line1, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=#device display _faobuf call lan_startup_prm - device, - log_channel, - iosb if then ; if anything goes wrong with that pushl iosb ; then we can't go any further calls #1, g^lib$stop endif ; then $fao_s ctrstr=intro_line2, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=#from, - p2=#from_name, - p3=#to, - p4=#to_name, - p5=#message_choice, - p6=#display_choice display _faobuf call queue_async_read endif ; then ret .subtitle Queue an asynchronous read I/O to the ethernet device .entry - queue_async_read, ^m<> ;++ ; Functional Description: ; Here we issue a read qio to the ethernet device and setup an ast to ; invoke the process_packet routine when we have something to read. ; ; Calling Sequence: ; ; call queue_async_read ; ; Formal Argument(s): ; None ; ; Implicit Inputs: ; ether_watch_data common area. ; ; Implicit Outputs: ; None ; ; Completion Codes: ; None ; ; Side Effects: ; None ;-- $qio_s chan=log_channel, - func=#io$_readvblk, - iosb=iosb, - astadr=process_packet, - p1=packet_data, - ; data location p2=#lan_s_ethernet, - ; size of data area p5=#packet_header ; header location if then signal code=r0 endif ; then 90$: ret .subtitle Lookup a nodename given an address .entry - lookup_name, ^m<> ;++ ; Functional Description: ; Check the ethernet address given and return the address of ascic ; string for the associated name. If the address was not found, then ; we return the address of the name UNKNOWN. ; ; Calling Sequence: ; call lookup_name (%descr(address), %ref(name_location)) ; ; Formal Argument(s): ; address.rt.ds Address of the descriptor for the string containing ; the ethernet address to be checked. ; name_location.wl.r Address of a longword that will contain the ; address of the ascic string containing the node name. ; ; Implicit Inputs: ; 4(ap) Address of descriptor of the ethernet address ; 8(ap) Address of a longword to receive the address of the ascic ; string containing the node name ; ; Implicit Outputs: ; None. ; ; Completion Codes: ; The low bit in R0 can be checked on return to see if the address was ; found or not (saves doing string comparisons etc.). ; ; Side Effects: ; None ;-- pushl 8(ap) pushl address_vector pushl 4(ap) calls #3, g^lib$lookup_key if then movab unknown_keyword, @8(ap) endif ; then ret .subtitle Lookup an address given a nodename .entry - lookup_address, ^m<> ;++ ; Functional Description: ; Check the name given and return the address of ascic string for the ; associated ethernet address. If the name was not found, then we ; return the address of the name UNKNOWN. ; ; Calling Sequence: ; call lookup_name (%descr(nodename), %ref(address_location)) ; ; Formal Argument(s): ; nodename.rt.ds Address of the descriptor for the string containing ; the node name to be checked. ; address_location.wl.r Address of a longword that will contain the ; address of the ascic string containing the ethernet ; address. ; ; Implicit Inputs: ; 4(ap) Address of descriptor of the node name ; 8(ap) Address of a longword to receive the address of the ascic ; string containing the node address ; ; Implicit Outputs: ; None. ; ; Completion Codes: ; The low bit in R0 can be checked on return to see if the name was ; found or not (saves doing string comparisons etc.). ; ; Side Effects: ; None ;-- pushl 8(ap) pushl name_vector pushl 4(ap) calls #3, g^lib$lookup_key if then movab unknown_keyword, @8(ap) endif ; then ret .subtitle Here's where we get to if they type control/c .entry - process_controlc, ^m<> ;++ ; Functional Description: ; This is where we end up if a control c is used. We just exit. ; ; Calling Sequence: ; via an ast... ; ; Formal Argument(s): ; None. ; ; Implicit Inputs: ; None. ; ; Implicit Outputs: ; None. ; ; Completion Codes: ; None ; ; Side Effects: ; None ;-- if then movaq recorded, r0 else movaq displayed, r0 endif $fao_s ctrstr=tally, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=lat_packets_read, - p2=packets_read, - p3=packets_displayed, - p4=r0 display _faobuf call lib$free_vm - vm_bytecount, - vm_base_address if then call lib$show_vm call lib$show_timer stats_context endif display command_buffer if then call close_record_file endif if then call close_record_file endif pushl #^X10000001 calls #1, g^lib$stop ret .subtitle Process a packet .entry - process_packet, ^m<> ;++ ; Functional Description: ; This routine gets the packet, formats the header and does the ; necessary checking to see if we want to look at it based on the ; selection criteria supplied by the user on the command line. ; We also queue another i/o request for the next packet. ; ; Calling Sequence: ; call process_packet ; ; Formal Argument(s): ; None. ; ; Implicit Inputs: ; None. ; ; Implicit Outputs: ; None. ; ; Completion Codes: ; None ; ; Side Effects: ; None ;-- incl packets_read if then movzwl rec_rab+rab$w_rsz, packet_length subl #rec_hdrsize, packet_length subl #lanhdr_s_lanhdrdef, packet_length else movzwl iosb_xfr_size, - ; grab the length of the packet we packet_length ; are going to look at endif cmpw #lat_protocol, - ; see if this is a LAT packet packet_header+lanhdr_w_protocol beql check_message_type ; yes, so keep checking brw exit ; no good, so do no more check_message_type: incl lat_packets_read ; 'tis LAT so count it extzv #lat_v_msg_type, - ; extract the message type from #lat_s_msg_type, - ; the virtual circuit header @packet_data_addr, - pkt_message_type movl pkt_message_type, r0 cmpl r0, #lat_c_max_valid_message bleq 10$ movl #m_msg_type3, r0 ; any "unknown" one will do 10$: bbs r0, selected_messages, check_header brw exit check_header: call lan_format_header - ; format the header so we can start packet_header_ds, - ; doing our matching pkt_destination, - pkt_source, - pkt_sap bicl #, - flag1 if then call lookup_name - ; get the friendly names if they pkt_destination, - ; exist in our list destination_ascic if then ; couldn't find them in the list bisl #m_dest_unknown, flag1 ; flag an unknown destination endif endif if then call lookup_name - ; see if the source is in our list pkt_source, - ; of known addresses source_ascic if then ; couldn't find this one either bisl #m_source_unknown, flag1 ; flag an unknown source endif endif check_source: bbs #v_from, cli_defaulted, - ; if /from was defaulted check_destination ; it always matches, check destination if then ; if /from=unknown if then ; if source is unknown brb check_destination ; then it's ours, check destination else if - and then brw do_display else brw exit ; else we don't want it endif endif endif call str$match_wild - ; check source of the packet pkt_source, from ; against the /from value blbs r0, check_destination ; it's a winner bbs #v_both, cli_supplied, - ; no match, so bail out unless they 10$ ; specified /both brw exit 10$: call str$match_wild - ; want /both so try to match dest pkt_destination, from ; address blbs r0, check_destination brw exit ; if that failed, just get out check_destination: bbs #v_to, cli_defaulted, - ; if /to was defaulted do_display ; it always matches, so display it if then ; if /to=unknown if then ; if destination is unknown brb do_display ; then we want to look at it else if - and then brw do_display else brb exit ; else we don't want it endif endif endif call str$match_wild - ; check destination of the packet pkt_destination, to ; against the /to value blbs r0, do_display ; it matches, so look at it bbc #v_both, cli_supplied, - ; no match, so bail out unless they exit ; said /both in the command call str$match_wild - ; want /both so try to match source pkt_source, to ; address blbc r0, exit ; if that failed, try another packet do_display: incl packets_displayed if then call record_a_packet else call display_a_packet endif exit: cmpl lat_packets_read, count_l ; see if we should finish yet blssu 10$ ; not yet... call process_controlc ; finish, don't want to look anymore 10$: bbs #v_playback, cli_supplied, 90$ call queue_async_read 90$: ret .subtitle Display a packet .entry - display_a_packet, ^m ;++ ; Functional Description: ; Here we display the packet header in a nice formatted way. Then, ; based on the display option chosen, display (or not) the contents ; of the packet in the chosen way. ; All registers are saved on the way in so that the display routines ; can have their way with them. ; ; R0 ; R1 ; R2 used to display ASCIC stuff ; R3 used to display ASCIC stuff ; R4 address of the byte after the last byte in the packet ; R5 ; R6 ; R7 slot/service counter - loop control ; R8 address of slot header ; R9 ; R10 address of fao parameter list ; R11 address of the start of the packet data ; ; Calling Sequence: ; call display_a_packet ; ; Formal Argument(s): ; None. ; ; Implicit Inputs: ; None. ; ; Implicit Outputs: ; None. ; ; Completion Codes: ; None ; ; Side Effects: ; None ;-- if then movaq rec_time, r0 else clrl r0 endif $fao_s ctrstr=display_header, - ; always display the header outbuf=_faobuf_ds, - outlen=_faobuf, - p1=#pkt_source, - p2=source_ascic, - p3=#pkt_destination, - p4=destination_ascic, - p5=packet_length, - p6=r0 display _faobuf movab packet_data, r11 ; address of packet data buffer ; used by all display routines addl3 packet_length, r11, r4 ; address not to go past... cmpl pkt_message_type, - ; check for vc header requirements #lat_c_command_msg bgeq 10$ ; yes, don't display the vc header cmpl pkt_message_type, - #lat_c_service_msg beql 10$ call display_vc_header ; no, so look at the vc header 10$: casel pkt_message_type, - #lat_c_min_valid_message, - #lat_c_max_valid_message dispatch: .word 100$-dispatch ; run message 0 .word 101$-dispatch ; start message 1 .word 102$-dispatch ; stop message 2 .word 116$-dispatch ; unknown 3 .word 116$-dispatch ; unknown 4 .word 116$-dispatch ; unknown 5 .word 116$-dispatch ; unknown 6 .word 116$-dispatch ; unknown 7 .word 116$-dispatch ; unknown 8 .word 116$-dispatch ; unknown 9 .word 110$-dispatch ; service info 10 .word 116$-dispatch ; unknown 11 .word 112$-dispatch ; command message 12 .word 113$-dispatch ; status message 13 .word 114$-dispatch ; solicit info 14 .word 115$-dispatch ; response info 15 brb 116$ 100$: call display_run_message brw exit1 101$: call display_start_message brw exit1 102$: call display_stop_message brw exit1 110$: call display_service_info brw exit1 112$: call display_command_message brw exit1 113$: call display_status_message brw exit1 114$: call display_solicit_message brw exit1 115$: call display_response_message brw exit1 116$: call display_unknown_message exit1: ret .subtitle Display the virtual circuit header details .entry - display_vc_header, ^m<> ; First extract all the bits we need... moval faol_prmlst, r10 ; address of the parameter list movab message_display, r1 ; pointer to message type descr's movl pkt_message_type, r0 ; grab the message type movl (r1)[r0], (r10)+ ; put it on the parameter list movzwl lat_w_dst_cir_id(r11), (r10)+ movzwl lat_w_src_cir_id(r11), (r10)+ movzbl lat_b_nbr_slots(r11), (r10)+ movzbl lat_b_msg_seq_nbr(r11), (r10)+ movzbl lat_b_msg_ack_nbr(r11), (r10)+ movab who_display, r0 ; assume slave bbc #lat_v_master, - ; see if master bit is set lat_b_msg_type(r11), 10$ addl #4, r0 ; bit set so must be master 10$: movl (r0), (r10)+ movab answer_display, r0 ; assume no response required bbc #lat_v_rrf, - ; see if flag bit is set lat_b_msg_type(r11), 20$ addl #4, r0 ; bit set so response required 20$: movl (r0), (r10)+ $faol_s ctrstr=virt_circ_hdr, - ; always display the vc header outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf ret .subtitle Format and display a RUN message .entry - display_run_message, ^m<> movzbl lat_b_nbr_slots(r11), r9 ; number of slots in this message beql 90$ ; none, so nothing to do movab slot_c_slot_header(r11), r8 ; address of first header movl #1, r7 ; counter for display purposes 10$: moval faol_prmlst, r10 ; address of fao parameter list movl r7, (r10)+ ; that's the counter call display_slot incl r7 cmpl r7, r9 bleq 10$ 90$: ret .entry - display_slot, ^m<> ; Inputs: ; R8 Address of the slot header ; Outputs: ; R8 On exit should point to the start of the next slot movzbl slot_b_credits(r8), r0 ; contains slot type & credits extzv #slot_v_slot_type, - #slot_s_slot_type, - r0, slot_type ; that's the slot type movab slot_display, r1 ; address of descriptions movl slot_type, r0 movl (r1)[r0], (r10)+ ; this is the one we want movl slot_type, (r10)+ movzbl slot_b_dst_slot_id(r8), (r10)+ movzbl slot_b_src_slot_id(r8), (r10)+ movzbl slot_b_slot_byte_count(r8), (r10)+ extzv #slot_v_credits, - #slot_s_credits, - slot_b_credits(r8), (r10)+ $faol_s ctrstr=slot_header, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf ; that's the slot header casel slot_type, - ; now do the contents #lat_c_min_slot_type, - #lat_c_max_slot_type slot_dispatch: .word 100$-slot_dispatch ; data a 0 .word 116$-slot_dispatch ; unknown 1 .word 116$-slot_dispatch ; unknown 2 .word 116$-slot_dispatch ; unknown 3 .word 116$-slot_dispatch ; unknown 4 .word 116$-slot_dispatch ; unknown 5 .word 116$-slot_dispatch ; unknown 6 .word 116$-slot_dispatch ; unknown 7 .word 116$-slot_dispatch ; unknown 8 .word 109$-slot_dispatch ; unknown 9 .word 110$-slot_dispatch ; data b 10 .word 111$-slot_dispatch ; attention 11 .word 112$-slot_dispatch ; reject 12 .word 113$-slot_dispatch ; stop 13 .word 116$-slot_dispatch ; unknown 14 .word 116$-slot_dispatch ; unknown 15 brb 116$ 100$: call display_data_a_slot brw exit2 109$: call display_start_slot brw exit2 110$: call display_data_b_slot brw exit2 111$: call display_attention_slot brw exit2 112$: call display_reject_slot brw exit2 113$: call display_stop_slot brw exit2 116$: call display_slot_contents exit2: movzbl slot_b_slot_byte_count(r8), r0 addl2 r0, r8 addl2 #slot_c_header_size, r8 pad r8 ; for the next time round ret .entry - display_start_slot, ^m<> moval faol_prmlst, r10 movzbl slot_b_service_class(r8), (r10)+ movzbl slot_b_min_attn_slot_size(r8), (r10)+ movzbl slot_b_min_data_slot_size(r8), (r10)+ $faol_s ctrstr=start_slot, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf init_item slot_r_start_slot(r8) item obj_srvc_name item subj_dscr ret .entry - display_reject_slot, ^m<> call display_stop_slot ret .entry - display_stop_slot, ^m<> moval faol_prmlst, r10 movab slot_stop_display, r1 ; address of descriptions extzv #slot_v_reason, - #slot_s_reason, - slot_b_reason(r8), r0 movl r0, (r10)+ movl (r1)[r0], (r10)+ ; this is the one we want $faol_s ctrstr=stop_slot, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf ret .entry - display_data_a_slot, ^m<> call display_slot_contents ret .entry - display_data_b_slot, ^m<> call display_slot_contents ret .entry - display_attention_slot, ^m<> call display_slot_contents ret .entry - display_slot_contents, ^m<> pushl packet_length pushq packet_data_ds movzbl slot_b_slot_byte_count(r8), - packet_length movl packet_length, - packet_data_ds movl r8, packet_data_addr call display_packet_contents popq packet_data_ds popl packet_length ret .subtitle Format and display a START message .entry - display_start_message, ^m<> moval faol_prmlst, r10 ; address of parameter list movzbl lat_b_prtcl_ver(r11), (r10)+ movzbl lat_b_prtcl_eco(r11), (r10)+ movzbl lat_b_prod_type_code(r11), (r10)+ movzbl lat_b_prod_vers_numb(r11), (r10)+ movzwl lat_w_facility_number(r11), (r10)+ movzbl lat_b_srv_circt_tmr(r11), r0 mull2 #10, r0 movl r0, (r10)+ movzbl lat_b_keep_alive_timer(r11), (r10)+ movzwl lat_w_min_rcv_datagram_size(r11), (r10)+ movzbl lat_b_max_sim_slots(r11), (r10)+ movzbl lat_b_nbr_dl_bufs(r11), (r10)+ $faol_s ctrstr=start_message, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf init_item lat_r_start_data(r11) item slave_node_name item master_node_name item location_text ret .subtitle Format and display a STOP message .entry - display_stop_message, ^m<> movzbl lat_b_stop_reason(r11), r0 ; grab the stop reason code movl r0, r1 ; and save a copy of it cmpl r1, #lat_c_max_valid_stop ; is it valid? bleq 10$ ; yes movl #lat_c_unknown_stop, r1 ; no, so fudge it 10$: movab stop_display, r9 ; here we get a pointer to some movl (r9)[r1], r1 ; text $fao_s ctrstr=stop_message, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=r1, - p2=r0 display _faobuf init_item lat_t_stop_reason(r11) item reason_given 90$: ret .subtitle Format and display a SERVICE INFO message .entry - display_service_info, ^m<> moval faol_prmlst, r10 ; address of parameter list movzbl lat_b_srv_circt_tmr(r11), r0 mull2 #10, r0 movl r0, (r10)+ movzbl lat_b_curr_prtcl_ver(r11), (r10)+ movzbl lat_b_curr_prtcl_eco(r11), (r10)+ movzbl lat_b_high_prtcl_ver(r11), (r10)+ movzbl lat_b_low_prtcl_ver(r11), (r10)+ ; movzbl lat_b_msg_incarnation(r11) ...? ; movzbl lat_b_change_flags(r11) ...? movzwl lat_w_dl_rcv_frame_size2(r11), (r10)+ movzbl lat_b_node_multi_timr(r11), (r10)+ movzbl lat_b_node_status(r11), (r10)+ $faol_s ctrstr=service_message, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf init_item lat_r_service_data(r11) movzbl (r3)+, r0 ; skip subj_group ... a bit field addl2 r0, r3 item node_name item node_desc movzbl (r3)+, r7 ; service count tstl r7 beql 90$ call display_services_list 90$: ret .entry - display_services_list, ^m<> $fao_s ctrstr=service_entries, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=r7 display _faobuf clrl r6 ; counter for display purposes 10$: incl r6 $fao_s ctrstr=service_number, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=r6 display _faobuf movzbl (r3)+, r0 ; service rating $fao_s ctrstr=service_status, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=#0, - p2=r0 display _faobuf item srvc_name item srvc_desc sobgtr r7, 10$ ret .subtitle Format and display a COMMAND message .entry - display_command_message, ^m<> moval faol_prmlst, r10 ; address of parameter list movab command_display, r1 ; address of descriptions movzbl lat_b_cmd_type(r11), r0 ; grab the command type tstb r0 ; is it zero? beql 10$ ; yes, then it's invalid cmpl r0, - ; no, is it within the maximum valid #lat_c_max_valid_command ; value? bleq 20$ ; yes, so use the value 10$: movl #lat_c_unknown_command, r0 ; else fudge it for the description 20$: movl (r1)[r0], (r10)+ ; now point to the ascic text movzbl lat_b_cmd_type(r11), (r10)+ movzbl lat_b_cmd_modifier(r11), (r10)+ movzbl lat_b_prtcl_fmt(r11), (r10)+ movzbl lat_b_curr_prtcl_ver(r11), (r10)+ movzbl lat_b_curr_prtcl_eco(r11), (r10)+ movzbl lat_b_high_prtcl_ver(r11), (r10)+ movzbl lat_b_low_prtcl_ver(r11), (r10)+ movzwl lat_w_dl_rcv_frame_size(r11), (r10)+ movzwl lat_w_req_id(r11), (r10)+ movzwl lat_w_entry_id(r11), (r10)+ $faol_s ctrstr=command_message, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf movzbl lat_b_cmd_type(r11), r0 tstb r0 beql 30$ cmpb r0, #lat_c_max_valid_command blequ 40$ 30$: call display_packet_contents brb 90$ 40$: init_item lat_r_cmd_data(r11) item obj_node_name movzbl (r3)+, r0 ; skip subj_group ... a bit field addl2 r0, r3 item subj_node_name item subj_port_name item subj_dscr item obj_srvc_name item obj_port_name 90$: ret .subtitle Format and display a STATUS message .entry - display_status_message, ^m<> moval faol_prmlst, r10 ; address of parameter list movzbl lat_b_prtcl_fmt(r11), (r10)+ movzbl lat_b_curr_prtcl_ver(r11), (r10)+ movzbl lat_b_curr_prtcl_eco(r11), (r10)+ movzbl lat_b_high_prtcl_ver(r11), (r10)+ movzbl lat_b_low_prtcl_ver(r11), (r10)+ movzwl lat_w_dl_rcv_frame_size(r11), (r10)+ movzwl lat_w_status_retrans_timer(r11), (r10)+ movzbl lat_b_entries_counter(r11), (r10)+ $faol_s ctrstr=status_message, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf init_item lat_r_status_data(r11) item subj_node_name movzbl lat_b_entries_counter(r11), r9 tstl r9 ; how many entries beql 90$ ; none, so bail out call display_status_entries 90$: ret .entry - display_status_entries, ^m<> $fao_s ctrstr=status_entries, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=r9 display _faobuf 10$: pad r3 movzbl (r3), r0 ; entry length, not used by us moval faol_prmlst, r10 ; address of parameter list movzbl entry_b_status(r3), (r10)+ movzbl entry_b_error(r3), (r10)+ movzwl entry_w_request_id(r3), (r10)+ movzwl entry_w_entry_id(r3), (r10)+ movzwl entry_w_elapsed_queue_time(r3), (r10)+ movzwl entry_w_min_queue_position(r3), (r10)+ movzwl entry_w_max_queue_position(r3), (r10)+ $faol_s ctrstr=entry_header, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf init_item entry_r_entry_data(r3) item obj_srvc_name item obj_port_name item subj_dscr decl r9 bleq 90$ brw 10$ 90$: ret .subtitle Format and display a SOLICIT INFO message .entry - display_solicit_message, ^m<> moval faol_prmlst, r10 ; address of parameter list movzbl lat_b_prtcl_fmt(r11), (r10)+ movzbl lat_b_curr_prtcl_ver(r11), (r10)+ movzbl lat_b_curr_prtcl_eco(r11), (r10)+ movzbl lat_b_high_prtcl_ver(r11), (r10)+ movzbl lat_b_low_prtcl_ver(r11), (r10)+ movzwl lat_w_dl_rcv_frame_size(r11), (r10)+ movzwl lat_w_solicit_id(r11), (r10)+ movzwl lat_w_response_timer(r11), (r10)+ $faol_s ctrstr=solicit_message, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf init_item lat_r_solicit_data(r11) item dst_node_name movzbl (r3)+, r0 ; skip subj_group ... a bit field addl2 r0, r3 item src_node_name item dst_srvc_name ret .subtitle Format and display a RESPONSE INFO message .entry - display_response_message, ^m<> moval faol_prmlst, r10 ; address of parameter list movzbl lat_b_prtcl_fmt(r11), (r10)+ movzbl lat_b_curr_prtcl_ver(r11), (r10)+ movzbl lat_b_curr_prtcl_eco(r11), (r10)+ movzbl lat_b_high_prtcl_ver(r11), (r10)+ movzbl lat_b_low_prtcl_ver(r11), (r10)+ movzwl lat_w_dl_rcv_frame_size(r11), (r10)+ movzwl lat_w_solicit_id(r11), (r10)+ movzwl lat_w_response_status(r11), (r10)+ movzwl lat_w_src_node_status(r11), (r10)+ movab lat_r_source_node_addr(r11), r0 movzbl (r0)+, (r10)+ ; ethernet address... 6 bytes movzbl (r0)+, (r10)+ movzbl (r0)+, (r10)+ movzbl (r0)+, (r10)+ movzbl (r0)+, (r10)+ movzbl (r0)+, (r10)+ movzwl lat_w_node_mc_timer(r11), (r10)+ $faol_s ctrstr=response_message, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf init_item lat_r_response_data(r11) item dst_node_name movzbl (r3)+, r0 ; skip subj_group ... a bit field addl2 r0, r3 item src_node_name item src_node_desc movzbl (r3)+, r7 ; service count tstl r7 beql 90$ call display_service_entries 90$: ret .entry - display_service_entries, ^m<> $fao_s ctrstr=service_entries, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=r7 display _faobuf 10$: movzbl (r3)+, r0 ; service entry length, not used by us item srvc_class moval faol_prmlst, r10 ; address of parameter list movzbl (r3)+, (r10)+ ; service status movzbl (r3)+, (r10)+ ; service rating $faol_s ctrstr=service_status, - outbuf=_faobuf_ds, - outlen=_faobuf, - prmlst=faol_prmlst display _faobuf movzbl (r3)+, r0 ; skip subj_group ... a bit field addl2 r0, r3 item srvc_name item srvc_desc sobgtr r7, 10$ ret .subtitle Format and display an UNKNOWN message .entry - display_unknown_message, ^m<> $fao_s ctrstr=unknown_message, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=pkt_message_type display _faobuf call display_packet_contents ret .subtitle Display a counted byte field with description .entry - display_desc_ascic, ^m<> ; Inputs: ; R2 Address of .ascic string to use as a description ; R3 Address of the item to display ; R4 Address of the byte after the last byte in the packet ; Outputs: ; R3 Is updated to point to the next (or past the last) item tstb (r3) ; anything to display beql 20$ ; no so don't... movl r3, r0 movzbl (r0), r1 addl2 r0, r1 cmpl r1, r4 ; at end of packet yet? blssu 10$ ; not yet movab bad_item, r0 ; yes, say it's bad 10$: $fao_s ctrstr=item_format, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=r2, - p2=r0 display _faobuf 20$: movzbl (r3)+, r0 ; grab the byte count addl2 r0, r3 ; and update R3 to point to the start ; of the next field (if any) ret .subtitle Display the packet contents according to their wishes .entry - display_packet_contents, ^m<> ; Display the packet based on what /display option was chosen. if then if then pushal ascii_segment_size pushal packet_length pushaq packet_data_ds calls #3, g^lib_output_seg_t else if then pushal all_segment_size pushal packet_length pushaq packet_data_ds calls #3, g^lib_output_seg_tzb else if then pushal hex_segment_size pushal packet_length pushaq packet_data_ds calls #3, g^lib_output_seg_zb else $fao_s ctrstr=fast_format, - outbuf=_faobuf_ds, - outlen=_faobuf, - p1=packet_length , - p2=#packet_data display _faobuf endif ; then endif ; then endif ; then endif ; then ret .subtitle Routines to handle the recording/playback file .entry - create_record_file, ^m<> movab record_t, rec_fab+fab$l_fna movb record, rec_fab+fab$b_fns movb #fab$m_put, rec_fab+fab$b_fac $create fab=rec_fab if then signal code=r0 endif $connect rab=rec_rab if then signal code=r0 endif ret .entry - open_record_file, ^m<> movab record_t, rec_fab+fab$l_fna movb record, rec_fab+fab$b_fns movb #fab$m_get, rec_fab+fab$b_fac $open fab=rec_fab if then signal code=r0 endif $connect rab=rec_rab if then signal code=r0 endif ret .entry - close_record_file, ^m<> $close fab=rec_fab ret .entry - record_a_packet, ^m<> movb #rec_binary, rec_type $gettim_s - timadr=rec_time addl3 packet_length, #rec_hdrsize, r0 addl2 #lanhdr_s_lanhdrdef, r0 movw r0, rec_rab+rab$w_rsz $put rab=rec_rab if then signal code=r0 endif ret .end latwatch