! file 'fep_gatex1' %conststring (7) vsn = "vsn001a" !**************************** !* emas-2900 fep gate * !* file: gatex1 * !* date: 22.jul.81 * !**************************** !! stack size = 300 %owninteger own term = 72; ! network address %owninteger subattach flag = 74 %control 1 %include "deimosperm" %begin %recordformat nsif((%byteinteger fn, sufl, st, ss, %c (%byte sn, dn, dt, ds, flag, ufl, %bytearray a(0:238) %or %c %byte sflag, suflag, %bytearray sa(0:242)) %or %c %byteintegerarray b(0:246))) %recordformat mef(%record (mef) %name link, %c %byte len, type, (%integer compatibility, %record (nsi)nsi %or %c %bytearray params(0:239))) %recordformat pe(%byteinteger ser, reply, %c fn, s1, %record (mef) %name mes, %byte gate port, task port) %recordformat qf(%record (mef) %name e) %recordformat line statef(%integer node state, att flag, %c line no, ser no, node number) %recordformat portf(%byte state, task port, %c no, mt, node, term, fl, rl, owner, niff, max fl, ss, %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 !************************************************************ !* Function Values between Upper level and Gate !************************************************************ %constinteger connect = 1 ;! start a call up %constinteger accept call = 2; ! accept a call %constinteger Disconnect = 3; ! Stop a call, or reject a connect %constinteger Enable Input = 4; ! Allow data, Gate -> Task %constinteger Put Output = 5; ! Output Block, Gate -> Task %constinteger Enable Output = 4; ! Allow Output, Task -> Gate %constinteger Input Here = 5; ! Input Block, Task -> Gate %constinteger Reset = 6; ! Reset the Virtual Circuit (!) %constinteger Expedited = 7; ! Pass 'Interrputs' %constinteger Datagram = 8; ! Send a 'datagram' %constinteger Datagram Reply = 9; ! Reply to a datagram %constinteger Enable Facility = 10; ! Claim incoming calls Task -> Gate %constinteger Disable Facility= 11; ! Stop them !********** 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 ************* %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 %constinteger port busy = 7 !**** 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 !! %owninteger mon = 0; ! monitoring off %owninteger sbrf = 1; ! remove sbr flag %constinteger maxt = 50 %ownrecord (portf) %name port %ownrecord (portf) %array porta(0:maxt) %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(*) %ownstring (3) %array fac type(1:4) = "ITP", "RJE", "TT", "FEP" !! %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 clear busy ports %integerfnspec unpack qual(%string (*) %name s) %string (127) %fnspec con qual(%integer n) %routinespec pack(%record (mef) %name mes, %string (*) %name s1,s2,s3,s4) %string (127) %fnspec convert(%integer node, term) %routinespec node monitor(%record (mef) %name mes) %ownstring (1) snil = "" %integer i %record (mef) %name mes %owninteger tsl, ib, ic, ob, oc change out zero = t3 ser; ! set 'select output(0)' to common i = map virt(buffer manager, 5, 4) i = 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 ask for block(attach rb, 0) ln_att flag = 0 int = 0 tidy ports %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 %finish %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, 5) write(port_term, 5) %if port_ln == l0 %then printstring(" ln0") %c %else printstring(" ln1") write(port_max fl, 5); write(port_rl, 1) newline %finish %repeat int = 0 %finish %if int = 'F' %then int=0 %and clear busy ports 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 %finish %else %if p_ser = from prot %start; ! message from prot han ln == lna(p_port) %if p_fn = line input %START 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 ") ask for block(attach rb, ln_line no) 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 (nsif) %name nsi %record (mef) %name mes %string (7) called, calling, qual %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 sw(send mess): type = message -> get sw(connect): type = incoming call get: 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) port_term = p_s1; ! copy to port port_ln == ln; ! remember which line port_mt = mes_nsl_dt; ! could be on sub-attach term port_node = sn; port_term = nsi_st; port_fac = nsi_ss port_niff = 0 called = "" calling = convert(nsi_sn, nsi_st) qual= con qual(nsi_flag) pack(mes, called, calling, qual, snil) to upper(connect, mes) %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): port n = nsl_ss; ! some nifs have differing addresses port == porta(portn) 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 p_s1 = 128+3 %start printstring("gate: busy port") write(port n, 1); newline port_state = port busy %finish %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 %unless port_state = port busy %result == null %finish to upper(open reply b, null) %if nsl_sufl # 0 %start port_state = down %unless port_state = port busy %FINISH %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 sw(remove r): 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_state # connected %start free buffer(mes) %return %finish %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 %FINISH %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 %FINISH %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_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) do att rem(attach , mes) %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_state fault"); write(n, 1) printstring(" strm:"); write(port n, 1) %if ln == null %start printstring(" lnx ") %FINISH%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 clear busy ports %integer i %cycle i = 1,1,maxt %if porta(i)_state = port busy %then porta(i)_state=down %repeat %end %integerfn unpack qual(%string (*) %name s) %integer for, rev %if charno(s,4)#'/' %or %not s->("W=").s %start printstring("illegal qual "); printstring(s); newline %result = -1 %finish for = charno(s,1); rev = charno(s,3) %result = (rev-'0')<<1!(for-'0')<<4 %end %string (127) %fn con qual(%integer n) %integer for, rev %string (5) s s = "W=" for = (n>>4)&7+'0' rev = (n>>1)&7+'0' s = s.tostring(for)."/".tostring(rev) %result = s %end %routine pack(%record (mef)%name mes, %string(*)%name s1, s2, s3, s4) %integer i, pt string(addr(mes_params(1))) = s1 pt = 1+length(s)+1 string(addr(mes_params(pt))) = s2 pt = pt+length(s)+1 string(addr(mes_params(pt))) = s3 pt = pt+length(s)+1 string(addr(mes_params(pt))) = s4 pt = pt+length(s) mes_params(0) = pt; mes_len = pt %end %routine node monitor(%record (mef) %name mes) %integer i, n, j, k, p %record (nsif) %name nsi nsi == mes_nsi p = mes_len write(p, 2) spaces(2) %cycle i = 0, 1, p n = nsa_b(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