! FILE 'NGATE3' %CONSTSTRING (7) VSN = "VSN003J" !**************************** !* GATE FOR USE WITH NODE * !* FILE: NGATE3 * !* DATE: 18.NOV.80 * !**************************** !! STACK SIZE = 300 %RECORDFORMAT DMF(%INTEGER I) %SYSTEMROUTINESPEC LINKIN(%INTEGER SERVICE) %SYSTEMROUTINESPEC ALARM(%INTEGER TICKS) %CONSTRECORD (DMF) %NAME NULL = 0 %CONSTINTEGER OWN TERM = 0; ! NETWORK ADDRESS %CONSTINTEGER MAX WRITES = 1; ! WRITE-AHEADS TO PROTOCOL HAND. %CONSTINTEGER LINE NO = 30 %CONSTINTEGER KENT = 0; ! KENT=1 - NO NODE IN NET %CONTROL K'100001' %BEGIN %RECORDFORMAT NSI1F(%BYTEINTEGER FN, SUFL, ST, SS, SN, DN, DT, %C DS, FLAG, UFL, LEN1, DATA, %BYTEINTEGERARRAY A(2:238)) %RECORDFORMAT NSI2F(%BYTEINTEGER FN, SUFL, ST, SS, FLAG, UFLAG %C , FLEN, FDATA, FD2, FD3, FD4) %RECORDFORMAT NSI3F(%BYTEINTEGERARRAY A(0:100)) %RECORDFORMAT MEF(%RECORD (MEF) %NAME LINK, %C %BYTEINTEGER LEN, TYPE, %RECORD (NSI1F)NSL) %RECORDFORMAT PE(%BYTEINTEGER SER, REPLY, %C FN, PORT, %RECORD (MEF) %NAME MES, %BYTEINTEGER LEN, S1) %RECORDFORMAT P2F(%BYTEINTEGER SER, REPLY, FN, PORT, %C FACILITY, FLAG, NODE, TERM) %RECORDFORMAT QF(%RECORD (MEF) %NAME E) %RECORDFORMAT PORTF(%BYTEINTEGER STATE, OWNER PORT, %C NODE, TERM, %INTEGER FL, RL, NO, %C OWNER, MAX FL, %RECORD (QF) OUT Q) %RECORDFORMAT NSI4F(%BYTEINTEGER FN, SUFL, ST, SS, SN, DN, DT, %C DS, FLAG, UFLAG, %INTEGERARRAY A(0:120)) %RECORDFORMAT KERN MONF(%INTEGERARRAY A(0:21)) %CONSTRECORD (KERN MONF) %NAME KERN MON = K'060140' %CONSTINTEGERNAME CPU = K'060012' %RECORD (NSI4F) %NAME NSI4 !********************************************** !* NSI FUNCTIONS FRON NODE * !********************************************** %CONSTINTEGER ATTACH = 1; ! NSI FN VALUES %CONSTINTEGER SEND MESS = 2 %CONSTINTEGER CONNECT = 3 %CONSTINTEGER SEND BLOCK = 4 %CONSTINTEGER STATUS = 5 %CONSTINTEGER NIF = 6 %CONSTINTEGER REMOVE = 7 %CONSTINTEGER REPLY = 128; ! ADDED TO ABOVE FOR REPLY %CONSTINTEGER ATTACH R = 8; ! 'REAL' VALUE IS ATTACH+128 %CONSTINTEGER SEND MESS R = 9 %CONSTINTEGER CONNECT R = 10 %CONSTINTEGER SEND BLOCK R = 11 %CONSTINTEGER STATUS R = 12 %CONSTINTEGER NIF R = 13 %CONSTINTEGER REMOVE R = 14 !************************************************************ !* UPPER LEVEL (ITP&RJE) HANDLER MESSAGES TO GATE !************************************************************ %CONSTINTEGER ENABLE FACILITY = 1; ! ENABLE THE FACILITY %CONSTINTEGER DISABLE FACILITY = 2; ! THE REVERSE %CONSTINTEGER CALL REPLY = 3; ! REPLY TO A 'CALL CONNECT' %CONSTINTEGER ENABLE INPUT = 4; ! ALLOW A BLOCK TO BE READ %CONSTINTEGER PUT OUTPUT = 5; ! SEND A BLOCK OF OUTPUT %CONSTINTEGER CLOSE CALL = 6; ! TERMINATE A CALL %CONSTINTEGER ABORT CALL = 7; ! ABORT THE CALL %CONSTINTEGER OPEN CALL = 8; ! OPEN A VIRTUAL CIRCUIT %CONSTINTEGER OPEN MESSAGE = 9; ! SEND A MESSAGE !******** FROM BUFFER MANAGER ****** %CONSTINTEGER BUFFER HERE = 0 !********************************************************** !* MESSAGES FROM GATE TO UPPER LEVEL PROTOCOLS !********************************************************** %CONSTINTEGER OPEN CALL REPLY = 1 %CONSTINTEGER INCOMING CALL = 2 %CONSTINTEGER INPUT RECD = 3; ! BLOCK ARRIVED FROM NODE %CONSTINTEGER OUTPUT TRANSMITTED = 4; ! PREPARED TO ACCEPT MORE %CONSTINTEGER CALL CLOSED = 5; ! EITHER END HAS CLOSED DOWN %CONSTINTEGER CALL ABORTED = 6; ! OTHER END HAS ABORTED %CONSTINTEGER OPEN REPLY A = 7 %CONSTINTEGER OPEN REPLY B = 8 %CONSTINTEGER MESSAGE = 9 %CONSTINTEGER MESSAGE REPLY = 10 !********** TO BUFFER MANAGER *********** %CONSTINTEGER REQUEST BUFFER = 0 %CONSTINTEGER RELEASE BUFFER = 1 !************************************************************** !******* CALLS ON LINE (OR PROTOCOL) HANDLER ********* !************************************************************ %CONSTINTEGER LINE INPUT = 2 %CONSTINTEGER LINE OUTPUT = 1 !************************************************************ !********** VARIOUS SERVICE NUMBERS ************* %CONSTBYTEINTEGERNAME OWN ID = K'160030' %CONSTINTEGER GATE SER = 16 %CONSTINTEGER BUFFER MANAGER = 17 %CONSTINTEGER PROT SER = 29 %CONSTBYTEINTEGERNAME CHANGE OUT ZERO = K'160310' %CONSTINTEGER T3 SER = 21 !********************************************** !* PORT STATES * !********************************************** %CONSTINTEGER DOWN = 0 %CONSTINTEGER CONNECTING = 1 %CONSTINTEGER CONNECTED = 2 %CONSTINTEGER DISCONNECTING = 3 %CONSTINTEGER DISCON 2 = 4 %CONSTINTEGER ABORTING = 5 %CONSTINTEGER CLEARING = 6; ! LINE HAS GONE DOWN !**** REST ARE SUB STATES OF 'AWAITING BUFFER' %CONSTINTEGER PUT READ ON RB = 4 %CONSTINTEGER ATTACH RB = 5 %CONSTINTEGER STATUS REPLY RB = 7 %CONSTINTEGER SEND STATUS RB = 8 %CONSTINTEGER SEND BL REPLY RB = 6 %CONSTINTEGER SEND BL REPLY DRB = 9; ! ALSO SET DISCONNECT %CONSTINTEGER SEND BL DRB = 10; ! SEND A BLOCK WITH DISCONNECT %CONSTINTEGER SEND MESSAGE = 11; ! SEND AN NSI MESSAGE %CONSTINTEGER SEND CONNECT = 12; ! SEND AN "NSI" CONNECT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! GENERAL VARIABLES !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! %RECORD (PE) P %RECORD (P2F) %NAME P2 !! %CONSTBYTEINTEGERNAME INT = K'160060' %OWNINTEGER MON = 0; ! MONITORING OFF %OWNINTEGER SBRF = 0; ! REMOVE SBR FLAG %CONSTINTEGER MAXT = 50 %OWNRECORD (PORTF) %NAME PORT %OWNRECORD (PORTF) %ARRAY PORTA(0:MAXT) %OWNRECORD (QF) NODE Q %OWNINTEGER NODE STATE = -1; ! -1 - DOWN, OTHERWISE WRITE AHEADS %OWNINTEGER ATT FLAG = 0; ! 1=ATTACHED OK %OWNINTEGER FORCE DOWN = 0; ! '1' WHEN IN DOWN STATE !******************************************************** !* FACILITY: CONTAINES EITHER - ZERO - NOT ALLOCATED * !* OR - SER NO OF OWNER PROC * !******************************************************** %CONSTINTEGER FAC MAX = 25 %OWNBYTEINTEGERARRAY FACILITY(0:FAC MAX) = 0(0) !! %PERMROUTINESPEC PUSH(%RECORD (QF) %NAME Q, %RECORD (MEF) %NAME M) !! %PERMRECORD (MEF) %MAPSPEC POP(%RECORD (QF) %NAME Q) %ROUTINESPEC FROM HIGHER LEVEL %ROUTINESPEC DO ATT REM(%INTEGER TYPE, %RECORD (MEF) %NAME MES) %ROUTINESPEC FAULT(%INTEGER TYPE, PORT N) %ROUTINESPEC TO UPPER(%INTEGER CALL, %RECORD (MEF) %NAME MES) %ROUTINESPEC TO NODE(%RECORD (MEF) %NAME MES) %ROUTINESPEC ASK FOR BLOCK(%INTEGER REASON, PORT NO) %RECORD (MEF) %MAPSPEC NODE %ROUTINESPEC BUFFER ARRIVED %ROUTINESPEC TIDY PORTS %ROUTINESPEC FREE BUFFER(%RECORD (MEF) %NAME MES) %ROUTINESPEC NODE MONITOR(%RECORD (NSI3F) %NAME NSA) %RECORDFORMAT R1F(%INTEGER X) %RECORDFORMAT R2F(%RECORD (MEF) %NAME MES) %RECORD (R1F)R1; %RECORD (R2F) %NAME R2 %INTEGER I %OWNINTEGER Q = 0 %RECORD (MEF) %NAME MES %OWNINTEGER TSL, IB, IC, OB, OC CHANGE OUT ZERO = T3 SER; ! SET 'SELECT OUTPUT(0)' TO COMMON R2 == R1 P2 == P MAP VIRT(BUFFER MANAGER, 4, 3) MAP VIRT(BUFFER MANAGER, 5, 4) MAP VIRT(BUFFER MANAGER, 6, 5) ! MAP BUF MAN SEG 6 TO SEG 4 LINKIN(GATE SER) ALARM(100) %CYCLE I = 1, 1, MAXT PORT == PORTA(I) PORT_NO = I %REPEAT P_SER = PROT SER; P_REPLY = OWN ID; ! SAY HEELO TO KERNEL P_FN = LINE INPUT; P_PORT = LINE NO P_LEN = 2 PON(P) FORCE DOWN = 0 ASK FOR BLOCK(ATTACH RB, 0) NODE STATE = 1 %CYCLE P_SER = 0; POFF(P) %IF 'M' <= INT <='O' %START MON = INT-'O'; INT = 0 %FINISH %IF INT = 'S' %START SBRF = SBRF!!1; ! CHANGE SBR FLAG INT = 0 %FINISH %IF INT = 'D' %START; ! FORCE DOWN FORCE DOWN = 1 %IF KENT = 0 %START; ! PROPER NODE ASK FOR BLOCK(ATTACH RB, 0) %ELSE PRINTSTRING("GATE CLOSEDOWN ") TIDY PORTS %FINISH ATT FLAG = 0 INT = 0 %FINISH !********************************* !* 1) MESSAGE FROM UPPER LEVEL * !* 2) MESSAGE FROM NODE * !********************************* %IF P_SER = GATE SER %THEN FROM HIGHER LEVEL %IF P_REPLY = BUFFER MANAGER %START BUFFER ARRIVED %ELSE %IF P_SER = OWN ID %START %IF P_REPLY = 0 %START; ! CLOCK TICK ALARM(100); ! 2 SECS %IF INT = '?' %START WRITE(Q, 1); NEWLINE %CYCLE I = 1, 1, MAXT PORT == PORTA(I) %IF PORT_STATE # DOWN %START WRITE(I, 2); WRITE(PORT_STATE, 2) WRITE(PORT_TERM, 3) WRITE(PORT_FL, 3); WRITE(PORT_RL, 1) NEWLINE %FINISH %REPEAT INT = 0 %FINISH TSL = TSL+1 %IF TSL = 15 %START; ! 30 SECS TSL = 0 %IF INT = 'P' %START PRINTSTRING("GATE: I,O") WRITE(IB, 3); WRITE(IC, 4) WRITE(OB, 4); WRITE(OC, 4); NEWLINE IB=0; IC=0; OB=0; OC=0 %FINISH %FINISH %CONTINUE %FINISH %IF P_FN = LINE INPUT MES == NODE %UNLESS MES == NULL %THEN FREE BUFFER(MES) %ELSE !! LINE OUTPUT %IF P_FN = 4 %START; ! PUT DOWN PRINTSTRING("GATE down ") NODE STATE = -1; ATT FLAG = 0 TIDY PORTS %ELSE !! UP MESSAGE OR WRITE ACK %CONTINUE %UNLESS P_FN = 5 %IF NODE STATE < 0 %START FORCE DOWN = 0 ASK FOR BLOCK(ATTACH RB, 0) %IF KENT = 0 NODE STATE = MAX WRITES %FINISH %FINISH %FINISH %FINISH %REPEAT %ROUTINE TO NODE(%RECORD (MEF) %NAME MES) %IF NODE STATE < 0 %START FREE BUFFER(MES); ! NODE IS DOWN %RETURN %FINISH %IF MON # 0 %START SELECT OUTPUT(1) PRINTSTRING('O '); WRITE(MES_LEN, 2); NODE MONITOR(MES_NSL) SELECT OUTPUT(0) %FINISH P_MES == MES; P_LEN = MES_LEN OB = OB+1; OC = OC+P_LEN !************************************************* !* MESSAGE TO NODE: P_MES POINTS TO HDLC SPACE * !************************************************* P_SER = PROT SER; P_REPLY = OWN ID P_FN = LINE OUTPUT; P_PORT = LINE NO PON(P) %END %ROUTINE ASK FOR BLOCK(%INTEGER REASON, PORT NO) %RECORD (PE) P P_SER = BUFFER MANAGER; P_REPLY = OWN ID P_FN = REQUEST BUFFER; P_S1 = REASON; P_PORT = PORT NO P_LEN = 0; ! ASK FOR LONG BLOCK PON(P) %END %RECORD (MEF) %MAP NODE %INTEGER FN, I, TERM, PORT N, DISCON, SITE, FAC NO, TYPE %RECORD (NSI1F) %NAME NSL %RECORD (NSI2F) %NAME NSS %RECORD (MEF) %NAME MES %RECORD (MEF) %NAME MES2 %CONSTBYTEINTEGERARRAY VALID(ATTACH:REMOVE R) = 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0 !! A "1" IN VALID SPECIFIES THAT NSS_SS = PORTN %SWITCH SW(0:15) !**************************************************** !* ALL MESSAGES FROM NODE COME TO HERE * !* P_A1 POINTS NO THE NSI HEADER * !* P_A2 IS THE LENGTH OF THE NSI PCKET * !**************************************************** MES == P_MES NSL == MES_NSL; NSS == NSL FN = NSL_FN %IF MON # 0 %START SELECT OUTPUT(1) PRINTSTRING('I '); WRITE(MES_LEN, 2); NODE MONITOR(NSL) SELECT OUTPUT(0) %FINISH IB = IB+1; IC = IC+MES_LEN %IF FN&128 # 0 %THEN FN = FN&127+7 PORT N = NSL_SS; ! PICK UP STREAM AS INDEX PORT == PORTA(PORT N); ! FOR THOSE WHO NEED IT %UNLESS 1<= FN <= 15 %START RUBBISH: FAULT(1, PORT N); NODE MONITOR(NSL) ->FREE %FINISH !! COMPILER FAULT WITH COMPLEX CONDITIO %IF FN = 7 %THEN -> RUBBISH %IF MES_LEN <= 5 %THEN -> RUBBISH %UNLESS 0<=PORT N<=MAXT %OR VALID(FN) = 0 %THEN -> RUBBISH -> SW(FN) SW(ATTACH): -> FAIL %IF KENT = 0 PRINTSTRING("TCP ATTACHED ") ATT FLAG = 1 -> REPLY SW(SEND MESS): TYPE = MESSAGE -> GET SW(CONNECT): TYPE = INCOMING CALL GET: MES_NSL_FN = MES_NSL_FN!128; ! SET THE REPLY BIT FAC NO = MES_NSL_DS; ! GET THE FACILITY NUMBER %IF FAC NO <= FAC MAX %AND FACILITY(FAC NO) # 0 %START; ! ENABLED OK %CYCLE I = 1, 1, MAXT PORT == PORTA(I) %IF PORT_STATE = DOWN %START PORT_STATE = CONNECTING PORT_OWNER = FACILITY(FAC NO) P_LEN = MES_NSL_FLAG; ! PASS FORWARD/REV BUFF LIM P_S1 = MES_NSL_ST; ! PASS TERMINAL NO PORT_TERM = P_S1; ! COPY TO PORT TO UPPER(TYPE, MES) PORT_OUT Q_E == MES; ! RETAIN CONNECT MESSAGE %RESULT == NULL %FINISH %REPEAT %FINISH !! EITHER FACILITY NOT ENABLED OR NO FREE PORTS %IF FAC NO = 21 %START; ! SPECIAL ON NGATE TO RETURN POLL NSI4 == MES_NSL NSI4_A(2) = CPU %CYCLE I = 0, 1, 21 NSI4_A(I+3) = KERN MON_A(I) %REPEAT MES_LEN = (21+3)*2+8 %ELSE MES_NSL_SUFL = 128+8; MES_NSL_LEN1 = 2 MES_NSL_DATA = 'N'; MES_NSL_A(2) = 'O' MES_LEN = 13; ! +2 ????? %FINISH TO NODE(MES) %RESULT == NULL SW(SEND BLOCK): -> FAIL %UNLESS PORT_STATE > DOWN !! DEAL WITH INCOMING BUFFER ACK %IF NSS_FLAG&X'70'#0 %START I = NSS_FLAG>>4 %IF PORT_RL = 0 %THEN TO UPPER(OUTPUT TRANSMITTED, NULL) PORT_RL = PORT_RL+I !! DISCON 2 STATE ? %FINISH DISCON = NSS_FLAG&128 TO UPPER(INPUT RECD, MES) %IF DISCON # 0 %START PORT_STATE = DISCONNECTING TO UPPER(CALL CLOSED, NULL) %FINISH %RESULT == NULL SW(STATUS): -> FAIL %UNLESS PORT_STATE > DOWN %IF NSS_FLAG&128 # 0 %START ! DISCONNECT SET DO STATUS: TO UPPER(CALL ABORTED, NULL) PORT_STATE = ABORTING ->FREE %FINISH -> REPLY SW(NIF): PRINTSTRING('GATE> NIF ') NODE MONITOR(NSL) %IF NSL_FLAG&128 # 0 %THEN -> DO STATUS !! WITHOUT DISCONNECT ->FREE SW(ATTACHR): %IF NSL_SUFL # 0 %START ! FAILED DO ATT REM(REMOVE, MES) %RESULT == NULL %FINISH ATT FLAG = 1 PRINTSTRING("GATE:Attached to Kernel ") -> FREE SW(SEND MESSR): SW(CONNECT R): %IF PORT_STATE # CONNECTING %THEN -> FAIL P_S1 = NSL_SUFL %IF FN = SEND MESS R %START P_LEN = PORT_OWNER PORT; ! RETURN USERS INDEX NO TO UPPER(MESSAGE REPLY, MES) !! NB: UPPER MUST FREE 'MES' PORT_STATE = DOWN %RESULT == NULL %FINISH TO UPPER(OPEN REPLY B, NULL) %IF NSL_SUFL # 0 %C %THEN PORT_STATE = DOWN %ELSE PORT_STATE = CONNECTED PORT_RL = NSL_FLAG>>4; ! TECHNICALLY IS FL NOT RL(SEE PUT OUTPUT) PORT_MAX FL = (NSL_FLAG>>1)&7; ! SBR REMOVAL CODE PORT_FL = 0; ! PORT_FL CONTAINS THE NO OF UNACK BLOCKS -> FREE SW(SEND BLOCK R): %IF PORT_RL = 0 %THEN TO UPPER(OUTPUT TRANSMITTED, NULL) I = NSS_FLAG>>4 %IF I = 0 %THEN I = 1 PORT_RL = PORT_RL+I %IF PORT_STATE = DISCONNECTING %AND NSS_FLAG&128 # 0 %START TO UPPER(CALL CLOSED, NULL) PORT_STATE = DOWN %FINISH %IF PORT_STATE = DISCON 2 %START; ! WAITING TO SEND DISCONNECT PORT_STATE = DISCONNECTING NSS_FN = 4; NSS_FLAG = 128; MES_LEN = 6 -> SEND TO NODE %FINISH ->FREE SW(STATUS R): -> FAIL %UNLESS PORT_STATE = ABORTING TO UPPER(CALL ABORTED, NULL); ! CONFIRMATION OF ABORT PORT_STATE = DOWN -> FREE SW(NIF R):-> FAIL SW(REMOVE): -> FAIL %IF KENT = 0 FORCE DOWN = 1; ! GET IT TO TIDY PORTS SW(REMOVE R): %IF FORCE DOWN # 0 %START PRINTSTRING("GATE: REMOVED OK ") TIDY PORTS -> FREE %FINISH DO ATT REM(ATTACH, MES) %RESULT == NULL REPLY: NSL_FN = NSL_FN!128 SEND TO NODE: TO NODE(MES) %RESULT == NULL FREE: %RESULT == MES; ! BLOCK IS PASSED BACK FOR ! NEXT READ FAIL: FAULT(100+FN, PORT N) PRINTSTRING("STATE ="); WRITE(PORT_STATE, 1); NEWLINE NODE MONITOR(NSL) %RESULT == MES %END !! %ROUTINE FROM HIGHER LEVEL %RECORD (MEF) %NAME MES %RECORD (NSI2F) %NAME NSS %INTEGER FN, PORT N, FLAG, REASON %SWITCH FUNCTION(ENABLE FACILITY:OPEN MESSAGE) PORT N = P_PORT %IF PORT N > MAXT %THEN FAULT(2, PORT N) %AND %RETURN PORT == PORTA(PORT N) MES == P_MES; NSS == MES_NSL FN = P_FN ->FUNCTION(FN) FUNCTION(ENABLE FACILITY): FACILITY(P_S1) = P_REPLY %RETURN FUNCTION(DISABLE FACILITY): FACILITY(P_S1) = 0 %RETURN FUNCTION(CALL REPLY): ! REPLY TO A 'CONNECT' FLAG = P_S1; ! 0 - REJECT, OTHERWISE NSL_FLAG MES == PORT_OUT Q_E; ! RECOVER CONNECT MESS %IF FLAG&127 = 0 %START; ! FAILED %IF FLAG = 0 %THEN FLAG = 128+8 %ELSE FLAG = 0 MES_NSL_SUFL = FLAG PORT_STATE = DOWN %ELSE MES_NSL_SUFL = 0 MES_NSL_DS = PORT_NO MES_NSL_FLAG = FLAG PORT_RL = FLAG>>1&7 PORT_FL = 0; PORT_MAX FL = FLAG>>4 PORT_STATE = CONNECTED %FINISH TO NODE (MES) %RETURN FUNCTION(ENABLE INPUT): ! ALLOW A BLOCK TO BE READ PORT_FL = PORT_FL+1 !! SBR REMOVAL CODE %IF SBRF#0 %AND PORT_MAX FL >= 2 %AND PORT_FL=1 %THEN %RETURN REASON = SEND BL REPLY RB; ! REQUEST BUFFER -> DO REQUEST BUFFER FUNCTION(PUT OUTPUT): ! P_MES TO BE SENT %IF PORT_RL > 0 %START; ! ALLOWED TO SEND ONE PORT_RL = PORT_RL-1 NSS_FN = 4; NSS_SUFL = 0 NSS_ST = OWN TERM; NSS_SS = PORT_NO !! SBR REMOVAL CODE %IF SBRF#0 %AND PORT_MAX FL >=2 %AND PORT_FL#0 %START NSS_FLAG = PORT_FL<<4; PORT_FL = 0 %ELSE NSS_FLAG = 0 TO NODE(MES) %IF PORT_RL > 0 %THEN TO UPPER(OUTPUT TRANSMITTED, NULL) %ELSE !! REVERSE BUFFER LIMIT IS ZERO ???? FAULT(3, PORT N); FREE BUFFER(MES) %FINISH %RETURN FUNCTION(CLOSE CALL): ! CLOSE IT DOWN %IF PORT_STATE = CONNECTED %START %IF PORT_RL = 0 %START; ! UNABLE TO SEND JUST NOW PORT_STATE = DISCON 2; ! HOLD IT %RETURN %FINISH REASON = SEND BL DRB; ! SEND IT NOW %ELSE REASON = SEND BL REPLY DRB; ! REPLY TO A DISCONNECT PORT_STATE = DISCONNECTING ->DO REQUEST BUFFER FUNCTION(ABORT CALL): %IF PORT_STATE = CLEARING %THEN PORT_STATE = DOWN %AND %RETURN ! CAUSED BY LINE DOWN, SO NO STATUS %IF PORT_STATE = CONNECTED %THEN %C REASON = SEND STATUS RB %ELSE %C REASON = STATUS REPLY RB PORT_STATE = ABORTING -> DO REQUEST BUFFER FUNCTION(OPEN MESSAGE): FUNCTION(OPEN CALL): PORT N = 0 %IF ATT FLAG # 0 %START; ! ATTACHED OK %CYCLE PORT N = MAXT, -1, 0 PORT == PORTA(PORT N) %IF PORT_STATE = DOWN %THEN %EXIT %REPEAT %IF PORT N = 0 %START !! FULL UP !! FAULT(4, 0) %ELSE PORT_OWNER = P_REPLY PORT_TERM = P2_TERM; PORT_NODE = P2_NODE PORT_FL = P2_FLAG; PORT_RL = P2_FACILITY PORT_OWNER PORT = P_PORT; ! KEEP USERS NO %FINISH %FINISH P_SER = P_REPLY; P_REPLY = GATE SER P_S1 = PORT N; ! PASS THE GATE "PORT NO" P_FN = OPEN REPLY A PON(P) %UNLESS FN = OPEN MESSAGE %RETURN %IF PORT N = 0 PORT_STATE = CONNECTING REASON = SEND CONNECT %IF FN = OPEN MESSAGE %START REASON = SEND MESSAGE PORT_RL = P_MES_NSL_DS; PORT_FL = 0 %FINISH DO REQUEST BUFFER: P_SER = BUFFER MANAGER; P_REPLY = OWN ID P_FN = REQUEST BUFFER P_PORT = PORT_NO; P_S1 = REASON P_LEN = 0; ! REQUEST A BIG BUFFER %IF FN = OPEN MESSAGE %THEN BUFFER ARRIVED %ELSE %C PON(P) %END %ROUTINE TO UPPER(%INTEGER CALL, %RECORD (MEF) %NAME MES) P_SER = PORT_OWNER; P_REPLY = GATE SER P_FN = CALL; P_MES == MES; P_PORT = PORT_NO PON(P) %END %ROUTINE BUFFER ARRIVED %SWITCH SUB STATE(PUT READ ON RB:SEND CONNECT) %RECORD (MEF) %NAME MES %RECORD (NSI2F) %NAME NSS %RECORD (NSI1F) %NAME NSL MES == P_MES NSS == MES_NSL; NSL == NSS PORT == PORTA(P_PORT); ! MAY BE ZERO NSS_SUFL = 0; NSS_ST = OWN TERM; NSS_SS = PORT_NO NSS_FLAG = 0 NSS_FN = SEND BLOCK+REPLY ->SUB STATE(P_S1) SUB STATE(PUT READ ON RB): P_MES == MES P_SER = PROT SER; P_REPLY = OWN ID P_FN = LINE INPUT PON(P) %RETURN SUB STATE(ATTACH RB): %IF FORCE DOWN = 0 %START DO ATT REM(ATTACH , MES) %ELSE DO ATT REM(REMOVE, MES) %FINISH %RETURN SUB STATE(STATUS REPLY RB): NSS_FN = 128+5; ! STATUS REPLY PORT_STATE = DOWN; ! FINISHED NOW -> SET DISC BIT; ! SET DISCONNECT AND SEND IT SUB STATE(SEND STATUS RB): !* ABORT THE CONNECTION NSS_FN = 5; ! STATUS -> SET DISC BIT; ! SET DISCONNECT AND SEND IT SUB STATE(SEND BL REPLY DRB): ! DISCONNECT REPLY NSS_FN = 4+128; ! SEND BLOCK REPLY PORT_STATE = DOWN; ! FINISHED NOW SET DISC BIT: NSS_FLAG = 128; ! SET THE NSI DISCONNECT BIT ->ONW SUB STATE(SEND BL REPLY RB): ! NORMAL REPLY NSS_FN = 128+4 ! SBR REMOVAL CODE %IF PORT_FL = 0 %START; ! ALREADY SENT ! FREE BUFFER(MES); %RETURN %FINISH NSS_FLAG = PORT_FL<<4; PORT_FL = 0 ONW: NSS_FLEN = 0 MES_LEN = 6 ->SEND IT SUB STATE(SEND BL DRB): ! BLOCK WITH DISCONNECT NSS_FN = 4; ! SEND BLOCK -> SET DISC BIT; ! SET NSI DISCONNECT AND SEND IT SUB STATE(SEND MESSAGE): SUB STATE(SEND CONNECT): NSL_FN = P_S1-SEND CONNECT+3 NSL_SN = 0; NSL_DN = PORT_NODE NSL_DT = PORT_TERM; NSL_DS = PORT_RL; ! TERM+FACILITY NSL_FLAG = PORT_FL MES_LEN = 11 %UNLESS P_S1 = SEND MESSAGE SEND IT: TO NODE(MES) %END %ROUTINE TIDY PORTS %INTEGER I %CYCLE I = 1, 1, MAXT PORT == PORTA(I) %IF PORT_STATE # DOWN %START TO UPPER(CALL ABORTED, NULL) %IF DISCONNECTING <= PORT_STATE <= ABORTING %C %OR PORT_STATE = CONNECTING %THEN %C PORT_STATE = DOWN %ELSE %C PORT_STATE = CLEARING %FINISH %REPEAT %END %ROUTINE FREE BUFFER(%RECORD (MEF) %NAME MES) P_SER = BUFFER MANAGER; P_REPLY = OWN ID P_FN = RELEASE BUFFER; P_MES == MES PON(P) %END %ROUTINE FAULT(%INTEGER N, PORT N) PRINTSTRING('GATE> FAULT'); WRITE(N, 1) PRINTSTRING(' STRM:'); WRITE(PORT N, 1); NEWLINE %END %ROUTINE DO ATT REM(%INTEGER TYPE, %RECORD (MEF) %NAME MES) MES_NSL_FN = TYPE MES_NSL_SUFL = 0 MES_NSL_ST = OWN TERM; MES_NSL_SS = 0 MES_NSL_SN = 0; MES_NSL_DN = 0 MES_NSL_DT = OWN TERM; MES_NSL_DS = 255 MES_NSL_FLAG = 0 MES_LEN = 12 TO NODE(MES) %END %ROUTINE NODE MONITOR(%RECORD (NSI3F) %NAME NSA) %INTEGER I, N, J, K, P P = 11 SPACES(2) !! %IF NSI1_SUFL&X'80'#0 %THEN P=20 %CYCLE I = 0, 1, P N = NSA_A(I) %CYCLE J = 4, -4, 0 K = (N >> J)&15 %IF K > 9 %THEN PRINTSYMBOL(K+'A'-10) %ELSE %C PRINTSYMBOL(K+'0') %REPEAT SPACE %REPEAT NEWLINE %END %ENDOFPROGRAM Ö MES_LEN = 8 € TO NODE(MES)