MODULE KMT_PP_MODULE; @******************************************************************************@ @* *@ @* Mode definitions *@ @* *@ @******************************************************************************@ MODE KMT_TRACE_FLAGS_S IS WORD STRUCT ( BIT PH_TRACING, PP_TRACING, FH_TRACING, DH_TRACING, 28-BIT SPARE); MODE KMT_FH_RECORD_DETAILS_S IS STRUCT ( BOOL FILE_OPEN, NEW_RECORD, END_OF_FILE, WORD TEXT_TYPE, @ 0 = EBCDIC @ @ 1 = ASCII @ @ 2 = BINARY @ INT MAX_RECORD_LENGTH, RECORD_LENGTH, (4098) BYTE RECORD); @ Maximum record size of 4096 @ @ plus 2 bytes for CRLF pair @ @ when constructing output @ @ records @ MODE KMT_DH_DEVICE_DETAILS_S IS STRUCT ( BOOL FILE_OPEN, WORD MAX_INPUT_LENGTH, MAX_OUTPUT_LENGTH, INPUT_PARITY, OUTPUT_PARITY, PAUSE); MODE KMT_PP_PACKET_DATA_S IS STRUCT ( INT DATA_LENGTH, (91) BYTE DATA); MODE KMT_PP_CONFG_PARAMS_S IS STRUCT ( BYTE MARK, MAXL, TIME, NPAD, PADC, EOL, QCTL, QBIN, CHKT, REPT, 4-BYTE CAPAS); MODE KMT_PP_PACKET_STATISTICS_S IS STRUCT ( INT INPUT_TOTAL, OUTPUT_TOTAL); MODE KMT_MTM_VALUES IS ANY ( LONG WORD LW_VALUE, LONG INT LI_VALUE, REF WORD RW_VALUE, REF INT RI_VALUE, REF LONG WORD RLW_VALUE, REF LONG INT RLI_VALUE, REF () BYTE RVB_VALUE, REF () REF () BYTE RVRVB_VALUE); ***PAGE @******************************************************************************@ @* *@ @* External procedure references *@ @* *@ @******************************************************************************@ EXT PROC (REF () BYTE, @ OUTPUT_PACKET @ BOOL, @ PROMPT @ RESPONSE @ RESPONSE @ ) KMT_DH_OUTPUT; EXT PROC (REF () BYTE, @ INPUT_BUFFER @ REF INT, @ INPUT_BUFFER_LENGTH @ RESPONSE @ RESPONSE @ ) KMT_DH_INPUT; EXT PROC (INT, @ RESULT_CODE @ WORD, @ DESTINATION @ REF () KMT_MTM_VALUES, @ PARAMS @ LONG WORD, @ PE_CONTINGENCY_MESSAGE @ BOOL, @ DUMP @ BOOL @ UNRECOVERABLE @ ) KMT_EH_LOG_ERROR; EXT PROC ( RESPONSE @ RESPONSE @ ) KMT_FH_READ; EXT PROC ( RESPONSE @ RESPONSE @ ) KMT_FH_WRITE; EXT PROC ( WORD, @ CHAR @ WORD, @ I/O FLAG @ RESPONSE @ RESPONSE @ ) KMT_SP_CHECK_VME_CHAR; EXT PROC ( INT, @ TYPE @ REF () KMT_MTM_VALUES @ PARAMS @ ) KMT_SP_LOG_TRACE_MESSAGE; ***PAGE @******************************************************************************@ @* *@ @* External data references *@ @* *@ @******************************************************************************@ @ Constants: @ @ ********** @ EXT (256) BYTE EBCDIC_TO_ASCII, @ translation tables @ ASCII_TO_EBCDIC; EXT (26) INT PACKET_CODES; @ packet codes to protocol handler state table events @ EXT INT BAD_PKT,INVALID_PKT,UNS_PKT,NON_PKT; ***LINES(4) @ Variables: @ @ ********** @ EXT () REF KMT_TRACE_FLAGS_S KMT_TRACE_FLAGS; EXT () REF KMT_FH_RECORD_DETAILS_S KMT_FH_RECORD_DETAILS; EXT () REF KMT_DH_DEVICE_DETAILS_S KMT_DH_DEVICE_DETAILS; EXT () REF KMT_PP_CONFG_PARAMS_S KMT_PP_LOCAL_CONFG_PARAMS; EXT () REF KMT_PP_CONFG_PARAMS_S KMT_PP_REMOTE_CONFG_PARAMS; EXT () REF KMT_PP_PACKET_STATISTICS_S KMT_PP_PACKET_STATISTICS; EXT () REF REF () BYTE KMT_PH_INPUT_PACKET_DATA; ***LINES(4) @ Results: @ @ ******** @ ***LINES(4) ***PAGE @******************************************************************************@ @* *@ @* Static data declarations. *@ @* *@ @******************************************************************************@ @ Constants: @ @ ********** @ STATIC WORD EBCDIC IS 0, @ transfer codes @ ASCII IS 1, BINARY IS 2; STATIC INT KMT_PP_PACKET_IN_MSG IS 251, KMT_PP_PACKET_OUT_MSG IS 252, KMT_PP_PACKET_DATA_IN_MSG IS 253, KMT_PP_PACKET_DATA_OUT_MSG IS 254, KMT_PP_PARAM_OUT_MSG IS 258, KMT_PP_PARAM_IN_MSG IS 259; ***LINES(4) @ Variables: @ @ ********** @ STATIC KMT_PP_PACKET_DATA_S KMT_PP_INPUT_PACKET_DATA; STATIC KMT_PP_PACKET_DATA_S KMT_PP_OUTPUT_PACKET_DATA; STATIC REF () BYTE KMT_PP_RECALL_DATA; ***LINES(4) @ Results: @ @ ******** @ ***LINES(4) ***PAGE @******************************************************************************@ @* *@ @* Procedure declarations *@ @* *@ @******************************************************************************@ STATIC PROC KMT_PP_CHECK_COMPLETE IS ( INT DATA_LENGTH, REF REF () BYTE BUFFER) BOOL: @******************************************************************************@ @* *@ @* This procedure is used to update a buffer pointer and to check if the *@ @* processing of BUFFER is complete. *@ @* The procedure returns TRUE if the processing of BUFFER has been completed, *@ @* FALSE otherwise. *@ @* *@ @******************************************************************************@ BEGIN IF LENGTH BUFFER GT DATA_LENGTH THEN @ Incomplete, update pointer @ BUFFER := BUFFER(DATA_LENGTH::); FALSE ELSE @ Complete return ZLR @ BUFFER := BUFFER(SIZE 0); TRUE FI END; @ KMT_PP_CHECK_COMPLETE @ ***PAGE STATIC PROC KMT_PP_MOVE IS ( () BYTE SOURCE, REF REF () BYTE DESTINATION, REF BOOL COMPLETE) INT: @******************************************************************************@ @* *@ @* This procedure is used to move the source string into the destination *@ @* buffer and to check if the destination buffer is full. *@ @* The procedure returns the number of characters moved. *@ @* *@ @******************************************************************************@ BEGIN INT S_LEN IS LENGTH SOURCE, D_LEN IS LENGTH DESTINATION; IF S_LEN GT D_LEN THEN @ Insufficient space in @ @ buffer for string @ UNLESS COMPLETE IS NIL THEN COMPLETE := TRUE; FI; 0 ELSE DESTINATION(SIZE S_LEN) := SOURCE; UNLESS COMPLETE IS NIL THEN COMPLETE := KMT_PP_CHECK_COMPLETE (S_LEN, DESTINATION); FI; S_LEN FI END; @ KMT_PP_MOVE @ ***PAGE STATIC PROC KMT_PP_GENERATE_CHECKSUM IS ( REF () BYTE PACKET) BYTE: @******************************************************************************@ @* *@ @* This procedure is used to generate a checksum for the data contained in *@ @* the packet. *@ @* *@ @******************************************************************************@ BEGIN WORD SUM := 0; FOR I FROM 1 @ 'MARK' character not @ @ included in checksum @ TO PACKET(1) - X"20" DO SUM := SUM + PACKET(I) REPEAT; ((SUM + ((SUM & X'C0') SCALE -6)) & X'3F') + X"20" END; @ KMT_PP_GENERATE_CHECKSUM @ ***PAGE STATIC PROC KMT_PP_LOG_TRACE_MESSAGE IS ( INT TYPE, REF () BYTE PACKET): @******************************************************************************@ @* *@ @* This procedure is used to log the packet contents to the job journal. *@ @* *@ @******************************************************************************@ BEGIN INT PACKET_LENGTH IS LENGTH PACKET; INT LEN := PACKET(1) - X"20", SEQ := PACKET(2) - X"20", TYP := PACKET_CODES(PACKET(3) - X"41"); () KMT_MTM_VALUES PARAMS := (PACKET @ COMPLETE PACKET @ AS KMT_MTM_VALUES.RVB_VALUE, PACKET(0) @ MARK @ AS KMT_MTM_VALUES.RVB_VALUE, LEN @ LEN @ AS KMT_MTM_VALUES.RI_VALUE, SEQ @ SEQ @ AS KMT_MTM_VALUES.RI_VALUE, TYP @ TYPE @ AS KMT_MTM_VALUES.RI_VALUE, PACKET(4 SIZE PACKET_LENGTH - 5) @ DATA @ AS KMT_MTM_VALUES.RVB_VALUE, PACKET(PACKET_LENGTH - 1) @ CHECKSUM @ AS KMT_MTM_VALUES.RVB_VALUE); KMT_SP_LOG_TRACE_MESSAGE (TYPE, PARAMS) END; @ KMT_PP_LOG_TRACE_MESSAGE @ ***PAGE STATIC PROC KMT_PP_DATA_TRACE_MESSAGE IS ( INT TYPE, INT CODE, REF () BYTE DATA): @******************************************************************************@ @* *@ @* This procedure is used to log the packet data to the job journal. *@ @* *@ @******************************************************************************@ BEGIN INT CHAR_CODE := CODE; () KMT_MTM_VALUES PARAMS := (CHAR_CODE @ character code of data @ AS KMT_MTM_VALUES.RI_VALUE, DATA @ data @ AS KMT_MTM_VALUES.RVB_VALUE); KMT_SP_LOG_TRACE_MESSAGE (TYPE, PARAMS) END; @ KMT_PP_DATA_TRACE_MESSAGE @ ***PAGE STATIC PROC KMT_PP_BUILD_PACKET_DATA IS ( REF REF () BYTE BUFFER, REF REF () BYTE DATA, WORD TEXT_TYPE, REF BOOL BUFFER_COMPLETE) BOOL: @******************************************************************************@ @* *@ @* This procedure is used to perform data translation of the data area *@ @* referenced by BUFFER. *@ @* If a binary file transfer is requested then the translation process *@ @* involves control character quoting and 8th bit prefixing. Otherwise (for *@ @* text files) the translation process involves control character quoting and *@ @* EBCDIC to ASCII data translation. *@ @* If the whole of BUFFER has been translated then BUFFER_COMPLETE is set *@ @* TRUE and BUFFER is returned referencing a zero length record. Otherwise *@ @* BUFFER_COMPLETE is returned FALSE and BUFFER is returned referencing the *@ @* untranslated part of the original buffer. *@ @* The translated data is returned in the area referenced by DATA. *@ @* The procedure returns TRUE if there is insufficient space in DATA for more *@ @* of the translated data. *@ @* *@ @******************************************************************************@ BEGIN STATIC BYTE SPACE IS X"20", @ ASCII codes @ DEL IS X"7F"; BYTE QCTL IS KMT_PP_LOCAL_CONFG_PARAMS.QCTL, QBIN IS KMT_PP_LOCAL_CONFG_PARAMS.QBIN; () BYTE QLF IS (QCTL,X"4A"), @ ASCII quoted LF @ QFF IS (QCTL,X"4C"), @ ASCII quoted FF @ QCR IS (QCTL,X"4D"), @ ASCII quoted CR @ QCRLF IS (QCTL,X"4D",QCTL,X"4A"); @ ASCII quoted CRLF @ BOOL DATA_COMPLETE := FALSE; SIM PROC PACKETISE IS (() BYTE SOURCE,INT DATA_LENGTH): BEGIN IF KMT_PP_MOVE(SOURCE,DATA,DATA_COMPLETE) NE 0 THEN BUFFER_COMPLETE := KMT_PP_CHECK_COMPLETE(DATA_LENGTH,BUFFER) FI END @ PACKETISE @ ; BUFFER_COMPLETE := (LENGTH BUFFER LE 0); UNTIL DATA_COMPLETE OR BUFFER_COMPLETE DO IF TEXT_TYPE GT EBCDIC THEN @ ASCII or binary data @ INT SEQ_LEN := 0; (3) BYTE SEQ; BYTE THIS_CHAR := BUFFER(0); SIM PROC ADD_TO_SEQ IS (BYTE OCTET): BEGIN SEQ(SEQ_LEN) := OCTET; SEQ_LEN := SEQ_LEN+1 END @ ADD_TO_SEQ @ ; IF (THIS_CHAR GT DEL) AND (TEXT_TYPE EQ BINARY) THEN @ need to add 8th bit prefix @ ADD_TO_SEQ(QBIN) FI; THIS_CHAR := THIS_CHAR & X"7F"; IF (THIS_CHAR LT SPACE) OR (THIS_CHAR EQ DEL) THEN @ control character @ ADD_TO_SEQ(QCTL); THIS_CHAR := THIS_CHAR NEQ X"40" ELSF (THIS_CHAR EQ QCTL) OR (THIS_CHAR EQ QBIN AND TEXT_TYPE EQ BINARY) THEN @ special char, quote it @ ADD_TO_SEQ(QCTL) FI; ADD_TO_SEQ(THIS_CHAR); PACKETISE(SEQ(SIZE SEQ_LEN),1) ELSE @ EBCDIC data @ BYTE THIS_CHAR IS EBCDIC_TO_ASCII(BUFFER(0)); IF THIS_CHAR GT DEL THEN @ Format effector @ IF (LENGTH BUFFER LT 2) OR (THIS_CHAR EQ X"FB") THEN @ Newline FE (1 byte) or FE at end of record with no specifier@ IF THIS_CHAR EQ X"FB" THEN @ End of record so ignore @ BUFFER_COMPLETE := KMT_PP_CHECK_COMPLETE(1,BUFFER) ELSE @ Newline @ PACKETISE(QCRLF,1) FI ELSE @ FE with qualifier @ REF BYTE QUALIFIER IS BUFFER(1); SIM PROC EXPAND_FE IS (() BYTE EXPANSION): BEGIN IF QUALIFIER := QUALIFIER - W'(TO QUALIFIER - 1 UNTIL DATA_COMPLETE DO KMT_PP_MOVE(EXPANSION,DATA, DATA_COMPLETE) REPEAT); QUALIFIER EQ 0 THEN BUFFER_COMPLETE := KMT_PP_CHECK_COMPLETE(2,BUFFER) FI END @ EXPAND_FE @ ; CASE X"FF" - THIS_CHAR THEN @ multiple space @ EXPAND_FE(SPACE) ELSE @ multiple newline @ IF QUALIFIER EQ X"00" THEN @ translate to CR @ PACKETISE(QCR,2) ELSE @ expand to CRLF pairs @ EXPAND_FE(QCRLF) FI ELSE @ vertical position @ IF (QUALIFIER EQ X"00") THEN PACKETISE(QFF,2) ELSE PACKETISE(QCRLF,2) FI ELSE @ horizontal position @ PACKETISE(SPACE,2) ESAC FI ELSF THIS_CHAR EQ QCTL THEN @ quote character @ PACKETISE((QCTL,THIS_CHAR),1) ELSF (THIS_CHAR LT SPACE) OR (THIS_CHAR EQ DEL) THEN @ control character @ PACKETISE((QCTL,THIS_CHAR NEQ X"40"),1) ELSE @ printable character @ PACKETISE(THIS_CHAR,1) FI FI REPEAT; DATA_COMPLETE END @ KMT_PP_BUILD_PACKET_DATA @ ; ***PAGE STATIC PROC KMT_PP_UNQUOTE_CHAR IS ( REF () BYTE DATA, REF BYTE UNQUOTED_CHAR, REF INT SEQUENCE_LENGTH): @******************************************************************************@ @* *@ @* This procedure is used to process a quoted (binary and/or control) *@ @* character sequence. *@ @* The area referenced by DATA contains the character sequence to be *@ @* processed. The area referenced by UNQUOTED_CHAR is returned containing the *@ @* unquoted character (with the control and 8th bit set as appropriate) and *@ @* the area referenced by SEQUENCE_LENGTH is returned containing the length *@ @* of the quoted sequence. If the first character in DATA is not a binary or *@ @* control quote character then UNQUOTED_CHAR is returned containing the *@ @* character and SEQUENCE_LENGTH is returned containing 1. *@ @* *@ @******************************************************************************@ BEGIN WORD TEXT_TYPE IS KMT_FH_RECORD_DETAILS.TEXT_TYPE; BYTE QCTL IS KMT_PP_REMOTE_CONFG_PARAMS.QCTL, QBIN IS KMT_PP_REMOTE_CONFG_PARAMS.QBIN; BYTE THIS_CHAR := DATA(0); BYTE OR_MASK IS IF (TEXT_TYPE EQ BINARY) AND (THIS_CHAR EQ QBIN) THEN @ Binary file and 8th bit @ @ quoted character found @ THIS_CHAR := DATA(1); SEQUENCE_LENGTH := 2; X"80" ELSE @ Not an 8th bit quoted @ @ character @ SEQUENCE_LENGTH := 1; X"00" FI; IF THIS_CHAR EQ QCTL THEN @ Control quoted character @ THIS_CHAR := DATA(SEQUENCE_LENGTH); SEQUENCE_LENGTH := SEQUENCE_LENGTH + 1; IF (THIS_CHAR NE QCTL) AND (THIS_CHAR NE QBIN OR TEXT_TYPE NE BINARY) THEN @ Control character @ THIS_CHAR := THIS_CHAR NEQ X"40" FI FI; UNQUOTED_CHAR := THIS_CHAR ! OR_MASK END; @ KMT_PP_UNQUOTE_CHAR @ ***PAGE GLOBAL STATIC () PROC KMT_PP_TRANSLATE_TO_EBCDIC IS (): @******************************************************************************@ @* *@ @* This procedure is used to translate the packet data from ASCII to EBCDIC *@ @* and to process any quoted characters. *@ @* The untranslated data is read from, and the translated data is returned in *@ @* the area referenced by KMT_PH_INPUT_PACKET_DATA. *@ @* *@ @******************************************************************************@ BEGIN () BYTE UNTRANSLATED_DATA := KMT_PH_INPUT_PACKET_DATA; @ Copy untranslated data @ REF () BYTE DATA := UNTRANSLATED_DATA; BOOL DATA_COMPLETE := (LENGTH DATA LE 0); INT T_LEN IS FOR I UNTIL DATA_COMPLETE DO INT SEQUENCE_LENGTH; KMT_PP_UNQUOTE_CHAR (DATA, KMT_PH_INPUT_PACKET_DATA(I), SEQUENCE_LENGTH); DATA_COMPLETE := KMT_PP_CHECK_COMPLETE (SEQUENCE_LENGTH, DATA) REPEAT; KMT_PH_INPUT_PACKET_DATA := KMT_PH_INPUT_PACKET_DATA(SIZE T_LEN); TRANSLATE (ASCII_TO_EBCDIC, KMT_PH_INPUT_PACKET_DATA, 0, NIL); IF KMT_TRACE_FLAGS.PP_TRACING AND LENGTH KMT_PH_INPUT_PACKET_DATA > 0 THEN () ( KMT_PP_DATA_TRACE_MESSAGE(KMT_PP_PACKET_DATA_IN_MSG, EBCDIC, KMT_PH_INPUT_PACKET_DATA) ) FI END; @ KMT_PP_TRANSLATE_TO_EBCDIC @ ***PAGE GLOBAL STATIC () PROC KMT_PP_GET_PACKET IS ( REF INT TYPE, REF INT SEQ, RESPONSE RESULT): @******************************************************************************@ @* *@ @* This procedure is used to receive a KERMIT packet from the remote end. *@ @* If a failure is detected whilst attempting to read a packet then TYPE is *@ @* set to BAD_PKT and the failing resultcode is returned. *@ @* If a zero length packet is read or no 'MARK' character is found in the *@ @* packet then TYPE is set to BAD_PKT and resultcode KMT_PP_NO_INPUT_DATA is *@ @* returned. *@ @* If the checksum validation fails then TYPE is set to BAD_PKT and *@ @* resultcode KMT_PP_INVALID_CHECKSUM is returned. *@ @* In all other cases TYPE will be set to either INVALID_PKT or the packet *@ @* type. In the case of an invalid packet then a resultcode of either UNS_PKT *@ @* or NON_PKT will be returned. *@ @* The packet sequence number is returned in the area referenced by SEQ and *@ @* the packet data is returned in the area referenced by *@ @* KMT_PH_INPUT_PACKET_DATA. *@ @* *@ @******************************************************************************@ BEGIN INT KMT_PP_PACKET_IN_MSG IS 251, KMT_PP_NO_INPUT_PACKET IS -80250, KMT_PP_INVALID_CHECKSUM IS -80253, KMT_PP_INVALID_PACKET_LENGTH IS -80254; INT INPUT_PACKET_LENGTH, INPUT_BUFFER_LENGTH, PACKET_POINTER_LENGTH; INT MAX_INPUT_LENGTH IS KMT_DH_DEVICE_DETAILS.MAX_INPUT_LENGTH; REF () BYTE INPUT_PACKET, PACKET_POINTER; (MAX_INPUT_LENGTH) BYTE INPUT_BUFFER; @ Allows for padding and @ @ 'noise' characters @ IF ( KMT_DH_INPUT (INPUT_BUFFER, INPUT_BUFFER_LENGTH, RESULT); RESULT GT 0 ) THEN @ I/O error @ TYPE := BAD_PKT ELSF INPUT_BUFFER_LENGTH EQ 0 OR ( BYTE MARK IS KMT_PP_REMOTE_CONFG_PARAMS.MARK; REF () BYTE REM := INPUT_BUFFER(SIZE INPUT_BUFFER_LENGTH); PACKET_POINTER := REM(SIZE 0); UNTIL @ Skip all but last 'MARK' @ SCANUNQ (MARK, @ character @ REM, 0, REM) DO PACKET_POINTER := REM; REM := REM(1::) REPEAT; PACKET_POINTER_LENGTH := LENGTH PACKET_POINTER; PACKET_POINTER_LENGTH LT 2 ) OR ( INPUT_PACKET_LENGTH := PACKET_POINTER(1) - X"20" + 2; PACKET_POINTER_LENGTH LT INPUT_PACKET_LENGTH ) THEN @ Either 'MARK' character not @ @ found or insufficient data @ @ after 'MARK' character or a @ @ recoverable I/O error @ @ occurred. @ TYPE := BAD_PKT; RESULT := KMT_PP_NO_INPUT_PACKET ELSF ( (INPUT_PACKET_LENGTH LT 5) OR (INPUT_PACKET_LENGTH GT 96) ) THEN @ Packet length invalid @ TYPE := BAD_PKT; RESULT := KMT_PP_INVALID_PACKET_LENGTH ELSF ( INPUT_PACKET := PACKET_POINTER(SIZE INPUT_PACKET_LENGTH); IF KMT_TRACE_FLAGS.PP_TRACING THEN () ( KMT_PP_LOG_TRACE_MESSAGE (KMT_PP_PACKET_IN_MSG, INPUT_PACKET) ) FI; INPUT_PACKET(INPUT_PACKET_LENGTH - 1) NE KMT_PP_GENERATE_CHECKSUM ( INPUT_PACKET) ) THEN @ Checksum error @ TYPE := BAD_PKT; RESULT := KMT_PP_INVALID_CHECKSUM ELSE @ Validate packet type @ WORD PACKET_TYPE IS INPUT_PACKET(3) - X"41"; IF PACKET_TYPE GT 25 THEN @ Not in range A to Z @ TYPE := INVALID_PKT; RESULT := NON_PKT ELSF ( TYPE := PACKET_CODES(PACKET_TYPE); TYPE LT 0 ) THEN RESULT := TYPE; TYPE := INVALID_PKT ELSE REF INT DATA_LENGTH IS KMT_PP_INPUT_PACKET_DATA.DATA_LENGTH; REF () BYTE DATA IS KMT_PP_INPUT_PACKET_DATA.DATA; REF INT STATISTICS IS KMT_PP_PACKET_STATISTICS.INPUT_TOTAL; STATISTICS := STATISTICS + 1; SEQ := INPUT_PACKET(2) - X"20"; DATA_LENGTH := INPUT_PACKET_LENGTH - 5; MOVE (INPUT_PACKET(4 SIZE DATA_LENGTH), DATA, 0, X"00", NIL, NIL); KMT_PH_INPUT_PACKET_DATA := DATA(SIZE DATA_LENGTH) FI FI END; @ KMT_PP_GET_PACKET @ ***PAGE GLOBAL STATIC () PROC KMT_PP_SEND_PACKET IS ( INT TYPE, INT SEQ, BOOL PROMPT, RESPONSE RESULT): @******************************************************************************@ @* *@ @* This procedure is used to frame and send a KERMIT packet to the remote end.*@ @* TYPE and SEQ specify the packet type and sequence number respectively. *@ @* The packet data and length is read from the areas *@ @* KMT_PP_OUTPUT_PACKET_DATA.DATA and KMT_PP_OUTPUT_PACKET_DATA.DATA_LENGTH *@ @* respectively. *@ @* If PROMPT is set TRUE then read interest is set at the PFI for the next *@ @* input packet. *@ @* *@ @******************************************************************************@ BEGIN INT KMT_PP_PACKET_OUT_MSG IS 252; INT DATA_LENGTH IS KMT_PP_OUTPUT_PACKET_DATA.DATA_LENGTH; REF () BYTE DATA IS KMT_PP_OUTPUT_PACKET_DATA.DATA; INT OUTPUT_PACKET_LENGTH IS 5 + DATA_LENGTH; (OUTPUT_PACKET_LENGTH) BYTE OUTPUT_PACKET; STATIC () BYTE PACKET_TYPES IS X"00" @ Not used @ X"42" @ B packet @ X"44" @ D packet @ X"45" @ E packet @ X"46" @ F packet @ X"47" @ G packet @ X"49" @ I packet @ X"4B" @ K packet @ X"4E" @ N packet @ X"52" @ R packet @ X"53" @ S packet @ X"59" @ Y packet @ X"5A"; @ Z packet @ OUTPUT_PACKET(0) := KMT_PP_LOCAL_CONFG_PARAMS.MARK; OUTPUT_PACKET(1) := DATA_LENGTH + 3 + X"20"; OUTPUT_PACKET(2) := SEQ + X"20"; OUTPUT_PACKET(3) := PACKET_TYPES(TYPE); OUTPUT_PACKET(4 SIZE DATA_LENGTH) := DATA; OUTPUT_PACKET(OUTPUT_PACKET_LENGTH - 1) := KMT_PP_GENERATE_CHECKSUM ( OUTPUT_PACKET); IF KMT_TRACE_FLAGS.PP_TRACING THEN () ( KMT_PP_LOG_TRACE_MESSAGE (KMT_PP_PACKET_OUT_MSG, OUTPUT_PACKET) ) FI; KMT_DH_OUTPUT (OUTPUT_PACKET, PROMPT, RESULT); IF RESULT LE 0 THEN REF INT STATISTICS IS KMT_PP_PACKET_STATISTICS.OUTPUT_TOTAL; STATISTICS := STATISTICS + 1 FI END; @ KMT_PP_SEND_PACKET @ ***PAGE GLOBAL STATIC () PROC KMT_PP_BUILD_FILE_PACKET_DATA IS ( RESPONSE RESULT): @******************************************************************************@ @* *@ @* This procedure is used to read file records and to construct data packets *@ @* from the record performing data translation, binary and control character *@ @* character quoting as appropriate. *@ @* The record and length are returned in the data areas *@ @* KMT_FH_RECORD_DETAILS.RECORD and KMT_FH_RECORD_DETAILS.RECORD_LENGTH *@ @* respectively. The processed packet data and length are returned is the *@ @* data areas *@ @* KMT_PP_OUTPUT_PACKET_DATA.DATA and KMT_PP_OUTPUT_PACKET_DATA.DATA_LENGTH *@ @* respectively. *@ @* End of file is indicated by returning resultcode DML_READ_PSEUDO_NODE. *@ @* *@ @******************************************************************************@ BEGIN INT DML_READ_PSEUDO_NODE IS 9034; REF BOOL END_OF_FILE IS KMT_FH_RECORD_DETAILS.END_OF_FILE; REF INT DATA_LENGTH IS KMT_PP_OUTPUT_PACKET_DATA.DATA_LENGTH; RESULT := 0; IF END_OF_FILE THEN @ End of file reached during @ @ previous read @ DATA_LENGTH := 0; RESULT := DML_READ_PSEUDO_NODE ELSF ( REF BOOL NEW_RECORD IS KMT_FH_RECORD_DETAILS.NEW_RECORD; WORD TEXT_TYPE IS KMT_FH_RECORD_DETAILS.TEXT_TYPE; REF INT RECORD_LENGTH IS KMT_FH_RECORD_DETAILS.RECORD_LENGTH; REF () BYTE RECORD IS KMT_FH_RECORD_DETAILS.RECORD; BYTE QCTL IS KMT_PP_LOCAL_CONFG_PARAMS.QCTL; BYTE MAXL IS KMT_PP_REMOTE_CONFG_PARAMS.MAXL; REF () BYTE DATA IS KMT_PP_OUTPUT_PACKET_DATA.DATA(SIZE MAXL - 5); () BYTE QCRQLF IS (QCTL, X"4D", QCTL, X"4A"); @ Quoted CRLF @ INT D_LEN IS LENGTH DATA; REF () BYTE DATA_REM := DATA; (91) BYTE PP_TRACE_BUFFER; @ debug trace area @ REF () BYTE PP_TRACE_PTR := PP_TRACE_BUFFER; INT PP_TRACE_COUNT := 0; UNTIL ( BOOL DATA_COMPLETE; IF NEW_RECORD AND ( KMT_FH_READ (RESULT); IF RESULT LE 0 THEN @ Record read successfully @ KMT_PP_RECALL_DATA := RECORD(SIZE RECORD_LENGTH); FI; RESULT GT 0 ) THEN @ Read error or end of file @ END_OF_FILE := TRUE; DATA_COMPLETE := TRUE ELSE @ Build packet data from @ @ record @ REF () BYTE TRACE_PTR := KMT_PP_RECALL_DATA; INT TRACE_CT; DATA_COMPLETE := KMT_PP_BUILD_PACKET_DATA (KMT_PP_RECALL_DATA, DATA_REM, TEXT_TYPE, NEW_RECORD); @ copy source to trace buffer @ TRACE_CT := LENGTH TRACE_PTR - LENGTH KMT_PP_RECALL_DATA; PP_TRACE_PTR(SIZE TRACE_CT) := TRACE_PTR(SIZE TRACE_CT); PP_TRACE_COUNT := PP_TRACE_COUNT + TRACE_CT; PP_TRACE_PTR := PP_TRACE_BUFFER(PP_TRACE_COUNT::); IF TEXT_TYPE EQ BINARY THEN @ Binary file transfer don't @ @ add CRLF end of record @ @ marker @ SKIP ELSF NEW_RECORD THEN @ EBCDIC or ASCII file @ @ transfer and end of record. @ @ Move in quote CRLF, end of @ @ record marker @ NEW_RECORD := KMT_PP_MOVE (QCRQLF, DATA_REM, DATA_COMPLETE) NE 0; IF NEW_RECORD @ add new record mark to trace @ THEN PP_TRACE_PTR(SIZE 4) := IF TEXT_TYPE = EBCDIC THEN " // " ELSE X"202F2F20" FI; PP_TRACE_COUNT := PP_TRACE_COUNT + 4; PP_TRACE_PTR := PP_TRACE_BUFFER(PP_TRACE_COUNT::); FI FI FI; DATA_COMPLETE ) DO SKIP REPEAT; DATA_LENGTH := D_LEN - LENGTH DATA_REM; IF KMT_TRACE_FLAGS.PP_TRACING AND PP_TRACE_COUNT > 0 THEN () ( IF TEXT_TYPE = ASCII THEN TRANSLATE(ASCII_TO_EBCDIC, PP_TRACE_BUFFER(SIZE PP_TRACE_COUNT), 0, NIL) FI; KMT_PP_DATA_TRACE_MESSAGE(KMT_PP_PACKET_DATA_OUT_MSG, TEXT_TYPE, PP_TRACE_BUFFER(SIZE PP_TRACE_COUNT)) ) FI; (RESULT EQ DML_READ_PSEUDO_NODE) AND (DATA_LENGTH NE 0) ) THEN @ End of file reached but @ @ packet data remains. @ @ Return end of file on next @ @ call @ RESULT := 0 FI END; @ KMT_PP_BUILD_FILE_PACKET_DATA @ ***PAGE GLOBAL STATIC () PROC KMT_PP_BUILD_STRING_PACKET_DATA IS ( REF () BYTE STRING, RESPONSE RESULT): @******************************************************************************@ @* *@ @* This procedure is used to translate the data held in STRING from EBCDIC to *@ @* ASCII. *@ @* The translated data and length is returned in the area *@ @* KMT_PP_OUTPUT_PACKET_DATA.DATA and KMT_PP_OUTPUT_PACKET_DATA.DATA_LENGTH *@ @* respectively. *@ @* If the translated data length exceeds the maximum packet data length then *@ @* resultcode KMT_PP_STRING_TOO_BIG is returned. *@ @* *@ @******************************************************************************@ BEGIN INT KMT_PP_STRING_TOO_BIG IS 80256; INT MAXL IS KMT_PP_REMOTE_CONFG_PARAMS.MAXL; REF INT DATA_LENGTH IS KMT_PP_OUTPUT_PACKET_DATA.DATA_LENGTH; REF () BYTE DATA IS KMT_PP_OUTPUT_PACKET_DATA.DATA(SIZE MAXL - 5); INT STRING_LENGTH IS IF STRING IS NIL THEN 0 ELSE LENGTH STRING FI; IF STRING_LENGTH EQ 0 THEN @ NIL or ZLR supplied @ DATA_LENGTH := 0; RESULT := 0 ELSE () BYTE STRING_COPY := STRING; @ Don't want to corrupt @ @ original string @ REF () BYTE STRING_POINTER := STRING_COPY, DATA_REM := DATA; RESULT := IF ( BOOL STRING_COMPLETE := TRUE; KMT_PP_BUILD_PACKET_DATA (STRING_POINTER, DATA_REM, EBCDIC, STRING_COMPLETE); STRING_COMPLETE ) THEN 0 ELSE @ String too big @ KMT_PP_STRING_TOO_BIG FI; DATA_LENGTH := LENGTH DATA - LENGTH DATA_REM; IF KMT_TRACE_FLAGS.PP_TRACING THEN () ( KMT_PP_DATA_TRACE_MESSAGE(KMT_PP_PACKET_DATA_OUT_MSG,EBCDIC, STRING(SIZE (STRING_LENGTH - LENGTH STRING_POINTER))) ) FI FI; END; @ KMT_PP_BUILD_STRING_PACKET_DATA @ ***PAGE GLOBAL STATIC () PROC KMT_PP_BUILD_FILE_RECORD IS ( RESPONSE RESULT): @******************************************************************************@ @* *@ @* This procedure is used to construct file records from KERMIT data packets *@ @* received. For text files control character quoting and data translation *@ @* from ASCII to EBCDIC is performed. For binary files control character *@ @* quoting and 8th bit quoting is performed. *@ @* The packet data is read from the area referenced by *@ @* KMT_PH_INPUT_PACKET_DATA. The processed record and length is returned in *@ @* the areas KMT_FH_RECORD_DETAILS.RECORD and *@ @* KMT_FH_RECORD_DETAILS.RECORD.LENGTH respectively. *@ @* When the end of record is detected the record is written to the file. *@ @* *@ @******************************************************************************@ BEGIN INT KMT_PP_RECORD_TOO_BIG IS 80255; REF () BYTE DATA := KMT_PH_INPUT_PACKET_DATA; INT DATA_LENGTH IS LENGTH DATA; REF BOOL NEW_RECORD IS KMT_FH_RECORD_DETAILS.NEW_RECORD; WORD TEXT_TYPE IS KMT_FH_RECORD_DETAILS.TEXT_TYPE; INT MAX_RECORD_LENGTH := KMT_FH_RECORD_DETAILS.MAX_RECORD_LENGTH; REF INT RECORD_LENGTH IS KMT_FH_RECORD_DETAILS.RECORD_LENGTH; INT RECORD_SIZE IS IF TEXT_TYPE EQ BINARY THEN @ Binary file transfer. CRLF @ @ end of record terminator @ @ not required @ MAX_RECORD_LENGTH ELSE @ EBCDIC or ASCII file xfer. @ @ Allow for CRLF pair, end of @ @ record terminator @ MAX_RECORD_LENGTH + 2 FI; REF () BYTE RECORD IS KMT_FH_RECORD_DETAILS.RECORD(SIZE RECORD_SIZE); () BYTE LF IS X"0A", @ ASCII LF @ CR IS X"0D"; @ CR @ () BYTE CRLF IS (CR,LF); BOOL DATA_COMPLETE := (DATA_LENGTH LE 0); (96) BYTE PP_TRACE_BUFFER; @ packet trace variables @ REF () BYTE PP_TRACE_PTR := PP_TRACE_BUFFER, TRACE_PTR := KMT_PP_RECALL_DATA; INT PP_TRACE_COUNT := 0; RESULT := 0; UNTIL DATA_COMPLETE OR (RESULT GT 0) DO INT LAST_CHAR_INDEX IS IF NEW_RECORD THEN KMT_PP_RECALL_DATA := RECORD; TRACE_PTR := RECORD; @ (for trace) @ -1 ELSE RECORD_SIZE - (LENGTH KMT_PP_RECALL_DATA + 1) FI; BYTE UNQUOTED_CHAR; INT SEQUENCE_LENGTH; KMT_PP_UNQUOTE_CHAR (DATA, UNQUOTED_CHAR, SEQUENCE_LENGTH); IF KMT_PP_MOVE (UNQUOTED_CHAR, KMT_PP_RECALL_DATA, NEW_RECORD) NE 0 THEN @ Moved in data @ DATA_COMPLETE := KMT_PP_CHECK_COMPLETE (SEQUENCE_LENGTH, DATA); FI; IF TEXT_TYPE EQ BINARY THEN @ Binary file transfer @ RECORD_LENGTH := RECORD_SIZE - LENGTH KMT_PP_RECALL_DATA; IF NEW_RECORD THEN @ Record complete, output it @ @ (obtain trace info) @ INT TRACE_CT := LENGTH TRACE_PTR - LENGTH KMT_PP_RECALL_DATA; PP_TRACE_PTR(SIZE TRACE_CT) := TRACE_PTR(SIZE TRACE_CT); PP_TRACE_COUNT := PP_TRACE_COUNT + TRACE_CT; PP_TRACE_PTR := PP_TRACE_BUFFER(PP_TRACE_COUNT::); KMT_FH_WRITE (RESULT) @ output record @ FI ELSF (LAST_CHAR_INDEX GE 0) AND (RECORD(LAST_CHAR_INDEX SIZE 2) EQ CRLF) THEN @ EBCDIC or ASCII file xfer @ @ end of record, output it @ @ (obtain trace info) @ INT TRACE_CT := LENGTH TRACE_PTR - (LENGTH KMT_PP_RECALL_DATA + 2); IF TRACE_CT = -1 @ CR LF split between two packets @ THEN TRACE_CT := 0 ELSE PP_TRACE_PTR(SIZE TRACE_CT) := TRACE_PTR(SIZE TRACE_CT); FI; PP_TRACE_PTR := PP_TRACE_BUFFER((PP_TRACE_COUNT + TRACE_CT)::); PP_TRACE_PTR(SIZE 4) := X"202F2F20"; PP_TRACE_COUNT := PP_TRACE_COUNT + TRACE_CT + 4; PP_TRACE_PTR := PP_TRACE_BUFFER(PP_TRACE_COUNT::); RECORD_LENGTH := RECORD_SIZE - (LENGTH KMT_PP_RECALL_DATA + 2); @ Don't want CRLF in file @ IF TEXT_TYPE EQ EBCDIC THEN @ EBCDIC file transfer @ TRANSLATE (ASCII_TO_EBCDIC, RECORD(SIZE RECORD_LENGTH), 0, NIL) FI; KMT_FH_WRITE (RESULT); NEW_RECORD := TRUE ELSF ( RECORD_LENGTH := RECORD_SIZE - LENGTH KMT_PP_RECALL_DATA; NEW_RECORD ) THEN @ EBCDIC or ASCII file xfer @ @ and record buffer full but @ @ no end of record found. @ () KMT_MTM_VALUES PARAMS := DISPLAY(MAX_RECORD_LENGTH AS KMT_MTM_VALUES.RI_VALUE); RESULT := KMT_PP_RECORD_TOO_BIG; KMT_EH_LOG_ERROR (RESULT, 2, PARAMS, 0, FALSE, FALSE) FI REPEAT; IF KMT_TRACE_FLAGS.PP_TRACING THEN () ( IF DATA_COMPLETE AND NOT NEW_RECORD @ (obtain rest of trace info) @ THEN INT TRACE_CT := LENGTH TRACE_PTR - LENGTH KMT_PP_RECALL_DATA; PP_TRACE_PTR(SIZE TRACE_CT) := TRACE_PTR(SIZE TRACE_CT); PP_TRACE_COUNT := PP_TRACE_COUNT + TRACE_CT FI; IF PP_TRACE_COUNT > 0 THEN IF TEXT_TYPE NE BINARY THEN TRANSLATE(ASCII_TO_EBCDIC, PP_TRACE_BUFFER(SIZE PP_TRACE_COUNT), 0, NIL) FI; KMT_PP_DATA_TRACE_MESSAGE(KMT_PP_PACKET_DATA_IN_MSG, TEXT_TYPE, PP_TRACE_BUFFER(SIZE PP_TRACE_COUNT)) FI ) FI END; @ KMT_PP_BUILD_FILE_RECORD @ ***PAGE GLOBAL STATIC () PROC KMT_PP_BUILD_PARAM_PACKET_DATA IS (): @******************************************************************************@ @* *@ @* This procedure is used to construct the packet data from the configuration *@ @* parameters. *@ @* The configuration parameters are read from the area *@ @* KMT_PP_LOCAL_CONFG_PARAMS and the packet data and length is returned in *@ @* the areas KMT_PP_OUTPUT_PACKET_DATA.DATA and *@ @* KMT_PP_OUTPUT_PACKET_DATA.DATA_LENGTH respectively. *@ @* *@ @******************************************************************************@ BEGIN REF () BYTE DATA IS KMT_PP_OUTPUT_PACKET_DATA.DATA; BYTE N IS X"4E"; @ ASCII N @ DATA(0) := KMT_PP_LOCAL_CONFG_PARAMS.MAXL + X"20"; DATA(1) := KMT_PP_LOCAL_CONFG_PARAMS.TIME + X"20"; DATA(2) := KMT_PP_LOCAL_CONFG_PARAMS.NPAD + X"20"; DATA(3) := KMT_PP_LOCAL_CONFG_PARAMS.PADC NEQ X"40"; DATA(4) := KMT_PP_LOCAL_CONFG_PARAMS.EOL + X"20"; DATA(5) := KMT_PP_LOCAL_CONFG_PARAMS.QCTL; DATA(6) := IF KMT_FH_RECORD_DETAILS.TEXT_TYPE NE EBCDIC THEN @ ASCII or binary file xfer @ @ requested, do 8th bit @ @ quoting @ KMT_PP_LOCAL_CONFG_PARAMS.QBIN ELSE @ EBCDIC file transfer @ @ requested, donot do 8th bit @ @ quoting @ N FI; @ We don't support any others @ @ so default them @ KMT_PP_OUTPUT_PACKET_DATA.DATA_LENGTH := 7; IF KMT_TRACE_FLAGS.PP_TRACING THEN () ( () INT P := (KMT_PP_LOCAL_CONFG_PARAMS.MAXL, KMT_PP_LOCAL_CONFG_PARAMS.TIME, KMT_PP_LOCAL_CONFG_PARAMS.NPAD); () KMT_MTM_VALUES PARAMS := (P(0) AS KMT_MTM_VALUES.RI_VALUE, P(1) AS KMT_MTM_VALUES.RI_VALUE, P(2) AS KMT_MTM_VALUES.RI_VALUE, KMT_PP_LOCAL_CONFG_PARAMS.PADC AS KMT_MTM_VALUES.RVB_VALUE, KMT_PP_LOCAL_CONFG_PARAMS.EOL AS KMT_MTM_VALUES.RVB_VALUE, KMT_PP_LOCAL_CONFG_PARAMS.QCTL AS KMT_MTM_VALUES.RVB_VALUE, DATA(6) AS KMT_MTM_VALUES.RVB_VALUE); KMT_SP_LOG_TRACE_MESSAGE(KMT_PP_PARAM_OUT_MSG,PARAMS) ) FI END; @ KMT_PP_BUILD_PARAM_PACKET_DATA @ ***PAGE GLOBAL STATIC () PROC KMT_PP_PROCESS_PARAM_PACKET_DATA IS ( RESPONSE RESULT): @******************************************************************************@ @* *@ @* This procedure is used to extract the configuration parameters from the *@ @* packet data. *@ @* The packet data is read from the area referenced by *@ @* KMT_PH_INPUT_PACKET_DATA and the configuration parameters are returned in *@ @* the area KMT_PP_REMOTE_CONFG_PARAMS. *@ @* *@ @******************************************************************************@ BEGIN ***PAGE SIM PROC KMT_PP_LOG_PARAM_ERROR IS ( INT NAME_CODE, REF () BYTE VALUE, INT REASON_CODE, RESPONSE RESULT): @******************************************************************************@ @* *@ @* This procedure is used to log configuration parameter validation errors to *@ @* the job journal. *@ @* *@ @******************************************************************************@ BEGIN INT KMT_PP_INVALID_CONFIG_PARAM IS 80257; INT NAME := NAME_CODE, REASON := REASON_CODE; () KMT_MTM_VALUES PARAMS := (NAME AS KMT_MTM_VALUES.RI_VALUE, VALUE AS KMT_MTM_VALUES.RVB_VALUE, REASON AS KMT_MTM_VALUES.RI_VALUE); RESULT := KMT_PP_INVALID_CONFIG_PARAM; KMT_EH_LOG_ERROR (RESULT,2,PARAMS,0,FALSE,FALSE) END; @ KMT_PP_LOG_PARAM_ERROR @ ***PAGE INT KMT_PP_QBIN_AND_QCTL_EQUAL IS 80258, KMT_PP_QCTL_WARNING IS -80259, KMT_PP_QBIN_REJECTED IS 80260; INT MAXL_CODE IS 0, NPAD_CODE IS 1, PADC_CODE IS 2, EOL_CODE IS 3, QCTL_CODE IS 4, QBIN_CODE IS 5; INT INFO_LENGTH IS SIZEOF KMT_PP_CONFG_PARAMS_S; (INFO_LENGTH) BYTE PACKET_INFO; WORD MAX_OUTPUT_LENGTH IS KMT_DH_DEVICE_DETAILS.MAX_OUTPUT_LENGTH; WORD TEXT_TYPE IS KMT_FH_RECORD_DETAILS.TEXT_TYPE; WORD MIN_PACKET_LENGTH IS 30; INT DATA_LENGTH IS LENGTH KMT_PH_INPUT_PACKET_DATA; REF BYTE MAXL IS KMT_PP_REMOTE_CONFG_PARAMS.MAXL, TIME IS KMT_PP_REMOTE_CONFG_PARAMS.TIME, NPAD IS KMT_PP_REMOTE_CONFG_PARAMS.NPAD, PADC IS KMT_PP_REMOTE_CONFG_PARAMS.PADC, EOL IS KMT_PP_REMOTE_CONFG_PARAMS.EOL, QCTL IS KMT_PP_REMOTE_CONFG_PARAMS.QCTL, QBIN IS KMT_PP_REMOTE_CONFG_PARAMS.QBIN, CHKT IS KMT_PP_REMOTE_CONFG_PARAMS.CHKT, REPT IS KMT_PP_REMOTE_CONFG_PARAMS.REPT; REF 4-BYTE CAPAS IS KMT_PP_REMOTE_CONFG_PARAMS.CAPAS; REF BYTE LOCAL_MARK IS KMT_PP_LOCAL_CONFG_PARAMS.MARK, LOCAL_QCTL IS KMT_PP_LOCAL_CONFG_PARAMS.QCTL, LOCAL_QBIN IS KMT_PP_LOCAL_CONFG_PARAMS.QBIN; INT RC; BYTE PARAM; BYTE NUL IS X"00", @ ASCII NUL @ CR IS X"0D", @ CR @ SPACE IS X"20", @ Space @ HASH IS X"23", @ # @ ONE IS X"31", @ 1 @ RAB IS X"3E", @ > @ CTLNUL IS X"40", @ Controlled NUL @ N IS X"4E", @ N @ Y IS X"59", @ Y @ GRAVE IS X"60", @ ` @ TILDE IS X"7E", @ ~ @ DEL IS X"7F"; @ DEL @ RESULT := 0; MOVEBYTE (SPACE, @ Set defaults @ PACKET_INFO, 0, NIL); PACKET_INFO(3) := CTLNUL; @ PADC default @ PACKET_INFO(SIZE DATA_LENGTH) := KMT_PH_INPUT_PACKET_DATA; IF KMT_TRACE_FLAGS.PP_TRACING THEN () ( () INT IP := (PACKET_INFO(0) - X"20", PACKET_INFO(1) - X"20", PACKET_INFO(2) - X"20", PACKET_INFO(7) - X"30"); () BYTE BP := (PACKET_INFO(3) NEQ X"40", PACKET_INFO(4) - X"20"); () KMT_MTM_VALUES PARAMS := (IP(0) @ MAXL @ AS KMT_MTM_VALUES.RI_VALUE, IP(1) @ TIME @ AS KMT_MTM_VALUES.RI_VALUE, IP(2) @ NPAD @ AS KMT_MTM_VALUES.RI_VALUE, BP(0) @ PADC @ AS KMT_MTM_VALUES.RVB_VALUE, BP(1) @ EOL @ AS KMT_MTM_VALUES.RVB_VALUE, PACKET_INFO(5) @ QBIN @ AS KMT_MTM_VALUES.RVB_VALUE, PACKET_INFO(6) @ QCTL @ AS KMT_MTM_VALUES.RVB_VALUE, IP(3) @ CHKT @ AS KMT_MTM_VALUES.RI_VALUE, PACKET_INFO(8) @ REPT @ AS KMT_MTM_VALUES.RVB_VALUE, PACKET_INFO(9 SIZE 4) @ CAPAS @ AS KMT_MTM_VALUES.RVB_VALUE); KMT_SP_LOG_TRACE_MESSAGE(KMT_PP_PARAM_IN_MSG,PARAMS(SIZE DATA_LENGTH)) ) FI; PARAM := PACKET_INFO(0) - X"20"; MAXL := IF (PARAM EQ 0) OR (PARAM GE MAX_OUTPUT_LENGTH) THEN @ Defaulted or greater than @ @ device line length @ MAX_OUTPUT_LENGTH ELSE PARAM FI; TIME := PACKET_INFO(1) - X"20"; NPAD := PACKET_INFO(2) - X"20"; PADC := PACKET_INFO(3) NEQ X"40"; PARAM := PACKET_INFO(4) - X"20"; EOL := IF PARAM EQ 0 THEN @ defaulted, set to CR @ CR ELSE PARAM FI; PARAM := PACKET_INFO(5); QCTL := IF PARAM EQ SPACE THEN @ Defaulted, set to # @ HASH ELSE PARAM FI; PARAM := PACKET_INFO(6); QBIN := IF PARAM EQ N @ ASCII N @ THEN @ 8th bit quoting rejected @ SPACE ELSF PARAM EQ Y @ ASCII Y @ THEN @ 8th bit quoting requested @ LOCAL_QBIN ELSE PARAM FI; @ We donot support any others @ @ so default them @ CHKT := ONE; REPT := NUL; CAPAS := NUL; @ Validate configuration @ @ parameters @ IF MAXL LT MIN_PACKET_LENGTH THEN @ Invalid MAXL parameter @ KMT_PP_LOG_PARAM_ERROR (MAXL_CODE,MAXL,80270,RESULT) FI; IF (MAXL + NPAD) LE MAX_OUTPUT_LENGTH THEN SKIP ELSF @ Device line length exceeded @ ( @ Adjust MAXL @ MAXL := MAX_OUTPUT_LENGTH - NPAD; MAXL LT MIN_PACKET_LENGTH ) THEN @ NPAD parameter invalid @ KMT_PP_LOG_PARAM_ERROR (NPAD_CODE,NPAD,80271,RESULT) FI; IF (PADC GT SPACE) AND (PADC NE DEL) THEN @ Invalid PADC character @ KMT_PP_LOG_PARAM_ERROR (PADC_CODE,PADC,80272,RESULT) FI; IF EOL = LOCAL_MARK THEN @ EOL conflicts with MARK @ KMT_PP_LOG_PARAM_ERROR (EOL_CODE,EOL,80276,RESULT) ELSF KMT_SP_CHECK_VME_CHAR(EOL,1,RC); RC NE 0 THEN @ EOL not acceptable to VME @ KMT_PP_LOG_PARAM_ERROR (EOL_CODE,EOL,80274,RESULT) FI; IF NPAD > 0 THEN @ check for PADC conflict @ IF PADC = LOCAL_MARK THEN @ PADC conflicts with MARK @ KMT_PP_LOG_PARAM_ERROR (PADC_CODE,PADC,80276,RESULT) ELSF PADC = EOL THEN @ PADC conflicts with EOL @ KMT_PP_LOG_PARAM_ERROR (PADC_CODE,PADC,80277,RESULT) ELSF KMT_SP_CHECK_VME_CHAR(PADC,1,RC); RC NE 0 THEN @ PADC not acceptable to VME @ KMT_PP_LOG_PARAM_ERROR (PADC_CODE,PADC,80274,RESULT) FI FI; IF (QCTL LE SPACE) OR (QCTL GE DEL) THEN @ Invalid QCTL character @ KMT_PP_LOG_PARAM_ERROR (QCTL_CODE,QCTL,80273,RESULT) FI; IF (QCTL GT RAB) AND (QCTL LT GRAVE) THEN @ KERMIT protocol permits the QCTL character to be any printable @ @ character. However a QCTL character value in the range X3F to X5F may @ @ result in data corruption. A warning message is logged but the choice @ @ of QCTL is permitted as the protocol allows it. eg Consider a QCTL @ @ character of '?' (X3F) and data containing the character DEL (X7F). @ @ The sender encodes this as a two byte sequence: QCTL (DEL XOR X40) @ @ ie '??' (X3F3F). The quoting rule states that QCTL caharacters @ @ appearing in the data must also be prefixed. Therefore the receiver @ @ will decode the sequence as '?' (X3F) not DEL (X7F) as required. @ BYTE CORRUPTED_CHAR := (QCTL NEQ X"40"); () KMT_MTM_VALUES PARAMS := (QCTL AS KMT_MTM_VALUES.RVB_VALUE, CORRUPTED_CHAR AS KMT_MTM_VALUES.RVB_VALUE); KMT_EH_LOG_ERROR (KMT_PP_QCTL_WARNING,2,PARAMS,0,FALSE,FALSE) FI; IF TEXT_TYPE EQ EBCDIC THEN @ EBCDIC file transfer @ SKIP ELSF (QBIN LT SPACE) OR (QBIN GT TILDE) OR ((QBIN GT RAB) AND (QBIN LT GRAVE)) THEN @ Invalid QBIN character @ KMT_PP_LOG_PARAM_ERROR (QBIN_CODE,QBIN,80275,RESULT) ELSF QBIN EQ SPACE THEN @ QBIN character rejected @ RESULT := KMT_PP_QBIN_REJECTED; KMT_EH_LOG_ERROR (RESULT,2,NIL,0,FALSE,FALSE) ELSF QBIN EQ QCTL OR QBIN EQ LOCAL_QCTL THEN @ ASCII or binary file xfer, @ @ but QBIN and QCTL characters@ @ are equal @ () KMT_MTM_VALUES PARAMS := (QBIN AS KMT_MTM_VALUES.RVB_VALUE, QCTL AS KMT_MTM_VALUES.RVB_VALUE, LOCAL_QCTL AS KMT_MTM_VALUES.RVB_VALUE); RESULT := KMT_PP_QBIN_AND_QCTL_EQUAL; KMT_EH_LOG_ERROR (RESULT,2,PARAMS,0,FALSE,FALSE) ELSE @ IA5 or binary file transfer,@ @ and QCTL and QBIN characters@ @ are acceptable @ LOCAL_QBIN := QBIN FI END; @ KMT_PP_PROCESS_PARAM_PACKET_DATA @ ENDMODULE @ KMT_PP_MODULE @