SUBTTL ARPANET NCP variables and tables EBLK IMPMQS==13. ;MESSAGE QUEUE SIZE (LENGTH WORD, 6-WORD LEADER, 6-WORD TEXT) ;MAIN PROGRAM CONTROL MESSAGE VARIABLES IMPMPU: -1 ;-1 => FREE 0 ;SWTL THREAD IMPMPL: -1 ;LINK WORD FOR CONTROL LINK QUEUE IMPMPC: BLOCK IMPMQS ;FIRST WORD HAS IMPHTB INDEX,,LENGTH OF TEXT ;PI CONTROL MESSAGE VARIABLES IMNPIC==NNETCH+3 ;NUMBER OF BLOCKS IN PI CONTROL QUEUE ;HOPEFULLY THIS IS ENOUGH. THE CODE RESPONDS VERY UNGRACEFULLY TO THIS ;QUEUE FILLING UP. IN PARTICULAR, WHEN IT HOLDS UP INPUT IT CAN CAUSE ;A DEADLOCK BY PREVENTING ITSELF FROM SEEING A CONTROL-LINK RFNM IT ;NEEDS IN ORDER TO SEND SOMETHING THAT'S IN THE QUEUE AND FREE UP SOME ;SPACE. FURTHERMORE THE IMP IS UNGRACEFUL AND WILL SOMETIMES REFUSE TO ;READ INPUT FROM US (EVEN IN THE MIDDLE OF A MESSAGE) UNTIL WE READ ;INPUT FROM IT. BUT WE DO THE SAME THING WHEN THIS QUEUE FILLS UP. ;FURTHERMORE SOMETIMES THE CORE JOB WILL WAIT FOR A NETWORK ;TRANSMISSION TO COMPLETE SO IT CAN MOVE A NETWORK BUFFER, HANGING THE ;ENTIRE SYSTEM. THE CORE-JOB WILL UNHANG AFTER THE IMP TIMES OUT AND ;FLASHES ITS READY LINE (SEE IMPBER). ;** BUT SOMETIMES THE IMP NEVER TIMES OUT AND SO THE SYSTEM IS HUNG ** IMPCQ: REPEAT IMNPIC-1,[ .+IMPMQS+1 ;POINTER TO NEXT FREE OR NEXT IN QUEUE BLOCK IMPMQS ;FIRST WORD HAS IMPHTB INDEX,,LENGTH OF TEXT ] -1 BLOCK IMPMQS IMPNCQ: -1 ;NEXT ENTRY TO BE SENT. -1 IF NONE IMPLCQ: -1 ;POINTER TO LAST ENTRY IN CONTROL QUEUE IMFFCQ: IMPCQ ;POINTER TO FIRST FREE. -1 IF NONE IMFCQL: IMNPIC ;NUMBER FREE CONTROL QUEUE ENTRIES LEFT ;PENDING RFC QUEUE IMNPQ==20 ;NUMBER OF PENDING QUEUE ENTRIES ;(0) POINTER TO NEXT IN CHAIN OR NEXT FREE. -1 IF NONE ;(1) LOCAL SOCKET NUMBER ;(2) FOREIGN SOCKET NUMBER ;(3) 4.9 = 1 => RTS = 0 => STR ; 1.1-1.8 = LINK NUMBER OR BYTE SIZE ; 1.9-2.7 = FOREIGN HOST NUMBER ; 3.1-3.9 = TIME RFC RECEIVED, IN SECONDS MOD 512. IMPPQ ;IMPBPQ-1 IS BEGINNING OF GETSYS BLOCK, THIS WORD FOR UNRELOCATION IMPBPQ: -1 ;BEGINNING OF PENDING QUEUE. -1 IF EMPTY IMPPQ: REPEAT IMNPQ-1,[ .+4 BLOCK 3 ] -1 BLOCK 3 IMPEPQ: -1 ;END OF PENDING QUEUE. -1 IF EMPTY (IMPEPQ IS END FOR GETSYS BLOCK) IMFFPQ: IMPPQ ;FIRST FREE PENDING QUEUE ENTRY. -1 IF NONE ;SOCKET TABLE IMSOKB: IMPSTL ;BEGIN OF GETSYS BLOCK, LENGTH STORED HERE IMSOC1: REPEAT IMPSTL,0 ;0 => FREE ;>0 MEANS ALLOCATED, NOT SET UP YET ;4.9 = 1 => SOCKET IN USE ;4.8 = 1 => CHNL TRYING TO BE CLOSED ;3.1-4.7 = MASK FOR CHANNEL SOCKET IS OPEN ON. ;RH = USER INDEX IMSOC2: BLOCK IMPSTL ;1.1-4.5 = LOCAL SOCKET NUMBER ;4.6-4.9 0 (MAKES COMPARISONS EASIER) IMSOC3: BLOCK IMPSTL ;1.1-4.5 = FOREIGN SOCKET NUMBER ;4.6-4.9 = 0 IMSOC4: BLOCK IMPSTL ;3.1-3.8 = LINK NUMBER ;3.9-4.7 = FOREIGN HOST NUMBER (IMPHTB INDEX) ; 377 MEANS NOT USING ANY HOST ;4.8 = SET BY RCV CLS - MAKES MATCH USING IMSCHD FAIL ;4.9 = SEND THIS BUFFER NOW .SEE %NS ;RH = SOCKET STATE IMSOC5: BLOCK IMPSTL ;1.1 - 1.9 => TTY # OF STY, IF CONNECTED TO ONE. ;2.1-2.9 = CLOSE-REASON ;3.1-3.8 = CONNECTION BYTE SIZE ;3.9 => ASCII MODE - 7 BIT ;4.1 => ASCII MODE - 8 BIT ;4.2 => 1 BIT BYTES ;4.3 => NET INT (INR\INS) RECEIVED ;4.4 => HAVE BEGUN COUNTING THE CLOSE TIME-OUT. ;4.5 => CLOSED WHILE IN RFNM WAIT, EXPECT ANOTHER RFNM ;4.6 => CONNECTED DIRECTLY TO A STY. ;4.7 => DON'T BUFFER MORE OUTPUT THAN ALLOCATION ;4.8 => STY WANTS WAKEUP AT 1/2 SEC CLK ;4.9 => TRANSFER IN 32 BIT MODE IMSOC6: BLOCK IMPSTL ;RH => BUFFER ADDRESS ;4.9 => LOCKED BY CORE JOB ;4.8 => ACTIVE AT PI LEVEL ;4.7 => INPUT OCCURRED WHILE BUFFER LOCKED ;3.1-3.8 => IOBFT INDEX (377 IF USING BIG BUFFER) IMSOC7: BLOCK IMPSTL ;BIT ALLOCATION IMSOC8: BLOCK IMPSTL ;MESSAGE ALLOCATION IMSC7I: BLOCK IMPSTL ;AMT TO INCREASE BIT ALLOCATION BY IN NEXT ALLOC MSG (INPUT) ;FOR OUTPUT, HAS NUMBER OF BITS IN BUFFER IMSC8I: BLOCK IMPSTL ;AMT TO INCREASE MESSAGE ALLOCATION BY NEXT ALLOC MSG (INPUT) IMSOCT: BLOCK IMPSTL ;TIME WHEN FIRST MESS PUT INTO BUF ;(DURING INPUT HAS NUMBER OF DATA BYTES LEFT IN CUR MSG) ;(DURING CLOSE HAS TIME TIME-OUT STARTED) IMSMPP: BLOCK IMPSTL ;MAIN PROGRAM POINTER, ILDB OR IDPB FOR NEXT BYTE IMSMPC: BLOCK IMPSTL ;MAIN PROGRAM COUNTER, FOR OUTPUT HAS NUMBER OF DATA ; BYTES OF ROOM LEFT IN BUFFER. FOR INPUT HAS TOTAL ; NUMBER OF DATA BYTES IN BUFFER. IMSPIP: BLOCK IMPSTL ;INTERRUPT LEVEL POINTER, FOR OUTPUT ILDB TO GET NEXT ; BYTE OUT AT P.I. LEVEL. FOR INPUT POINTS TO WHERE ; HEADER WORD OF NEXT MESSAGE IN WILL BE STORED. IMSBFE: BLOCK IMPSTL ;BYTE POINTER TO LAST BYTE IN BUFFER ;USE CAILE X,@IMSBFE(I) TO CHECK A WORD ADDRESS IMSOKE==.-1 ;END OF BLOCK FOR GETSYS CALL BBLK IMSCLN: 221000,,IMSOC4(I) ;LINK NUMBER IMSCBS: 221000,,IMSOC5(I) ;BYTE SIZE IMSCLS: 111100,,IMSOC5(I) ;CLOSE REASON IMSCFH: 321000,,IMSOC4(I) ;FOREIGN HOST IMSCHD: 222100,,IMSOC4(I) ;FOREIGN HOST AND LINK NUMBER ; EXTRA BIT, SET WHEN RCV CLS IMSCHL: 222000,,IMSOC4(I) ;FOREIGN HOST AND LINK WITHOUT EXTRA BIT NTRFCL: SIXBIT /NETRFC/ ;FOR ICP ON ANY SOCKET < 1000 EBLK 0 NETSRS==1000 ;SMALLEST USER RECEIVE SOCKET NUMBER NRSOC: NETSRS ;NUMBER OF NEXT RECEIVE SOCKET TO BE GENERATED NETOSW: -1 ;SWITCH LOCKED AT NET OPEN 0 NETHSW: -1 ;SWITCH LOCKED IF HACKING HOST TABLE (IMPHTB) 0 NETLST: 0 ;LIST OF USERS IN NETWORK OPEN CODE ;INPUT BUFFER FORMAT: ;THE BUFFER IS CIRCULAR, AND EITHER 200 OR 2000 WORDS LONG. ;MAY CONTAIN SEVERAL MESSAGES. EACH CONSISTS OF A HEADER WORD CONTAINING ; THE NUMBER OF BYTES IN THE MESSAGE, FOLLOWED BY THE BYTES, FOLLOWED BY ; UNUSED BITS UP TO THE NEXT WORD BOUNDARY. THIS WEIRD FORMAT IS USED ; TO AVOID HAVING TO DO BYTE OPERATIONS AT P.I. LEVEL. ;A HEADER WORD OF -1 MEANS THAT THAT MESSAGE HAS NOT YET BEEN STORED. ;IMSPIP(I) ALWAYS CONTAINS THE ADDRESS OF A HEADER WORD OF -1. ;IMSMPP(I) HAS A BYTE POINTER TO THE NEXT DATA BYTE TO BE READ. ;P.I. LEVEL CAN STORE A MESSAGE INTO THE PART OF THE BUFFER FROM ;@IMSPIP TO @IMSMPP-1. ;IMSOCT(I) HAS THE NUMBER OF BYTES THAT MAIN PROGRAM LEVEL CAN ; READ BEFORE IT GETS TO THE END OF THE CURRENT MESSAGE AND HAS ; TO CHECK THE NEXT HEADER. ;IMSMPC(I) HAS THE TOTAL NUMBER OF DATA BYTES IN ALL THE MESSAGES ; IN THE BUFFER. ;OUTPUT BUFFER FORMAT: ;THE BUFFER IS CIRCULAR, AND EITHER 200 OR 2000 WORDS LONG. ;IT SIMPLY CONTAINS A STRING OF BYTES. ;IMSMPP(I) HAS A BYTE POINTER TO WHERE THE NEXT BYTE TO BE OUTPUT WILL BE DEPOSITED. ;IMSPIP(I) HAS A BYTE POINTER TO WHERE THE NEXT BYTE TO BE SENT OUT AT P.I. ; LEVEL WILL COME FROM. P.I. LEVEL TRIES TO KEEP EVERYTHING ALIGNED ON ; WORD BOUNDARIES SO THAT IT DOESN'T HAVE TO DO BYTE OPERATIONS. ;IMSMPC(I) HAS THE NUMBER OF BYTES THAT MP LEVEL MAY STORE BEFORE RUNNING ; INTO OLD BYTES THAT HAVEN'T YET BEEN TRANSMITTED. ;IMSOCT(I) IS SET TO THE TIME THE FIRST BYTE IS PUT INTO THE BUFFER. ; IT IS CLEARED WHENEVER THE BUFFER GETS EMPTIED. BBLK SUBTTL ARPANET NCP Main Prog system call routines ;NET .CALL RCHST/RFNAME NETRCH: MOVEI W,8 ;WE RETURN 8 VALUES. HRRE I,A JUMPL I,NETRC3 ;NET WENT DOWN AFTER THIS CHANNEL WAS OPENED. MOVE B,IMSOC2(I) ;LOCAL SOCKET NUMBER MOVE C,IMSOC3(I) ;FOREIGN SOCKET NUMBER LDB TT,IMSCFH ;FOREIGN HOST FOR 4TH WORD. CAIN TT,377 TDZA D,D ; 377 MEANS NOT USING ANY HOST IFN 1,[ JRST [MOVE D,A MOVE A,IMPHTN(TT) ; Get host addr TLO A,(NW%ARP) ; Make full HOSTS3 format CALL CVH2NA ; Convert to HOSTS2 for compatibility EXCH A,D JRST .+1] ] ;IFN 1 IFN 0,[ TDZA Q,Q MOVE Q,IMPHTN(TT) LDB D,[112000,,Q] ;TRANSLATE NEW HOST NUMBER TO OLD ANDI Q,377 ;IF IT WILL FIT IN OLD NOTATION CAIGE D,100 CAIL Q,4 SKIPA D,IMPHTN(TT) DPB Q,[060200,,D] ] ;IFN 0 LDB Q,IMSCBS ;GET BYTE SIZE FOR HERE AND BELOW ;FOLLOWING LINE HAS BEEN PUNTED, AN INCOMPATIBLE CHANGE ; DPB Q,[111100,,D] ;INTO 2.9-2.1 OF 4TH WORD MOVE A,IMSOC5(I) ;RANDOM WORD TLNE A,4000 ;SKIP IF 4.3 BIT OFF (NETWRK INT) TLO D,400000 ;SET FOR USER PUSHJ P,NETRC1 ;GET TIME IMP GOING DOWN, HRR TT,IMSOC4(I) ;MERGE IN SOCKET STATE. IMUL Q,IMSMPC(I) ;MULTIPLY BYTE SIZE BY BYTES AVAIL TO GET BITS AVAIL LDB I,IMSCLS ;CLS REASON POPJ P, NETRC3: MOVEI I,%NCNCP ;GIVE CLOSE REASON THAT OUR NCP WENT DOWN. NETRC1: SKIPG TT,IMPDWN+1 ;SYS TIME AT WHICH IMP IS GOING DOWN JRST NETRC2 SUB TT,TIME ;(TIME TIL IMP DOWN -1=NOT. 0=DOWN, +=GOING DOWN, N/30. SEC) SKIPG TT MOVEI TT,1 ;IF SET TO GO DOWN, AND TIME "PASSED", SAY SOON IF NOT ALREADY DOWN NETRC2: HRLZS TT POPJ P, ;NET .CALL STATUS - SOCKET STATE IN BITS 2.4-2.9 STANET: TRNN A,400000 ;SKIP IF NET WENT DOWN ON THIS LOSER SKIPA E,IMSOC4(A) ;GET STATE MOVEI E,0 ;IF NCP WENT DOWN, STATE IS "CLOSED" DPB E,[140600,,D] POPJ P, ;NET .CALL RESET - ONLY RESETS "INT FM NETWORK" BIT (INR/INS) NETRS: HLRZ A,(R) ;GET LH IOCHNM MOVSI B,4000 ;4.3 BIT TRNN A,400000 ;SKIP IF SET TO -1 (NET WENT DOWN ON THIS CHAN) ANDCAM B,IMSOC5(A) ;CLEAR BIT POPJ P, ;NET .CALL IOPUSH/IOPOP - ALTER THE CHANNEL-OPEN MASK IN IMSOC1. NETIOP: HRRZ T,UUAC(U) IMUL I,CHNBIT(T) ;PUSHING => 0; ELSE BIT FOR CHANNEL BEING POPPED. HLRZ T,(R) ;GET SOCKET TABLE IDX TRNN T,400000 ;SKIP IF NET WENT DOWN ON THIS LOSER DPB I,[222000,,IMSOC1(T)] ;STORE MASK AWAY. POPJ P, ;NET .CALL WHYINT ;RESULTS ARE %WYNET, SOCKET STATE, BYTES AVAIL, CLS REASON NETWHY: HRRE I,A ;GET IMSOC INDEX MOVEI A,%WYNET ;FIRST RESULT IS DEVICE CODE SETZB B,C ;SET UP RESULTS 2-4 IN CASE NCP WENT DOWN MOVEI D,%NCNCP JUMPL I,POPJ1 ;RETURN IF NCP WENT DOWN ON THIS LOSER HRRZ B,IMSOC4(I) ;SECOND RESULT IS SOCKET STATE MOVE Q,IMSOC5(I) TLNE Q,4000 TLO B,400000 ;SIGN OF SECOND RESULT SET IF NETWRK INT TLNE Q,40000 ;DIRECT CONNECTED? TDZA C,C ;YES, NO BYTES AVAILABLE FOR INPUT MOVE C,IMSMPC(I) ;THIRD RESULT IS BYTES AVAILABLE LDB D,IMSCLS ;FOURTH RESULT IS CLOSE REASON JRST POPJ1 ;AIDS TO NETWORK OPEN AND NETHST CALLS ;SET THINGS UP AND ALLOCATE AN IMSOC INDEX. ;SKIP RETURNS WITH NETLST AND IMSOC1(I) LOCKED. ;OR, RETURNS NO-SKIP WITH NOTHING LOCKED AND AN ERROR SIGNALLED. NETO00: PUSHJ P,LSTSET ;ADD THIS JOB TO LIST OF NET OPENERS NETLST PUSHJ P,SWTL ;GET AN IMSOC ENTRY TO GC-PROTECT OUR IMPHTB ENTRY NETOSW MOVSI I,-IMPSTL SKIPE IMSOC1(I) AOBJN I,.-1 JUMPG I,OPNL6 ;DEVICE FULL MOVEI H,377 ;NO HOST YET DPB H,IMSCFH HRRZM U,IMSOC1(I) ;IMSOC1 POSITIVE MEANS ALLOCATED BUT NOT INITED YET PUSHJ P,LSWPOP ;NETOSW PUSHJ P,LOSSET ;RETURN IMSOC ENTRY IF PCLSR NETIRT JRST POPJ1 ;LOSSET ROUTINE TO RETURN IMSOC ENTRY NETIRT: MOVE T,AC0S+I(U) HRRZ A,U CAME A,IMSOC1(T) JRST 4,. SETZM IMSOC1(T) POPJ P, ;SUBROUTINE TO OPEN UP COMMUNICATIONS WITH THE DESIRED HOST. ;ENTER WITH HOST NUMBER IN SRN3(U), SKIP-RETURN WITH HOST ;UP AND IMPHTB INDEX IN H AND IMSCFH. OR NON-SKIP RETURN WITH ERROR SIGNALLED. NETOR: MOVE T,SRN3(U) ;USER-SPECIFIED HOST NUMBER JSP J,STDHST ;STANDARDIZE, OPNL25 IF IT IS NO GOOD CONO PI,NETOFF PUSHJ P,FNDHST ;H GETS HOST TABLE INDEX JRST OPNL6 ;DEVICE FULL (HOST TABLE FULL) DPB H,IMSCFH ;PROTECT IN IMSOC4 CONO PI,NETON PUSHJ P,SWTL ;POSSIBLY SEND RST TO HOST OPENING CONNECTION TO NETHSW LDB J,IMHSBT ;GET STATUS SOJG J,NETORS ;-1 => DOWN, 0 => RST SENT, 1 => UP JUMPE J,NETOR1 ;WAIT FOR REPLY PUSHJ P,NETOW ;WAIT FOR IMPMPC TO BE FREE LDB W,[051100,,TIME] DPB W,[221100,,IMPHTB(H)] MOVEI J,1 DPB J,IMHSBT ;MARK AS SENT AOS IMRFCT PUSHJ P,STHSTM ;STORE HOST#, LINK 0 , MESSAGE TYPE 0 MOVE W,[8_24.+1_8] ;BYTE SIZE = 8, BYTE COUNT = 1 MOVEM W,IMPMPC+6 MOVE W,[12._28.] ;RST MOVEM W,IMPMPC+7 MOVEI W,1 HRRM W,IMPMPC ;MESSAGE LENGTH PUSHJ P,IMPMPQ ;SEND IT OUT NETOR1: PUSHJ P,LSWPOP ;NETHSW PCLT MOVSI T,1000 TDNE T,IMPHTB(H) ;RRP -> 2000, DOWN -> 0000 PUSHJ P,UFLS LDB J,IMHSBT ;GET STATUS SOJL J,OPNL41 ;HOST DOWN JUMPE J,NETOR ;TRY ALL THIS AGAIN JRST POPJ1 ;HOST UP NETORS: PUSHJ P,LSWPOP ;NETHSW JRST POPJ1 ;HOST IS UP ;NETWORK OPEN ; .OPEN CH,BLK ; ERROR RETURN ; NORMAL RETURN ;BLK: MODE BITS,,(SIXBIT /NET/) ; LOCAL SOCKET NUMBER (1.1-4.5) ; FOREIGN SOCKET NUMBER (1.1-4.5) ; FOREIGN HOST NUMBER ;BLK: 3.1-3.3 => STANDARD ASCII/IMAGE, UNIT/BLOCK, INPUT/OUTPUT ; 3.4 = 1 => GENERATE UNIQUE LOCAL RECEIVE (SEND) SOCKET NUMBER ; 3.4 = 0 => USE LOCAL SOCKET NUMBER SPECIFIED IN BLK+1 ; 3.5 => OPEN SOCKET IN LISTEN MODE ; 3.6 => IF IMAGE MODE, USE BYTE SIZE IN 4.1-4.6 ; IF ASCII MODE, USE 8 BIT BYTES RATHER THAN 7 ; 3.7 => USE BIG BUFFER (2000 WORDS INSTEAD OF 200) ; 3.8 => DON'T BUFFER MORE OUTPUT THAN ALLOCATION ; 4.1-4.6 = BYTE SIZE IN IMAGE MODE ;OPEN CODE NETO: SKIPN IMPUP JRST NETOUP SKIPL IMPUP JRST OPNL7 ;DEVICE NOT READY CONO PI,NETOFF SKIPN IMPTCU AOS IMPTCU CONO PI,NETON MOVSI I,SCLIMP IORM I,SUPCOR ;HAVE SYS JOB BRING UP THE NETWORK PCLT SKIPE IMPTCU ;WAIT WHILE IT TRIES TO COME UP PUSHJ P,UFLS SKIPE IMPUP JRST OPNL7 ;LOSE IF NOT UP BY NOW NETOUP: TLZ A,740000 ;IGNORE EXTRA BITS IN SOCKET NUMBERS TLZ B,740000 PUSHJ P,NETO00 ;INITIALIZE THINGS POPJ P, ;NETWORK NOT UP OR FULL TLNE C,20 ;SKIP IF NOT LISTEN JRST NETO10 PUSHJ P,NETOR ;DO RESET STUFF, OPEN COMMUNICATIONS WITH HOST POPJ P, ;HOST DOWN OR ILLEGAL MOVE J,B ;CHECK GENDER OF FOREIGN SOCKET ROT J,-1 XOR J,D JUMPGE J,OPNL2 ;WRONG DIRECTION ;DROPS THROUGH ;DROPS IN NETO10: PUSHJ P,SWTL ;ONLY ONE PROCESS AT A TIME COMPARING SOCKET NUMBERS NETOSW TLNN C,20 ;SKIP IF LISTEN PUSHJ P,NETOW ;GOBBLE MP CONTROL LINK BLOCK (FOR NETOS) TLNN C,10 JRST NETO1 ;USE SOCKET NUMBER GIVEN IN WORD 2 MOVEI A,10 ;ADVANCE SYSTEM UNIQUE SOCKET NUMBER ADDB A,NRSOC SUBI A,10 ;UNIQUE RECEIVE SOCKET NUMBER SKIPGE D ;SKIP IF OPEN IS FOR READ (RECEIVE) IORI A,1 ;MAKE INTO SEND SOCKET JRST NETO6 NETO1: MOVE J,A ;USER SPECIFIED SOCKET NUMBER ROT J,-1 ;J 4.9: 0 => RECEIVE 1 => SEND EQV J,D ;D 4.9: 0 => READ 1 => WRITE JUMPGE J,OPNL2 ;WRONG DIRECTION MOVE J,A CAIL A,NETSRS ;SKIP IF SPECIAL SOCKET TRZA J,7 ;J HAS BASE OF SOCKET GROUP MOVNI J,1 ; OR -1 IF NOT IN A GROUP MOVSI Q,-IMPSTL MOVEI E,0 NETO2: SKIPL W,IMSOC1(Q) JRST NETO3 ;NOT HOOKED UP CAMN A,IMSOC2(Q) JRST NETO2A ;DUPLICATE LOCAL SOC # MOVE T,IMSOC2(Q) TRZ T,7 CAMN J,T JRST NETO4 ;JUMP IF PART OF SOCKET GROUP NETO3: AOBJN Q,NETO2 SKIPL J ;SKIP IF NOT PART OF A SOCKET GROUP JUMPE E,OPNL23 ;FOUND NO EVIDENCE THAT THIS GUY OWNS THIS GROUP JRST NETO6 ;WINNING NETO2A: TLNN W,200000 ;SKIP IF BEING CLOSED JRST OPNL13 ;NO, GIVE ERROR TLNN C,20 PUSHJ P,LSWPOP ;POP MP CONTROL LINK BLOCK PUSHJ P,LSWPOP ;NETOSW MOVSI T,200000 PCLT TDNE T,IMSOC1(Q) PUSHJ P,UFLS ;WAIT TILL CLOSED JRST NETO10 ;TRY AGAIN NETO4: CAIE U,(W) JRST OPNL23 ;SOMEONE ELSE HAS IT MOVNI E,1 ;OK IF NO OTHER CONFLICTS JRST NETO3 ;HERE WITH SUITABLE LOCAL SOCKET IN A NETO6: TLNN C,4 ;SKIP IF IMAGE MODE JRST NETOC ;ASCII MODE MOVEI TT,36. TLNN C,40 ;SKIP IF BYTE SIZE SUPPLIED JRST NETOB LDB E,[330600,,C] ;USE USER SUPPLIED BYTE SIZE IDIVI E,36. ;TT GETS BYTE SIZE MOD 36. JUMPN TT,NETOB MOVEI TT,36. ;36 BITS ANYWAY NETOB: PUSH P,TT MOVEI E,36. IDIV E,TT ;36/BS JUMPE TT,NETOB1 ;EXACT MOVEI E,32. IDIV E,(P) ;32/BS JUMPE TT,[MOVEI TT,400000 ;32BIT MODE FLAG JRST NETOB1] MOVEI TT,2000 ;FUNNY BYTESIZE FLAG NETOB1: POP P,E ;BS ADD TT,E ;FLAGS+BS JRST NETOA NETOC: MOVEI TT,400410 ;7 BIT TLNE C,40 MOVEI TT,401010 ;8 BIT NETOA: TLNE C,200 TRO TT,100000 ;DON'T BUFFER MORE OUTPUT THAN ALLOCATION HRLZM TT,IMSOC5(I) ;STORE FLAGS AND BC, CLEAR CLOSE REASON MOVEM A,IMSOC2(I) ;LOCAL SOCKET NUMBER MOVEM B,IMSOC3(I) ;FOREIGN SOCKET NUMBER SETZM IMSOCT(I) ;IF INPUT, NOT IN MIDDLE OF A MESSAGE MOVEI W,%NSRFS TLNE C,20 ;3.5 LISTEN MOVEI W,%NSLSN DPB H,[321000,,W] ;DON'T CHANGE HOST NUMBER FIELD OF IMSOC4 MOVEM W,IMSOC4(I) ;SET INITIAL STATE, CLEAR FLAGS SKIPE IMSOC6(I) ;SKIP IF HAVEN'T ASSIGNED BUFFER YET JRST 4,. PUSH P,A PUSH P,B PUSH P,D NETOE1: TLNN C,100 ;LAST PLACE TO PCLSR (REALLY NETMW) JRST NETOE7 PUSHJ P,TCALL ;GET FULL-PAGE BUFFER JRST IOMQ JRST NETMW MOVEI W,MUNET DPB W,[MUR,,MEMBLT(A)] DPB I,[MNUMB,,MEMBLT(A)] LSH A,10. MOVE W,A ;BUFFER START ADDRESS HRLI W,377 ;NOT AN IOBFT-TYPE BUFFER MOVEI A,1777(A) ;BUFFER END ADDRESS JRST NETOE4 NETOE7: MOVEI D,NFNETC(I) PUSHJ P,TCALL JRST IUTCO1 ;GET 200-WD BUFFER JRST NETMW ;NO MEM AVAIL LDB W,[IOSA,,IOBFT(A)] LSH W,6 ;STARTING ADDRESS HRL W,A ;IOBFT INDEX MOVEI A,177(W) ;BUFFER END ADDRESS NETOE4: MOVEM A,IMSBFE(I) ;(LH WILL BE STORED LATER) MOVEM W,IMSOC6(I) ;CLEAR THE BUFFER FOR EASE IN DEBUGGING. COMMENT USED TO CLAIM ;THAT CLEARING IT WAS NECESSARY IN ORDER TO OUTPUT CORRECT HEADERS, ;BUT THAT WAS FRAUDULENT SINCE HEADERS NEVER COME FROM THE BUFFER. MOVEI D,1(W) HRLI D,(W) SETZM (W) BLT D,(A) POP P,D POP P,B POP P,A ;DROPS THROUGH ;DROPS IN MOVSI Q,000100 ;SET UP THE VARIOUS BYTE POINTERS LDB TT,IMSCBS ;TO POINT TO END OF BUFFER MOVE E,IMSOC5(I) ;SO ILDB WILL GET FIRST BYTE IN BUFFER TLNN E,2000 ;SKIP IF ONE BIT BYTES DPB TT,[300600,,Q] ;OTHERWISE USE USER BYTE SIZE SKIPGE E TLO Q,040000 ;32 BIT WORD ENDS 4 BITS OVER HRR Q,IMSBFE(I) MOVEM Q,IMSMPP(I) MOVEM Q,IMSPIP(I) MOVEM Q,IMSBFE(I) MOVE T,C ;GET 3.5 BIT OF C INTO LSH T,13. ;4.9 OF T JUMPL D,NETOE5 ;JUMP IF SENDER SETOM (W) ;NULL FIRST HEADER WORD TLO Q,440000 ;-> LEFT END OF WORD HRR Q,W MOVEM Q,IMSPIP(I) ;SET PI PNTR TO POINT TO FIRST MESSAGE HEADER SETZM IMSMPC(I) ;NO INPUT BYTES AVAILABLE YET MOVEI TT,20. ;MESSAGE ALLOCATION ALWAYS 20 MOVEM TT,IMSOC8(I) HRRZ TT,IMSBFE(I) ;COMPUTE BIT ALLOCATION SUBI TT,2*20.(W) ;TT := # WORDS IN BUFFER, -1 FOR LUCK, -2 FOR EACH MSG SKIPGE IMSOC5(I) ; (-1 FOR HEADER WORD, AND -1 FOR BREAKAGE) IMULI TT,32. ;CONVERT TO # BITS SKIPL IMSOC5(I) IMULI TT,36. LDB Q,IMSCBS ;BREAKAGE WAS OVER-ESTIMATED BY 1 BYTE PER MSG IMULI Q,20. ADD TT,Q MOVEM TT,IMSOC7(I) ;STORE CORRECT BIT ALLOCATION SETZM IMSC8I(I) SETZM IMSC7I(I) MOVEI Q,2(I) ;LINK # DPB Q,IMSCLN ;STORE IN LINK # FIELD JRST NETOE6 NETOE5: SETZM IMSOC7(I) ;INITIALIZE SENDER'S ALLOCATIONS SETZM IMSC7I(I) SETZM IMSOC8(I) HRRZ TT,IMSBFE(I) SUBI TT,(W) ;# BUFFER WORDS, -1 FOR LUCK SKIPGE IMSOC5(I) ;SKIP IF 36BIT IMULI TT,32. ;ALLOW 32 BITS PER WORD SKIPL IMSOC5(I) IMULI TT,36. ;OR 36 BITS PER WORD LDB E,IMSCBS IDIVM TT,E ;CONVERT TO NUMBER OF BYTES MOVEM E,IMSMPC(I) ;THAT MANY ARE FREE AT FIRST NETOE6: PUSHJ P,IMPSPQ ;SEARCH PENDING QUEUE (LEAVES UTCOFF) JRST NETOG ;NOTHING THERE JUMPGE T,NETOH ;JUMP IF NOT LISTENING STATE MOVE W,2(Q) ;FOREIGN SOCKET NUMBER MOVEM W,IMSOC3(I) LDB H,[101000,,3(Q)] ;FOREIGN HOST IMPHTB INDEX DPB H,IMSCFH SKIPA W,[%NSRFC] NETOH: MOVEI W,%NSOPN HRRM W,IMSOC4(I) JUMPGE D,NETOD1 ;JUMP IF RECEIVER SKIPL W,3(Q) ;SKIP IF RTS, GET LINK # JRST 4,. ;HE SENT STR DPB W,IMSCLN ;STORE LINK NUMBER NETOD: HRRZ Q,UUAC(U) ;CHANNEL OPEN ON MOVE Q,CHNBIT(Q) PUSHJ P,IMPUIM ;INTERRUPT SELF JRST NETOG ;GO FINISH THE OPEN NETOD1: SKIPGE W,3(Q) ;SKIP IF STR, GET BYTE SIZE JRST 4,. ;HE SENT RTS ANDI W,377 LDB Q,IMSCBS CAMN W,Q JRST NETOD ;BYTE SIZES DIFFER, LOSE PUSHJ P,IMPBRT ;RETURN THE BUFFER JRST OPNL22 ;SELF-CONTRADICTORY OPEN? NETOG: HRRZ W,UUAC(U) MOVS W,CHNBIT(W) TLO W,400000 ;IN USE HRR W,U ;SETZ+<,,> MOVEM W,IMSOC1(I) ;WE ARE NOW FULLY SET UP TO THIS SOCKET CONO PI,NETON TLNN C,20 ;SKIP IF LISTENING TYPE SOCKET PUSHJ P,NETOS ;SEND RFC (CAN'T HANG, ALREADY GOT NETOW) PUSHJ P,LSWPOP ;UNLOCK NETOSW, NOW THAT IMSOC1 4.9 IS SET PUSHJ P,LSWDEL ;UNLOCK IMSOC1(I) PUSHJ P,LSWPOP ;REMOVE FROM LIST OF NETWORK OPENS IN PROGRESS HRLZ A,I ;LEFT HALF OF IOCHNM GETS SOCKET INDEX HLRZS C JSP Q,OPSLC7 NETDUI,,NETDUO NETDBI,,NETDBO NETDUI,,NETDUO NETDBI,,NETDBO ;GOBBLE MAIN PROGRAM CONTROL LINK BLOCK NETOW: JUMPL U,NETOW1 ;FROM STYNET CLOCK LEVEL PCLT SKIPGE IMPHTB(H) ;SKIP IF NOT RFNM WAIT ON LINK 0 PUSHJ P,UFLS PUSHJ P,SWTL ;GRAB CONTROL LINK BLOCK IMPMPU SKIPL IMPHTB(H) ;DID CTL LINK TO THIS HOST GET BACK INTO RFNM WAIT? POPJ P, ;NO, OK PUSHJ P,LSWPOP ;YES, RELEASE RESOURCE WHILE AWAITING RFNM JRST NETOW ;FROM NETIDC (AT CLOCK INTERRUPT LEVEL) NETOW1: SKIPL IMPHTB(H) AOSE IMPMPU CAIA ;INPUT CAN'T BE READ YET. POPJ P, CONO PI,NETOFF PUSHJ P,IMPUIN ;REACTIVATE SO WILL CHECK AGAIN SUB P,[2,,2] ;THROW THROUGH NETI6, NETID JRST NETOJ1 ;TAKE NO-INPUT-AVAILABLE EXIT ;WAIT FOR MEMORY SO CAN ALLOCATE BUFFER NETMW: PCLT MOVEI T,3 CAMG T,LMEMFR JRST [ PUSHJ P,UDELAY ;MAYBE MEMORY FROZEN, GIVE CORE JOB JRST NETOE1 ] ;A CHANCE TO PCLSR US, THEN TRY AGAIN CAMLE T,LMEMFR ;SKIP WHEN MORE THAN 3K FREE PUSHJ P,UFLS JRST NETOE1 ;SEND RFC AND MAYBE ALLOCATE. IMSOC INDEX IN I, HOST INDEX IN H. NETOS: PUSHJ P,STHSTM ;STORE HOST ADDRESS IN IMPMPC+n, ALSO MESSAGE TYPE MOVE J,[8_24.+13._8] ;BYTE SIZE = 8, BYTE COUNT = 13. MOVEM J,IMPMPC+6 MOVEI J,1_4 ;3 NOPS + RTS SKIPGE D ;SKIP IF INPUT MOVEI J,2_4 ;3 NOPS + STR MOVEM J,IMPMPC+7 LSH A,4 ;LOCAL SOCKET NUMBER MOVEM A,IMPMPC+10 LSH B,4 ;FOREIGN SOCKET NUMBER MOVEM B,IMPMPC+11 MOVEI TT,2(I) ;LINK NUMBER FOR RECEIVE SOCKET SKIPGE D LDB TT,IMSCBS ;BYTE SIZE FOR SEND SOCKET LSH TT,28. HRRZ J,IMSOC4(I) CAIE J,%NSRFC CAIN J,%NSOPN ;SKIP IF CONNECTION NOT YET OPEN JUMPGE D,NETOS2 ;JUMP IF CONNECTION OPEN AND READ MOVEM TT,IMPMPC+12 MOVEI TT,4 ;TEXT LENGTH NETOS3: HRRM TT,IMPMPC JRST IMPMPQ NETOS2: MOVEI J,<4_8>+2(I) ;NOP + ALL + LINK # LSH J,4 IOR TT,J MOVEM TT,IMPMPC+12 MOVE TT,IMSOC8(I) ;SEND MESSAGE ALLOC LSH TT,16.+4 MOVEM TT,IMPMPC+13 MOVE TT,IMSOC7(I) ;SEND BIT ALLOC LSH TT,16.+4 MOVEM TT,IMPMPC+14 MOVE TT,[8_24.+22._8] ;BYTE COUNT = 22. MOVEM TT,IMPMPC+6 MOVEI TT,6 ;MESSAGE LENGTH JRST NETOS3 ;.NETAC CH, ;ACCEPT CONNECTION ;ERROR RETURN ;NORMAL RETURN ANETAC: JSP T,NETCHK HRRZ T,IMSOC4(I) ;SOCKET STATE CAIE T,%NSRFC JRST OPNL41 ;NOT IN RFC RECEIVED STATE LDB H,IMSCFH PUSHJ P,NETOW ;GET IMPMPC MOVE A,IMSOC2(I) ;LOCAL SOCKET NUMBER MOVE B,IMSOC3(I) ;FOREIGN SOCKET NUMBER MOVE D,A ROT D,-1 PUSHJ P,NETOS ;SEND RFC (AND MAYBE ALL) CONO PI,NETOFF HRRZ T,IMSOC4(I) MOVEI TT,%NSOPN CAIN T,%NSRFC HRRM TT,IMSOC4(I) ;CONNECTION OPEN JRST NETOJ1 NETCHK: HRRZ A,(R) CAIL A,NETDUI CAILE A,NETDBO JRST OPNL34 ;NOT A NETWORK CHANNEL HLRE I,(R) ;SOCKET TABLE INDEX JUMPGE I,(T) JRST OPNL41 ;OTHER END OF PIPELINE GONE (NET WENT DOWN) ;.NETS CH, ;SEND BUFFER NOW ;RETURN NETFRC: JSP T,NETCHK ;ENTRY FROM .CALL FORCE MOVE T,IMSOC2(I) TRNN T,1 JRST OPNL2 ;NOT SEND SOCKET CONO PI,NETOFF MOVE T,IMSMPP(I) CAMN T,IMSPIP(I) JRST NETOJ1 ;BUF EMPTY MOVSI TT,400000 ;TURN ON SEND BUFFER BIT IORM TT,IMSOC4(I) PUSHJ P,IMPOST ;TURNS NETON JRST POPJ1 NETFIN: HRRZ TT,IMSBFE(I) ;ENTRY FROM .CALL FINISH (NETFRC HAS BEEN CALLED) SUB TT,IMSOC6(I) .SEE NETOE5 ;FOR COMMENTS FOR THIS CODE HRRZS TT SKIPGE IMSOC5(I) IMULI TT,32. SKIPL IMSOC5(I) IMULI TT,36. LDB T,IMSCBS IDIVM TT,T ;T NOW HAS SIZE OF OUTPUT BUFFER IN BYTES CAME T,IMSMPC(I) ;WAIT FOR BUFFER TO EMPTY OUT PUSHJ P,UFLS MOVEI T,%NSRFN ;WAIT FOR RFNM HLL T,IMSOC4(I) ;4.9 IS KNOWN TO BE OFF NOW! CAMN T,IMSOC4(I) PUSHJ P,UFLS JRST POPJ1 ;.NETINT CH, ;SEND NETWORK INTERRUPT "INR" OR "INS" ;INR FROM RECEIVER TO SENDER (LOCAL SOCKET EVEN, FOREIGN ODD) ;INS FROM SND TO RCV ( -", -") ;ALSO .CALL NETINT, ARG 1 IS CH NNETINT:JSP T,NETCHK AOSA (P) ;GOING TO WIN, SKIP RETURN ANETINT: JSP T,NETCHK ;I<- SOCKET TABLE INDEX LDB H,IMSCFH ;HOST INDEX FOR NETOW PUSHJ P,NETOW ;WAIT FOR IMPMPU MOVEI A,1 ;SET COUNT MOVEM A,IMPMPC PUSHJ P,STHSTM ;STORE HOST ADDRESS MOVE A,[8_24.+2_8] ;BYTE SIZE 8, COUNT 2 MOVEM A,IMPMPC+6 MOVE A,IMSOC2(I) ;LCL SOCK # MOVSI B,7_10. ;INR TRNE A,1 ;SKIP IF RCV MOVSI B,8_10. ;INS LDB A,IMSCLN ;LINK # DPB A,[241000,,B] MOVEM B,IMPMPC+7 JRST IMPMPQ ;QUE IT, START OUTPUT (IMPOST) ;STORE HOST ADDRESS FROM H INTO LEADER IN IMPMPC. BASHES W, Q. STHSTM: MOVEI Q,IMPMPL HRLM H,IMPMPC ;ALSO SAVE HOST INDEX FOR PI LEVEL ;STORE HOST ADDRESS FROM H INTO LEADER IN (Q), BASHES W. STHSTP: MOVE W,IMPHTN(H) ;FOREIGN HOST NUMBER IFN 1, DPB W,[103000,,3(Q)] ; Store host address IFN 0,[ DPB W,[301000,,3(Q)] ;STORE HOST NUMBER LSH W,-9 DPB W,[102000,,3(Q)] ;STORE IMP NUMBER ] ;IFN 0 MOVSI W,17_10. ;NEW-FORMAT FLAG MOVEM W,2(Q) ;MESSAGE TYPE 0 (LINK, ETC. ARE ALWAYS ZERO) POPJ P, ;.CALL NETBLK ;WAIT FOR STATE TO CHANGE OR TIME OUT ; ARG 1 - CHANNEL ; ARG 2 - STATE ; ARG 3 - TIME, AS IN .SLEEP (OPTIONAL) (WRITTEN BACK) ; VAL 1 - NEW STATE ; VAL 2 - TIME LEFT ANETBLK:JSP T,NETCHK MOVE T,I ;SAVE INDEX IN T HRL T,B ;STATE ALSO CAIGE W,3 ;SKIP IF 3 ARGS (TIME GIVEN) JRST ANETB3 ;USE DEFAULT TIME TLNE C,1000 ;SKIP IF POINTER, RATHER THAN IMMEDIATE JRST ANETB5 XCTR XRW,[MOVES B,(C)] ;GET TIME FROM USER (CHECK WRITE ALSO) JUMPL B,ANETB1 ;NEG MEANS ALREADY ABS TIME MOVNS B ;MAKE NEG SUB B,TIME ;-TIME TO GO TO ANETB1: UMOVEM B,(C) ;STORE NEG TIME FOR PCLSR MOVNS B ;MAKE + ANETB4: MOVEM B,EPDL(U) ;ALSO USED IN B LATER PUSHJ P,ANETB2 ;SKIP IF STATE CHANGE OR TIMEOUT PUSHJ P,UFLS SUB B,TIME ;HOW MUCH USED? HRRZ A,IMSOC4(I) ;RETURN STATE JRST POPJ1 ANETB2: HLR A,T ;DESIRED STATE XOR A,IMSOC4(T) ;CURRENT STATE TRNE A,-1 ;SKIP IF STILL MATCH JRST POPJ1 MOVE A,EPDL(U) ;SAVED TIME HERE CAMG A,TIME AOS (P) ;TIME OUT! POPJ P, ANETB3: HRLOI B,377777 ;NO TIME SUPPLIED, USE INFINITY JRST ANETB4 ANETB5: HRRZ B,C ;IMMEDIATE TIME SUPPLIED ADD B,TIME ;(TIMEOUT WILL RESTART ON EACH PCLSR, TOO BAD) JRST ANETB4 IFE INETP,[ ;.CALL STYNET ;ARG 1 - STY CHANNEL ;ARG 2 - NET INPUT CHANNEL TO CONNECT STY OUTPUT TO, OR -1 TO DISCONNECT ;ARG 3 - NET OUTPUT CHANNEL TO CONNECT STY INPUT TO ;ARG 4 - CHARS TO SEND WHEN OUTPUT .RESET HAPPENS ON STY'S TTY ; UP TO 3 8-BIT CHARACTERS, LEFT JUSTIFIED. NSTYNT: TLNN R,%CLSST JRST OPNL34 ;1ST ARG NOT A STY CHANNEL. HLRZ I,(R) ;GET TTY # OF STY HRRES B ;ALLOW IMMEDIATE -1 JUMPGE B,NSTYN2 ;JUMP IF CONNECTING. PUSHJ P,NSTYN0 ;DISCONNECT JRST OPNL41 ;WASN'T CONNECTED JRST POPJ1 ;VARIOUS ROUTINES CALL HERE WITH THE TTY# OF A STY IN I, TO DISCONNECT THE ; STY FROM THE NETWORK. NOTE THIS ROUTINE MUST NOT CHANGE U AND MUST NOT ; LSWCLR, SINCE IT COULD BE CALLED FROM IODCL VIA STYCLS OR NETCLS. NSTYN0: MOVSI B,%SSNET ;DISCONNECTING BOTH SIDES. CONO PI,NETOFF TDNN B,STYSTS-NFSTTY(I) POPJ P, ;THIS STY NOT CONNECTED? ANDCAB B,STYSTS-NFSTTY(I) ;MARK AS NO LONGER CONNECTED MOVE C,STYNTL-NFSTTY(I) ;REMOVE THIS STY FROM ACTIVATION LIST MOVEI D,STYNTA-STYNTL+NFSTTY NSTYN1: CAMN I,STYNTL-NFSTTY(D) ;FIND THE STY THAT POINTS TO THIS ONE, MOVEM C,STYNTL-NFSTTY(D) ;AND PATCH US OUT OF THE LIST. SKIPE D,STYNTL-NFSTTY(D) ;SEARCH WHOLE LIST TILL FIND WHO POINTS TO US. JRST NSTYN1 SETOB C,STYNTL-NFSTTY(I) EXCH C,STYNTI-NFSTTY(I) ;MARK THIS STY AS HAVING NO CONNECTION, GET SOCKET INDICES IFN CHAOSP,[ TLNE B,%SSCHA JRST [ MOVSI B,%SSCHA ;DISCONNECT FROM CHAOS NET ANDCAM B,STYSTS-NFSTTY(I) MOVSI B,%CFSTY TDNN B,CHSSTA(C) JRST 4,. ;CHAOS DOESN'T THINK IT WAS CONNECTED? ANDCAM B,CHSSTA(C) JRST NETOJ1 ] ];CHAOSP MOVE B,[40000,,777] TDNN B,IMSOC5(C) JRST 4,. ;SOCKET DOESN'T THINK IT WAS CONNECTED? ANDCAM B,IMSOC5(C) ;AND MARK SOCKETS WE WERE CONNECTED TO AS DISCONNECTED MOVSS C TDNN B,IMSOC5(C) JRST 4,. ;SOCKET DOESN'T THINK IT WAS CONNECTED? ANDCAM B,IMSOC5(C) JRST NETOJ1 NSTYN2: MOVE Q,I ;SAVE TTY # OF STY MOVEI E,1 MOVE A,B ;DECODE THE NETWORK INPUT CHANNEL JSP T,CHNDCD IFN CHAOSP,[ HRRZ A,(R) CAIE A,CHAIDN CAIN A,CHAODN JRST [ HLRZ I,(R) ;CONNECT TO CHAOS NET CONO PI,NETOFF MOVSI B,%CFSTY TDNE B,CHSSTA(I) JRST OPNL23 ;ALREADY CONNECTED, FILE LOCKED MOVSI C,%SSNET+%SSCHA TDNE C,STYSTS-NFSTTY(Q) JRST OPNL23 ;ALREADY CONNECTED, FILE LOCKED IORM B,CHSSTA(I) ;OK, HOOK UP DPB Q,[$CFTTN,,CHSSTA(I)] JRST NSTYN3 ] ];CHAOSP JSP T,NETCHK ;TEST LEGALITY; OPNL IF LOSES TDNE E,IMSOC2(I) JRST OPNL2 ;WRONG DIRECTION IF IT'S AN OUTPUT CHANNEL MOVE B,I ;SAVE INPUT IMSOC INDEX MOVE A,C ;DECODE OUTPUT CHANNEL JSP T,CHNDCD JSP T,NETCHK TDNN E,IMSOC2(I) JRST OPNL2 ;WRONG DIRECTION IF INPUT SOCKET CONO PI,NETOFF MOVE E,[40000,,777] TDNN E,IMSOC5(B) ;ERROR IF EITHER CHANNEL ALREADY CONNECTED TDNE E,IMSOC5(I) JRST OPNL23 ;"FILE LOCKED" MOVSI C,%SSNET TDNE C,STYSTS-NFSTTY(Q) JRST OPNL23 ;SIMILAR ERROR IF STY ALREADY CONNECTED HRR E,Q ;GET 40000,,TTY # IORM E,IMSOC5(I) IORM E,IMSOC5(B) ;MARK SOCKETS AS CONNECTED NSTYN3: SKIPGE STYNTL-NFSTTY(Q) ;HALT IF STY'S VARS ARE NOT CORRECT FOR A SKIPL STYNTI-NFSTTY(Q) ;NON-CONNECTED STY. JRST 4,. IORM C,STYSTS-NFSTTY(Q) ;ALL ERROR CAUGHT, SO MARK STY CONNECTED. HRL B,I ;PUT INPUT IMSOC IDX,, OUTPUT IMSOC IDX MOVSM B,STYNTI-NFSTTY(Q) ;INTO THE STY TRZ D,7777 ;STORE THE OUTPUT RESET CHARACTERS - AT MOST 3 MOVEM D,STYORC-NFSTTY(Q) IFN CHAOSP,[ ;ACTIVATE IN CASE HAS UNREAD INPUT TLNN C,%SSCHA PUSHJ P,IMPUIN TLNE C,%SSCHA PUSHJ P,CHINTI ];CHAOSP .ELSE PUSHJ P,IMPUIN JRST NETOJ1 ] ;IFE INETP SUBTTL ARPANET MP I/O ROUTINES IFE INETP,[ ;CALL STYNTC AT CLOCK LEVEL TO PROCESS ALL NECESSARY TRANSFERS OF DATA ;BETWEEN CONNECTED STYS AND NET SOCKETS STYNTC: CONO PI,NETOFF SKIPN I,STYNTA ;GET HEAD OF ACTIVATE LIST JRST NETONJ ;EMPTY SETZM STYNTA ;COPY LIST IN CASE A STY IS PUT BACK ON CONO PI,NETON STYNT7: MOVE A,STYNTL-NFSTTY(I) ;GET NEXT ON LIST MOVEM A,STYNTB ;SAVE FOR NEXT TIME AROUND LOOP SETOM STYNTL-NFSTTY(I) ;THIS ONE IS NO LONGER ON ACTIVATE LIST MOVE A,STYSTS-NFSTTY(I) TLNN A,%SSNET JRST 4,. ;STY CLAIMS NOT TO BE CONNECTED?? MOVE R,I ;SAVE TTY # IFN CHAOSP,[ TLNE A,%SSCHA JRST STYCHA ;CONNECTED TO CHAOS NET ];CHAOSP ] ;IFE INETP IFN INETP,STYNCP: SKIPGE TTYOAC(I) JRST STYNT1 ;NO OUTPUT, CHECK FOR INPUT ;HANDLE OUTPUT TO NET HRRZ I,STYNTI-NFSTTY(I) ;GET IMSOC IDX OF OUTPUT CHANNEL MOVSI A,40000 TDNN A,IMSOC5(I) JRST 4,. ;SOCKET CLAIMS NOT TO BE CONNECTED?? STYNT5: CONO PI,NETOFF ;INCLUDES TTYOFF PUSHJ P,NSOSE0 ;CAN WE OUTPUT TO NET NOW? JRST STYNT6 ;NO, WAIT TILL LATER, PI LVL WILL REACTIVATE WHEN STATE CHANGES LDB T,IMSCBS ;SINCE THIS IS PI LEVEL, MOVE Q,IMSOC7(I) ;NO POINT IN SENDING MORE OUTPUT THAN ALLOCATED SUB Q,IMSC7I(I) IDIVM Q,T ;T GETS NUMBER OF BYTES ALLOCATED AND NOT BUFFERED CAMLE E,T MOVE E,T JUMPLE E,STYNT6 ;NO ALLOC, SEND NOTHING EXCH R,I ;BEFORE EXCH, R HAS TTY #, I HAS NET IMSOC IDX MOVEM D,DBBBP ;SET UP BUFFER-POINTING VARS FOR TTY OUTPUT INTERRUPT LEVEL MOVEM E,DBBCC MOVEM E,DBBCC1 PUSH P,R SETOM TYPNTF PUSHJ P,TYP ;OUTPUT THROUGH THOSE POINTERS, INTO THE NET CHNL BUFFER SETZM TYPNTF POP P,R EXCH I,R MOVE D,DBBBP MOVE E,DBBCC MOVE Q,DBBCC1 PUSHJ P,NSOFIN ;FIGURE OUT HOW MANY CHARS WERE TYPED, AND UPDATE SOCKET. JRST STYNT4 ;MORE ROOM IN BUFFER => MAYBE TYPE SOME MORE. JRST STYNT6 ;ELSE TRY INPUT FROM NET, BUT SEND WHATEVER WE GOT STYNT4: SKIPL TTYOAC(R) ;MORE OUTPUT IN TTY BUFFER? JRST STYNT5 ;YES, PROCESS IT STYNT6: PUSHJ P,NSOFN1 ;NO, BE SURE NET BUFFER GETS SENT SOON ;HERE TO TRY TO HANDLE INPUT FROM NET STYNT1: HLRZ I,STYNTI-NFSTTY(R) ;INPUT IMSOC INDEX MOVSI A,40000 TDNN A,IMSOC5(I) JRST 4,. ;SOCKET CLAIMS NOT TO BE CONNECTED? STYNT2: PUSHJ P,NETIDC ;GET CHAR FROM NET SOCKET JRST STYNT3 ;GOT CHAR IN W JRST STYNT8 ;NO CHAR AVAIL, HANDLE OTHER STYS ;2 SKIPS => GIVE UP, SPECIAL CHARACTER SEEN, OR BAD STATE PUSHJ P,IMPUIP ;WAKE UP THE TELNET SERVER MOVE I,R ;DISCONNECT THE STY AND SOCKETS PUSHJ P,NSTYN0 JRST 4,. IFE INETP,[ STYNT8: SKIPE I,STYNTB ;GET NEXT STY FROM COPIED ACTIVATION LIST JRST STYNT7 POPJ P, ] ;IFE INETP .ELSE JRST STYNT8 STYNT3: EXCH I,R ;HERE IF GET CHAR FROM NET IN W. I GETS TTY #. PUSH P,R PUSH P,I MOVE A,W CONO PI,TTYOFF PUSHJ P,NTYI5 ;GIVE CHARACTER TO TTY INPUT INTERRUPT LEVEL. CONO PI,TTYON POP P,R ;TTY #; POP IN REVERSE ORDER TO UNDO THE EXCH POP P,I ;IMSOC IDX JRST STYNT2 ;TRY TO GET ANOTHER INPUT CHARACTER. ;STYNTC'S INTERFACE TO NET INPUT IOT. ;I HAS IMSOC IDX OF INPUT SOCKET. ;1 SKIP => NO DATA AVAILABLE. ;2 SKIPS => TELNET CONTROL CHARACTER FOUND, SO DISCONNECT STY AND ;INTERRUPT THE USER PROGRAM. NETIDC: MOVNI U,1 ;U=-1 TELLS NETI IT CAME FROM HERE HRRZ H,IMSOC4(I) ;CHECK SOCKET STATE CAIN H,%NSOPN JRST POPJ1 ;NO DATA CAIGE H,%NSCLI ;SKIP IF IN ONE OF THE TWO INPUT AVAILABLE STATES JRST POPJ2 ;STATE IS ABNORMAL, SO DISCONNECT FROM STY. JRST NETID ;ELSE TRY AN IOT. ;NETWORK UNIT INPUT. NETI: HRRE I,A ;SOCKET TABLE INDEX JUMPL I,IOCER1 NETIB: MOVE A,IMSOC5(I) ;ENTER HERE FROM BLOCK-MODE INPUT TLNE A,40000 JRST IOCR10 ;CAN'T IOT AT M.P. LEVEL WHILE SOCKET CONNECTED TO A STY. NETID: MOVE A,IMSC8I(I) LDB B,IMSCBS IMUL B,IMSMPC(I) ADD B,IMSOC7(I) ;TOTAL NUMBER OF BITS YET TO BE READ CAIGE A,8. ;IF MESS REALL OF 8 OR MORE CAMG B,IMSC7I(I) ;OR BIT REALL SATISFIES "DOUBLE BUFFERING" CRITERION PUSHJ P,NETI6 ;THEN SEND ALLOCATE JUMPL U,NETI4 ;JUMP IF READING INPUT TO GIVE DIRECTLY TO A STY NETI0: CONO PI,NETOFF ;DON'T ALLOW INTO IMPUIN WHILE CHECKING STATE, #BITS HRRZ A,IMSOC4(I) JUMPE A,NETIB1 ;CONNECTION CLOSED CAIE A,%NSINP CAIN A,%NSCLI JRST .+3 CAIE A,%NSOPN JRST IOCR10 ;SOCKET IN BAD STATE PCLT SKIPG IMSMPC(I) ;WAIT FOR BITS TO ARRIVE PUSHJ P,UFLS CONO PI,NETON ;NETON IN CASE DIDN'T UFLS SKIPG IMSMPC(I) ;DID THEY? JRST NETI0 ;NO, STATE MUST HAVE CHANGED, CHECK IT AGAIN NETI4: SOSL IMSOCT(I) ;TAKE BYTE JRST NETI4A MOVE A,IMSMPP(I) ;END OF MESSAGE, FIND ADDRESS OF NEXT HEADER WORD MOVEI A,1(A) ;WHICH IS IN NEXT WORD AFTER LAST BYTE LOADED CAILE A,@IMSBFE(I) HRRZ A,IMSOC6(I) ;WRAP AROUND SOSGE B,(A) ;GET HEADER WORD, COUNT DOWN FOR BYTE ABOUT TO TAKE JRST 4,. ;NO MESSAGE, ALTHOUGH IMSMPC > 0 MOVEM B,IMSOCT(I) ;SAVE # BYTES LEFT IN THIS MESSAGE HLL A,IMSBFE(I) ;SET UP BYTE POINTER LH TO LAST BYTE IN WORD MOVEM A,IMSMPP(I) ; SO ILDB WILL GET FIRST DATA BYTE OF THIS MSG AOS IMSC8I(I) ;INCREASE MESSAGE ALLOCATION NETI4A: MOVE TT,IMSMPP(I) ;CHECK FOR WRAP-AROUND MOVE H,IMSOC5(I) TLNE H,2000 JRST NETI2 ;JUMP IF ONE BIT BYTES CAMN TT,IMSBFE(I) JRST [ HRRZ TT,IMSOC6(I) HLL TT,IMSPIP(I) ;B.P. TO FIRST BYTE IN BUFFER JRST .+1 ] ILDB W,TT JRST NETI3 NETI2: LDB E,IMSCBS ;BITS PER BYTE MOVEI W,0 NETI1: CAME TT,IMSBFE(I) JRST NETI1A HRRZ TT,IMSOC6(I) ;WRAP AROUND HLL TT,IMSPIP(I) NETI1A: ILDB A,TT LSH W,1 IORI W,(A) SOJG E,NETI1 ;DROPS THROUGH ;DROPS IN NETI3: TRNN W,200 ;IS THIS A TELNET CONTROL CHAR (>= 200)? JRST NETI3A JUMPL U,[AOS IMSOCT(I) ;YES; IF DIRECT-CONNECTED TO A STY, BREAK CONNECTION. JRST POPJ2] ; WITHOUT GOBBLING THAT CHARACTER TLNE H,400 ;IF 7-BIT ASCII MODE, REPLACE CHARACTER BY ^@. SETZ W, NETI3A: MOVEM TT,IMSMPP(I) LDB TT,IMSCBS ADDM TT,IMSC7I(I) ;INCREASE BIT ALLOCATION CONO PI,NETOFF ;WHILE CHANGING STATE SOSLE IMSMPC(I) ;ONE LESS BYTE IN BUFFER JRST NETONJ ;OK, THERE IS MORE IN BUFFER MOVNI E,1 ;YES, STATE IS CHANGING. HRRZ A,IMSOC4(I) CAIN A,%NSCLI MOVEI E,%NSCLS CAIN A,%NSINP MOVEI E,%NSOPN ;NO INPUT AVAILABLE JUMPL E,[JRST 4,.] ;WAS IN SOME RANDOM STATE CAIN E,%NSCLS PUSHJ P,IMPUIP ;IF STATE CHANGING TO "CLOSED", GIVE USER AN INTERRUPT. HRRM E,IMSOC4(I) JRST NETONJ ;COME HERE WHEN INPUT IOT FINDS THAT CONNECTION IS CLOSED NETIB1: CONO PI,NETON LDB D,IMSCLS CAIE D,%NCFRN JRST IOCR10 ;ABNORMAL CLOSURE, GIVE IOCER INSTEAD OF EOF MOVE TT,IMSOC5(I) POP P,D ;GET OUR RETURN ADDRESS. ANDI D,-1 CAIE D,AIOT3 ;IF WE ARE NOT DOING A UNIT MODE IOT, JRST 1(D) ;JUST RETURN WITH 1 SKIP. TLNN TT,1400 ;SKIP IF ASCII MODE JRST IOCER2 ;EOF IN IMAGE MODE IS IOCERROR. HRROI W,EOFCH ;EOF IN ASCII MODE RETURNS ^C. JRST 1(D) NETI6: HRRZ H,IMSOC4(I) ;SEND ALL MSG CAIE H,%NSINP CAIN H,%NSOPN CAIA POPJ P, ;CLOSED, DON'T SEND ALLOCATE LDB H,IMSCFH ;HOST INDEX FOR NETOW PUSHJ P,NETOW ;GOBBLE MAIN PROG CONTROL LINK BLOCK MOVEI J,2(I) ;LINK # IORI J,<4_8> ;SEND ALLOC LSH J,16. ADD J,IMSC8I(I) LSH J,4 MOVEM J,IMPMPC+7 MOVE J,IMSC7I(I) LSH J,4 MOVEM J,IMPMPC+10 PUSHJ P,STHSTM ;STORE HOST ADDRESS, MESSAGE TYPE MOVE J,[8_24.+8_8] MOVEM J,IMPMPC+6 MOVEI J,2 HRRM J,IMPMPC ;TEXT LENGTH SETZB A,TT EXCH A,IMSC8I(I) EXCH TT,IMSC7I(I) ADDM A,IMSOC8(I) ADDM TT,IMSOC7(I) JRST IMPMPQ ;UNIT MODE NETWORK OUTPUT (DOESN'T CLOBBER C) JRST NETSIO ;SIOT VECTOR NETW: HRRE I,A ;SOCKET TABLE INDEX JUMPL I,IOCER1 SKIPGE C SKIPA A,(C) UMOVE A,(C) NETWB: CONO PI,NETOFF ;BYTE TO OUTPUT IN A. HERE FROM BLOCK MODE. HRRZ B,IMSOC4(I) CAIE B,%NSOPN CAIN B,%NSRFN JRST .+2 JRST IOCR10 SKIPG IMSMPC(I) ;SKIP IF ROOM TO PUT BYTE IN BUF JRST [ MOVSI B,400000 IORM B,IMSOC4(I) ;SET TO SEND IT NOW IFN DMIMP,CONSZ FI,70 PUSHJ P,IMPIOS SKIPG IMSMPC(I) ;WAIT FOR AT LEAST ONE BYTE OF ROOM PUSHJ P,UFLS CONO PI,NETON SKIPG IMSMPC(I) JRST NETWB ;NO ROOM, STATE MUST HAVE CHANGED JRST .+1] MOVE E,IMSOC5(I) MOVE T,IMSOC7(I) TLNE E,100000 CAML T,IMSC7I(I) JRST NETW4 MOVSI B,400000 ;ALLOCATION USED UP (AND FEATURE ENABLED) IORM B,IMSOC4(I) ;SEND BUFFER NOW PUSHJ P,IMPOST CAMN T,IMSOC7(I) ;WAIT FOR DATA TO GO OUT OR ALLOC TO COME IN PUSHJ P,UFLS JRST NETWB ;TRY AGAIN NETW4: MOVE T,IMSMPP(I) ;GET POINTER MOVE E,TIME CAMN T,IMSPIP(I) ;SKIP UNLESS BUFFER EMPTY MOVEM E,IMSOCT(I) ;SET TIME FOR FIRST BITS INTO BUF LDB B,IMSCBS ;BYTE SIZE MOVE E,IMSOC5(I) ;FLAGS CONO PI,NETOFF ;WANT TO MUNG POINTERS WITHOUT PI INTERFERENCE TLNE E,2000 ;SKIP IF BYTES FIT EXACTLY IN WORD TLNN T,770000 ;SKIP IF NOT AT RIGHT END OF WORD JRST NETW2 ;IDPB, CHECK FOR POINTER WRAP LDB TT,[360600,,T] ;GET BYTE POS CAML TT,B ;SKIP IF BYTE SPLITS ACROSS WORDS JRST NETW1 ;JUST DO IDPB DPB TT,[301400,,T] ;SET BYTE TO STORE IN RIGHT OF THIS WORD SUB TT,B ;=> -(# OVERFLOW BITS) ROT A,(TT) ;HIGH PART OF BYTE IN RIGHT END OF A DPB A,T ;STORE PART BYTE AOS T,IMSMPP(I) ;INCR TO NEXT WORD MOVEI E,(T) CAILE E,@IMSBFE(I) HRR T,IMSOC6(I) ;WRAP MOVEM A,@T ;STASH REST OF BYTE IN LEFT PART OF NEXT WORD ADDI TT,36. ;SET TO NEW POSITION DPB TT,[360600,,T] ;NEW BYT POS MOVEM T,IMSMPP(I) ;STORE UPDATED PTR JRST NETW3 ;WRAP UP ;DEPOSIT A BYTE WHICH MAY WRAP AROUND NETW2: CAME T,IMSBFE(I) JRST NETW1 ;NO WRAP HRR T,IMSOC6(I) TLO T,440000 MOVEM T,IMSMPP(I) ;DEPOSIT BYTE KNOWN TO FIT IN WORD NETW1: IDPB A,IMSMPP(I) ;STORE IT ;COUNT THE BITS NOW NETW3: SOS IMSMPC(I) ;1 BYTE LESS FREE LDB T,IMSCBS ADDM T,IMSC7I(I) JRST NETONJ ;NETWORK OUTPUT SIOT NETSIO: CONO PI,NETOFF PUSHJ P,NSOSET ;SET UP FOR FAST SIOT JRST NSIOT1 ;CHANNEL ISN'T SET UP FOR IT => USE NORMAL SIOT LOOP. PUSH P,B PUSH P,C NETSO0: XCTR XRW,[MOVES B,@-1(P)] ;COPY ARGS XCTR XRW,[MOVES C,@(P)] NETSO1: IBP B .SEE NSIOOL ;FOR WHY THIS HAIR IS NEEDED XCTRI XR,[MOVE TT,(B)] SKIPA T,B JRST NETSO3 ;PAGE FAULT, CLEAN UP IMSMPP BEFORE TAKING IT HRRI T,TT LDB TT,T IDPB TT,D SOS E UMOVEM B,@-1(P) ;UPDATE USER'S ARGS XCTR XRW,[SOSLE C,@(P)] JUMPG E,NETSO1 ;LOOP IF BOTH USER AND SYSTEM WILLING SKIPL E SKIPGE C JRST 4,. ;WENT TOO FAR!! PUSHJ P,NSOFIN ;FINISH UP HACKING NET CHANNEL. JRST NETSO2 ;OUTPUT BUFFER HAS MORE ROOM JUMPLE C,PPBAJ1 ;NO ROOM BUT DON'T WANT ANY MORE ANYWAY, SO RETURN SKIPG IMSMPC(I) ;NO ROOM, WAIT FOR SOME PUSHJ P,UFLS ;NOTE ANY STATE CHANGE WILL UNHANG POP P,C ;NOW TRY TO SIOT SOME MORE POP P,B MOVE D,IOTTB(H) ;RESTORE D IN CASE GOES TO NSIOT1 JRST NETSIO NETSO3: PUSHJ P,NSOFIN ;TOOK PAGE FAULT, CLEAN UP JFCL PUSHJ P,TPFLT NETSO2: JUMPLE C,PPBAJ1 ;BUFFER HAS ROOM BUT NO DESIRE TO SEND ANY MORE, RETURN CONO PI,NETOFF PUSHJ P,NSOSE0 ;SET UP TO SEND MORE JRST IOCR10 ;STATE MUST HAVE GONE BAD JRST NETSO0 ;OK, SEND MORE ;SET UP FOR NET OUTPUT SIOT, OR (NSOSE0) FOR DIRECT OUTPUT FROM STY. ;AT ENTRY, A HAS LH(IOCHNM). ;CALL WITH NETOFF, AND DON'T TURN IT BACK ON BEFORE CALLING NSOFIN, ;BECAUSE WE HAVE A COPY OF IMSMPP IN D, AND PI LEVEL MIGHT BE TRYING TO MUNG IT. ;SETS D TO POINTER, E TO COUNT OF CHARS OF SPACE, AND Q TO COPY OF COUNT. ;SETS I TO IMSOC IDX. CLOBBERS T AND TT. ;NO SKIP => CAN'T USE FAST SIOT, OR CAN'T DO DIRECT OUTPUT AT THIS MOMENT. ;IN THAT CASE, D HASN'T BEEN CLOBBERED YET. NSOSET: HRRE I,A JUMPL I,IOCER1 NSOSE0: MOVE E,IMSOC5(I) HRRZ T,IMSOC4(I) CAIE T,%NSOPN CAIN T,%NSRFN ;STATE BAD, OR BYTES CROSS WORD BOUNDARIES, TLNE E,2000 JRST NETONJ ;IMPLIES CAN'T WIN THIS WAY. SKIPG E,IMSMPC(I) JRST NSOFN1 ;JUMP IF BUFFER FULL, SET SEND BUFFER AND NETONJ MOVE D,IMSMPP(I) CAME D,IMSBFE(I) JRST NSOSE2 HRR D,IMSOC6(I) ;IF BUFFER STORING PTR POINTS AT END OF BUFFER, TLO D,440000 ;WRAP AROUND. NSOSE2: LDB Q,IMSCBS MOVEI TT,36. SKIPGE IMSOC5(I) MOVEI TT,32. IDIVM TT,Q ;GET # BYTES/WD OF CONNECTION. HRRZ TT,IMSBFE(I) SUBI TT,(D) IMUL TT,Q ;# BYTES BETWEEN POINTER AND END OF BUFFER. LDB T,[360600,,D] LDB Q,IMSCBS IDIVM T,Q ;# BYTES NOT STORED IN WORD POINTER POINTS AT ADD TT,Q ;THEY ARE AVAILABLE, TOO. CAML E,TT MOVE E,TT ;GET MINIMUM OF FULL BYTES AND BYTES AFTER THE POINTER. MOVE T,TIME MOVE Q,IMSMPP(I) CAMN Q,IMSPIP(I) ;SKIP IF BUFFER NOT EMPTY MOVEM T,IMSOCT(I) ;TIME FOR FIRST BITS INTO BUF. CAILE E,600 ;DON'T LEAVE NETOFF FOR MORE THAN ONE CLOCK TICK OR SO MOVEI E,600 MOVE Q,E ;ORIGINAL E. (FOR NSOFIN) JRST POPJ1 ;FINISH UP AFTER NET OUTPUT SIOT OR DIRECT OUTPUT FROM STY. ;SKIP IF BUFFER FULL ;ASSUME Q,I LEFT OVER FROM NSOSET, AND D,E ADVANCED BY STORING CHARS. NSOFIN: PI2SAF ;NETOFF SHOULD STILL BE IN EFFECT FROM NSOSET SUBM E,Q ;- <# BYTES XFERED> JUMPE Q,NETONJ ;IF OUTPUT NO BYTES, DON'T CHANGE IMSMPP (IMPORTANT!) MOVEM D,IMSMPP(I) ;UPDATE STORING POINTER OF SOCKET BUFFER LDB TT,IMSCBS IMUL TT,Q MOVNS TT ADDM TT,IMSC7I(I) ;INCREASE COUNT OF BITS IN BUFFER ADDB Q,IMSMPC(I) ;UPDATE COUNT OF FREE SPACE IN BUFFER. JUMPG Q,.+2 ;ANY SPACE LEFT => NO SKIP. AOS (P) JUMPG E,NETONJ ;ONLY SEND BUFFER IF CALL OUTPUT ALL IT COULD NSOFN1: MOVSI TT,400000 ;SEND BUFFER NOW. IORM TT,IMSOC4(I) JRST IMPOST ;TURNS NETON NETBO: HRRE I,A JUMPL I,IOCER1 XCTR XRW,[MOVES D,(C)] ;TAKE TRAP GETTING POINTER IF SWAPPED OUT MOVE E,IMSOC5(I) TLNE E,1400 ;SKIP IF IMAGE MODE JRST NETBOA ;ASCII MODE JUMPGE D,CPOPJ ;TRANSFER NO WORDS NETBO1: UMOVEM D,(C) UMOVE A,(D) PUSHJ P,NETWB UMOVE D,(C) AOBJN D,NETBO1 UMOVEM D,(C) POPJ P, NETBOA: TLNN E,400 ;SKIP IF 7 BIT JRST NETBA8 MOVEI E,NETBOR JRST NBTOCH NETBOR: PUSH P,D PUSH P,TT PUSHJ P,NETWB POP P,TT POP P,D MOVEI E,NETBOR POPJ P, NETBA8: XCTR XRW,[MOVES D,(C)] LDB TT,[410300,,D] CAIGE TT,4 ;ONLY 4 BYTES PER WORD (3 < CNT < 8) POPJ P, SKIPA TT,NETCHT-4(TT) NTBA8A: UMOVEM D,(C) UMOVE W,(D) ILDB A,TT PUSH P,TT PUSHJ P,NETWB POP P,TT UMOVE D,(C) ADD D,[700000,,] ;ADVANCE CHAR CNT JUMPL D,NTBA8A ;GO TO NEXT CHAR MOVE TT,NETCHT+3 ADD D,[400001,,1] ;INCR TO NEXT WORD JUMPL D,NTBA8A UMOVEM D,(C) POPJ P, NETCHT: REPEAT 4,<44-<3-.RPCNT>*10>_12.+1000,,W NETBI: HRRE I,A JUMPL I,IOCER1 XCTR XRW,[MOVES D,(C)] ;ENSURE POINTER WILL BE WRITABLE MOVE E,IMSOC5(I) TLNE E,1400 ;SKIP IF IMAGE MODE JRST NETBIA ;ASCII MODE NETBI1: UMOVEM D,(C) ;STORE BACK POINTER XCTR XRW,[MOVES (D)] ;ENSURE BYTE WILL BE WRITABLE PUSH P,C PUSHJ P,NETIB ;GET NEXT BYTE CAIA ;NORMAL RETURN. JRST POP1J ;NO INPUT AVAIL. POP P,C UMOVE D,(C) UMOVEM W,(D) AOBJN D,NETBI1 UMOVEM D,(C) POPJ P, NETBIA: TLNN E,400 ;SKIP IF 7 BIT ASCII JRST NTBIA8 MOVEI E,NETBIR JRST INBTCH NETBIR: PUSHJ P,NETI JRST [ MOVEI E,NETBIR ;INPUT IN W POPJ P, ] MOVE E,[600000,,NETBCC] ;NO INPUT AVAIL JRST POPJ1 NETBCC: MOVEI H,EOFCH JRST POPJ2 NTBIA8: HRRZS E ;8-BIT ASCII BLOCK MODE XCTR XRW,[MOVES D,(C)] LDB TT,[410300,,D] CAIGE TT,4 POPJ P, SKIPA TT,NETCHT-4(TT) NTBI8A: UMOVEM D,(C) XCTR XRW,[MOVES (D)] JUMPL E,NTBI8B PUSH P,C PUSH P,TT PUSHJ P,NETIB JRST [ MOVEI E,0 JRST NETBI5 ] ;NORMAL RETURN - BYTE IN W. MOVSI E,600000 ;NO BYTES AVAIL - SOCKET CLOSED. NETBI5: MOVE H,W POP P,TT POP P,C UMOVE D,(C) LDB W,[410300,,D] CAIN W,7 TLNN E,200000 JRST NTBI8C POPJ P, NTBI8C: UMOVE W,(D) IDPB H,TT UMOVEM W,(D) ADD D,[700000,,] JUMPL D,NTBI8A MOVE TT,NETCHT+3 ADD D,[400001,,1] SKIPL E JUMPL D,NTBI8A UMOVEM D,(C) POPJ P, NTBI8B: MOVEI H,EOFCH UMOVE D,(C) JRST NTBI8C NETCLS: HRRE I,A ;SOCKET TABLE INDEX JUMPL I,CPOPJ MOVE T,IMSOC2(I) TRNN T,1 ;SKIP IF SEND SOCKET JRST NETCL2 MOVSI T,400000 IORM T,IMSOC4(I) ;CAUSE BUFFER TO BE SENT PUSHJ P,IMPOST NETCL2: MOVSI B,600000 CONO PI,CLKOFF IORM B,IMSOC1(I) ;MARK CHANNEL TO BE CLOSED AOS IMNCS HRRZ R,UUAC(U) MOVE A,CHNBIT(R) TDNE A,MSKST2(U) ANDCAM A,IFPIR(U) MOVE I,IMSOC5(I) ;IF CHANNEL CONNECTED TO A STY, TLNN I,40000 JRST CLKONJ ANDI I,777 ;DISCONNECT THEM. PUSHJ P,NSTYN0 JRST 4,. JRST CLKONJ ;SEARCH PENDING QUEUE FOR LOCAL SOCKET NUMBER IN A, ;T 4.9 = 1 => LISTENING, 4.9 => 0 => ALSO CHECK ;FOREIGN SOCKET NUMBER IN B AND FOREIGN HOST NUMBER (IMPHTB INDEX) IN H ;SKIPS IF ENTRY IS FOUND. RETURNS ENTRY TO FREE LIST. ;Q GETS ADDRESS OF ENTRY BLOCK. RETURN WITH NETOFF IMPSPQ: CONO PI,NETOFF IMSPQP: SKIPGE Q,IMPBPQ ;BEGINNING OF QUEUE POPJ P, ;QUEUE EMPTY MOVNI J,1 ;PREVIOUS ENTRY IMSPQL: CAME A,1(Q) ;SKIP IF SAME LOCAL SOCKET NUMBER JRST IMSPQ1 ;TRY NEXT JUMPL T,IMSPQW ;WIN IF LISTENING SOCKET LDB W,[101000,,3(Q)] ;FOREIGN HOST IMPHTB INDEX CAMN W,H ;SKIP IF WRONG FOREIGN HOST CAME B,2(Q) ;SKIP IF FOREIGN SOCKET NUMBER AGREES JRST IMSPQ1 ;TRY NEXT IMSPQW: SKIPGE W,(Q) ;FOUND IT MOVEM J,IMPEPQ ;PATCH OUT OF THE QUEUE SKIPGE J MOVEI J,IMPBPQ MOVEM W,(J) MOVE W,IMFFPQ ;ADD TO FREE LIST MOVEM W,(Q) MOVEM Q,IMFFPQ JRST POPJ1 IMSPQ1: MOVE J,Q ;PREVIOUS ENTRY SKIPL Q,(Q) ;NEXT ENTRY JRST IMSPQL ;LOOP POPJ P, ;NOT FOUND SUBTTL ARPANET CLOCK LEVEL OVHMTR IMP ;NETWORK INTERRUPT LEVEL (NOT STYNET STUFF) ;HERE TO TIME OUT THE RFC QUEUE IMFCT1: CONO PI,NETOFF SKIPGE Q,IMPBPQ JRST NETONJ ;... IF QUEUE IS EMPTY MOVNI J,1 ;J HAS PTR TO PREV ELT OF LIST, FOR IMSPQW TO PATCH (DELQ). IMFCT2: LDB E,[221100,,3(Q)] ;TIME IN 16/15'THS, MOD 512., THAT RFC WAS RECEIVED LDB TT,[051100,,TIME] ;TIME, IN SAME UNITS, NOW. CAMLE E,TT ;MAKE SURE THE SUB TT,E GIVES A POSITIVE ANSWER. ADDI TT,1_9 ;WE ASSUME THAT TIME >= TIME OF RECEIPT. SUB TT,E CAIGE TT,IMFCTO_<-5> JRST IMFCT3 ;THIS RFC HASN'T TIMED OUT - LOOK AT NEXT PUSHJ P,IMSPQW ;IT HAS - FLUSH IT JFCL JRST IMFCT1 ;AND START AGAIN LOOKING FOR RFC'S TO FLUSH IMFCT3: MOVE J,Q SKIPL Q,(Q) JRST IMFCT2 JRST NETONJ ;END OF QUEUE ;FLUSH CLOSED NETWORK CHANNELS (CALLED AT HALF SEC CLOCK) IMPCCL: MOVSI I,-IMPSTL IMPCCR: CONO PI,NETON MOVSI T,200000 IMPCCZ: TDNN T,IMSOC1(I) ;LOOK FOR CHANNELS NO LONGER OPEN. AOBJN I,IMPCCZ JUMPL I,IMPCCA POPJ P, IMPCCA: CONO PI,NETOFF MOVE B,IMSOC6(I) TLNE B,600000 ;ACTIVE AT PI LEVEL OR LOCKED BY CORE JOB JRST IMPCCS HRRZ B,IMSOC4(I) ;DISPATCH ON SOCKET STATE. JRST @IMPCCT(B) IMPCCT: OFFSET -. %NSCLS::IMPCC1 %NSLSN::IMPCC1 %NSRFC::IMPCC2 %NSRCL::IMPCC1 %NSRFS::IMPCC2 %NSOPN::IMPCC5 %NSRFN::IMPCC6 %NSCLW::IMPCC7 %NSCLI::IMPCC1 %NSINP::IMPCC2 OFFSET 0 ;IMP BUFFER RETURN IMPBRT: SKIPN IMSOC6(I) POPJ P, ;NO BUF?? LDB A,[221000,,IMSOC6(I)] CAIE A,377 JRST IMBRT1 LDB A,[121000,,IMSOC6(I)] PUSHJ P,IMEMR CAIA IMBRT1: PUSHJ P,IBRTN SETZM IMSOC6(I) POPJ P, IMPCC1: PUSHJ P,IMPBRT MOVSI A,20000 TDNE A,IMSOC5(I) JSP T,IMPC5D ;WAITING FOR FINAL RFNM SETZM IMSOC1(I) SOS IMNCS ;WE HAVE FINISHED CLOSING ONE SOCKET IMPCCS: AOBJN I,IMPCCR ;WE CLOSED ONE, OR GAVE UP ON ONE; LOOK AT NEXT JRST NETONJ ;OR WE'RE FINISHED LOOKING AT ALL. IMPCC2: PUSHJ P,IMPBRT SKIPLE T,IMFCQL CAIG T,2 ;SKIP IF MORE THAN 2 FREE JRST IMPCCS ;NOT ENUF PI CONTROL QUEUE BLOCKS AVAIL LDB A,IMSCFH ;GET HOST# SKIPGE IMPHTB(A) ;SKIP IF NO RFNM WAIT ON LINK 0 JRST IMPCCS ;NOT NOW! PUSH P,IMPCSH MOVEM A,IMPCSH JSP T,IMSTCM 12.,,3 ;12. BYTES, 3 WORDS JRST 4,. ;NO SLOTS AVAIL. CHECKED BEFORE MOVEI H,3_4 ;3 NOPS + CLS MOVEM H,10(Q) MOVE H,IMSOC2(I) ;LOCAL SOCKET LSH H,4 ;MOVE INTO 32 BIT FIELD MOVEM H,11(Q) MOVE H,IMSOC3(I) ;FOREIGN SOCKET LSH H,4 MOVEM H,12(Q) PUSHJ P,IMWCQ ;SEND CLS POP P,IMPCSH MOVEI H,%NSCLW HRRM H,IMSOC4(I) MOVE H,TIME MOVEM H,IMSOCT(I) ;TIME CLS SENT JRST IMPCCS IMPCC5: MOVE H,IMSOC2(I) TRNN H,1 ;SKIP IF SEND SOCKET JRST IMPC5B ;RECEIVE SOCKET MOVE A,IMSPIP(I) CAMN A,IMSMPP(I) ;IS THERE STILL DATA TO SEND? AT MP LEVEL CAMN I,IMPOPI ;OR PI LEVEL? OR RFNM WAIT? IMPCC6: JSP T,IMPC5D ;YES, SEND IT AND GET RFNM BEFORE SENDING CLS IMPC5B: MOVEI H,%NSRFS ;NO, OK TO SEND A CLS NOW. HRRM H,IMSOC4(I);SET STATE SO WILL LOOP BACK TO IMPCC2 JRST @IMPCCT(H) IMPC5A: IORM H,IMSOC5(I) MOVE H,TIME MOVEM H,IMSOCT(I) JRST IMPCCS IMPC5D: MOVSI H,10000 TDNN H,IMSOC5(I) JRST IMPC5A ;TIME-OUT NOT ALREADY STARTED - START IT. IMPC7A: MOVE H,TIME ;ALREADY STARTED, OVER YET? SUB H,IMSOCT(I) CAIG H,IMPCTO ;SKIP IF TIMED OUT JRST IMPCCS ;NOT YET JRST (T) IMPCC7: JSP T,IMPC7A ;IF CLOSE TIME-OUT ISN'T UP, GIVE UP TO IMPCCS. JRST IMPCC1 ;ELSE FLUSH. ;HERE FROM 1/2 SECOND CLOCK IF IMNAS IS NON-ZERO. ;WE WAKE UP ANY STYNET CHANNELS THAT NEED IT. IMPAAA: SOS IMNAS ;DECREASE NEED-THIS-ROUTINE COUNT MOVSI I,-IMPSTL IMPAA1: MOVSI T,200000 TDNN T,IMSOC5(I) AOBJN I,.-1 JUMPGE I,CPOPJ CONO PI,NETOFF ANDCAM T,IMSOC5(I) PUSHJ P,IMPUIN CONO PI,NETON JRST IMPAA1 SUBTTL ARPANET NCP INPUT INTERRUPT LEVEL ;GET HERE PI IN PROG ON NETCHN ;IMP HAS NETCHN PIA, TT HAS CONI WORD, A HAS LAST WD OF CONTROL LINK MSG ;PROCESS THE CONTROL LINK HOST-HOST PROTOCOL OPCODES. IMPBK3: AOS B,IMBLKI ;STORE LAST WORD AS IF BLKI HAD MOVEM A,(B) MOVEI B,-IMPINB+1(B) ;B HAS NUMBER OF WORDS READ CAMGE B,IMPNIW JRST IMPCIS ;MESSAGE IS SHORT MOVE A,IMPCBC ;NUMBER OF BYTES MOVE B,[441000,,IMPINB] ;8 BIT BYTE POINTER TO MESSAGE SETZM IMPNEA SETZM IMPNRA IMPBKL: SOJL A,IMPIR1 ;LOOP HERE TO PROCESS CONTROL MESSAGE MOVE H,IMPCSH ;RESTORE HOST INDEX ILDB C,B CAIL C,IMPCDL JRST IMPCIG ;ILLEGAL OPCODE AOS IMPCMR(C) ;COUNT CTL MSG RCD JRST @IMPCDT(C) ;DISPATCH ON OPCODE IMPCIG: BUG INFO,[NET: NEW CTL MSG FM HST ],OCT,IMPHTN(H),[COD=],OCT,C,[CT=],OCT,A JRST IMPIR1 IMPCIS: MOVE H,IMPCSH BUG INFO,[NET: SHORT CTL MSG FM HST ],OCT,IMPHTN(H) AOS IMNSCM JRST IMPIR1 IMPCDT: IMPBKL ;NOP ( 0) IMPRFC ;RTS ( 1) IMPRFC ;STR ( 2) IMPCLS ;CLS ( 3) IMPALL ;ALL ( 4) IMPCIG ;GVB ( 5) IMPCIG ;RET ( 6) IMPINR ;INR ( 7) IMPINS ;INS (10) IMPECO ;ECO (11) IMPCIG ;ERP (12) IMPERM ;ERR (13) IMPRST ;RST (14) IMPRRP ;RRP (15) IMPCIG ;RAR (16) IMPCIG ;RAS (17) IMPCIG ;RAP (20) IMPNXR ;NXR (21) IMPNXR ;NXS (22) IMPCDL==.-IMPCDT IMSHRT: MOVNS A BUG INFO,[NET: SHORT CTL MSG HST ],OCT,IMPHTN(H),[COD=],OCT,C,[MISSING],OCT,A JRST IMPIR1 IMPNXR: ILDB C,B ;LINK NUMBER FOR NXR OR NXS SOJA A,IMPBKL ;JUST IGNORE IT, USELESS ANYWAY ;RFC RECEIVED C HAS OPCODE IMPRFC: SUBI A,9 ;MUST BE AT LEAST 9 MORE BYTES JUMPL A,IMSHRT ;MESSAGE IS SHORT ILDB D,B ;D GETS 32 BIT FOREIGN SOCKET NUMBER REPEAT 3,[ LSH D,8 ILDB T,B IORI D,(T) ] ILDB E,B ;E GETS 32 BIT LOCAL SOCKET NUMBER REPEAT 3,[ LSH E,8 ILDB T,B IORI E,(T) ] ILDB R,B ;LINK NUMBER OR BYTE SIZE MOVE Q,E EQVI Q,(C) ;Q 1.1 = 1 IF E 1.1 = C 1.1 ANDI Q,1 JUMPE Q,IMPRF3 ;WRONG DIRECTION RFC CAIE C,2 ;SKIP IF STR JRST IMPRF5 CAILE R,36. ;SKIP IF STR AND BYTE SIZE < 37 JRST IMREFU ;REFUSE CONNECTION IMPRF5: PUSHJ P,IMPLLS ;LOOK FOR LOCAL SOCKET (RET INDEX IN I) JRST IMPRFQ ;NO SUCH SOCKET. QUEUE IT HRRZ W,IMSOC4(I) ;SOCKET STATE CAIE W,%NSLSN ;SKIP IF LISTENING JRST IMPRF4 MOVEM D,IMSOC3(I) ;STORE FOREIGN SOCKET NUMBER DPB H,IMSCFH ;STORE FOREIGN HOST INDEX MOVEI Q,%NSRFC HRRM Q,IMSOC4(I) ;RFC RECEIVED STATE CAIN C,2 ;SKIP IF RTS JRST [ LDB Q,IMSCBS ;STR, CHECK CONNECTION BYTE SIZE CAME Q,R JRST IMCLDA JRST .+2 ] DPB R,IMSCLN ;RTS, STORE LINK # PUSHJ P,IMPUIN ;INTERRUPT USER IMRFCX: LDB Q,IMHSBT CAIN Q,1 SOS IMRFCT MOVEI Q,2 DPB Q,IMHSBT ;MARK HOST UP JRST IMPBKL IMPRF3: BUG INFO,[NET: WRONG DIR RFC HST ],OCT,IMPHTN(H),[OP ],SIXBIT,[(C)[SIXBIT /RTS STR/]-1],[SOK],OCT,E JRST IMPBKL IMPRF4: CAIE W,%NSRFS ;SKIP IF IN RFC SENT STATE JRST IMPRFQ ;QUEUE IT LDB Q,IMSCFH CAMN Q,IMPCSH CAME D,IMSOC3(I) ;FROM CORRECT FOREIGN SOCKET? JRST IMREFU ;NO, REFUSE AOS IMSOC4(I) ;PUT INTO STATE 5 - OPEN CAIE C,1 ;SKIP IF RTS JRST IMPRF2 ;STR DPB R,IMSCLN ;STORE LINK # IMPRF1: PUSHJ P,IMPUIN ;INTERRUPT USER JRST IMPBKL IMPRF2: LDB Q,IMSCBS CAME Q,R JRST IMCLDA ;BYTE SIZES DIFFER, REFUSE JSP T,IMSTCM 8,,2 ;TEXT: 8 BYTES, 2 WORDS JRST [ AOS IMNANS JRST IMPRF1 ] MOVEI H,2(I) LSH H,16. ;LINK # IOR H,IMSOC8(I) ;MSG ALLOC LSH H,4 TLO H,(4_28.) ;ALL MOVEM H,10(Q) MOVE H,IMSOC7(I) ;BIT ALLOC LSH H,4 MOVEM H,11(Q) PUSHJ P,IMWCQ ;SEND IT OUT JRST IMPRF1 IMPRFQ: CAIL E,NETSRS ;IF < 1000, START JOB "NETRFC" JRST IMRFQ5 MOVE T,IMPHTN(H) ; CAIE T,+_9 CAME T,[IMPUS3-NW%ARP] ; Compare with our own host (minus net #) SKIPL NETUSW CAIA JRST IMREFU ;REFUSE CONNECTION HRROI T,NTRFCL PUSHJ P,NUJBST ;LOAD SERVER JRST IMREFU ;RING BUFFER FULL IMRFQ5: SKIPGE Q,IMFFPQ ;SKIP IF ANY FREE SLOTS JRST IMRFQ1 ;CLS OLDEST MOVE W,(Q) MOVEM W,IMFFPQ ;NEW FIRST FREE IMRFQ9: SETOM (Q) ;END OF QUEUE MOVEM E,1(Q) ;LOCAL SOCKET NUMBER MOVEM D,2(Q) ;FOREIGN SOCKET NUMBER CAIE C,2 ;SKIP IF STR TLO R,400000 ;MARK AS RTS MOVEM R,3(Q) ;LINK NUMBER OR BYTE SIZE DPB H,[101000,,3(Q)] ;FOREIGN HOST INDEX LDB W,[051100,,TIME] ;STORE TIME OF RECEIPT, IN 16/15 MOD 512. DPB W,[221100,,3(Q)] SKIPGE W,IMPEPQ ;END OF QUEUE JRST IMRFQ2 ;QUEUE EMPTY MOVEM Q,(W) ;PUT IN AT END OF QUEUE MOVEM Q,IMPEPQ ;NEW END OF QUEUE JRST IMRFCX IMRFQ2: MOVEM Q,IMPEPQ ;END OF QUEUE MOVEM Q,IMPBPQ ;AND BEGINNING OF QUEUE JRST IMRFCX IMRFQ1: MOVE J,IMPBPQ ;BEGINNING OF PENDING QUEUE MOVE E,1(J) ;LOCAL SOCKET MOVE D,2(J) ;FOREIGN SOCKET PUSH P,IMPCSH LDB H,[101000,,3(J)] ;FOREIGN HOST INDEX MOVEM H,IMPCSH PUSHJ P,IMPSCL ;SEND CLS JRST IMRFQ3 ;NO BUFFERS AVAILABLE AOSA IMNRFC ;# RFCS CLOSED IMRFQ3: AOS IMNRFI ;# RFCS IGNORED POP P,IMPCSH MOVE H,IMPCSH MOVE Q,IMPBPQ ;FLUSH FIRST ENTRY ON PENDING QUEUE MOVE W,(Q) MOVEM W,IMPBPQ JRST IMRFQ9 IMREFU: PUSHJ P,IMPSCL ;SEND CLS AOS IMNCNS ;CAN'T AOS IMNRFI JRST IMPBKL IMPCLS: SUBI A,8 ;MUST BE AT LEAST 8 MORE BYTES JUMPL A,IMSHRT ;MESSAGE IS SHORT ILDB D,B ;D GETS 32 BIT FOREIGN SOCKET NUMBER REPEAT 3,[ LSH D,8 ILDB T,B IORI D,(T) ] ILDB E,B ;E GETS 32 BIT LOCAL SOCKET NUMBER REPEAT 3,[ LSH E,8 ILDB T,B IORI E,(T) ] PUSHJ P,IMPLC ;LOOK FOR CONNECTION JRST IMCLSQ ;LOOK IN QUEUE MOVSI W,200000 ;SET CLS RCD BIT IORB W,IMSOC4(I) ;RH IS STATE FOR DISPATCH JRST @IMCLDT(W) IMCLDT: OFFSET -. %NSCLS::IMPCLI %NSLSN::IMPCLI %NSRFC::IM2CLS %NSRCL::IMPCLI %NSRFS::IM4CLS %NSOPN::IM5CLS %NSRFN::IM6CLS %NSCLW::IM7CLS %NSCLI::IMPCLI %NSINP::IMECLS OFFSET 0 IM4CLS: HLLZS IMSOC4(I) .SEE %NSCLS MOVEI W,%NCRFS JRST IMCLDB IMECLS: MOVEI W,%NSCLI JRST IMCCLS IMCLDA: HLLZS IMSOC4(I) .SEE %NSCLS MOVEI W,%NCBYT ;BYTE MISMATCH JRST IMCLDB IM6CLS: MOVSI W,20000 ;CLSED DURING RFNM WAIT IORM W,IMSOC5(I) IM5CLS: TDZA W,W .SEE %NSCLS IM2CLS: MOVEI W,%NSRCL IMCCLS: HRRM W,IMSOC4(I) ;CHANGE STATE MOVEI W,%NCFRN IMCLDB: DPB W,IMSCLS ;CLS REASON PUSHJ P,IMPUIN ;INTERRUPT USER IMCLQ2: PUSHJ P,IMPSCL ;SEND CLS AOS IMNCNS JRST IMPBKL IMPSCL: JSP T,IMSTCM ;SEND A CLS TO LOCAL SOCKET IN E AND FOREIGN SOCKET IN D (CLOBBERS D AND E) 12.,,3 ;TEXT: 12 BYTES, 3 WORDS POPJ P, MOVEI H,3_4 ;3 NOPS + CLS MOVEM H,10(Q) LSH E,4 MOVEM E,11(Q) ;LOCAL SOCKET NUMBER LSH D,4 MOVEM D,12(Q) ;FOREIGN SOCKET NUMBER PUSHJ P,IMWCQ ;SEND CLS JRST POPJ1 IMPCLI: AOS IMNCLI JRST IMPBKL IM7CLS: HLLZS IMSOC4(I) .SEE %NSCLS JRST IMPBKL IMCLSQ: PUSH P,A PUSH P,B MOVE A,E ;LOCAL SOCKET NUMBER MOVEI T,0 MOVE B,D ;FOREIGN SOCKET NUMBER PUSHJ P,IMSPQP ;SEARCH PENDING QUEUE JRST IMCLQ1 ;NOT THERE MOVE E,A POP P,B POP P,A JRST IMCLQ2 ;SEND HIM A CLS IMCLQ1: POP P,B POP P,A JRST IMPCLI ;CAN'T FIND HIM. IGNORE IMPALL: SUBI A,7 ;MUST BE AT LEAST 7 MORE BYTES JUMPL A,IMSHRT ;MESSAGE IS SHORT ILDB R,B ;LINK # ILDB D,B LSH D,8 ILDB T,B IORI D,(T) ;D GETS MESSAGE ALLOCATION ILDB E,B ;E GETS BIT ALLOCATION REPEAT 3,[ LSH E,8 ILDB T,B IORI E,(T) ] MOVE T,IMPCSH ;FOREIGN HOST LSH T,8 IOR R,T ;HEADER (HOST AND LINK #) MOVEI W,1 ;TO TEST DIRECTION OF SOCKET MOVSI I,-IMPSTL IMPAL2: LDB T,IMSCHD ;FOREIGN HOST AND LINK NUMBER SKIPGE IMSOC1(I) ;SKIP IF SLOT NOT IN USE CAME T,R ;SKIP IF HEADER AGREES JRST IMPAL1 TDNE W,IMSOC2(I) ;SKIP IF NOT SEND JRST IMPAL3 IMPAL1: AOBJN I,IMPAL2 ANDI R,377 BUG INFO,[NET: IGNORED ALLOC HST ],OCT,IMPHTN(H),[LNK],OCT,R AOS IMNALI JRST IMPBKL ;IGNORE IMPAL3: SKIPL D SKIPGE E JRST 4,. LDB T,IMSCBS ;GET BYTESIZE IDIV E,T ;TRUNCATE TO 0 MODULO BYTESIZE IMUL E,T ;(CLOBBER TT) SKIPL IMSOC8(I) SKIPGE IMSOC7(I) JRST 4,. ADDB D,IMSOC8(I) ;INCREASE ALLOCATIONS ADDB E,IMSOC7(I) MOVE Q,IMSOC5(I) TLNE Q,140000 ;ACTIVATE IF USER (OR DIRECT CONN) CHECKING ALLOC PUSHJ P,IMPUIN MOVE T,IMSPIP(I) CAME T,IMSMPP(I) ;SKIP IF OUTPUT BUFFER EMPTY PUSHJ P,IMPIOS ;THIS GUY MAY HAVE STUFF TO GO OUT JRST IMPBKL IMPLLS: MOVSI I,-IMPSTL ;LOOK FOR SOCKET IN E MOVSI W,200000 IMPLL2: TDNN W,IMSOC1(I) SKIPL IMSOC1(I) ;NOT IN USE JRST IMPLL1 CAME E,IMSOC2(I) ;SKIP IF RIGHT LOCAL SOCKET NUMBER IMPLL1: AOBJN I,IMPLL2 JUMPL I,POPJ1 ;RETURN SOCKET TABLE INDEX IN RH OF I POPJ P, ;NOT FOUND ;INTERRUPT USER ASSOCIATED WITH CHANNEL IN I IMPUIN: MOVSI U,200000 TDNE U,IMSOC1(I) POPJ P, ;CHNL BEING CLOSED MOVE U,IMSOC5(I) TLNE U,40000 JRST IMPUIS ;JUMP IF SOCKET IS CONNECTED TO A STY. IMPUIP: HRRZ U,IMSOC1(I) ;USER INDEX LDB Q,[222000,,IMSOC1(I)] ;MASK FOR CHANNEL OPEN ON IMPUIM: AND Q,MSKST2(U) ;ONLY ENABLED CHANNELS. PUSH P,T ;VALIDATE THE USER INDEX MOVEI T,LUBLK IDIVM U,T IMULI T,LUBLK CAMN T,U CAML U,USRHI JRST 4,. MOVSI T,(SETZ) ;PCLSR SO IT GETS IOC ERROR IF NEEDFUL IORM T,PIRQC(U) ; EVEN IF IT DOESN'T HAVE NORMAL INTERRUPTS ENABLED POP P,T IORM Q,IFPIR(U) ;GEN SECOND WORD INTERRUPT POPJ P, IMPUIS: PI2SAF ;HERE FOR INT. ON SOCKET CONNECTED TO A STY: ANDI U,777 SKIPL STYNTL-NFSTTY(U) POPJ P, ;ALREADY ACTIVATED MOVE Q,STYNTA ;PUT THAT STY ON THE XFER ACTIVATION LIST. MOVEM Q,STYNTL-NFSTTY(U) MOVEM U,STYNTA ;THEN RETURN. DON'T ACTUALLY INTERRUPT THE JOB; POPJ P, ;IF ANYTHING FUNNY HAS HAPPENED, STYNTC WILL INTERRUPT. ;LOOK FOR CONNECTION: LOCAL SOCKET IN E, FOREIGN SOCKET IN D, FOREIGN HOST IN H IMPLC: MOVSI I,-IMPSTL IMPLC2: SKIPGE IMSOC1(I) ;NOT IN USE CAME E,IMSOC2(I) ;LOCAL SOCKET NUMBER JRST IMPLC1 LDB T,IMSCFH CAMN D,IMSOC3(I) ;FOREIGN SOCKET NUMBER CAME H,T IMPLC1: AOBJN I,IMPLC2 JUMPL I,POPJ1 POPJ P, IMPINR: SOJL A,IMSHRT ;SHORT COUNT ILDB D,B ;LINK # DPB H,[101000,,D] ;CONCAT HOST&LINK MOVSI I,-IMPSTL LDB E,IMSCHD ;GET HOST FOR SOCKET CAME D,E AOBJN I,.-2 ;SEARCH FOR MATCHING HOST&LINK JUMPGE I,IMPILS ;NOT FOUND NCPIRS: HRRZ E,IMSOC4(I) ;STATE MOVE E,CHNBIT(E) ;BIT TO CORRESPOND TRNN E,1_%NSRFC+1_%NSRFS+1_%NSOPN+1_%NSRFN+1_%NSCLW+1_%NSINP ;OK STATES RFCRCV, RFCSNT, OPEN, RNMWT, CLSSNT, DATA JRST IMPILS ;IN BAD STATE TRNE E,1_%NSCLW ;IGNORE INT IF CLSSNT STATE (NOT ERROR) JRST IMPBKL MOVSI D,4000 IORM D,IMSOC5(I) ;INT FLAG 4.3 BIT OF IMSOC5(SOCK) PUSHJ P,IMPUIN ;INT TO USER JRST IMPBKL IMPINS: SOJL A,IMSHRT ;SHORT ILDB D,B ;LINK MOVEI I,-2(D) ;0,1 -> 777776,777777 ILLEGAL LINKS CAIGE I,IMPSTL ;CHECK IN RANGE 2 TO IMPSTL+1 SKIPL IMSOC1(I);AND IN USE JRST IMPILS ;BAD LINK LDB T,IMSCFH CAMN T,IMPCSH ;SKIP IF HOST NOT MATCHED BY MSG JRST NCPIRS IMPILS: BUG INFO,[NET: BAD INT CTL MSG HST ],OCT,IMPHTN(H),[LNK ],OCT,D,[IMSOC4],OCT,IMSOC4(I) JRST IMPBKL ;NOTE- I MAY BE -1 OR -2 OR UP TO 256, IF LNK BAD, IGNORE IMPECI: AOS IMPNEI ;WILL EVENTUALLY GIVE JOB TO MAIN PROG JRST IMPBKL IMPECO: ILDB D,B ;GET 8 BIT DATA TO ECHO SOJL A,IMSHRT SKIPE IMPNEA JRST IMPECI ;ONLY ONE TO A CUSTOMER JSP T,IMSTCM 2,,1 ;TEXT: 2 BYTES, 1 WORD JRST IMPECI LSH D,20. ;DATA TO BE ECHOED TLO D,(10._28.) ;ERP MOVEM D,10(Q) PUSHJ P,IMWCQ ;SEND IT OUT AOS IMPNEA JRST IMPBKL IMPERM: SUBI A,11. ;COUNT BYTES MOVE C,TIME MOVEM C,IMPERB MOVE C,IMPHTN(H) ;REAL HOST NUMBER MOVEM C,IMPERB+1 MOVE C,[441100,,IMPERB+2] MOVEI D,11. ;BYTES TO COPY ILDB T,B ;COPY BYTES FROM THEIR MSG IDPB T,C SOJG D,.-2 BUG INFO,[NET: ERR MSG FM HST ],OCT,IMPERB+1,[MSG],OCT,IMPERB+2,OCT,IMPERB+3 ;ONLY PRINTS FIRST 8 BYTES OF ERR INFO JUMPGE A,IMPBKL ;IF COUNT OK, GET MORE JRST IMSHRT ;SHORT COUNT IMPRSI: AOS IMPNRI JRST IMPBKL IMPRST: MOVE T,IMPHTN(H) ; CAIE T,+_9 ;IF RST FROM OURSELVES, JUST SEND RRP CAME T,[IMPUS3-NW%ARP] PUSHJ P,IMPRSR SKIPE IMPNRA JRST IMPRSI JSP T,IMSTCM 1,,1 ;TEXT: 1 BYTE, 1 WORD JRST IMPRSI MOVSI D,(13._28.) ;RRP MOVEM D,10(Q) PUSHJ P,IMWCQ ;SEND IT OUT PUSHJ P,IMPIOS AOS IMPNRA JRST IMPBKL IMPRSR: MOVSI I,-IMPSTL ;LOOK FOR USERS OF THIS HOST MOVSI TT,200000 IMPRS2: TDNN TT,IMSOC1(I) ;GUY GOING AWAY ANYHOW SKIPL IMSOC1(I) JRST IMPRS1 LDB C,IMSCFH ;FOREIGN HOST CAME C,IMPCSH JRST IMPRS1 ;WRONG HOST HRRZ C,IMSOC4(I) MOVEI D,%NSCLS CAIN C,%NSINP MOVEI D,%NSCLI ;INPUT STILL AVAILABLE HRRM D,IMSOC4(I) MOVEI D,%NCRST DPB D,IMSCLS ;CLS REASON IS RST PUSHJ P,IMPUIN ;INTERRUPT USER IMPRS1: AOBJN I,IMPRS2 ;IF HOST CAN SEND A RST, IT IS UP, BUT DON'T ;REALLY CONSIDER IT UP UNTIL RRP, RTS, OR STR IS RECEIVED ;I DON'T KNOW WHY IT'S DONE THIS WAY POPJ P, IMPRRP: LDB J,IMHSBT SOJL J,IMPRR1 JUMPG J,IMPBKL ;ALREADY UP, MAYBE BECAUSE OF PRIOR RTS,STR MOVEI J,2 DPB J,IMHSBT ;MARK HIM UP SOS IMRFCT JRST IMPBKL IMPRR1: BUG INFO,[NET: RRP W-O RST HST],OCT,IMPHTN(H) JRST IMPBKL ;GET CONTROL QUEUE SLOT IMGCQS: SKIPG IMFCQL ;SKIP IF ANY LEFT JRST IMGCQL ;NONE SKIPG Q,IMFFCQ ;POINTER TO SLOT JRST 4,. MOVE W,(Q) MOVEM W,IMFFCQ ;PATCH OUT OF FREE LIST SETOM (Q) SOS W,IMFCQL ;NUMBER FREE LEFT CAIN W,1 ;SKIP IF MORE THAN ONE LEFT SETOM IMPHI ;SET FLAG TO HOLD UP INPUT JRST POPJ1 IMGCQL: AOS IMNPIL POPJ P, IMWCQ: PUSHJ P,IMWPCQ JRST IMPIOS ;START OUTPUT ;ADD BLOCK IN Q TO OUTPUT CONTROL QUEUE, BASHES W IMWPCQ: SETOM (Q) SKIPGE W,IMPLCQ JRST IMWCQ1 ;CONTROL QUEUE EMPTY AOSE (W) JRST 4,. ;END OF QUEUE DIDN'T POINT TO -1 MOVEM Q,(W) MOVEM Q,IMPLCQ POPJ P, IMWCQ1: MOVEM Q,IMPLCQ MOVEM Q,IMPNCQ POPJ P, ;ADD MAIN PROGRAM BLOCK TO PI QUEUE (CALL AT MP LEVEL) IMPMPQ: MOVSI Q,777 IORM Q,IMPMPU+1 ;NOT LOCKED BY THIS JOB ANY MORE SKIPL U ;SKIP IF CALLED FROM DIRECT-CONNECT CLOCK LEVEL PUSHJ P,LSWDEL ;PI LEVEL WILL UNLOCK CONO PI,NETOFF MOVEI Q,IMPMPL PUSHJ P,IMWPCQ CONO PI,NETON JRST IMPOST ;CALL BY JSP T,IMSTCM ;SET UP STANDARD PI CONTROL MESSAGE ;BYTE COUNT,,TEXT LENGTH ;ERROR RETURN IMSTCM: PUSHJ P,IMGCQS ;GET CONTROL QUEUE SLOT IN Q JRST 1(T) ;NONE AVAILABLE MOVSI H,17_10. ;MESSAGE TYPE = 0, LINK # = 0, NEW FMT MOVEM H,2(Q) MOVE H,IMPCSH ;GET IMP AND HOST MOVE H,IMPHTN(H) IFN 1, DPB H,[103000,,3(Q)] ; Store host addr IFN 0,[ DPB H,[301000,,3(Q)] ;STORE HOST LSH H,-9 DPB H,[102000,,3(Q)] ;STORE IMP ] ;IFN 0 HLRZ H,(T) ;BYTE COUNT LSH H,8 IOR H,[8_24.] ;BYTE SIZE = 8 MOVEM H,7(Q) HRLZ H,(T) HRR H,IMPCSH MOVSM H,1(Q) ;HOST INDEX,,TEXT LENGTH JRST 2(T) ;NORMAL RETURN (NOTE THAT H HAS BEEN RESTORED TO IMPCSH) ;RECEIVED LEADER OF REGULAR MESSAGE NOT ON CONTROL LINK ;THE HOST-HOST LEADER WORD (WD 6) HAS NOT YET BEEN DATAI'ED. ;SWITCH TO 32-BIT MODE FIRST IF NECESSARY. IMPRMD: IFN INETP,[ CAIE B,IMPILB+4 ; Verify that NCP leader is next word JRST IMPLD3 ; Barf... ] MOVE D,IMPCSH LSH D,8 MOVE I,IMPCLN IOR D,I ;HEADER SUBI I,2 ;SOCKET TABLE INDEX JUMPL I,IMPRM7 ;BAD LINK # SKIPGE A,IMSOC1(I) TLNE A,200000 ;SKIP IF NOT BEING CLOSED JRST IMPRM7 ;SOCKET DOESNT EXIST OR BEING CLOSED MOVEI A,1 CAIGE I,IMPSTL TDNE A,IMSOC2(I) ;SKIP IF RECEIVER JRST IMPRM7 ;BAD LINK # OR MESSAGE FOR A SENDER LDB C,IMSCHD ;HEADER CAME D,C ;SEE IF HEADERS AGREE JRST IMPRM7 ;NOPE, I.E. FROM WRONG HOST OR CLOSED HRRZ D,IMSOC4(I) CAIE D,%NSOPN CAIN D,%NSINP JRST IMPRMA JRST IMPRM7 IMPRMA: SKIPGE IMSOC6(I) ;SKIP IF NOT LOCKED BY CORE JOB JRST IMPRMP ;LOCKED, COME BACK LATER IFN KAIMP,[ SKIPL IMSOC5(I) ;SKIP IF 32 BIT TRANSFER CONO IMP,IMI32C ;SET 36 BIT INPUT SKIPGE IMSOC5(I) ;SKIP IF NOT 32 BIT TRANSFER CONO IMP,IMI32S ;SET 32 BIT INPUT ]IFN DMIMP,[ SKIPL IMSOC5(I) ;SKIP IF 32BIT CONO FI,FII32C ;SET 36BIT SKIPGE IMSOC5(I) ;SKIP IF 36 BIT CONO FI,FII32S ;SET 32 BIT ] DATAI IMP,IMPILB+5 ;GET THE HEADER WORD LDB A,IMCBBP MOVEM A,IMPCBS LDB B,IMSCBS ;Check for fraudulent byte size CAME A,B JRST IMPRMZ ;Discard message LDB B,IMBCBP MOVEM B,IMPCBC MOVEM B,IMPNBI ;SAVE BYTE COUNT FOR LATER SOSGE IMSOC8(I) JRST IMRMAF ;MESSAGE ALLOCATION EXCEEDED JUMPE B,IMPIRT ;ZERO LENGTH MESSAGE IMUL A,B ;BIT COUNT MOVN D,A ADDB D,IMSOC7(I) ;REMAINING BIT ALLOCATION JUMPL D,IMRMAH ;BIT ALLOCATION EXCEEDED TRNE TT,IMPLW JRST IMRMAG ;MESSAGE IS SHORT MOVSI D,200000 IORB D,IMSOC6(I) ;ACTIVE AT PI LEVEL SKIPGE IMSOC5(I) IDIVI A,32. SKIPL IMSOC5(I) IDIVI A,36. SKIPE B ADDI A,1 ;NUMBER OF WORDS MESSAGE WILL TAKE HRRZ B,IMSPIP(I) ;ADDRESS WHERE MESSAGE HEADER WILL GO SKIPL (B) JRST 4,. ;HEADER WORD SHOULD BE -1 HRRZ C,IMSBFE(I) ;GET ADDRESS OF LAST WORD IN BUFFER CAML B,C MOVEI B,-1(D) ;HEADER IS LAST IN BUFFER, SO DATA IS FIRST MOVE E,B ;RH(BLKI POINTER) IN E ADD A,B ;ADDRESS WHERE LAST WORD OF MESSAGE WILL GET STORED SETZM IMNWSI ;ASSUME WILL ONLY NEED ONE BLKI CAMG A,C JRST IMPRM8 ;JUMP IF NO WRAP ;DROPS THROUGH ;DROPS IN SUB B,C ;- # WDS TO READ FIRST TIME SUB A,C ;+ # WDS TO READ SECOND TIME SKIPGE B SKIPG A JRST 4,. ;SCREW MOVN C,A ;NEG OF REMAINING WORD COUNT MOVSS C ;TO LEFT HALF FOR BLKI POINTER HRRI C,-1(D) ;RING AROUND TO BEGIN OF BUFFER MOVEM C,IMNWSI ;STORE FOR INTCHN BLKI RUNOUT (FLAG IF -) ADD C,A ;ADR+COUNT HRRZM C,IMPNIW ;EXPECTED END OF BLKI SKIPA A,B IMPRM8: SUBM B,A ;A GETS - # WORDS TO READ MOVE B,E HRL B,A ;BLKI POINTER SUB E,A ;EXPECTED LAST WORD SKIPE IMNWSI ;IF DOING 2 BLKIS, EXPECTED END ALREADY STORED SKIPA E,IMPNIW MOVEM E,IMPNIW ;EXPECTED LAST BLKI ADDRESS HRRZ A,IMSPIP(I) ;SEE IF CLOBBERING GOOD-DATA PART OF BUFFER CAIL A,@IMSMPP(I) ;SKIP IF MPP > PIP JRST [ CAIG E,(A) CAIGE E,@IMSMPP(I) JRST IMPRMT JRST 4,. ] CAIGE E,@IMSMPP(I) CAIG E,(A) JRST 4,. IMPRMT: HRRZ A,IMSOC6(I) ;SEE IF CLOBBERING CORE NOT PART OF BUFFER CAIL E,(A) CAILE E,@IMSBFE(I) JRST 4,. HRRZM I,IMPIPI ;THIS SOCKET NOW ACTIVE AT P.I. LEVEL MOVEI C,%ISIND ; New state = reading NCP data message JRST IMPRM9 ; Start reading IMPRMP: MOVSI D,100000 ;SET INPUT HELD UP BY CORE JOB IORM D,IMSOC6(I) IFN KAIMP,[ MOVE D,IMPPIA MOVEM D,IMPSVP SETZM IMPPIA ;TURN OFF NETWORK FOR A WHILE ] IFN DMIMP,CONO FI,FIIN+0 ;SET PIA TO 0 FOR A WHILE, CORE JOB WILL GET BACK JRST IMPRET IMRMAH: AOSA IMNBAE IMRMAF: AOS IMNMAE JRST IMPIRT IMPRM7: AOSA IMNMNC IMRMAG: AOS IMNMSS JRST IMPIRT ; Got Last Imp Word (in A) of regular NCP data message ; Comes here from IMPBKX. IMPRMB: MOVE I,IMPIPI MOVE B,IMBLKI CAMN B,IMPNIW JRST IMPRMC ;ONE EXTRA WORD OF IMP PADDING, IGNORE IT ADD B,[1,,1] ;ADDR TO NEXT WORD, COUNT TO ZERO CAME B,IMPNIW JRST IMPRMY MOVEM A,(B) ;STORE LAST WORD IMPRMC: MOVE E,IMPNBI ;# BYTES IN ADDM E,IMSMPC(I) ;MAKE AVAIL TO M.P. MOVEM E,@IMSPIP(I) ;STORE HEADER AOS E,IMPNIW ;WORD AFTER MSG WILL BE NEXT HEADER CAILE E,@IMSBFE(I) HRRZ E,IMSOC6(I) ;WRAP HRRM E,IMSPIP(I) ;LEAVE LH OF IMSPIP ALONE CAIN E,@IMSMPP(I) JRST 4,. ;BUFFER 1 WORD TOO SMALL? SETOM (E) MOVEI E,%NSINP HRRM E,IMSOC4(I) ;INPUT AVAILABLE PUSHJ P,IMPUIN ;INTERRUPT USER MOVSI D,200000 ;CLEAR ACTIVE AT P.I. LEVEL ANDCAM D,IMSOC6(I) SETOM IMPIPI JRST IMPIR1 IMPRMY: HRRZ E,IMPNIW ;NOT ENDING WHERE IT'S SUPPOSED TO SUBI E,(B) ;E GETS NUMBER OF MISSING WORDS MOVE H,IMPCSH BUG INFO,[NET: MSG FM HST ],OCT,IMPHTN(H),[SHORT ],DEC,E,[WDS, BC],DEC,IMPCBC JRST IMPRMC ;PRETEND HOST TRANSMITTING GARBAGE IMPRMZ: MOVE H,IMPCSH BUG INFO,[NET: HST ],OCT,IMPHTN(H),[SENT BYTE SIZE ],DEC,A,[SHOULD BE],DEC,B JRST IMPIRT ;Discard message SUBTTL ARPANET NCP OUTPUT INTERRUPT LEVEL ;HERE ON COMPLETION OF TRANSMISSION OF CONTROL MESSAGE IMPOB6: SETZM IMPOS SKIPN A,IMPSVQ JRST IMPRET ;THAT WAS A NOP HLRZ B,1(A) ;HOST TABLE INDEX MOVSI D,400000 IORM D,IMPHTB(B) ;SET RFNM WAIT BIT AOS IMRFCT LDB D,[051100,,TIME] DPB D,[221100,,IMPHTB(B)] ;STORE TIME TOO HLRZ T,A HRRZS A MOVE B,(A) MOVEM B,(T) JUMPGE B,IMOB7A CAME A,IMPLCQ JRST 4,. ;IMPLCQ GAVE WRONG LAST MESS NO. MOVEM T,IMPLCQ CAIN T,IMPNCQ SETOM IMPLCQ IMOB7A: CAIN A,IMPMPL ;SKIP IF NOT MAIN PROG BLOCK JRST [ SETOM IMPMPU JRST IMPRET ] MOVE B,IMFFCQ CAIN B,(A) JRST 4,. ;MAKING INFINITE LOOP MOVEM B,(A) MOVEM A,IMFFCQ AOS A,IMFCQL SKIPGE B,IMPHI ;RETURN IF INPUT NOT HELD UP CAIG A,1 ;SKIP IF INPUT HELD UP AND NOW ENOUGH FREE JRST IMPRET SETZM IMPHI AOJE B,IMPRET ;INPUT WAS NOT YET SUCCESSFULLY HELD UP AOJN B,[JRST 4,.] ;IMPHI SHOULD HAVE BEEN -2 AOS IMPNUH MOVE TT,IMSTAS ;GET OLD CONI TRNE TT,IMPLW IFN KAIMP,[ CONO IMP,IMI32C DATAI IMP,A ];KAIMP IFN DMIMP,[ CONO FI,FII32C MOVE A,IMPSUS ];DMIMP TRNE TT,IMPLW ;RESUME INPUT JRST IMPBKV SKIPE IMPIS JRST 4,. JRST IMSTRT ;HERE ON COMPLETION OF TRANSMISSION OF DATA MESSAGE IMPOBG: SETZM IMPOS MOVE I,IMPOPI HRRZ Q,IMSOC4(I) CAIN Q,%NSOPN AOS IMSOC4(I) .SEE %NSRFN ;PUT INTO RFNM WAIT STATE MOVSI A,20000 CAIN Q,%NSCLS IORM A,IMSOC5(I) MOVSI Q,200000 ANDCAB Q,IMSOC6(I) ;NO LONGER ACTIVE AT P.I. LEVEL SETOM IMPOPI MOVN A,IMPNBT ;BITS SENT ADDM A,IMSC7I(I) ;DECREASE BITS IN BUFFER ADDB A,IMSOC7(I) ;DECREASE ALLOCATION SKIPL A ;SKIP IF ALLOC LOST SOSGE IMSOC8(I) ;SKIP IF MSG ALLOC DIDN'T LOSE JRST 4,. ;LOST MOVE Q,IMSOC5(I) TLNN Q,140000 ;INTERRUPT USER IF DIRECT CONNECT (CHEAP), DEPEND ON ALLOC, SKIPN IMSMPC(I) ; OR IF OUTPUT BUFFER WAS FULL, PUSHJ P,IMPUIN ; SINCE HE MAY WANT TO SEND MORE MOVE A,IMPNBO ;# BYTES FREED IN BUFFER BY REMOVAL OF MSG ADDM A,IMSMPC(I) ;SPACE USED BY MESSAGE NOW FREE MOVE A,IMPNPT ;UPDATE IMSPIP HRRZ Q,IMSOC6(I) ;VALIDATE THIS CAILE Q,(A) JRST 4,. ;POINTS BEFORE BUFFER HRRZ Q,IMSBFE(I) CAIGE Q,(A) JRST 4,. ;POINTS AFTER BUFFER MOVEM A,IMSPIP(I) ;.. JRST IMPRET ;OUTPUT A DATA MESSAGE. IMPOBD: MOVE T,TIME SUB T,IMSOCT(I) SKIPL IMSOC4(I) ;SKIP IF WANT TO SEND THIS BUFFER CAIL T,30.*2 ;SKIP IF BUFFER FIRST WRITTEN LESS THAN 2 SEC AGO JRST IMOBD1 JRST IMPOBA ;DON'T SEND NOW, GO BACK AND LOOK FOR OTHERS IMOBD1: MOVE TT,IMSPIP(I) CAMN TT,IMSMPP(I) ;SKIP IF ANY BITS TO SEND JRST IMPOBA ;NO SKIPE IMSOC7(I) ;SKIP IF NO BITS ALLOCATED SKIPN IMSOC8(I) ;SKIP IF MSG ALLOCATED JRST IMPOBA ;NO BITS OR NO MSGS ALLOWED MOVSI Q,200000 IORB Q,IMSOC6(I) ;ACTIVE AT PI LEVEL ;CODE TO SEND OUT A BUFFER OR PARTIAL BUFFER ;ON ENTRY - I/ SOCKET TABLE INDEX ; Q/ BUFFER POINTER FROM IMSOC6 ; TT/ BYTE POINTER TO FIRST BYTE TO SEND ;SETS UP - T/ WORD SIZE (32 OR 36) ; E/ FLAGS FROM IMSOC5 ; B/ BYTE SIZE ; C/ # BITS TO SEND SETZM IMPNBO MOVE T,IMSMPP(I) MOVEM T,IMOB0Z ;SAVE FOR DEBUGGING MOVEI T,32. SKIPL E,IMSOC5(I) ;SKIP IF IN 32BIT MODE MOVEI T,36. ;SET 36BIT LDB B,IMSCBS ;BYTE SIZE HRRZ C,IMSMPP(I) ;COMPUTE # OF BYTES TO SEND SUBI C,(TT) JUMPL C,[MOVE D,IMSBFE(I) ;WRAPS AROUND SUB D,Q ADDI C,1(D) ;SO ADD # WDS IN BUFFER JRST .+1] IMUL C,T ;FIRST GUESS AT NUMBER OF BITS LDB A,[360600,,TT] ;GETS POSITION FIELD OF BYTE PTR LDB D,[360600,,IMSMPP(I)] SUBM A,D ;CORRECTION TO NUMBER OF BITS ADD C,D ;C NOW HAS NUMBER OF SENDABLE BITS IN BUFFER SKIPL E ;SKIP IF 32BIT JUMPN A,IMOB5A ;36BIT - JUMP IF NOT 0 (MIDDLE OF WORD) CAILE A,4 ;32BIT - SKIP IF 4, OR 36BIT 0 - SKIP IF NOT MID-WORD JRST IMOB5B ;32BIT MID-WORD - SEND PART OR REST OF WORD CAME TT,IMSBFE(I) ;AT RIGHT OF WORD, IS IT LAST WORD? AOSA TT ;NO, ADVANCE TO NEXT HRR TT,Q ;YES, WRAP AROUND TO FIRST TLO TT,440000 ;SWITCH FROM RIGHT OF WORD TO LEFT OF WORD CAMG C,IMSOC7(I) ;SKIP IF TOO BIG FOR ALLOCATE CAILE C,8000. ;FITS IN ALLOCATE, SKIP IF FITS IN IMP MESSAGE JRST IMOB1 ;MUST SEND LESS THAN ALL THE BITS IN BUFFER IMOB0F: MOVE D,IMSMPP(I) ;SENDING WHOLE BUFFER LDB J,[360600,,D] ;ADVANCE IMSMPP TO NEXT WORD BOUNDARY ADDI J,-36.(T) ;RH(J) := # BITS TO ADVANCE TO WORD BOUNDARY MOVNI J,(J) IDIV J,B ADDM J,IMSMPC(I) ;SUBTRACT FROM FREE THE BYTES SKIPPED OVER MOVNM J,IMPNBO ;BUT RETURN TO FREE AFTER TRANSMISSION HLL D,IMSBFE(I) ;NOW ADVANCE IMSMPP TO RIGHT END OF WORD MOVEM D,IMSMPP(I) ;AND IMSPIP WILL GET SET EQUAL TO IMSMPP IMOB0A: MOVEM D,IMPNPT ;ILDB -> FIRST BYTE TO SEND OUT NEXT TIME JUMPLE C,[JRST 4,.] ;SOMEBODY COMPUTED BAD # BITS MOVE A,C IDIV C,B ;C := # BYTES GETTING SENT JUMPN D,[JRST 4,.] ;LOSS, TRYING TO SEND PARTIAL BYTE ADDM C,IMPNBO ;# BYTES TO RETURN TO FREE AFTER MSG SENT MOVEM A,IMPNBT ;# BITS TO SUBTRACT FROM ALLOCATION THEN ;DROPS THROUGH ;DROPS IN ;NOW SET UP BUFFER HEADER FOR IMP MESSAGE IN IMOLDR ; TT -> FIRST WORD TO SEND ; A NUMBER OF BITS TO SEND ; C NUMBER OF BYTES ; B BYTE SIZE ; T WORD SIZE ; E FLAGS LDB H,IMSCFH ;HOST TABLE INDEX MOVEI Q,IMOLDR-2 ;HACK HACK PUSHJ P,STHSTP ;STORE HOST NUMBER, MESSAGE TYPE 0 LDB Q,IMSCLN ;LINK NUMBER DPB Q,[001000,,IMOLDR+1] LDB Q,[221000,,IMSOC6(I)] ;GET BUFFER TYPE MOVEI D,4 CAIN Q,377 MOVEI D,7 DPB D,[400400,,IMOLDR+1] ;STORE HANDLING TYPE, DEPENDING ON BUFFER SIZE DPB B,[201000,,C] ;STORE SIZE IN SAME WD AS COUNT LSH C,8 MOVEM C,IMOLDR+5 ;HOST-HOST HEADER - 00,SIZE,BYTE-COUNT,0000 IFN KAIMP,CONO IMP,IMO32C IFN DMIMP,CONO FI,FIO32C ;36BIT MODE FOR HEADER, AND NO PIA YET DATAO IMP,IMOLDR ;OUTPUT THE FIRST LEADER WORD SETZM IMOPNT ;START AT BEGINNING OF IMOLST MOVE B,[-5,,IMOLDR] ;SEND REST OF LEADER MOVEM B,IMOLST MOVEI B,3 SKIPGE E MOVEI B,2 MOVEM B,IMOMOD ;SEND DATA IN 32 OR 36 BIT MODE AS APPROPRIATE ADDI A,-1(T) ;ROUND UP IF NOT EXACT IDIV A,T ;# WDS TO SEND MOVEI D,-1(TT) ;FIRST WORD TO SEND MINUS ONE ADDI D,(A) ;LAST WORD TO SEND CAIG D,@IMSBFE(I) ;SKIP IF WRAP JRST IMOB7 HRRZ B,IMSBFE(I) ;COMPUTE # TO SEND FIRST TIME SUBI B,-1(TT) ;B GETS PLUS NUMBER TO SEND FIRST TIME SUBM B,A ;A GETS MINUS NUMBER TO SEND SECOND TIME MOVNI C,(B) HRLI C,-1(TT) ;C GETS SWAPPED BLKO POINTER FOR FIRST TIME MOVE Q,IMSOC6(I) ;POINTER TO BUFFER IFN KAIMP,[ MOVEI B,3 ;SEND LAST WORD SEPARATELY MOVEM B,IMOBK2 AOJE A,.+3 ] HRLI A,-1(Q) ;BLKO POINTER FOR SECOND TIME MOVSM A,IMOBK2 IFN KAIMP,[ MOVNI A,(A) ADDI A,-1(Q) HRROM A,IMOBK3 ;STORE BLKO POINTER TO LAST WORD ] JRST IMOB8 IMOB7: MOVSI C,3 ;NO WRAP, SO NO SECOND BLKO MOVSM C,IMOBK2 IFN KAIMP,[ SOS D HRROM D,IMOBK3 ;DO LAST WORD SEPARATELY SOJE A,IMOB8 ;SPECIAL CASE LAST WORD IS ONLY WORD ] MOVNI C,(A) ;MAKE BLKO POINTER HRLI C,-1(TT) IMOB8: MOVSM C,IMOBK1 MOVSI TT,400000 ;TURN OFF "SEND ME" ANDCAM TT,IMSOC4(I) HRRZM I,IMPOPI ;SAVE INDEX FOR BLKO RUNOUT AOS IMPMSS+0 MOVEI C,%ISOND ;STATE FOR "END OF DATA" JRST IMOB9 ;BUFFER CANNOT BE SENT AS 1 MSG. GRT ALLOC OR 8000 BITS. IMOB1: MOVE C,IMSOC7(I) ;ALLOC CAILE C,8000. MOVEI C,8000. ;C := MIN(BITS IN BUFFER, ALLOC, MAX IMP MSG SIZE) TLNE E,2000 ;SKIP IF BYTES EXACTLY FIT IN WORD JRST IMOB3 ;MUST SEND MULTI WORDS CAMGE C,T ;SKIP IF ALLOC GEQ WDSIZ JRST IMOB2 ;MUST SEND PART WORD IDIV C,T ;#WDS MOVE D,C IMUL C,T ;#BITS IN THOSE WDS IMOB1A: ADDI D,-1(TT) ;LAST WORD OUTPUT CAIG D,@IMSBFE(I) JRST .+3 SUBI D,@IMSBFE(I) ;WRAP AROUND ADDI D,-1(Q) HLL D,IMSBFE(I) ;PUT IN BYTE PART (RIGHT END OF WORD) JRST IMOB0A ;BUILD HEADER AND OUTPUT ;SEND PART OF WORD BECAUSE ALLOC IS TOO SMALL IMOB2: MOVE D,TT ;-> FIRST BYTE TO BE SENT MOVNI A,-36.(C) ;36-BITS SENT DPB A,[360600,,D] ;IS NEXT BYTE TO GO JRST IMOB0A ;SEND PARTIAL BUFFER OF BYTES WHICH DO NOT FIT EXACTLY IN WORDS (E.G. 7BIT BYTES) ;MUST SEND A "QUANTUM" WHICH FOR LAZINESS' SAKE IS 36 BYTES IMOB3: MOVEI A,36. ;#BITS IN A WORD IMUL A,B ;#BITS IN A QUANTUM IDIV C,A ;# QUANTA JUMPE C,IMOB4 ;NOT ENOUGH ALLOC FOR EVEN 1 QUANTUM, SORRY CHARLIE MOVE D,C IMUL C,A ;#BITS TO SEND IMUL D,B ;#WDS TO SEND (36 BYTES TAKE WDS) JRST IMOB1A ;NEED MORE ALLOCATE TO SEND A BUFFER FOR THIS ODD-SIZE CONNECTION IMOB4: MOVSI T,200000 ANDCAM T,IMSOC6(I) ;CLEAR "ACTIVE AT PI LEVEL" BIT JRST IMPOBA ;MAYBE TRY ANOTHER ONE ;SENDING REST OF PARTIAL WORD (PI PTR NOT AT WORD BOUNDARY) ;A/ BITS LEFT IN WORD IMOB5A: SKIPA C,A ;36BIT GETS WHOLE WD IMOB5B: HRREI C,-4(A) ;32BIT GETS 4 LESS MOVNI J,-36.(A) ;# BITS SHIFT TO LEFT JUSTIFY HRRZ D,TT CAIN D,@IMSMPP(I) ;IF WHOLE REST OF BUFFER IS IN THIS WORD JRST [ LDB D,[360600,,IMSMPP(I)] SUB A,D ;A := NUMBER OF BITS TO SEND MOVE C,(TT) ;ALIGN BITS TO BE SENT IN LEFT OF WORD LSH C,(J) MOVEM C,(TT) MOVE C,A JRST IMOB0F ] ;RE-ALIGN POINTERS TO WORD BOUNDARY CAMLE C,IMSOC7(I) ;SKIP IF WILL FIT IN ALLOC JRST IMOB6 ;MUST SEND BYTES NOT LEFT JUST IN WD, AND MORE TO RIGHT MOVE D,(TT) ;GET WORD LSH D,(J) ;LEFT JUSTIFY MOVEM D,(TT) MOVE D,TT HLL D,IMSBFE(I) ;ADVANCE PI POINTER TO END OF THIS WORD JRST IMOB0A ;BUILD HDR & SEND ;SEND MIDDLE PART OF WORD. BECAUSE OF SMALL ALLOCATES, THE LEFT END OF THE ; WORD WAS SENT AND ALSO THERE IS NOT ENOUGH ALLOCATE TO SEND THE REST ; OF THE ONE WORD. THIS MIGHT NEVER OCCUR EXCEPT FOR 8 BIT BYTES. ;MUST MOVE GOOD BITS TO LEFT END OF WORD, WITHOUT DISTURBING BITS TO THE RIGHT IMOB6: MOVE C,IMSOC7(I) ;CAN ONLY SEND ALLOC BITS SUB A,C ;POS OF LO BIT TO PICK UP DPB A,[360600,,TT] ;POS IN BYTE PTR MOVE D,TT ;SAVE ADVANCED PI PNTR DPB C,[300600,,TT] ;STORE AS SIZE OF BYTE LDB R,TT ;GET BYTE MOVNI A,-36.(C) ;POS OF LO BIT TO STORE DPB A,[360600,,TT] ;POS IN B PTR DPB R,TT ;STORE BYTE AWAY JRST IMOB0A ;SEND THE BYTE(S) OVHMTR UUO ;YET MORE RANDOM UUOS