! FILE 'FEP_GATE5' %CONSTSTRING (7) VSN = "VSN005F" !**************************** !* EMAS-2900 FEP GATE * !* FILE: GATE5 * !* DATE: 27.OCT.80 * !**************************** !! STACK SIZE = 300 %RECORDFORMAT DMF(%INTEGER I) %SYSTEMROUTINESPEC LINKIN(%INTEGER SERVICE) %SYSTEMROUTINESPEC ALARM(%INTEGER TICKS) %CONSTRECORD (DMF) %NAME NULL = 0 %OWNINTEGER OWN TERM = 72; ! NETWORK ADDRESS %OWNINTEGER SUBATTACH FLAG = 74 %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 LINE STATEF(%INTEGER NODE STATE, ATT FLAG, %C LINE NO, SER NO, NODE NUMBER) %RECORDFORMAT PORTF(%BYTEINTEGER STATE, OWNER PORT, %C NO, MT, NODE, TERM, FL, RL, OWNER, NIFF, MAX FL, S1, %C %RECORD (QF) OUT Q, %RECORD (LINE STATEF) %NAME LN) !********************************************** !* 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 SUBATTACH = 255 %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 = 1 %CONSTINTEGER LINE OUTPUT = 2 %CONSTINTEGER HELLO = 2; ! IN P_LEN !************************************************************ !********** VARIOUS SERVICE NUMBERS ************* %CONSTBYTEINTEGERNAME OWN ID = K'160030' %CONSTINTEGER GATE SER = 16 %CONSTINTEGER FROM PROT = 10 %CONSTINTEGER BUFFER MANAGER = 17 %CONSTINTEGERNAME PKT = K'100010' %CONSTINTEGERNAME SBR = K'100006' %CONSTINTEGERNAME BYT = K'100004' %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 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 = 1; ! REMOVE SBR FLAG %CONSTINTEGER MAXT = 50 %OWNRECORD (PORTF) %NAME PORT %OWNRECORD (PORTF) %ARRAY PORTA(0:MAXT) %OWNINTEGER FORCE DOWN = 0; ! '1' WHEN IN DOWN STATE %RECORD (LINE STATEF) %NAME LN, L0, L1 %RECORD (LINE STATEF) %ARRAY LNA(0:1) !******************************************************** !* 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 %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, 5, 4) MAP VIRT(BUFFER MANAGER, 6, 5) ! MAP BUF MAN SEG 6 TO SEG 4 PORT == PORTA(1) LINKIN(GATE SER); LINKIN(FROM PROT) P_SER = 0; POFF(P); ! WAIT FOR INSTRUCTIONS OWN TERM = P_FN; SUB ATTACH FLAG = P_PORT ALARM(100) %CYCLE I = 1, 1, MAXT PORT == PORTA(I) PORT_NO = I %REPEAT L0 == LNA(0) L1 == LNA(1) %CYCLE P_SER = 0; POFF(P) %IF 'M' <= INT <='O' %START MON = INT-'O'; 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 LN_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 = 'S' %START SBRF = SBRF!!1; ! CHANGE SBR FLAG INT = 0 %FINISH %IF INT = '?' %START PRINTSTRING("SBRF:"); WRITE(SBRF, 1); NEWLINE %CYCLE I = 0, 1, 1 %IF I = 0 %THEN %C PRINTSTRING("LN0 ") %ELSE PRINTSTRING("LN1 ") LN == LNA(I) %IF LN_ATT FLAG = 0 %THEN PRINTSTRING("DOWN") %C %ELSE PRINTSTRING("ATT ") PRINTSTRING(" to Node") WRITE(LN_NODE NUMBER, 1); NEWLINE %REPEAT PRINTSTRING("Strm State T Line F/B Buff ") %CYCLE I = 1, 1, MAXT PORT == PORTA(I) %IF PORT_STATE # DOWN %START WRITE(I, 2); WRITE(PORT_STATE, 4) WRITE(PORT_TERM, 3) %IF PORT_LN == L0 %THEN PRINTSTRING(" LN0") %C %ELSE PRINTSTRING(" LN1") WRITE(PORT_MAX 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 %ELSE %IF P_SER = FROM PROT %START; ! MESSAGE FROM PROT HAN LN == LNA(P_PORT) %IF P_FN = LINE INPUT MES == NODE %UNLESS MES == NULL %THEN FREE BUFFER(MES) %ELSE !! LINE OUTPUT %IF P_LEN = HELLO %START LN == LNA(P_PORT); ! ITS LINE NUMBER LN_LINE NO = P_PORT LN_SER NO = P_REPLY %CONTINUE %FINISH %IF P_LEN = 1 %START; ! NODE DOWN PRINTSTRING("LINE ") PRINTSYMBOL(LN_LINE NO+'0'); PRINTSTRING(" DOWN ") LN_NODE STATE = 0; LN_ATT FLAG = 0 TIDY PORTS %ELSE !! UP MESSAGE OR WRITE ACK %IF LN_NODE STATE = 0 %START PRINTSTRING("LINE ") PRINTSYMBOL(LN_LINE NO+'0'); PRINTSTRING(" UP ") FORCE DOWN = 0 ASK FOR BLOCK(ATTACH RB, LN_LINE NO) %IF KENT = 0 LN_NODE NUMBER = P_S1 LN_NODE STATE = 1 %FINISH %FINISH %FINISH %FINISH %REPEAT %ROUTINE TO NODE(%RECORD (MEF) %NAME MES) %IF LN_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 PKT = PKT+1; BYT = BYT+(P_LEN>>2) OB = OB+1; OC = OC+P_LEN !************************************************* !* MESSAGE TO NODE: P_MES POINTS TO HDLC SPACE * !************************************************* P_SER = LN_SER NO; P_REPLY = OWN ID P_FN = LINE OUTPUT 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, FAC NO, TYPE %RECORD (NSI1F) %NAME NSL %RECORD (NSI2F) %NAME NSS %RECORD (MEF) %NAME MES %CONSTBYTEINTEGERARRAY VALID(ATTACH:REMOVE R) = 0, 0, 0, 1, 1, 1, 1, 0, 0, 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 ") LN_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 PORT_LN == LN; ! REMEMBER WHICH LINE PORT_MT = MES_NSL_DT; ! COULD BE ON SUB-ATTACH TERM PORT_NIFF = 0 %RESULT == NULL %FINISH %REPEAT %FINISH !! EITHER FACILITY NOT ENABLED OR NO FREE PORTS MES_NSL_SUFL = 128+8; MES_NSL_LEN1 = 2 MES_NSL_DATA = 'N'; MES_NSL_A(2) = 'O' MES_LEN = 13; ! +2 ????? 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) %IF PORT_STATE >= DISCONNECTING %THEN %C PORT_STATE = DOWN %ELSE %C PORT_STATE = ABORTING ->FREE %FINISH -> REPLY SW(NIF): PRINTSTRING('GATE> NIF') NODE MONITOR(NSL) %IF NSL_FLAG&128#0 %THEN PORT_NIFF=1 %AND -> DO STATUS !! WITHOUT DISCONNECT ->FREE SW(ATTACHR): -> FREE %IF NSL_ST = SUB ATTACH FLAG %IF NSL_SUFL # 0 %START ! FAILED DO ATT REM(REMOVE, MES) %RESULT == NULL %FINISH LN_ATT FLAG = 1 PRINTSTRING("ATTACHED OK ") %IF SUBATTACH FLAG#0 %AND LN == L0 %START DO ATT REM(SUBATTACH, MES) %RESULT == NULL %FINISH -> 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 FLAG 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 FN = P_FN %IF PORT N > MAXT %AND FN <= ABORT CALL %THEN %C FAULT(2, PORT N) %AND %RETURN PORT == PORTA(PORT N) LN == PORT_LN; ! PICK UP OUTPUT LINE MES == P_MES; NSS == MES_NSL ->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 %C %THEN %RETURN REASON = SEND BL REPLY RB; ! REQUEST BUFFER SBR = SBR+1 -> 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 = PORT_MT; 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 L0_ATT FLAG#0 %OR L1_ATT FLAG # 0 %C %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 !! PRINTSTRING("Gate: Ports full ") %ELSE PORT_OWNER = P_REPLY; PORT_OWNER PORT = P_PORT PORT_TERM = P2_TERM; PORT_NODE = P2_NODE PORT_FL = P2_FLAG; PORT_RL = P2_FACILITY PORT_MT = OWN TERM; ! FOR NOW AT LEAST, ALWAYS MAIN ADDRESS PORT_NIFF = 0 %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 %IF PORT N = 0 %START %IF FN = OPEN MESSAGE %START FLAG = P_PORT; FN = P_SER; ! HOLD FOR 'FREE' FREE BUFFER(MES) P_LEN = FLAG; P_SER = FN P_MES == NULL; P_REPLY = GATE SER P_FN = MESSAGE REPLY PON(P) %FINISH %RETURN %FINISH PORT_STATE = CONNECTING; PORT_LN == NULL 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(ATTACH 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 = PORT_MT; NSS_SS = PORT_NO NSS_FLAG = 0 NSS_FN = SEND BLOCK+REPLY %IF P_S1 > ATTACH RB %THEN LN == PORT_LN ->SUB STATE(P_S1) SUB STATE(ATTACH RB): LN == LNA(P_PORT) %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 %IF PORT_NIFF # 0 %THEN NSS_FN = 5; ! RESPONSE TO NIF 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 %IF SBRF = 0 %START; ! NO SBR REMOVAL NSS_FLAG = X'10'; PORT_FL = PORT_FL-1 %ELSE NSS_FLAG = PORT_FL<<4; PORT_FL = 0 %FINISH 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 = 10 %UNLESS P_S1 = SEND MESSAGE PORT_FL = NSL_FN; ! REMEMBER TYPE %IF (L1_ATT FLAG # 0 %AND NSL_DN = L1_NODE NUMBER) %OR %C L0_ATT FLAG = 0 %THEN LN == L1 %ELSE LN == L0 PORT_LN == LN; ! NEEDED FOR REPLY ETC %IF L0_ATT FLAG=0 %AND L1_ATT FLAG=0 %START PORT_STATE = DOWN NSL_SUFL = X'81' TO UPPER(OPEN REPLY B, MES) %RETURN %FINISH SEND IT: TO NODE(MES) %END %ROUTINE TIDY PORTS %INTEGER I %CYCLE I = 1, 1, MAXT PORT == PORTA(I) %IF PORT_STATE # DOWN %AND PORT_LN == LN %START %IF PORT_STATE = CONNECTING %START %IF PORT_FL = SEND CONNECT %START; ! CONNECT P_S1 = 125; ! LINE DOWN TO UPPER(OPEN REPLY B, NULL) %ELSE; ! SEND MESSAGE P_LEN = PORT_OWNER PORT TO UPPER(MESSAGE REPLY, NULL) %FINISH PORT_STATE = DOWN; ! SHOULD REPLY %ELSE 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 %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) %IF LN == NULL %START PRINTSTRING(" LNX ") %ELSE %START %IF LN == L0 %THEN PRINTSTRING(" LN0 ") %C %ELSE PRINTSTRING(" LN1 ") %FINISH %END %ROUTINE DO ATT REM(%INTEGER TYPE, %RECORD (MEF) %NAME MES) %INTEGER TERM, NODE %IF TYPE = SUBATTACH %START TYPE = ATTACH; NODE=0; TERM = SUB ATTACH FLAG %ELSE NODE = OWN TERM; TERM = OWN TERM %FINISH MES_NSL_FN = TYPE MES_NSL_SUFL = 0 MES_NSL_ST = TERM; MES_NSL_SS = 0 MES_NSL_SN = NODE; MES_NSL_DN = NODE MES_NSL_DT = 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 %CYCLE I = 0, 1, P