! file 'nbsp9s' !******************************** !* bsp to nsi interface * !* file: nbsp9s * !* date: 17.aug.82 * !* based on kents_bsp4s & gate5 * !********************************* !! stk = 1000, strm = 1 %constinteger own node = 72 %constinteger fep address = 3 %owninteger sbrf = 0 %recordformat dmf(%integer i) %constrecord (*) %name nil == 0 %control X'4001' %include "b_deimosspecs" %begin %conststring (51)vsn = "nbsp...9c 08.dec.82 (not n72t72) " %owninteger datamark=k'123456' %recordformat mef(%record (mef) %name link, %byteinteger len, %c type, %integer address,port,rcomm,tcomm, %c %integerarray a(0:100) ) ! think about the position of ! 'len' !buffer queues %recordformat meqf(%record (mef) %name link); %recordformat pe(%byteinteger ser, reply, fn, port, %c %record (mef) %name mes, %byteinteger len, s1) %recordformat pe2(%byteinteger ser, reply, fn, port, %c %integer lport, hport ); !low nd high port limits %recordformat pe3(%byteinteger ser,reply,fn,port,a,b,c,d) %recordformat qf(%record (mef) %name e) %recordformat nsi1f(%byteinteger fn, sufl, st, ss, sn, dn, dt, %c ds, flag, ufl, %integerarray a(0:238)) %recordformat nsi2f(%byteinteger fn, sufl, st, ss, flag, uflag %c , flen, fdata, fd2, fd3, fd4) %recordformat nsi3f(%byteintegerarray a(0:100)) %recordformat menf(%record (menf) %name link, %c %byteinteger len, type, %record (nsi1f)nsl) %recordformat portf(%byteinteger state, owner port, %c no, st, dn, dt, ds, fl, rl, owner, niff, max fl, s1, %c %record (qf) out q) !********************************************** !********************************************** !* 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 remove r = 14 !************************************************************ !******* calls on line (or protocol) handler ********* !************************************************************ %constinteger line input = 2 %constinteger line output = 1 %constinteger hello = 2; ! in p_len %constinteger bounce = 3 %constinteger put down = 4 %constinteger put up = 5 %constinteger monit = 6 %constinteger varbs address = 7 %constinteger varbs 2 = 8 !************************************************************ !byte stream command codes %constinteger rdy=x'3000' %constinteger notrdy=x'5000' %constinteger reset=x'6300' %constinteger close=x'6600' %constinteger data=x'a000' %constinteger nodata=x'c000' %constinteger closereq=4 !transport service command codes %constinteger open=x'6a00' %constinteger sspreq=x'6c00' %constinteger openack=x'6500' !byte stream states %constinteger closed=0; ! %constinteger opening=1; !waiting for open ack %constinteger closing=2; !waiting for close %constinteger idle=3; !byte stream state %constinteger nesent=4; !ditto %constinteger esent=5; !ditto %constinteger openinput=6; !open or send mess has been input %constinteger open mess=7; !waiting for response to send mess ! array to define which bs states are closeable %ownbyteintegerarray closeable(0:open mess)=0,1,0,1,1,1,0,0 %constinteger bslimit=30; !number of byte streams %constinteger bslim2=61; !bslimit*2+1 ! function codes to and from ! ring ser !values below added to function codes %constinteger releaseflag=x'80'; !release buffer after output %constinteger tellflag=x'40'; !notify at end of output %constinteger cs0flag=x'20' %constinteger command mask=x'1f'; !to mask out values above %constinteger enable port=0 %constinteger xdata=1 %constinteger ssout=2; !not used %constinteger xrdy=3 %constinteger xnotrdy=4 %constinteger xnodata=5 %constinteger xclose=6 %constinteger xreset=7 %constinteger xclosereq=8 %constinteger output trace=16; !force output of ring trace ! %constinteger r output done=0 %constinteger transfer error=1 %constinteger r input done=2 ! %constinteger input error=3 ! reasons for (internal) wait for a buffer ! ----------------------------------------- %constinteger incomingcall=2 %constinteger outputdone=4 %constinteger callclosed=5 %constinteger callaborted=6 %constinteger message r=9 %constinteger send attach = 11 %constinteger timeout=2; !number of alarm calls !timeout between 9 and 10 secs. %constinteger faultlimit = 5; !byte stream is closed after !this number of accumulated errors !stream 1 is used only for open/openack transfers !format of records defining the byte streams !each byte stream has 2 bsf records. one for the !receiver and one for the transmitter. all the !bs records are in array bs, the records for port !p are the 2*p (transmitter) and the 2*p+1 (receiver) !elements of the array. %recordformat bsf( %integer tout, destport, %c %record (mef) %name buf, %c %byteinteger state, sequence, dest, %c faultcount, number, closeflag, %c %record (meqf) bufq, %record (portf) %name port) %ownrecord (bsf) %array bs(0:bslim2) %ownrecord (portf) %array porta(0:bslimit) !info describing input transfer %owninteger isource,iport,ircomm,itcomm %ownrecord (bsf) %name tbsp,rbsp %ownrecord (portf) %name port !time is incremented on every alarm call, on overflow to !zero it is set to 1 as time 0 implies time-not-set %owninteger time %integer t,i %ownrecord (bsf) %name bsp !************************************************************** !* buffer manager calls (to) * !************************************************************** %constinteger request buffer = 0 %constinteger release buffer = 1 !**************************************************************** !********** various service numbers ************* %constinteger line no = 61 %constinteger prot ser = 29; !?????????????????????????????? %constinteger ring ser = 13 %constinteger buffer manager = 17 ! %constbyteintegername change out zero = k'160310' %constinteger t3 ser = 21 !************************************************************ %record (pe2) %name pp; !points to p below %record (pe3) %name op3; !points to op below %record (pe2) %name op1; !points to op below !& %ownrecord (pe) %array ptrace(0:300) !& %owninteger ptp=0 %ownrecord (pe)p %ownrecord (pe) op %owninteger x=0 %ownrecord (mef) %name inbufq %owninteger mon = 0 %owninteger node state = 1 %owninteger rstate, input exp, w pend, q max, %c ird, itr, noread, ttime, rtime, retrc !! leave the order of the above alone, kernel reads them %switch sw(line output: varbs 2) %recordformat r3f(%integername n) %recordformat r4f(%record (mef) %name x) %record (r3f) %name r3; %record (r4f) r4 !& %routinespec pont(%record (pe) %name p) %routinespec fromabove %integerfnspec findfreeport %routinespec get buffer(%integer reason) %routinespec from buffer manager %routinespec from below %routinespec processinput %routinespec ssinput %routinespec doopenack %routinespec error(%integer n,source) %routinespec init p rec(%record (bsf) %name bsp, %c %integer seq,state,tout, %c dest,destport) %routinespec initport( %integer i,dest,destport) %routinespec do i rdy %routinespec doinotrdy %routinespec dodataack %routinespec doidata %routinespec doinodata %routinespec ttimedout(%record (bsf) %name bsp) %routinespec rtimedout(%record (bsf) %name bsp) %routinespec send to ring(%integer fn, %record (bsf) %name bsp) %routinespec tsend(%record (bsf) %name bsp) %routinespec initialise %routinespec doclose %routinespec free buffer(%record (mef) %name mef) %routinespec send openack(%record (bsf) %name bsp, %integer suflag) %routinespec fault(%record (bsf) %name bsp) %routinespec forceclose(%integer port, type) %routinespec startclose(%record (bsf) %name bsp) %routinespec finishclose( %integer port) %routinespec clearbsport(%record (bsf) %name bsp) %routinespec to prot(%record (menf) %name mes) %routinespec do att rem(%integer type, %record (menf) %name mes) %routinespec close all %routinespec move and swab(%integername from,to, %integer len) %routinespec move down and swab(%integername addr, %integer len) !$e %routinespec monp(%record (pe) %name p) %routinespec node monitor(%integer i, %record (menf) %name m) !********************************************** !* initialisation * !********************************************** i = map virt(buffer manager, 4, 3) i = map virt(buffer manager, 6, 5) i = map virt(buffer manager, 5, 4); ! map to my seg 4 use tt(t3 ser); ! switch op to commy printstring(vsn) set prio(2) initialise; !initialise data structures alarm(100) p_ser = prot ser; p_reply = own id; ! say hello to kernel p_fn = line input; p_port = line no p_len = hello pon(p) !send startup command to ring handler op1_ser=ring ser; op1_reply=own id op1_fn=enable port op1_lport=1; !low port limit op1_hport=bslimit; !high port limit !& pont(op) pon(op1) sw(put up): node state = 1; ! up automatically port == bs(2)_port; ! purely for from buffer manager get buffer(send attach); ! attach to kernel %cycle p_ser = 0; poff(p) ! clock call %if p_reply=0 %start; !clock call alarm(100) time=time+1 %if time=0 %then time=1; !time=0 => time not set %if 'M' <= int <= 'P' %start mon = int-'O'; int = 0 %finish x=x+1 !look for timeouts %cycle i=4,2,bslim2-1 t=bs(i)_tout %if t#0 %and time-t>timeout %thenc ttimedout(bs(i)) t=bs(i+1)_tout %if t#0 %and time-t>timeout %thenc rtimedout(bs(i+1)) %repeat %continue %finish !& pont(p) %if p_reply=ring ser %start from below; %continue %finish %if p_reply=buffer manager %start from buffer manager %continue %finish ->sw(p_fn) sw(line input): from above %continue sw(bounce): sw(put down): printstring("NBSP Down ") node state = 2; ! '2' stops blocks being sent close all get buffer(send attach); ! will send remove %continue sw(varbs address): r3 == r4 r3_n == node state p_ser = p_reply; p_reply = own id p_fn = 2; ! type is parr link handler p_mes == r4_x; ! plant address pon(p) %continue sw(varbs 2): p_ser = p_reply; p_reply = own id p_mes == bs(0) pon(p) sw(monit): %repeat !miscellaneous routines %routine handle input enable(%integer portn) !-------------------------------------------- %record (bsf) %name bsp bsp==bs( portn<<1+1 ) %if bsp_closeflag=0 %start %if bsp_state=nesent %start send to ring( xrdy, bsp) bsp_state=esent bsp_tout=time %finish %finish %end %routine from above !------------------ !deocde message from higher level protocol software. !p-fn = function code !p_port = byte stream number !p_mes = buffer pointer !p_s1 used on call reply, #0 => ok, =0 => reject open ! also bs function code on enable/disable %integer i,fn,s1,portn,l, disflag, dest, dstrm %record (nsi1f) %name nsl %record (nsi2f) %name nss %record (menf) %name mes %record (mef) %name mr %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) %integerfn start open portn = find free port %if portn # 0 %start bsp == bs(portn<<1); port == bsp_port bsp_dest = nsl_dt port_st = nsl_dt port_dn = nsl_sn port_dt = nsl_st port_ds = nsl_ss port_niff = 0 %else mes_nsl_fn = mes_nsl_fn!128 mes_nsl_sufl = 128+8 to prot(mes) %finish %result = portn %end !**************************************************** !* 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; mr == mes nsl == mes_nsl; nss == nsl fn = nsl_fn %if mon < 0 %start node monitor('i', mes) select output(0) %finish i tr = i tr+1 %if fn&128 # 0 %then fn = fn&127+7 port n = nsl_ss; ! pick up stream as index %unless 1<= fn <= 15 %start rubbish: printstring("Invalid frame: ") node monitor('x', mes) ->free %finish !! compiler fault with complex conditio %if fn = 7 %then -> rubbish %if mes_len <= 5 %then -> rubbish %if fn = nif %then portn = nsl_ds; ! nif is a special case %unless 0<=port n<=bslimit %or valid(fn) = 0 %then -> rubbish %unless port n > bslimit %start bsp == bs(portn<<1) port == bsp_port %finish -> sw(fn) sw(attach r): %if nsl_sufl # 0 %start printstring("attach FAILS "); write(nsl_sufl-128, 1) newline do att rem(remove, mes); %return %finish printstring("NBSP:Attached ok ") node state = 0 -> free sw(remove r): !remove reply %return %if node state = 2; ! hold it down do att rem(attach, mes); %return sw(send mess r): s1 = 0 sw(connect r): %if bsp_state#open input %then error(11, bsp_state) %and %return 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 port_niff = 0 %if nsl_sufl = 0 %start %if fn = connect r %then s1 = 1 i = 0 %else s1 = 0; i = 1; ! failed %if mon # 0 %start printstring("nbsp: con fails") write(nsl_sufl, 1); newline %finish %finish !send open ack reply send openack(bsp , i) !if open failed or sendmessage response clear the portn %if s1=0 %then clearbsport(bsp) %and ->free initport(portn<<1, bsp_dest, bsp_destport) handle input enable(portn) -> free !fns(enable input): sw(send block r): i = nss_flag>>4 %if i = 0 %then i = 1 handle input enable(portn) %if port_rl = 0 port_rl = port_rl+i disflag = nss_flag&x'80' free buffer(mes) %if disflag#0 %then -> close call1 %return !fns(put output): sw(send block): disflag = nss_flag&x'80' %if nss_flag&x'70'#0 %start i = nss_flag>>4 %if port_rl = 0 %then handle input enable(portn) port_rl = port_rl+i %finish %if bsp_stateesent %or bsp_closeflag #0 %start freebuffer(mr) %else !swab the data part of the buffer l=(mes_len-4+1)>>1 %if l # 0 %start; ! zero with disconect if empty move down and swab(mr_rcomm, l) ! nb: word containing uflag goes into data field !convert the buffer length to packet count, leaving the odd byte !flag bit in tcomm mr_tcomm = mes_len&1 mr_len=l+1 %if bsp_state=nesent %start bsp_buf==mr tsend(bsp) %else push(bsp_bufq, mr); !queue buffer on byte stream %finish %finish %finish %return %unless disflag # 0 ! fns(closecall): closecall1: rbsp==bs(portn<<1+1) !see if response to close request %if rbsp_closeflag#0 %start; !yes forceclose(portn, 0); !send out close %return %finish %if bsp_state # closing %start bsp_closeflag=1 %if bsp_buf==nil %and bsp_state=nesent %then tsend(bsp) %finish port_niff = 3 %return sw(status): -> free %unless nss_flag&x'80' # 0 -> do status sw(nif): printstring("nbsp> nif") node monitor('x', mes) %if nsl_flag&128#0 %start port_outq_e == mes; ! hold it for reply port_niff = 1; ! disconnect type = nif forceclose(portn, call aborted) %return %finish !! without disconnect ->free sw(status r): port_niff = 2; ! _niff contains reason for closedown do status: ! fns(abort call): forceclose(portn, call aborted) ->free ! fns(open message): sw(send mess): portn = start open %if portn#0 %start bsp_state = open mess bsp_destport = 1 port_s1 = nsl_ds port_outq_e == mes get buffer(0); ! get buffer to transfer it into %finish %return ! fns(open call): sw(connect): portn = start open %if portn#0 %start !s1 = dest port (facility) !len = destination address bsp_state=opening bsp_destport = nsl_ds port_out q_e == mes; ! retain connect message l = nsl_flag; ! get buffer specs port_rl = l >>1&7 port_fl = 0 port_max fl = l>>4 port_max fl = 2 %if port_max fl > 2 nsl_flag = port_max fl<<4+port_rl<<1 port_niff = 0 get buffer(0); ! get buffer for bsp open !& pont(op) %finish %return free: free buffer(mes) %end; !from above %integerfn findfreeport !----------------------------- %integer i %cycle i=4,2,bslim2-1 %if bs(i)_state=closed %then %result=i>>1 %repeat %result=0 %end %routine get buffer(%integer reason) !------------------------------------ %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 pon(p) %end %routine from buffer manager !----------------------------- %record (mef) %name mes %record (bsf) %name bsp %record (menf) %name m %record (nsi1f) %name nsl %record (nsi2f) %name nss %integer reason, type %switch sw(0:12) %routine set bits(%integer fn) nsl == m_nsl; nss == nsl nsl_fn = fn; nsl_sufl = 0 nsl_st = port_st; nsl_ss = p_port nsl_sn = own node; nsl_dn = port_dn nsl_dt = port_dt; nsl_ds = port_ds nsl_flag = x'24'; nsl_ufl = 5 %end !$e %if mon < 0 %start !$e select output(1) !$e printstring("bm:") !$e monp(p) !$e select output(0) !$e %finish bsp==bs(p_port << 1) port == bsp_port m == p_mes; mes == m reason = p_s1 -> sw(reason) sw(0): ! send a ring open %if bsp_state#opening %and bsp_state # open mess %start freebuffer(mes) %return %finish m == port_outq_e %if bsp_state = open mess %start mes_len = (m_len+1)>>1-5+4 mes_rcomm = sspreq+(m_len&1) mes_a(0) = port_s1 move and swab(m_nsl_a(0), mes_a(3), mes_len-4) %else mes_len = 4 mes_rcomm = open mes_a(0) = bsp_destport ! (m_nsl_ufl)<<8; ! 'F' numbers for ftp %finish mes_a(1) = port_dt mes_a(2) = port_dn mes_port=1 mes_tcomm=p_port; !reply port number %if bsp_dest = 72 %then bsp_dest = fep address; ! n72t72->n72t9 mes_address = bsp_dest op_mes==mes send to ring(xdata+release flag, bsp) bsp_tout=(time+2)!1; ! 8-10 secs %return sw(incoming call): set bits(connect) m_len = 10 to prot(m) %return sw(message r): set bits(send mess) !! move in message text !!!!!!!!!! mes == bsp_buf move and swab(mes_a(3), nsl_a(0), mes_len>>1-3) m_len = mes_len-8+10 to prot(m) %return sw(output done): set bits(send block+128) ! 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 m_len = 6 to prot(m) %return sw(call closed): set bits(send block) -> disc sw(call aborted): set bits(status); ! nif ???? disc: %if port_niff = 1 %and %not port_outq_e == nil %start ! nif originally free buffer(m) m == port_outq_e; nsl == m_nsl port_outq_e == nil nsl_flag = x'80' %else nss_flag = x'80' m_len = 6 %finish %if port_niff # 0 %then nsl_fn = nsl_fn!128 to prot(m) %return sw(send attach): ! attach/remove %if node state = 2 %then type = remove %else type = attach do att rem(type, m) %return sw(12): ! timeout on sm send to ring %end %routine from below !------------------ ! messages are :- transfer error (with bsp port number in p_port) ! r input done ! ring down %record (mef) %name mes %integer fn, i2, i !$ %if mon<0 %start !$ select output(1) !$ printstring("ri:") !$e monp(p) !$ select output(0) !$ %finish fn=p_fn %if fn=r input done %start !validate input transfer and put bs info into global variables mes==p_mes !after processing the input the buffer in p_mes is released !unless p_mes is set to nil iport=mes_port i2=iport<<1 isource=mes_address %if mes_len<1 %then ->error tbsp==bs(i2) rbsp==bs(i2+1) port == rbsp_port itcomm=mes_tcomm ircomm=mes_rcomm %if iport=1 %start ssinput %else %if tbsp_dest#isource %then ->error process input %finish %unless p_mes==nil %then freebuffer(p_mes) %return error: fault(tbsp) printstring("bsp:illegal input from"); write(isource, 3); newline freebuffer(p_mes) %else %if fn=transfer error %start fault(bs(p_port<<1)) %else printstring("nbsp: fn? = "); write(fn, 1); newline %finish %finish %end %routine process input !--------------------- !input transfer has just finished ! assume it's byte stream and process the commands !if it's data the data will have been input into the !requisite buffer %if ircomm&x'f000'=rdy %start do i rdy %else %if ircomm&x'f000'=notrdy %start do i not rdy %else %if ircomm=reset %start do close %else %if ircomm=openack %start doopenack %else %if ircomm=close %thenc do close %finish %finish %finish %finish ! obey transmitter command %if itcomm & x'f008'=data %start do i data %else %if itcomm & x'f000' =nodata %thenc do i nodata %finish %end; !process input %routine ssinput !--------------------- %integer i,openflag,portn,f, ifacno, type, len %record (bsf) %name bsp %record (menf) %name m !received open command or single shot request !see if there's a free port !also check there's not a bs open to this dest,port %if ircomm=open %start type=incoming call %else %if ircomm&x'ff00'=sspreq %start type=message r p_mes_len=p_mes_len<<1-(ircomm&1); ! includes 3 word nsi addr %else %return %finish %finish portn=0 %cycle i=4,2,bslim2-1 bsp==bs(i) %if bsp_state=closed %start portn=i >> 1 %else %if bsp_dest=isource %andc bsp_destport=(itcomm & x'fff') %start %if mon # 0 %start printstring("nbsp:port reuse, t") write(isource, 1); printstring(" port:") write(bsp_destport, 1); newline %finish %return %finish %finish %repeat %if portn#0 %start bsp==bs(portn<<1) f=0 port == bsp_port port_ds = p_mes_a(0); port_dt = p_mes_a(1) port_dn = p_mes_a(2); ! note the extensions to bsp ! -------------------------- !if message then set portn to 0, this is stored !in seq in the bs record and used as a reply port !on openack %if type=message r %then portn=0 init p rec(bsp, portn, open input, 0, %c isource, itcomm & x'fff') bsp_buf==p_mes; !save buffer to send openack p_mes==nil; !don't release buffer port_st = isource %if isource = fep address %then port_st = 72; ! ->n72t72 get buffer(type) %finish %end; !do open request %routine do open ack !--------------------- %record (mef) %name mes %record (menf) %name m %integer flag mes==p_mes port == porta(tbsp_number) flag = mes_a(0) %if tbsp_state=open mess %start; !ack of message m == port_outq_e; port_outq_e == nil m_nsl_fn = 128+2 m_nsl_flag = 0 %if flag = 0 %start m_nsl_sufl = 0 mes_len = mes_len-4; ! discount header&nsi address move and swab(mes_a(3), m_nsl_a(0), mes_len) m_len = 10+mes_len<<1 %else m_nsl_sufl = 128+8 m_len = 10+1 %finish free buffer(mes) to prot(m) p_mes==nil clearbsport(tbsp) %return %finish %if tbsp_state#opening %or mes_len<2 %start error(6,isource) %return %finish %if itcomm&x'fff' = 0 %then %return; ! message reply ! %if flag#0 %start; !fail flag on openack flag = 128+8; ! kent version distinguishes !!!!! clearbsport(tbsp) %else initport(tbsp_number<<1,isource,itcomm&x'fff') send to ring(xrdy, rbsp) rbsp_state=esent rbsp_tout=time flag = 0 %finish m == port_outq_e; port_outq_e == nil m_nsl_fn = m_nsl_fn!128 m_nsl_sufl = flag m_nsl_ds = port_no; ! set it to my stream m_len = 10+2 to prot(m) %end %routine error( %integer n, source) !------------------------------------- printstring("*********** error-") write(n, 3); write(source,3) newline !send pon to ring ser to force output of trace buffer op_ser=ring ser op_reply=own id op_fn=output trace !& pont(op) pon(op) %end %routine init p rec( %record (bsf) %name bsp, %c %integer seq,state,tout,dest,destport) !----------------------------------------------------------------- !initialise one record of the byte stream pair bsp_sequence=seq bsp_closeflag=0 bsp_state=state bsp_tout=tout bsp_dest=dest bsp_destport=destport bsp_buf==nil bsp_bufq_link==nil %end %routine init port( %integer i, dest, destport) !--------------------- !initialise receiver and transmitter data for port i !transmitter init p rec(bs(i), x'f', idle, (time+20) ! 1, %c dest, destport) !receiver init p rec(bs(i+1), 0, nesent, 0, %c dest, destport) %end; !initport %routine do i rdy !--------------------- %integer sq,sqin; !sequence numbers !ready command has been input !check sequence number sq=tbsp_sequence sqin=ircomm >> 8 &x'f' %if (sq+1)&x'f'=sqin %start %if tbsp_state=esent %start !rdy signals ack of previous data -release buffer etc. do data ack; %finish %if tbsp_state=esent %or tbsp_state=idle %start tbsp_sequence=sqin; !increment sequence !reply 'data' or 'nodata' depending on whether bufq is nil or not tbsp_buf == pop(tbsp_bufq) tsend(tbsp) %else error(1, isource) %unless tbsp_state = closing %finish; !ignore it if state illegal %else %if sq=sqin %start !got repeated rdy - need to retransmit %if tbsp_state=esent %or tbsp_state=nesent %start tbsp_tout=0 tsend(tbsp) %if tbsp_state=esent %start retrc = retrc+1 %if mon#0 %start printstring("retransmit to "); write(isource,3) newline %finish %finish %else error(2, isource) %finish %else error(3, isource) %finish %finish %end; !do i rdy %routine do i notrdy !--------------------- %integer sq,sqin; !sequence numbers !acknowledgement of data sq=tbsp_sequence sqin=ircomm>>8&x'f' %if (sq+1)&x'f'=sqin %start %if tbsp_state=esent %start do data ack; !release buffers etc. tbsp_state=idle tbsp_tout = (time+120)!1; ! nasty timeout to catch hung conns %finish %finish %end; !do i notrdy %routine do data ack !--------------------- !release buffers, and reset the timeout %if tbsp_buf==nil %start !see if close request acknowledged %if tbsp_closeflag#0 %then tbsp_closeflag=2 %else %if tbsp_closeflag = 0 %start; ! otherwise no acks port_fl = port_fl+1 !! sbr removal code - time to send ack? %if sbrf=0 %or port_max fl<2 %or port_fl>1 %then %c get buffer(output done) %finish freebuffer(tbsp_buf) tbsp_buf==nil %if tbsp_faultcount>0 %thenc tbsp_faultcount=tbsp_faultcount-1 %finish tbsp_tout=0 %end; !do data ack %routine do i data !--------------------- %integer i,sqin; !sequence number of input %record (mef) %name buf %record (menf) %name m %record (nsi2f) %name nss !data has been input buf==p_mes sqin=itcomm>>8&x'f' %if rbsp_sequence=sqin %and ( rbsp_state=esent %or %c rbsp_state=idle) %start !signal line input to higher level op_mes==buf p_mes==nil; !buffer not to be released !swab the data bytes %if buf_len < 2 %then free buffer(buf) %and -> ignore move and swab(buf_a(0), buf_rcomm, buf_len) !! 1st word of data=uflag, so is moved there !convert bcount from header packet to byte length buf_len=(buf_len << 1) -(itcomm & 1)+4-2; ! fl & uflag already there m == buf; nss == m_nsl nss_fn = 4; nss_sufl = 0 nss_st = port_st; nss_ss = port_no !! sbr removal code- jam in reverse ack if possible %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 prot(m) ignore: !set new sequence number rbsp_sequence=(sqin+1)&x'f' !at this point should reply notrdy and wait for higher level to !process buffer and give input enable and then send rdy. in fact !we pretend to send the notrdy and hope the higher levels !respond before the data gets retransmitted . if it does then !a notrdy is sent (see below). ! nsi vsn: input enable sent if allowed by port_rl rbsp_state=nesent rbsp_tout=0 %if rbsp_faultcount>0 %thenc rbsp_faultcount=rbsp_faultcount-1 %if itcomm & closereq # 0 %start rbsp_closeflag=1 get buffer(call closed) send to ring(xnotrdy, rbsp); !ack of close req %finish port_rl = port_rl-1 %if port_rl > 7 %then error(10, isource) %unless port_rl = 0 %then handle input enable(port_no) %else %if rbsp_sequence=((sqin+1)&x'f') %start !repeated data requeue rdy or notrdy %if rbsp_state=esent %start send to ring(xrdy, rbsp) rbsp_tout=time %else %if rbsp_state=nesent %start send to ring(xnotrdy, rbsp) %else error(5, isource) %finish %finish %else error(4, isource) %finish %finish %end; !do i data %routine do i nodata !--------------------- %integer sqin !nodata response input sqin=itcomm>>8&x'f' %if rbsp_sequence=sqin %and rbsp_state=esent %start ! set idle timeout to 30 secs rbsp_tout=time+30 %if rbsp_tout=0 %then rbsp_tout=1 rbsp_state=idle %finish %end; !do i nodata %routine ttimedout(%record (bsf) %name bsp) !------------------------------------------- %record (menf) %name m bsp_tout=0 ttime = ttime+1 %if mon#0 %start printstring("bsp:timeout dest=") write(bsp_dest, 3); newline %finish fault(bsp) %if bsp_state=esent %start tsend(bsp) %finish %if bsp_state = opening %or bsp_state = open mess %then get buffer(0) ! get a buffer to repeat action %if bsp_state = idle %then bsp_tout = (time+120)!1 ! nasty timeout to catch hung conns %end %routine rtimedout(%record (bsf) %name bsp) !------------------------------------------- port == bsp_port bsp_tout=0 %if bsp_state#idle %start rtime = rtime+1 fault(bsp) %finish %if bsp_state=idle %or bsp_state=esent %start send to ring(xrdy, bsp) bsp_state=esent bsp_tout=time %finish %end %routine send to ring(%integer fn, %record (bsf) %name bsp) !------------------------------------------------------------ op_ser=ring ser; op_reply=own id op_fn=fn op_port=bsp_number; %if fn&command mask>= xrdy %start op_len=bsp_dest op1_lport=bsp_destport op_s1=bsp_sequence %finish !& pont(op) !$e %if mon < 0 %start !$e selectoutput(1) !$e printstring("ro:") !$e monp(p) !$e select output(0) !$e %finish pon(op) %end %routine tsend(%record (bsf) %name bsp) !--------------------- !send transmitter command (data or nodata) , if data !then calculate the length of the transfer from buf_len %record (mef) %name m m==bsp_buf %if m==nil %start !send nodata %if bsp_closeflag=0 %start send to ring(xnodata, bsp) bsp_state=nesent bsp_tout=0 %else !if closereq has been acknowledged then don't !send it again %if bsp_closeflag=2 %thenreturn send to ring(xclosereq, bsp) bsp_state=esent bsp_tout=time %finish %else bsp_state=esent m_address=bsp_dest m_port=bsp_destport m_rcomm=0 m_tcomm=bsp_sequence<<8 + data + (m_tcomm&1) op_mes==m !transmit data with buffer not released and no !notification at eot (unless it timeouts) send to ring(xdata, bsp) bsp_tout=time %finish %end; !tsend %routine initialise !------------------ %integer i, j %record (bsf) %name bsp pp==p op3==op op1==op !rest of data initialised to 0 %cycle i=2,1,bslim2 bsp==bs(i) clearbsport(bsp) j = i>>1 bsp_number=j port == porta(j) port_no = j bsp_port == port %repeat %end; !initialise %routine doclose !-------------- %integer n n=tbsp_number %if closeable(tbsp_state)=0 %start finishclose(n) %else %if tbsp_closeflag=2 %then forceclose(n,call closed) %elsec forceclose(n, call aborted) finishclose(n) %finish %end %routine freebuffer(%record (mef) %name mes) !!-------------------------------------------- %record (pe) p p_ser=buffer manager; p_reply=own id p_fn=release buffer; p_mes==mes !& pont(p) pon(p) %end %routine send openack(%record (bsf) %name bsp, %integer suflag) !-------------------------------------------------------------- ! buffer pointer saved in bsp_buf %record (mef) %name mes mes==bsp_buf %return %if mes == nil; ! left hanging ? ************ bsp_buf==nil mes_address=bsp_dest mes_len=4 mes_port=bsp_destport mes_rcomm=openack mes_tcomm= bsp_sequence; !reply port saved here(=0 if message resp) mes_a(0)=suflag op_mes==mes send to ring(xdata + release flag, bsp) %end %routine fault(%record (bsf) %name bsp) !-------------------------------------- %record (menf) %name m %integer i port == porta(bsp_number) %if bsp_state=closing %thenc finishclose(bsp_number) %and %return i=bsp_faultcount %if i>faultlimit %start %if bsp_state = opening %or bsp_state = open mess %start port == bsp_port m == port_outq_e; port_outq_e == nil m_nsl_fn = m_nsl_fn!128 m_nsl_sufl = 128+8 m_len = 10+2 %if bsp_state = opening to prot(m) clearbsport(bsp) %return %finish printstring("nbsp:Call fails to T"); write(bsp_dest, 1) printstring(", From N"); write(port_dn, 1); printstring(" T") write(port_dt, 1); newline forceclose(bsp_number, call aborted) %else bsp_faultcount=i+1 %finish %end %routine forceclose(%integer port, type) !------------------------------------------- %record (bsf) %name bsp bsp==bs(port << 1) %if bsp_state=open input %or bsp_state=open mess %then clearbsport(bsp) %if closeable(bsp_state) = 0 %then %return %if type#0 %then get buffer(type) startclose(bsp); bsp==bs(port <<1 +1) startclose(bsp); !send close transfer send to ring(xclose, bsp) bsp_tout=time %end %routine startclose(%record (bsf) %name bsp) !----------------------------------------------------------- %record (mef) %name buf,p bsp_state=closing bsp_tout=0 !return active output buffer (if any) %unless bsp_buf==nil %then freebuffer(bsp_buf) bsp_buf == nil %whilenot bsp_bufq_link == nil %cycle free buffer(pop(bsp_bufq)) %repeat %end %routine finishclose(%integer port) !------------------------------------ %record (bsf) %name bsp bsp==bs(port<<1) clearbsport(bsp) clearbsport(bs(port<<1+1)) %end %routine clearbsport(%record (bsf) %name bsp) !----------------------------------------- bsp_tout=0 bsp_closeflag=0 bsp_dest=0 bsp_faultcount=0 bsp_state=closed %end %routine to prot(%record (menf) %name mes) !------------------------------------------ %record (pe) p; %record (pe2) %name p2 p2 == p %if node state > 1 %start; ! 0=up,1=able to att,2=held free buffer(mes); ! node is down %return %finish %if mon < 0 %then node monitor('o', mes) ird = ird+1 p_mes == mes; p_len = mes_len %if p2_lport&k'140000'=k'140000' %start printstring("nbsp: bad buffer to kern ") %cycle; %repeat %finish !************************************************* !* message to node: p_mes points to hdlc space * !************************************************* p_ser = 29; p_reply = own id p_fn = line output; p_port = line no pon(p) %end %routine do att rem(%integer type, %record (menf) %name mes) mes_nsl_fn = type mes_nsl_sufl = 0 mes_nsl_st = 0; mes_nsl_ss = 0 mes_nsl_sn = own node; mes_nsl_dn = own node mes_nsl_dt = 254; mes_nsl_ds = 255; ! nb 72 now illegal mes_nsl_flag = 0 mes_len = 12 to prot(mes) %end %routine close all %integer i %cycle i = 2, 1, bslimit forceclose(i, call aborted) %repeat %end %routine move and swab(%integername from, to, %integer len) !------------------------------------ ! move 'len' words from 'from' to 'to' %label loop %constinteger r0 = 0, r1 = 1, r2 = 2 *mov_from, r1 *mov_to, r2 *mov_len,r0 loop: *mov_(r1)+,(r2) *swab_(r2)+ *dec_r0 *bgt_loop %end %routine move down and swab(%integername addr, %integer len) !----------------------------------------------------------- ! move 'len' words at 'addr' four bytes down buffer and swab %label loop %constinteger r0=0,r1=1,r2=2 ! addr is in r1, len is in r2 *add_r2,r1 *add_r2,r1 loop: *mov_-(r1),r0 *swab_r0 *mov_r0,4(r1) *dec_r2 *bgt_loop %end !$e %routine monp(%record (pe) %name p) !$e !---------------------------------- !$e %record (mef) %name buf !$e %integer i,c !$e !$e write(p_ser,3) !$e write(p_reply,3) !$e write(p_fn,3) !$e write(p_port,3) !$e write(p_len,3) !$e write(p_s1,3) !$e newline !$e %end !& %routine pont(%record (pe) %name p) !& ptrace(ptp)=p !& ptp=ptp+1 !& %if ptp>300 %then ptp=0 !&%end %routine node monitor(%integer i, %record (menf) %name m) %record (nsi3f) %name nsa %integer n, j, k, p nsa == m_nsl select output(1) %unless i='x' write(m_len, 3) spaces(2) printsymbol(i) spaces(2) %cycle p = 0, 1, m_len n = nsa_a(p) %cycle j = 4, -4, 0 k = (n >> j)&15 %if k > 9 %then printsymbol(k+'a'-10) %else %c printsymbol(k+'0') %repeat space newline %if p&31=31 %repeat newline select output(0) %end %endofprogram *=k'016501'; *=6; ! mov addr, r1 %repeat *=k'016500'; *=4; ! mov len, r0 space