PAGE 56,132 ; DATA SEGMENT PUBLIC 'DATA' ; ; ; 22/11/95 - Add second port alias for digipeating (for APRS) ; ; 13/9/99 - Check for corrupt calls ; ; 11/3/2001 - Fix corrupt calls check INCLUDE ENVIRON.ASM INCLUDE STRUCS.ASM EXTRN QCOUNT:BYTE,BUFFER:WORD,SDCBYTE:BYTE,SDRBYTE:BYTE EXTRN ADJBUFFER:WORD,MYCALL:BYTE,BBSCALL:BYTE,MYALIAS:BYTE,BBSALIAS:BYTE EXTRN NODECALL:BYTE,CURRENTPORT:BYTE,CURRENTPORTPTR:WORD EXTRN NORMCALL:BYTE,SAVEPORT:BYTE IFDEF PCSWITCH EXTRN HH:BYTE,MM:BYTE,SSECS:BYTE ENDIF EXTRN MAXLINKS:WORD,LINKS:WORD,L2KILLTIME:WORD,T3:WORD,BUFFLEN:ABS EXTRN FULL_CTEXT:BYTE,CTEXTMSG:WORD,CTEXTLEN:WORD EXTRN REALTIMETICKS:WORD IFDEF PCSWITCH ONEMINUTE EQU 60*3 TENSECS EQU 10*3 THREESECS EQU 3*3 ELSE ONEMINUTE EQU 60*10 ; 60 SECS IN TIMER TICKS TENSECS EQU 10*10 THREESECS EQU 3*10 ENDIF IFDEF KANT INCLUDE KANTEQU.ASM ENDIF CR EQU 0DH CONNECTEDMSG DB 'Connected to ' LCONNECTEDMSG EQU $-CONNECTEDMSG DISCONNMSG DB '*** DISCONNECTED',0DH LDISCONNMSG EQU $-DISCONNMSG FAILEDMSG DB 'Failure to connect to ' LFAILEDMSG EQU $-FAILEDMSG BUSYMSG DB 'Busy from ' LBUSYMSG EQU $-BUSYMSG TEMPFIELD DB 7 DUP (0) TEMPDIGI DB 57 DUP (0) ; 7*8 FOR 8 DIGIS, PLUS ONE ON END f COMPAREFIELD DB 14 DUP (0) ; FOR FINDING LINK TABLE ENTRIES COMPAREPORT DB 0 ; PORT FOR ABOVE MSGFLAG DB 0 ; CMD/RESPONSE BITS CMD EQU 100B ; CURRENT MESSAGE IS A COMMAND RESP EQU 10B ; CURRENT MSG IS RESPONSE VER1 EQU 1B ; CURRENT MSG IS VERSION 1 BBSMSG DB 0 ALIASMSG DB 0 CQ DB 'C'+'C','Q'+'Q',40h,40h,40h,40h,11100000B ; CQ IN AX25 FORM QSTCALL DB 'Q'+'Q','S'+'S','T'+'T',40h,40h,40h,11100000B; QST IN AX25 TEMP DB 0 ; WORK FIELD MHLEN DW TYPE MHSTRUC EXTRN BBS:BYTE,NODE:BYTE,APPLMASK:BYTE PUBLIC CQ,COMPAREFIELD,COMPAREPORT IFDEF MSC EXTRN HOURS:BYTE,MINS:BYTE,SECS:BYTE ENDIF DATA ENDS CODE SEGMENT PUBLIC 'CODE' ASSUME CS:CODE,DS:DATA,ES:DATA ; PUBLIC SDETX,L2TIMERPROC,L2ROUTINE,L2SETUPCROSSLINK,RESET2 PUBLIC COMPARECALLS,FINDLINK,SENDSABM,GETPORTWINDOW,GETPORTPACLEN PUBLIC PUT_ON_PORT_Q,FINDLINKXX,CLEAROUTLINK EXTRN Q_REM:NEAR,Q_ADDF:NEAR,GETBUFF:NEAR,PROCESSNODEMESSAGE:NEAR EXTRN Q_ADD:NEAR,GETPORTTABLEENTRY:NEAR,CONVFROMAX25:NEAR EXTRN RELBUFF:NEAR,COUNT_QUEUED_FRAMES:NEAR EXTRN SETUPNODEHEADER:NEAR,CONNECTFAILED:NEAR,SENDCONNECTREPLY:NEAR EXTRN INFORMPARTNER:NEAR,CONNECTREFUSED:NEAR,FINDNEIGHBOUR:NEAR EXTRN CLEARSESSIONENTRY:NEAR EXTRN CHECKIFBUSY:NEAR,Q_IP_MSG:NEAR EXTRN ATTACHTOBBS:NEAR,TRACEFRAME:NEAR EXTRN SETUPUSERSESSION:NEAR ; ; CALCULATE TX SLOT OFFSET ; SDGETS MACRO A LEA SI,FRAMES[BX] ; TO START OF SLOTS FOR THIS GROUP ; MOV AL,A MOV AH,0 ADD AX,AX ; *2 ADD SI,AX ENDM ; ; UPDATE A TX SLOT POINTER ; SDUPDS MACRO A INC A AND A,7 ; MOD 8 ENDM L2TIMERPROC: ; ; CHECK FOR TIMER EXPIRY OR BUSY CLEARED ; MOV CX,MAXLINKS MOV BX,LINKS HTIM00: CMP BYTE PTR [BX],0 JNE HTIM01 JMP HTIM400 ; SPARE ENTRY HTIM01: PUSH BX MOV AL,LINKPORT[BX] CALL GETPORTTABLEENTRY MOV BP,BX POP BX MOV AX,L2TIMER[BX] OR AX,AX JZ HTIM100 ; NOT RUNNING DEC AX MOV L2TIMER[BX],AX ; DECREMENT JNZ HTIM101 ; NOT EXPIRED CALL L2TIMEOUT ; TIMEOUT HAS OCCURED JMP SHORT HTIM101 HTIM100: ; ; TIMER NOT RUNNING - MAKE SURE STATE NOT BELOW 5 - IF ; IT IS, SOMETHING HAS GONE WRONG, AND LINK WILL HANG FOREVER ; CMP L2STATE[BX],2 JE HTIM101 ; CONNECT - PROBABLY TO CQ CMP L2STATE[BX],5 JAE HTIM101 ; OK MOV L2TIMER[BX],2 ; ARBITRARY VALUE HTIM101: ; ; TEST FOR RNR SENT, AND NOT STILL BUSY ; TEST L2FLAGS[BX],RNRSENT JZ NOTBSY ; RNR NOT SENT CALL RR_OR_RNR ; SEE IF STILL BUSY CMP AH,RNR JE NOTBSY ; STILL BUSY MOV L2ACKREQ[BX],1 ; SEND RR NOTBSY: CMP L2ACKREQ[BX],0 ; DELAYED ACK TIMER JE HTIM200 ; NOT RUNNING CMP L2RETRIES[BX],0 JNE HTIM200 ; DONT SEND RR RESPONSE WHILEST RR(P) OUTSTANDING DEC L2ACKREQ[BX] JNZ HTIM200 ; STILL OK ; MOV AL,0 ; NO F BIT CALL SEND_RR_RESP HTIM200: ; ; CHECK FOR REJ TIMEOUT ; CMP REJTIMER[BX],0 JE NOTREJTIMER DEC REJTIMER[BX] JNZ NOTREJTIMER ; ; REJ HAS TIMED OUT (THIS MUST BE A VERSION 1 SESSION) ; ; ; CANCEL REJ STATE ; CMP L2STATE[BX],6 ; REJ? JNE NOTREJTIMER MOV L2STATE[BX],5 ; CLEAR REJ NOTREJTIMER: CMP L2SLOTIM[BX],0 JZ HTIM300 DEC L2SLOTIM[BX] JNZ HTIM300 ; STILL OK JMP HTIM40 ; SEND RR/RNR(P) AS LINK VALIDATION HTIM300: INC KILLTIMER[BX] MOV AX,L2KILLTIME OR AX,AX JZ HTIM400 ; ZERO = RUN FOR EVER CMP KILLTIMER[BX],AX JB HTIM400 ; ; CIRCUIT HAS BEEN IDLE TOO LONG - SHUT IT DOWN ; MOV KILLTIMER[BX],0 MOV L2TIMER[BX],1 ; TO FORCE DISC MOV L2STATE[BX],4 ; DISCONNECTING PUSH BX PUSH CX CALL INFORMPARTNER ; TELL OTHER LEVELS POP CX POP BX MOV CIRCUITPOINTER[BX],0 HTIM400: ADD BX,TYPE LINKTABLE LOOP HTIM00_J RET HTIM00_J: JMP HTIM00 SEND_RR_RESP: PUSH BX PUSH CX ; ; SEND RR RESPONSE TO ACK OUTSTANDING FRAMES ; PUSH AX ; F BIT CALL RR_OR_RNR ; GET COMMAND MOV AL,LINKNR[BX] ; ELSE GET CURRENT N(R) ROR AL,1 ; SHIFT IT TO TOP 3 BITS ROR AL,1 ROR AL,1 OR AL,AH ; COMBINE WITH CONTROL BYTE POP CX ; F BIT OR AL,CL ; CALL SETUPL2MESSAGE JZ HTIM143 ; NO BUFFERS ; OR BYTE PTR MSGORIGIN+6[DI],80H ; SET RESPONSE CALL L2QUEUEFRAME HTIM143: MOV AX,T3 MOV L2SLOTIM[BX],AX ; SET FRAME SENT RECENTLY CALL ACKMSG ; SEE IF STILL WAITING FOR ACK POP CX POP BX RET L2TIMEOUT: ; ; TIMER EXPIRED ; ; IF LINK UP (STATE 5 OR ABOVE) SEND RR/RNR AS REQUIRED ; IF S2, REPEAT SABM ; IF S3, REPEAT FRMR ; IF S4, REPEAT DISC ; ; ADD DS:L2TIMEOUTS[BP],1 ; FOR STATS ADC DS:L2TIMEOUTS+2[BP],0 CMP L2STATE[BX],1 ; NO IDLE STATE JLE HTIMRET CMP L2STATE[BX],4 JA HTIM30 ; LINK UP JE HTIM05 ; SEND DISC AGAIN CMP L2STATE[BX],2 JE HTIM10 ; SEND SABM AGAIN ; ; FRMR ; INC L2RETRIES[BX] MOV AL,DS:PORTN2[BP] CMP L2RETRIES[BX],AL JL HTIM60 ; ; RETRIED N2 TIMES - RESET LINK ; MOV L2RETRIES[BX],0 MOV L2STATE[BX],2 JMP SENDSABM HTIM60: ; CALL SENDFRMR HTIMRET: RET HTIM05: ; ; DISCONNECTING ; INC L2RETRIES[BX] MOV AL,DS:PORTN2[BP] CMP L2RETRIES[BX],AL JL HTIM08 ; ; RETRIED N2 TIMES - JUST CLEAR OUT LINK ; PUSH BX PUSH CX CALL CLEAROUTLINK POP CX POP BX RET HTIM08: PUSH BX PUSH CX MOV AL,DISC OR PFBIT CALL L2SENDCOMMAND POP CX POP BX RET HTIM10: ; ; CONNECTING ; INC L2RETRIES[BX] MOV AL,DS:PORTN2[BP] CMP L2RETRIES[BX],AL JL HTIM12 ; ; RETRIED N2 TIMES - FAIL LINK ; PUSH BX PUSH CX CALL CONNECTFAILED ; TELL LEVEL 4 IT FAILED CALL CLEAROUTLINK POP CX POP BX RET HTIM12: SENDSABM: PUSH BX PUSH CX MOV AL,SABM OR PFBIT CALL L2SENDCOMMAND POP CX POP BX RET HTIM30: ; ; STATE 5 OR ABOVE ; ; SEND RR(P) UP TO N2 TIMES ; INC L2RETRIES[BX] MOV AL,DS:PORTN2[BP] CMP L2RETRIES[BX],AL JL HTIM40 ; ; RETRIED N2 TIMES - SEND A COUPLE OF DISCS AND THEN CLOSE ; PUSH BX PUSH CX CALL INFORMPARTNER ; TELL OTHER END ITS GONE SUB L2RETRIES[BX],2 MOV L2STATE[BX],4 ; CLOSING POP CX POP BX CALL HTIM08 RET ; HTIM40: CMP VER1FLAG[BX],1 JE HTIMVER1 ; VERSION 1 TIMEOUT ; ; SEND RR/RNR/REJ(P) ; PUSH BX PUSH CX ; ; SEND RR COMMAND - EITHER AS LINK VALIDATION POLL OR FOLLOWING TIMEOUT ; MOV L2ACKREQ[BX],0 ; CLEAR ACK NEEDED CALL RR_OR_RNR ; MOV L2STATE[BX],5 ; CANCEL REJ - ACTUALLY GOING TO 'PENDING ACK' MOV AL,LINKNR[BX] ; ELSE GET CURRENT N(R) ROR AL,1 ; SHIFT IT TO TOP 3 BITS ROR AL,1 ROR AL,1 OR AL,AH ; COMBINE WITH CONTROL BYTE OR AL,PFBIT OR L2FLAGS[BX],POLLSENT CALL L2SENDCOMMAND MOV AX,T3 MOV L2SLOTIM[BX],AX ; SET FRAME SENT RECENTLY POP CX POP BX RET HTIMVER1: ; ; RESET TO RESEND I FRAMES ; MOV AL,LINKOWS[BX] MOV LINKNS[BX],AL PUSH CX CALL SDETX ; PREVENT FRMR (I HOPE) POP CX RET SENDFRMR: ; RESEND FRMR ; PUSH BX PUSH CX MOV AL,L2TIME[BX] MOV AX,0 MOV L2TIMER[BX],AX ; SET TIMER CALL GETBUFF JZ HTIM66 ; NO BUFFER - JUST PRETEND, AND SET TIMER PUSH DI CALL SETUPADDRESSES ; SET UP ADDRESS STRING MOV AL,FRMR STOSB MOV AL,SDRBYTE ; MOVE REJECT C-BYTE STOSB MOV AL,LINKNR[BX] ; GET OUR N(R) ROR AL,1 ; SHIFT TO TOP 3 BITS ROR AL,1 ROR AL,1 MOV AH,AL ; SAVE IT MOV AL,LINKNS[BX] ; GET OUR N(S) SHL AL,1 ; SHIFT TO BITS 1-3 OR AL,AH ; COMBINE WITH N(S) STOSB MOV AL,SDREJF[BX] ; MOVE REJECT FLAGS TO IDP STOSB MOV CX,DI POP DI SUB CX,DI MOV MSGLENGTH[DI],CX ; SET LENGTH ; OR BYTE PTR MSGORIGIN+6[DI],80H ; SET RESPONSE CALL L2QUEUEFRAME HTIM66: POP CX POP BX RET CLEAROUTLINK: CALL CLEARL2QUEUES ; TO RELEASE ANY BUFFERS MOV DI,BX MOV CX,TYPE LINKTABLE XOR AL,AL REP STOSB ; CLEAR OUT ENTRY RET RESET3: RET L2ROUTINE: ; ; LEVEL 2 PROCESSING ; ; BX = PORT CONTROL TABLE ; DI = BUFFER ADDR ; CURRENTPORT = PORT NUMBER ; MOV AL,CURRENTPORT MOV COMPAREPORT,AL ; PORT FOR FIND LINK ROUTINES MOV SAVEPORT,AL ; FOR L3 ROUTINES ; MOV BP,BX ; PORT CONTROL ADD DS:L2FRAMES[BP],1 ADC DS:L2FRAMES+2[BP],0 MOV BBSMSG,0 MOV ALIASMSG,0 MOV MSGFLAG,0 ; CMD/RESP UNDEFINED ; ; Check for Corrupted Callsign in Origin ; (to keep MH list clean) ; MOV BUFFER,DI ; SAVE BUFFER 11/3/2001 MOV CX,6 CHKL2LOOP: CMP MSGORIGIN[DI],40H ; SPACE SHIFTED BY ONE JB L2DISCARD_J INC DI LOOP CHKL2LOOP SUB DI,6 CALL TRACEFRAME ; TRACE MOV DI,BUFFER CALL MHPROC MOV DI,BUFFER ; ; CHECK THAT ALL DIGIS HAVE BEEN ACTIONED, ; AND ADJUST FOR DIGIPEATERS IF PRESENT ; MOV CX,8 ; MAX DIGIS (NOT OUR LIMIT - AX25'S) L2DIGI00: TEST MSGORIGIN+6[DI],1 JZ L2DIGI02 ; MORE TO COME ; JMP L2DIGI10 ; END OF LIST L2DIGI02: ADD DI,7 ; TEST MSGORIGIN+6[DI],80H ; REPEATED BIT JZ L2DIGI05 ; NOT SET LOOP L2DIGI00 ; ; MESSAGE CORRUPT - DISCARD IT ; L2DISCARD_J: JMP L2DISCARD L2DIGI05: ; ; FRAME HAS NOT BEEN REPEATED THROUGH CURRENT DIGI - ; SEE IF WE ARE MEANT TO DIGI IT ; PUSH DI MOV SI,OFFSET MYCALL LEA DI,MSGORIGIN[DI] ; TO DIGI CALL CALL COMPARECALLS POP DI JE L2DIGIPEAT ; WE MUST REPEAT IT ; PUSH DI MOV SI,OFFSET MYALIAS LEA DI,MSGORIGIN[DI] ; TO DIGI CALL CALL COMPARECALLS POP DI JE L2DIGIPEAT ; WE MUST REPEAT IT PUSH DI LEA SI,PORTALIAS[BP] LEA DI,MSGORIGIN[DI] ; TO DIGI CALL CALL COMPARECALLS POP DI JE L2DIGIPEAT ; WE MUST REPEAT IT PUSH DI LEA SI,PORTALIAS2[BP] LEA DI,MSGORIGIN[DI] ; TO DIGI CALL CALL COMPARECALLS POP DI JE L2DIGIPEAT ; WE MUST REPEAT IT DISCARDIT: JMP L2DISCARD L2DIGIPEAT: ; ; WE MAY HAVE DISABLED DIGIPEAT ALTOGETHER, (DIGIFLAG=0), ; OR ALLOW ALLOW ONLY UI FRAMES TO BE DIGIED (DIGIFLAG=-1) ; CMP DS:DIGIFLAG[BP],0 JE DISCARDIT OR MSGORIGIN+6[DI],80H ; SET HAS BEEN REPEATED CMP DS:DIGIFLAG[BP],-1 JNE OKTODIGI ; ; SEE IF UI FRAME ; FINDCTRL: TEST MSGORIGIN+6[DI],1 ; LAST CALL BIT? JNZ CHKCTRL ; YES ADD DI,7 LOOP FINDCTRL JMP DISCARDIT ; DUFF CHKCTRL: MOV AL,MSGORIGIN+7[DI] ; CONTROL BYTE AND AL,0FFH-10H ; MASK OFF P/F BIT CMP AL,3 JNE DISCARDIT ; NOT UI FRAME OKTODIGI: ADD DS:L2DIGIED[BP],1 ADC DS:L2DIGIED+2[BP],0 MOV AL,DS:DIGIPORT[BP] ; CROSSBAND DIGI ENABLED? OR AL,AL JZ NOTMAPPED ; NO PORT MAPPING DEFINED MOV DI,BUFFER MOV 2[DI],AL ; CHANGE PORT CALL GETPORTTABLEENTRY MOV CURRENTPORTPTR,BX NOTMAPPED: JMP L2QUEUEONPORT ; SEND IT L2DIGI10: MOV ADJBUFFER,DI ; ; GET CMD/RESP BITS ; MOV DI,BUFFER MOV AH,MSGDEST+6[DI] MOV AL,MSGORIGIN+6[DI] ; GET COMMAND/RESPONSE BITS TEST AH,80H JNZ L2_CMD TEST AL,80H JNZ L2_RESP ; VALID COMBINATION L2_VER1: ; MUST BE VERSION 1 OR MSGFLAG,VER1 JMP SHORT CHECKFORUS L2_RESP: OR MSGFLAG,RESP JMP SHORT CHECKFORUS L2_CMD: TEST AL,80H JNZ L2_VER1 ; BOTH SET - ASSUME VER 1 OR MSGFLAG,CMD ; SET COMMAND CHECKFORUS: ; ; SEE IF FOR AN ACTIVE LINK SESSION ; MOV DI,ADJBUFFER ; BASE EXCLUDING DIGIS MOV AL,MSGCONTROL[DI] MOV SDCBYTE,AL ; SAVE ; ; IF A UI, THERE IS NO SESSION ; MOV DI,BUFFER CALL FINDLINK ; GET LINK FOR THIS ADDRESS PAIR (IN BX) JNZ NOSESSION JMP L2LINKACTIVE ; THERE IS AN ACTIVE SESSION NOSESSION: ; ; NOT FOR ACTIVE LINK - SEE IF ADDRESSED TO OUR NODE ADDR ; ; FIRST TRY PORT ADDR/ALIAS ; TEST DS:PORTBBSFLAG[BP],1 JNZ PORTCALLISBBS ; PORT CALL/ALIAS ARE FOR BBS CMP NODE,0 JNE USINGNODE ; PORTCALLISBBS: ; ; NODE IS NOT ACTIVE, SO PASS CALLS TO PORTCALL/ALIAS TO BBS ; MOV BBSMSG,1 USINGNODE: MOV DI,BUFFER LEA DI,MSGDEST[DI] ; DEST FROM MESSAGE LEA SI,PORTCALL[BP] CALL COMPARECALLS ; COMPARE WITH LINKCALL JE L2FORUS_JMP1 ; WE ARE TARGET ; MOV ALIASMSG,1 MOV DI,BUFFER LEA DI,MSGDEST[DI] ; DEST FROM MESSAGE LEA SI,PORTALIAS[BP] MOV CX,6 REP CMPSB ; ALLOW ANY SSID JE L2FORUS_JMP ; WE ARE TARGET ; CMP NODE,0 JE TRYBBS ; NOT USING NODE SYSTEM MOV BBSMSG,0 MOV ALIASMSG,0 MOV DI,BUFFER LEA DI,MSGDEST[DI] ; DEST FROM MESSAGE MOV SI,OFFSET MYCALL CALL COMPARECALLS ; COMPARE WITH LINKCALL L2FORUS_JMP1: JE L2FORUS_JMP ; WE ARE TARGET ; MOV ALIASMSG,1 MOV DI,BUFFER LEA DI,MSGDEST[DI] ; DEST FROM MESSAGE MOV SI,OFFSET MYALIAS MOV CX,6 REP CMPSB ; ALLOW ANY SSID JE L2FORUS_JMP ; WE ARE TARGET ; ; WE MAY NOT BE ALLOWED TO USE THE BBS CALL ON SOME BANDS DUE TO ; THE RATHER ODD UK LICENCING RULES! ; CMP DS:BBSBANNED[BP],1 JE SEEIFNODES TRYBBS: MOV BBSMSG,1 ; MSG TO BBS ADDR CMP BBS,0 JE SEEIFNODES ; NOT USING BBS CALLS MOV DI,BUFFER LEA DI,MSGDEST[DI] ; DEST FROM MESSAGE MOV SI,OFFSET BBSCALL CALL COMPARECALLS ; COMPARE WITH LINKCALL JE L2FORUS_JMP ; WE ARE TARGET ; MOV DI,BUFFER LEA DI,MSGDEST[DI] ; DEST FROM MESSAGE MOV SI,OFFSET BBSALIAS MOV CX,6 REP CMPSB ; ALLOW ANY SSID JNE SEEIFNODES L2FORUS_JMP: JMP L2FORUS ; WE ARE TARGET ; ; NOT FOR US - SEE IF 'NODES' OR IP/ARP BROADCAST MESSAGE ; SEEIFNODES: MOV DI,BUFFER PUSH DI ; SAVE MOV SI,OFFSET QSTCALL LEA DI,MSGDEST[DI] ; DEST CALL CALL COMPARECALLS POP DI JE L2IPMSG ; BROADCAST ; CMP MSGPID[DI],0CFH ; NETROM MSG? JNE L2NOTFORUS ; NO PUSH DI ; SAVE MOV SI,OFFSET NODECALL LEA DI,MSGDEST[DI] ; DEST CALL CALL COMPARECALLS POP DI JNE L2DISCARD ; NOT TO NODES ; CMP MSGDATA[DI],0FFH JNE L2DISCARD ; NOT CORRECT FORMAT? CALL PROCESSNODEMESSAGE JMP SHORT L2DISCARD L2IPMSG: MOV DI,BUFFER CALL Q_IP_MSG ; PASS WHOLE FRAME RET L2NOTFORUS: ; ; MAY JUST BE A REPLY TO A 'PRIMED' CQ CALL ; MOV AL,SDCBYTE AND AL,NOT 10H ; MASK P/F CMP AL,SABM JNE L2DISCARD ; NOT LINK SETUP ; ; LOOK FOR A CQ ENTRY IN OUR TABLES MATCHING TARGET CALL ; MOV DI,BUFFER LEA SI,MSGDEST[DI] MOV DI,OFFSET COMPAREFIELD MOV CX,7 REP MOVSB MOV SI,OFFSET CQ ; AX25 CQ MOV CX,7 REP MOVSB ; MOV DI,OFFSET COMPAREFIELD CALL FINDLINKXX ; GET LINK FOR THIS ADDRESS PAIR (IN BX) ; JNZ L2DISCARD ; ; MATCHING CIRCUIT FOUND - UPDATE CALLS, SET LINK ACTIVE, AND ; SEND CONNECTED MSG TO REMOTE STATION ; CALL SETUPNEWSESSION CMP L2STATE[BX],5 ; SESSION SETUP SUCCESSFUL? JE CQSETUPOK JMP L2SENDDM ; FAILED - ? TOO MANY DIGIS, ETC CQSETUPOK: MOV LINKTYPE[BX],2 ; DOWNLINK PUSH BX CALL L2SENDUA POP BX ; ; TELL PARTNER CONNECTION IS ESTABLISHED ; CALL GETBUFF ; WILL USE CQ MSG BUFFER EVENTUALLY JZ CQEXIT ; NO BUFFERS! MOV SI,OFFSET CONNECTEDMSG MOV CX,LCONNECTEDMSG CALL SENDCONNECTREPLY CQEXIT: RET L2DISCARD: MOV DI,BUFFER CALL RELBUFF RET L2FORUS: ; ; MESSAGE ADDRESSED TO OUR CALL OR ALIAS, BUT NOT FOR AN ACTIVE SESSION ; ADD DS:L2FRAMESFORUS[BP],1 ADC DS:L2FRAMESFORUS+2[BP],0 ; ; ONLY SABM IS ALLOWED IF NO SESSION ; MOV AL,SDCBYTE AND AL,NOT 10H ; MASK P/F CMP AL,3 JNE NOT_ADDR_UI ADDRUI: ; ; A UI ADDRESSED TO US - SHOULD ONLY BE FOR IP ; MOV DI,ADJBUFFER CMP MSGPID[DI],0CDH JE TCP ; ARP CMP MSGPID[DI],0CCH JE TCP ; TCP/IP CMP MSGPID[DI],08H ; NOS FRAGMENTED AX25 TCP/IP JNE L2DISCARD TCP: MOV DI,BUFFER JMP L2IPMSG NOT_ADDR_UI: ; CMP AL,SABM JNE NOTSABM IF BLACKBITS ; ; CHECK BLACKLIST ; EXTRN CHECKBLACKLIST:NEAR MOV DI,BUFFER LEA SI,MSGORIGIN[DI] ; ORIGIN FROM MESSAGE CALL CHECKBLACKLIST ; RETURN Z IF NODE IS IN LIST JZ IGNORESABM ; DONT ACCEPT ENDIF ; ; IF WE HAVE A PERMITTED CALLS LIST, SEE IF HE IS IN IT ; CMP DS:PERMITTEDCALLS[BP],0 JE CALLISOK ; NO LIMITS ; PUSH BP MOV BP,DS:PERMITTEDCALLS[BP] CHECKLOOP: MOV DI,BUFFER LEA DI,MSGORIGIN[DI] ; ORIGIN FROM MESSAGE MOV SI,BP CMP BYTE PTR [SI],0 JE ENDLIST MOV CX,6 ; IGNORE SSID REP CMPSB JE CALLISINLIST ADD BP,7 JMP CHECKLOOP ENDLIST: ; ; NOT IN LIST ; POP BP IGNORESABM: JMP L2DISCARD ; IGNORE IT ; CALLISINLIST: POP BP CALLISOK: ; ; IF CALL REQUEST IS FROM A LOCKED NODE WITH QUALITY ZERO, IGNORE IT ; MOV DI,BUFFER LEA SI,MSGORIGIN[DI] PUSH BX CALL FINDNEIGHBOUR ; IS IT A NODE? JNE NOTNODE CMP NEIGHBOUR_FLAG[BX],1 JNE NOTNODE ; NOT LOCKED CMP NEIGHBOUR_QUAL[BX],0 JNE NOTNODE ; NOT ZERO QUALITY POP BX DISCARDJMP: JMP L2DISCARD ; IGNORE IT NOTNODE: POP BX ; ; CHECK PORT CONNECT LIMITS ; CMP DS:USERS[BP],0 JE SABMOK ; NO LIMIT MOV AL,CURRENTPORT CALL COUNTLINKS CMP AH,DS:USERS[BP] JL L2SABM JMP L2SENDDM SABMOK: JMP L2SABM NOTSABM: MOV BBSMSG,0 ; ONLY DO BBS PROCESSING ON CONNECT MOV ALIASMSG,0 ; ; IF COMMAND WITH P SET, SEND DM ; TEST MSGFLAG,CMD JZ DISCARDJMP ; RESPONSE TEST SDCBYTE,PFBIT JZ DISCARDJMP ; P NOT SET JMP L2SENDDM ; SEND DM IF NOT FOUND L2LINKACTIVE: ; ; MESSAGE ON AN ACTIVE LINK (IN BX) ; ADD DS:L2FRAMESFORUS[BP],1 ADC DS:L2FRAMESFORUS+2[BP],0 MOV AL,SDCBYTE AND AL,NOT 10H ; MASK P/F CMP AL,3 JNE NOTACTUI ; ; UI ON ACTIVE LINK - MUST BE IP DATAGRAM ; JMP ADDRUI NOTACTUI: CMP AL,DISC JE L2_DISC ; DISCONNECT REQUEST ; CMP AL,SABM JE L2SABM_OLD ; LINK SETUP CALL L2_PROCESS RET L2_DISC: ; ; SEE IF CROSSLINK ACTIVE ; CALL INFORMPARTNER ; SEND DISC TO OTHER END ; ; CLEAR OUT TABLE ENTRY, AND RETURN RESPONSE (UA) VIA PORT TX QUEUE ; CALL CLEAROUTLINK CALL L2SENDUA RET L2SABM_OLD: ; ; SABM ON EXISTING SESSION - IF DISCONNECTING, REJECT ; CMP L2STATE[BX],4 ; DISCONNECTING? JNE OLDSABMOK ; JMP L2SENDDM ; FAILED OLDSABMOK: ; ; THIS IS A SABM ON AN EXISTING SESSION ; ; THERE ARE SEVERAL POSSIBILITIES: ; ; 1. RECONNECT COMMAND TO TNC ; 2. OTHER END THINKS LINK HAS DIED ; 3. RECOVERY FROM FRMR CONDITION ; 4. REPEAT OF ORIGINAL SABM COS OTHER END MISSED UA ; ; FOR 1-3 IT IS REASONABLE TO FULLY RESET THE CIRCUIT, BUT IN 4 ; SUCH ACTION WILL LOSE THE INITIAL SIGNON MSG IF CONNECTING TO A ; BBS. THE PROBLEM IS TELLING THE DIFFERENCE. I'M GOING TO SET A FLAG ; WHEN FIRST INFO RECEIVED - IF SABM REPEATED BEFORE THIS, I'LL ASSUME ; CONDITION 4, AND JUST RESEND THE UA ; CMP SESSACTIVE[BX],0 JNE L2SABM ; RESET OF ACTIVE CIRCUIT SENDUA_JMP1: ; JMP L2SENDUA L2SABM: ; ; SET UP NEW SESSION (OR RESET EXISTING ONE) ; CMP BX,0 JNE L2SABM000 ; OK JMP L2SENDDM ; NO LINK ENTRIES - SEND DM RESPONSE ; L2SABM000: CALL SETUPNEWSESSION CMP L2STATE[BX],5 ; SETUP OK? JE SABM021 JMP L2SENDDM ; FAILED SABM021: ; ; IF CONNECT TO BBS ADDRESS, SET UP BBS SESSION ; CMP BBSMSG,0 JNE SABM22 ; TRY TO ATTACH TO BBS ; ; IF CONNECT TO ALIAS, SEND CTEXT ; CMP FULL_CTEXT,1 JE SENDCT ; FOR ANY CONNECT CMP ALIASMSG,0 JE SENDUA_JMP1 SENDCT: CMP CTEXTLEN,0 JE SENDUA_JMP1 ; NOT DEFINED PUSH BX CALL L2SENDUA ; SEND ACK POP BX CALL GETBUFF JZ CTEXTRET ; NO BUFFERS MOV BUFFER,DI ADD DI,5 MOV AL,0F0H STOSB ; PID MOV SI,CTEXTMSG MOV CX,CTEXTLEN REP MOVSB MOV CX,DI MOV DI,BUFFER SUB CX,DI MOV MSGLENGTH[DI],CX LEA SI,TX_Q[BX] CALL Q_ADD ; SEND MESSAGE TO CALLER CTEXTRET: RET SABM22: ; CMP LINKTYPE[BX],1 JNE L2SENDUA_JMP ; RESET OF DOWN/CROSSLINK CMP CIRCUITPOINTER[BX],0 JNE L2SENDUA_JMP ; ALREADY SET UP - MUST BE REPEAT OF SABM OR LINK RESET ; ; IF RUNNING ONLY BBS (NODE=0), THIS MAY BE EITHER A USER OR NODE ; TRYING TO SET UP A L4 CIRCUIT - WE DONT WANT TO ATTACH A NODE TO ; THE BBS! ; CMP NODE,1 JE CALLTOBBS ; MUST BE L2 CALL TO BBS ; ; NOW THINGS GET DIFICULT - WE MUST EITHER WAIT TO SEE IF A PID CF MSG ; ARRIVES, OR ASSUME ALL NODES ARE IN NEIGHBOURS - I'LL TRY THE LATTER ; AND SEE HOW IT GOES. tHIS MEANS THAT YOU MUST DEFINE ALL ROUTES ; IN CONFIG FILE ; MOV DI,BUFFER LEA SI,LINKCALL[BX] PUSH BX CALL FINDNEIGHBOUR ; IS IT A NODE? POP BX JE L2SENDUA_JMP ; YES CALLTOBBS: PUSH BX CALL SETUPUSERSESSION ; CREATE INCOMING L4 SESSION POP BX JNZ BBSFAILED ; COULDNT ; ; NOW TRY A BBS CONNECT ; PUSH BX ; SAVE LINK MOV BX,CIRCUITPOINTER[BX] ; SESSION MOV AL,DS:PORTPACLEN[BP] ; PACLEN FOR THIS PORT MOV SESSPACLEN[BX],AL ; TO SESSION MOV APPLMASK,1 ; APPLICATION 1 IS BBS CALL ATTACHTOBBS ; AL = PACLEN POP BX JZ L2SENDUA_JMP ; SUCCESS ; ; NO BBS AVAILABLE ; PUSH BX MOV BX,CIRCUITPOINTER[BX] CALL CLEARSESSIONENTRY ; RELEASE SESSION POP BX BBSFAILED: CALL CLEAROUTLINK ; DELETE NEW SESSION L2SENDDM_JMP: JMP L2SENDDM ; SEND BUSY L2SENDUA_JMP: JMP L2SENDUA SETUPNEWSESSION: ; ; COPY ADDRESS INFO TO LINK TABLE ; MOV DI,BUFFER PUSH DI LEA SI,MSGORIGIN[DI] LEA DI,LINKCALL[BX] MOV CX,7 REP MOVSB AND BYTE PTR -1[DI],00011110B ; MASK SSID POP DI PUSH DI LEA SI,MSGDEST[DI] ; DEST FROM MESSAGE LEA DI,OURCALL[BX] ; OUR CALL/ALIAS BEING USED MOV CX,7 REP MOVSB ; AND BYTE PTR -1[DI],00011110B ; MASK SSID POP DI LEA SI,MSGCONTROL[DI] ; START OF DIGIS IF PRESENT LEA DI,DIGIS[BX] ; OUR CALL/ALIAS BEING USED PUSH DI MOV CX,MAXDIGIS*7 JCXZ NODIGIS XOR AL,AL REP STOSB ; CLEAR DIGI FIELD IN CASE RECONNECT NODIGIS: POP DI ; ; COPY DIGIS IF PRESENT ; MOV AL,DS:PORTT1[BP] MOV L2TIME[BX],AL ; SET L2 TIMOUT FOR NO DIGIS SABM010: TEST BYTE PTR -1[SI],1 JNZ SABM020 ; NONE ; ; THERE ARE DIGIS TO PROCESS - COPY TO WORK AREA, THEN COPY BACK ; MOV DI,OFFSET TEMPDIGI MOV CX,7*8 XOR AX,AX REP STOSB ; CLEAR (MAX 8 DIGIS, 7 BYTES EACH) SUB DI,7 ; TO LAST TEMP FIELD SABM012: MOV CX,7 REP MOVSB AND BYTE PTR -1[DI],01111110B ; MASK REPEATED AND LAST BITS TEST BYTE PTR -1[SI],1 JNZ SABM014 ; END OF LIST SUB DI,14 ; TO PREVIOUS JMP SABM012 SABM014: ; ; LIST OF DIGI CALLS COMPLETE - COPY TO LINK CONTROL ENTRY ; MOV SI,DI SUB SI,7 ; TO START OF LAST DIGI (BECOMES FIRST) LEA DI,DIGIS[BX] MOV AH,DS:PORTMAXDIGIS[BP] SABM016: CMP BYTE PTR [SI],0 JE SABM020 ; NO MORE CMP AH,0 JE SABM018 ; TOO MANY MOV CX,7 REP MOVSB DEC AH MOV AL,DS:PORTT1[BP] ADD L2TIME[BX],AL ; ADJUST TIMEOUT FOR DIGI'ED LINK ADD L2TIME[BX],AL ; ADJUST TIMEOUT FOR DIGI'ED LINK JMP SABM016 ; LOOP SABM018: CALL CLEAROUTLINK ; GET RID OF PART BUILT SESSION ENTRY RET SABM020: ; ; THIS MAY BE RESETTING A LINK - BEWARE OF CONVERTING A CROSSLINK TO ; AN UPLINK AND CONFUSING EVERYTHING ; MOV AL,CURRENTPORT ; FROM PORT TABLE MOV LINKPORT[BX],AL ; PUT IN CMP LINKTYPE[BX],0 JNE SABM020X MOV LINKTYPE[BX],1 ; UPLINK SABM020X: MOV L2TIMER[BX],0 ; CANCEL TIMER MOV AX,T3 MOV L2SLOTIM[BX],AX ; SET FRAME SENT RECENTLY MOV AL,DS:PORTWINDOW[BP] MOV LINKWINDOW[BX],AL CALL RESET2 ; RESET ALL FLAGS MOV L2STATE[BX],5 ; ; IF VERSION 1 MSG, SET FLAG ; TEST MSGFLAG,VER1 JZ SABM020A ; NOMAL (VERSION 2) MOV VER1FLAG[BX],1 SABM020A: RET L2SENDUA: MOV AL,UA JMP L2SENDRESP ; SEND UA L2SENDDM: MOV AL,DM L2SENDRESP: ; ; QUEUE RESPONSE TO PORT CONTROL - MAY NOT HAVE A LINK ENTRY ; MOV DI,ADJBUFFER ; ADDRESS ADJUSTED FOR DIGIS ; ; SET APPROPRIATE P/F BIT ; MOV AH,AL MOV AL,SDCBYTE ; LAST RECEIVED COMMAND AND AL,10H ; GET P/F BIT OR AH,AL ; MODIFIED RESPONSE IN AH MOV MSGCONTROL[DI],AH LEA CX,MSGCONTROL+1[DI] ; END OF MESSAGE MOV DI,BUFFER SUB CX,DI ; CALCULATE LENGTH MOV MSGLENGTH[DI],CX ; SET UP BYTE COUNT CALL L2SWAPADDRESSES ; SWAP ADDRESSES AND SET RESP BITS L2QUEUEONPORT: MOV DI,BUFFER MOV BX,CURRENTPORTPTR CALL PUT_ON_PORT_Q RET L2SWAPADDRESSES: ; ; EXCHANGE ORIGIN AND DEST, AND REVERSE DIGIS (IF PRESENT) ; MOV DI,BUFFER LEA SI,MSGORIGIN[DI] LEA DI,TEMPFIELD MOV CX,7 REP MOVSB ; SAVE ORIGIN MOV DI,BUFFER LEA SI,MSGDEST[DI] LEA DI,MSGORIGIN[DI] MOV CX,7 REP MOVSB ; AND BYTE PTR -1[DI],00011110B ; MASK SSID OR BYTE PTR -1[DI],11100000B ; SET RESPONSE AND RESERVED MOV DI,BUFFER LEA SI,TEMPFIELD LEA DI,MSGDEST[DI] MOV CX,7 REP MOVSB ; AND BYTE PTR -1[DI],00011110B ; MASK SSID - C BIT ZERO FOR RESPONSE OR BYTE PTR -1[DI],01100000B ; SET RESERVED ; ADD DI,7 ; TO FIRST DIGI IF PRESENT TEST BYTE PTR -1[SI],1 JNZ L2SWAPRET ; ; THERE ARE DIGIS TO PROCESS - COPY TO WORK AREA, THEN COPY BACK ; MOV SI,DI ; TO FIRST DIGI PUSH SI ; SAVE MOV DI,OFFSET TEMPDIGI MOV CX,7*8 XOR AX,AX REP STOSB ; CLEAR (MAX 8 DIGIS, 7 BYTES EACH) SUB DI,7 ; TO LAST TEMP FIELD L2SWAP000: MOV CX,7 REP MOVSB AND BYTE PTR -1[DI],01111110B ; MASK REPEATED AND LAST BITS TEST BYTE PTR -1[SI],1 JNZ L2SWAP010 ; END OF LIST SUB DI,14 ; TO PREVIOUS JMP L2SWAP000 L2SWAP010: MOV SI,DI SUB SI,7 ; TO START OF LAST DIGI (NOW FIRST) POP DI L2SWAP020: CMP BYTE PTR [SI],0 JE L2SWAPRET ; NO MORE MOV CX,7 REP MOVSB JMP L2SWAP020 ; LOOP L2SWAPRET: OR BYTE PTR -1[DI],1 ; SET END OF ADDRESS BIT RET L2_PROCESS: ; ; PROCESS LEVEL 2 PROTOCOL STUFF ; ; SEE IF COMMAND OR RESPONSE ; TEST MSGFLAG,CMD JNZ L2_COMMAND ; ; RESPONSE OR VERSION 1 ; L2_RESPONSE: ; ; IF RETRYING, MUST ONLY ACCEPT RESPONSES WITH F SET (UNLESS RUNNING V1) ; CMP VER1FLAG[BX],1 JE HDRX09 ; VERSION 1 TEST SDCBYTE,PFBIT JZ HDRX10 ; F NOT SET - DONT RESET TIMER ; ; F SET - CAN CANCEL TIMER ; HDRX09: MOV L2TIMER[BX],0 ; CANCEL LINK TIMER JMP SHORT HDRX10 L2_COMMAND: HDRX10: CMP L2STATE[BX],3 JNE NOTFRMRSTATE ; ; FRMR STATE - IF C(P) SEND FRMR, ELSE IGNORE ; MOV AL,SDCBYTE AND AL,NOT PFBIT CMP AL,FRMR JE BOTHFRMR ; DONT EXCHANGE FOR EVER! TEST MSGFLAG,CMD JZ FRMRDISCARD ; RESPONSE TEST SDCBYTE,PFBIT JZ FRMRDISCARD ; ; SEND FRMR AGAIN ; JMP SDFRMR FRMRDISCARD: JMP L2DISCARD BOTHFRMR: JMP SDUF80 ; SEND SABM NOTFRMRSTATE: CMP L2STATE[BX],5 ; LINK OK? JB SDNDM ; NO - PROCESS LINK SETUP ; ; LINK IN STATE 5 OR ABOVE - LINK RUNNING ; MOV AL,SDCBYTE ; GET CONTROL BYTE AND AL,0FFH-10H ; MASK OFF P/F BIT TEST AL,1 JNZ NOTIFRM JMP SDIFRM ; J IF AN I-FRAME NOTIFRM: TEST AL,2 JZ NOTUFRM JMP SDUFRM ; J IF UNNUMBERED FORMAT NOTUFRM: AND AL,0FH ; ELSE SUPERVISORY, MASK OFF N(R) AND P-BIT CMP AL,RR JNE NOTRR JMP SDSFRM ; J IF 'RECEIVE READY' NOTRR: CMP AL,RNR JNE NOTRNR JMP SDSFRM ; J IF 'RECEIVE NOT READY' NOTRNR: CMP AL,REJ JNE SDRX50 ; ADD DS:L2REJCOUNT[BP],1 ADC DS:L2REJCOUNT+2[BP],0 ; JMP SDSFRM ; ; UNRECOGNISABLE COMMAND ; SDRX50: MOV AL,SDCBYTE MOV SDRBYTE,AL ; SAVE FOR FRMR RESPONSE OR SDREJF[BX],SDINVC ; SET INVALID COMMAND REJECT CALL SDFRMR ; PROCESS FRAME REJECT CONDITION RET ; NORMAL DISCONNECT MODE ; ; COULD BE UA, DM - SABM AND DISC HANDLED ABOVE ; SDNDM: MOV AL,SDCBYTE ; GET FRAME CONTROL BYTE AND AL,0FFH-10H ; MASK P/F CMP AL,UA JE SDND40 CMP AL,DM JE SDND30 CMP AL,FRMR JNE NOTFRMR JMP SDUF80 NOTFRMR: JMP L2DISCARD ; ANY OTHER - IGNORE ; SDND30: ; ; DM RESPONSE - IF TO SABM, SEND BUSY MSG ; CMP L2STATE[BX],2 ; CONNECTING? JNE SDND35 ; NO - CLEAR OUT LINK PUSH BX CALL CONNECTREFUSED ; SEND MESSAGE IF DOWNLINK POP BX SDND35: ; ; DM OR UA RESP TO DISC RECEIVED - OTHER END HAS LOST SESSION ; ; ; CLEAR OUT TABLE ENTRY - IF INTERNAL TNC, SHOULD SEND *** DISCONNECTED ; CALL L2DISCARD CALL CLEAROUTLINK RET SDND40: ; ; UA RECEIVED ; CMP L2STATE[BX],2 ; RESPONSE TO SABM? JNE SDND42 ; NO ; ; RESPONSE TO SABM - SET LINK UP ; CALL RESET2X ; LEAVE QUEUED STUFF MOV L2STATE[BX],5 MOV L2TIMER[BX],0 ; CANCEL TIMER MOV L2RETRIES[BX],0 MOV AX,T3 MOV L2SLOTIM[BX],AX ; SET FRAME SENT RECENTLY ; ; IF VERSION 1 MSG, SET FLAG ; TEST MSGFLAG,VER1 JZ SDND41 ; NORMAL (VERSION 2) MOV VER1FLAG[BX],1 SDND41: ; TELL PARTNER CONNECTION IS ESTABLISHED MOV SI,OFFSET CONNECTEDMSG MOV CX,LCONNECTEDMSG PUSH BX MOV DI,BUFFER CALL SENDCONNECTREPLY POP BX RET SDND42: CMP L2STATE[BX],4 ; DISCONNECTING? JE SDND35 ; CLEAR OUT LINK ; ; UA, BUT NOT IN STATE 2 OR 4 - IGNORE ; JMP L2DISCARD SDSF20: JMP SDFRMR ; PROCESS FRAME REJECT CONDITION ; ; SUPERVISORY COMMAND ; ; ONLY VALID ONES ARE RR/RNR ; ; CHECK COUNTS, AND IF RNR INDICATE BUFFER SHORTAGE AT OTHER END ; SDSFRM: CMP SDREJF[BX],0 ; ARE ANY REJECT FLAGS SET? JNE SDSF20 ; J IF YES SDSF10: CALL SDNRCHK ; CHECK RECEIVED N(R) CMP SDREJF[BX],0 ; ARE ANY REJECT FLAGS SET? JNE SDSF20 ; J IF YES ; ; VALID RR/RNR RECEIVED ; AND L2FLAGS[BX],NOT RNRSET ; CLEAR RNR MOV AL,SDCBYTE ; GET CONTROL BYTE AND AL,0FH CMP AL,RNR ; IS COMMAND RNR? JNE SDSF15 ; NO OR L2FLAGS[BX],RNRSET ; SET OTHER END CANT RECEIVE SDSF15: TEST MSGFLAG,CMD JNZ SDSF17 ; ALWAYS REPLY TO RR COMMAND TEST SDCBYTE,PFBIT JNZ SDSF16 ; RESPONSE WITH F SET - RESET N(S) ; ; RESPONSE WITHOUT P/F DONT RESET N(S) (UNLESS V1) ; CMP VER1FLAG[BX],1 JE SDSF16 JMP L2DISCARD SDSF16: ; ; RESPONSE WITH P/F - MUST BE REPLY TO POLL FOLLOWING TIMEOUT OR I(P) ; AND L2FLAGS[BX],NOT POLLSENT; CLEAR I(P) SET ; ; THERE IS A PROBLEM WITH REPEATED RR(F), SAY CAUSED BY DELAY AT L1 ; ; AS FAR AS I CAN SEE, WE SHOULD ONLY RESET N(S) IF AN RR(F) FOLLOWS ; AN RR(P) AFTER A TIMEOUT - AN RR(F) FOLLOWING AN I(P) CANT POSSIBLY ; INDICATE A LOST FRAME. ON THE OTHER HAND, A REJ(F) MUST INDICATE ; A LOST FRAME. ; ; ; AL STILL CONTAINS THE COMMAND ; CMP AL,REJ JE SDSF16A ; RESET NS ; CMP L2RETRIES[BX],0 ; RETRYING? JE SDSF16B ; NO, SO PROBABLY REPLY TO REPEATED ; RR(P), DELAYED IN LINK LEVEL CODE SDSF16A: MOV AL,SDCBYTE ROL AL,1 ; SHIFT IT TO BOTTOM 3 BITS ROL AL,1 ROL AL,1 AND AL,7 CALL RESETNS ; RESET N(S) AND COUNT RETRIED FRAMES MOV L2RETRIES[BX],0 MOV L2TIMER[BX],0 ; WILL RESTART TIMER WHEN RETRY SENT SDSF16B: JMP L2DISCARD ; ; RR/RNR/REJ COMMAND - SEND RESPONSE ; SDSF17: ; ; FIRST PROCESS RESEQ QUEUE ; ; PUSH BUFFER ; CALL PROCESS_RESEQ ; POP BUFFER ; ; IGNORE IF AN 'F' HAS BEEN SENT RECENTLY ; IFDEF PCSWITCH MOV AX,REALTIMETICKS SUB AX,LAST_F_TIME[BX] CMP AX,27 ; 1.5 SECS JB SDSF16B ; DISCARD ELSE MOV AX,REALTIMETICKS ; 10 MS SUB AX,LAST_F_TIME[BX] CMP AX,150 ; 1.5 SECS JB SDSF16B ; DISCARD ENDIF CALL RR_OR_RNR MOV AL,LINKNR[BX] ; ELSE GET CURRENT N(R) ROR AL,1 ; SHIFT IT TO TOP 3 BITS ROR AL,1 ROR AL,1 OR AL,AH ; COMBINE WITH CONTROL BYTE SDCB10: MOV L2ACKREQ[BX],0 ; CANCEL DELAYED ACK MOV CX,T3 MOV L2SLOTIM[BX],CX ; SET FRAME SENT RECENTLY PUSH BX CALL L2SENDRESP POP BX ; ; SAVE TIME IF 'F' SENT' ; TEST SDCBYTE,10H JZ SDSF18 MOV AX,REALTIMETICKS ; 10 MS MOV LAST_F_TIME[BX],AX SDSF18: RET RESETNS: MOV AH,LINKNS[BX] MOV LINKNS[BX],AL ; RESET N(S) SUB AH,AL ; FRAMES TO RESEND AND AH,7 ; MODULO SEVEN CMP LINKTYPE[BX],3 JNE RESETNSRET PUSH BX MOV BX,NEIGHBOUR[BX] OR BX,BX JZ NONEIGHBOUR ; WOT!! MOV AL,AH CBW ADD WORD PTR NBOUR_RETRIES[BX],AX ADC WORD PTR NBOUR_RETRIES+2[BX],0 NONEIGHBOUR: POP BX RESETNSRET: RET ; PROCESS AN UNSEQUENCED COMMAND (IN LINK UP STATES) ; SDUFRM: CMP AL,UA JE SDUF75 ; DISCARD - PROBABLY REPEAT OF ; ACK OF SABM CMP AL,FRMR JE SDUF80 ; CMP AL,DM JE SDUF70 ; DM RESPONSE - SESSION MUST HAVE GONE ; ; UNDEFINED COMMAND ; JMP SDFRMR ; SEND FRAME REJECT SDUF70: ; ; SEE IF CROSSLINK ACTIVE ; CALL INFORMPARTNER ; SEND DISC TO OTHER END ; ; CLEAR OUT TABLE ENTRY ; CALL CLEAROUTLINK ; CLEAR OUT ENTRY SDUF75: JMP L2DISCARD SDUF80: ; ; FRAME REJECT RECEIVED - LOG IT AND RESET LINK ; CALL RESET2 ; RESET SESSION CALL L2DISCARD ; RELEASE MESSAGE MOV L2STATE[BX],2 ; INITIALISING MOV L2ACKREQ[BX],0 ; DONT SEND ANYTHING ELSE MOV L2RETRIES[BX],0 ; ALLOW FULL RETRY COUNT FOR SABM ADD DS:L2FRMRRX[BP],1 ADC DS:L2FRMRRX+2[BP],0 MOV AL,SABM OR PFBIT CALL L2SENDCOMMAND ; SEND COMMAND RET ; ;*** PROCESS AN INFORMATION FRAME ; SDIFRM: CMP SDREJF[BX],0 ; ARE ANY REJECT FLAGS SET? JNE SDIF40 ; J IF YES CALL SDNRCHK ; CHECK RECEIVED N(R) CMP SDREJF[BX],0 ; ARE ANY REJECT FLAGS SET? JNE SDIF40 ; J IF YES MOV SESSACTIVE[BX],1 ; SESSION IS DEFINITELY SET UP MOV AL,SDCBYTE ; GET FRAME CONTROL BYTE SHR AL,1 ; ISOLATE RECEIVED N(S) AND AL,7 CMP AL,LINKNR[BX] ; EQUAL TO OUR N(R)? JE SDIF05 ; OK ; ; BAD FRAME, SEND REJ (AFTER RESPTIME - OR WE MAY SEND LOTS!) ; ; ALSO SAVE THE FRAME - NEXT TIME WE MAY GET A DIFFERENT SUBSET ; AND SOON WE WILL HANDLE SREJ ; ADD DS:L2OUTOFSEQ[BP],1 ADC DS:L2OUTOFSEQ+2[BP],0 ; MOV L2STATE[BX],6 ; ; IF RUNNING VER1, AND OTHER END MISSES THIS REJ, LINK WILL FAIL ; SO TIME OUT REJ SENT STATE (MUST KEEP IT FOR A WHILE TO AVOID ; 'MULTIPLE REJ' PROBLEM) ; CMP VER1FLAG[BX],1 JNE VER2REJ ; VERSION 1 TIMEOUT ; MOV REJTIMER[BX],TENSECS VER2REJ: ; ; SET ACK REQUIRED TIMER - REJ WILL BE SENT WHEN IT EXPIRES ; MOV L2ACKREQ[BX],THREESECS ; EXTRA LONG RESPTIME, AS ; SENDING TOO MANY REJ'S IS SERIOUS ; ; SEE IF WE ALREADY HAVE A COPY OF THIS ONE - AL = N(S) FROM FRAME ; PUT_ON_RESEQ: ; MOV SI,L2RESEQ_Q[BX] ; ;CHECK_FRAME_LOOP: ; ; CMP SI,0 ; JE NOTONQUEUE ; ; CMP AL,BUFFLEN-2[SI] ; JE MSGONQUEUE ; ; MOV SI,[SI] ; FOLLOW CHAIN ; ; JMP CHECK_FRAME_LOOP ; ;NOTONQUEUE: ;!!! LEA SI,L2RESEQ_Q[BX] ;!!! MOV DI,BUFFER ;!!! MOV BUFFLEN-2[DI],AL ; PUT SEQNO ON END ;!!! CALL Q_ADD ; ADD TO CHAIN ; ;!!! JMP SHORT CHECKPF MSGONQUEUE: ; ; ALREADY HAVE A COPY - DISCARD IT ; CALL L2DISCARD JMP SHORT CHECKPF ; SDIF40: CALL SDFRMR ; PROCESS FRAME REJECT CONDITION RET SDIF05: ; ; IF THERE IS ALREADY SOMETHING ON THE RESEQ QUEUE, ADD THIS ONE AS ; WELL. WHEN 'P' IS RECEIVED, PROCESS WHOLE RESEQ QUEUE ; ; CMP L2RESEQ_Q[BX],0 ; JE OK_TO_PROC ; ; CALL PUT_ON_RESEQ ; ;CHECKPF: ; ; IF THIS FRAME HAD 'P' SET, PROCESS RESEQ Q (AS THERE WONT BE ANY ; MORE FRAMES COMING) ; ; TEST SDCBYTE,PFBIT ; JZ RESEQ_EXIT ; ;PROCESS_RESEQ: ; ; CALL CHECK_RESEQ ; SEE IF ANY SAVED STUFF TO PROCESS ; ; IF RESEQ Q IS NOW EMPTY, WE CAN CANCEL REJ STATE ; ; CMP L2RESEQ_Q[BX],0 ; JNE RESEQ_EXIT ; ; RESEQ Q IS EMPTY ; ; CMP L2STATE[BX],6 ; REJ? ; JNE SDIF02 ; ; MOV L2STATE[BX],5 ; CLEAR REJ ; ;SDIF02: ; ; JMP SDIF15 ; SEND REJ(F) ; ;RESEQ_EXIT: ; ; RET ; ;OK_TO_PROC: ; ; IN SEQUENCE FRAME - CANCEL REJ ; CMP L2STATE[BX],6 ; REJ? JNE SDIF02 ; MOV L2STATE[BX],5 ; CLEAR REJ AND L2FLAGS[BX],NOT REJSENT ; SDIF02: ; CALL PROC_I_FRAME ; ; IF P SET, SEND RR(F) ; CHECKPF: TEST L2FLAGS[BX],REJSENT JNZ CHECKX ; DONT SEND ANOTHER TILL REJ IS CANCELLED TEST SDCBYTE,PFBIT JNZ SDIF15 CHECKX: RET SDIF15: CMP L2STATE[BX],6 JNE NOTREJSTATE OR L2FLAGS[BX],REJSENT NOTREJSTATE: MOV L2ACKREQ[BX],0 ; CANCEL RR NEEDED MOV AL,PFBIT CALL SEND_RR_RESP ; ; RECORD TIME ; MOV AX,REALTIMETICKS MOV LAST_F_TIME[BX],AX RET SDIF20: JMP L2DISCARD ; I FIELD TOO BIG ?? SHOULD BE FRMR PROC_I_FRAME: INC LINKNR[BX] ; ELSE INCREMENT OUR N(R) AND LINKNR[BX],7 ; MODULO 8 ; ; ATTACH I FRAMES TO LINK TABLE RX QUEUE - ONLY DATA IS ADDED (NOT ADDRESSES) ; MOV DI,BUFFER ; ; IF DISC PENDING SET, IGNORE FRAME ; TEST L2FLAGS[BX],DISCPENDING JZ SDIF06 ; NO DISC PENDING CALL L2DISCARD RET SDIF06: MOV AX,MSGLENGTH[DI] SUB AX,20 ; STATION ADDRESSES AND CONTROL CALL ADJUSTFORDIGIS ; ADJUSTS DI AND AX FOR ANY DIGIS PRESENT CMP MSGPID[DI],0CCH JE IF_IP CMP MSGPID[DI],0CDH JE IF_IP CMP MSGPID[DI],08H ; NOS FRAGMENTED IP JNE NOT_IF_IP ; ; FRAGMENTED MESSAGE ; PUSH DI LEA SI,L2FRAG_Q[BX] MOV DI,BUFFER CALL Q_ADD POP DI CMP MSGPID+1[DI],0 JNE SDIF12 ; NOT LAST ; ; THERE IS A WHOLE MESSAGE ON FRAG_Q - PASS TO IP ; PUSH BX PUSH BP LEA SI,L2FRAG_Q[BX] FRAGLOOP: PUSH SI CALL Q_REM JZ NOMOREFRAGS CALL Q_IP_MSG POP SI JMP FRAGLOOP NOMOREFRAGS: POP SI POP BP POP BX JMP SDIF12 IF_IP: PUSH BX PUSH BP CALL L2IPMSG POP BP POP BX JMP SDIF12 NOT_IF_IP: LEA SI,MSGPID[DI] ; START OF 'REAL' DATA MOV DI,BUFFER LEA DI,5[DI] ; TO DATA IN INTERNAL MESSAGE MOV CX,AX JCXZ SDIF10 ; NO PID?? CMP CX,257 JA SDIF20 ; TOO BIG REP MOVSB SDIF10: ADD AX,5 ; HEADER LENGTH MOV DI,BUFFER MOV MSGLENGTH[DI],AX LEA SI,RX_Q[BX] MOV DI,BUFFER CALL Q_ADD SDIF12: MOV AL,DS:PORTT2[BP] MOV L2ACKREQ[BX],AL ; SET RR NEEDED MOV KILLTIMER[BX],0 ; RESET IDLE LINK TIMER RET ; ; L2 RESEQUENCE CODE. MAINLY FOR WHEN WE DO SREJ BUT WILL SAVE ; SOME RETRIES EVEN WITHOUT IT ; CHECK_RESEQ: ; ; SEE IF ANYTHING ON RESEQ QUEUE TO PROCESS ; LEA SI,L2RESEQ_Q[BX] MOV DI,[SI] MOV AL,LINKNR[BX] ; WHAT WE WANT FIND_FRAME_LOOP: CMP DI,0 JE NOTFOUND CMP AL,BUFFLEN-2[DI] JE FOUNDMESSAGE MOV SI,DI ; SAVE PREVIOUS IN CHAIN MOV DI,[DI] ; FOLLOW CHAIN JMP FIND_FRAME_LOOP NOTFOUND: RET FOUNDMESSAGE: ; ; REMOVE IT FROM QUEUE,AND PROCESS IT ; ; SI IS PREVIOUS IN QUEUE ; MOV AX,[DI] ; NEXT IN CHAIN MOV [SI],AX ; CHAIN TO PREVIOUS MOV BUFFER,DI ; SAVE ADDRESS ADD DS:L2RESEQ[BP],1 ADC DS:L2RESEQ+2[BP],0 CALL PROC_I_FRAME JMP CHECK_RESEQ ; SEE IF MORE ; ; *** B900 - SDLC RESET PROCESSING ; *** ; CLEAR FRAME REJECT FLAGS ; CLEAR ALL WINDOW POINTERS ; CLEAR N(R), N(S) ; CLEAR ALL BUFFERS ; ;*** RESET HDLC AND PURGE ALL QUEUES ETC. ; RESET2: CALL CLEARL2QUEUES RESET2X: XOR AL,AL MOV SDREJF[BX],AL ; CLEAR FRAME REJECT FLAGS MOV LINKWS[BX],AL ; CLEAR WINDOW POINTERS MOV LINKOWS[BX],AL MOV LINKNR[BX],AL ; CLEAR N(R) MOV LINKNS[BX],AL ; CLEAR N(S) MOV SDTSLOT[BX],AL MOV L2STATE[BX],5 ; RESET STATE MOV L2FLAGS[BX],0 RET CLEARL2QUEUES: ; ; GET RID OF ALL FRAMES THAT ARE QUEUED ; LEA SI,FRAMES[BX] MOV CX,8 SDSN10: PUSH SI PUSH CX CALL Q_REM JZ SDSN15 ; NONE THERE ; CALL RELBUFF SDSN15: POP CX POP SI INC SI INC SI LOOP SDSN10 ; CLEAR ALL 8 SLOTS ; ; GET RID OF ALL FRAMES THAT ARE ; QUEUED ON THE TX HOLDING QUEUE, RX QUEUE AND LEVEL 3 QUEUE ; SDSN20: LEA SI,TX_Q[BX] CALL SDSN50 LEA SI,RX_Q[BX] CALL SDSN50 LEA SI,L2RESEQ_Q[BX] CALL SDSN50 RET ; ; RELEASE BUFFERS CHAINED TO SI ; SDSN50: PUSH SI CLI CALL Q_REM STI JZ SDSN30 ; FINISHED CALL RELBUFF POP SI JMP SHORT SDSN50 SDSN30: POP SI RET ; *** B903 - RECEIVED N(R) CHECK ; *** ; CHECK RECEIVED N(R) ; IF WITHIN CURRENT WINDOW LIMITS ; THEN ; SET LOWER WINDOW LIMIT = RECEIVED N(R) ; SET 'ACKNOWLEDGE' FLAG ; ELSE ; SET 'INVALID N(R)' FLAG ; SAVE FRAME CONTROL BYTE FOR 'FRMR' RESPONSE ; ENDC ; RETURN ; ; ;*** CHECK RECEIVED N(R) COUNT ; SDNRCHK: MOV AL,SDCBYTE ; GET FRAME CONTROL BYTE ROL AL,1 ; ISOLATE N(R) IN L.S. BITS ROL AL,1 ROL AL,1 AND AL,7 CMP AL,LINKWS[BX] ; N(R) >= WINDOW START? JC SDNR30 ; J IF NO ; ; N(R) ABOVE OR EQUAL TO WINDOW START - OK IF NOT ABOVE N(S), OR N(S) BELOW WS ; CMP AL,LINKNS[BX] ; N(R) <= WINDOW END? JC SDNR20 ; J IF YES JE SDNR20 ; J IF YES SDNR10: ; ; N(R) ABOVE N(S) - DOES COUNT WRAP? ; MOV AH,AL ; KEEP TRACK OF RECEIVED N(R) MOV AL,LINKNS[BX] ; GET WINDOW END CMP AL,LINKWS[BX] ; WINDOW START > WINDOW END? JNC SDNR40 ; J IF NOT (ERROR) MOV AL,AH ; RESTORE RECEIVED N(R) ; ; RECEIVED N(R) IS VALID ; SDNR20: MOV LINKWS[BX],AL ; NEW WINDOW START = RECEIVED N(R) CALL ACKMSG RET ; SDNR30: ; ; N(R) LESS THAN WINDOW START - ONLY OK IF WINDOW WRAPS ; CMP AL,LINKNS[BX] ; N(R) <= WINDOW END? JC SDNR20 ; J IF YES JE SDNR20 ; J IF YES ; ; RECEIVED N(R) IS INVALID ; SDNR40: OR SDREJF[BX],SDNRER ; FLAG A REJECT CONDITION MOV AL,SDCBYTE MOV SDRBYTE,AL ; SAVE FOR FRMR RESPONSE RET ; FRAME REJECT CONDITION - SEND FRMR RESPONSE ; SDFRMR: ADD DS:L2FRMRTX[BP],1 ADC DS:L2FRMRTX+2[BP],0 MOV L2STATE[BX],3 ; ENTER FRMR STATE MOV AL,L2TIME[BX] MOV AH,0 MOV L2TIMER[BX],AX ; SET TIMER MOV DI,ADJBUFFER MOV MSGCONTROL[DI],FRMR ; CONTROL BYTE = FRMR MOV AL,SDRBYTE ; MOVE REJECT C-BYTE MOV MSGCONTROL+1[DI],AL MOV AL,LINKNR[BX] ; GET OUR N(R) ROR AL,1 ; SHIFT TO TOP 3 BITS ROR AL,1 ROR AL,1 MOV AH,AL ; SAVE IT MOV AL,LINKNS[BX] ; GET OUR N(S) SHL AL,1 ; SHIFT TO BITS 1-3 OR AL,AH ; COMBINE WITH N(S) MOV MSGCONTROL+2[DI],AL ; STORE MOV AL,SDREJF[BX] ; MOVE REJECT FLAGS TO IDP MOV MSGCONTROL+3[DI],AL LEA CX,MSGCONTROL+4[DI] ; END OF MESSAGE MOV DI,BUFFER SUB CX,DI ; CALCULATE LENGTH MOV MSGLENGTH[DI],CX ; SET UP BYTE COUNT CALL L2SWAPADDRESSES ; SWAP ADDRESSES AND SET RESP BITS CALL L2QUEUEONPORT ; SEND DIRECT TO PORT ; RET ; L2SENDCOMMAND: ; ; SEND COMMAND IN AL ; CALL SETUPL2MESSAGE JZ L2NOBUFFS ; NO BUFFERS - SET TIMER TO FORCE RETRY ; OR BYTE PTR MSGDEST+6[DI],80H ; SET COMMAND PUSH AX CALL L2QUEUEFRAME POP AX TEST AL,PFBIT ; RESPONSE EXPECTED? JZ L2SCRET ; NO MOV L2TIMER[BX],ONEMINUTE ; SET TIMER ; ; FLAG BUFFER TO CAUSE TIMER TO BE RESET AFTER SEND ; MOV BUFFLEN-2[DI],BX RET L2NOBUFFS: TEST AL,PFBIT ; RESPONSE EXPECTED? JZ L2SCRET ; NO MOV L2TIMER[BX],10*3 ; SET TIMER ; L2SCRET: RET SETUPL2MESSAGE: PUSH AX CALL GETBUFF POP AX JZ L2SETUPCMD99 ; NO BUFFER - JUST PRETEND, AND SET TIMER PUSH DI CALL SETUPADDRESSES ; SET UP ADDRESS STRING STOSB ; COMMAND BYTE MOV CX,DI POP DI SUB CX,DI MOV MSGLENGTH[DI],CX ; SET LENGTH ; L2SETUPCMD99: RET L2QUEUEFRAME: ; ; QUEUE IT FOR TRANSMISSION ; PUSH BX MOV AL,LINKPORT[BX] MOV MSGPORT[DI],AL CALL GETPORTTABLEENTRY ; POINT TO PORT CALL PUT_ON_PORT_Q POP BX RET SETUPADDRESSES: ; ; COPY ADDRESSES FROM LINK TABLE TO MESSAGE BUFFER ; LEA SI,LINKCALL[BX] LEA DI,MSGDEST[DI] ; MOV CX,14 REP MOVSB ; COPY DEST AND ORIGIN OR BYTE PTR -1[DI],60H ; SET FIXED BITS OR BYTE PTR -8[DI],60H ; MOV CX,MAXDIGIS JCXZ SETUPEND ; DIGIS NOT ALLOWED SETUPADDRESS00: CMP BYTE PTR [SI],0 ; END OF LIST JE SETUPEND PUSH CX MOV CX,7 REP MOVSB ; COPY CALLSIGN POP CX LOOP SETUPADDRESS00 ; COPY ANOTHER CALL SETUPEND: OR BYTE PTR -1[DI],1 ; SET END OF ADDRESSES ; ; RETURN DI POINTING TO COMMAND BYTE LOCATION ; RET ACKMSG: ; ; RELEASE ANY ACKNOWLEDGED FRAMES ; MOV AL,LINKOWS[BX] ; GET OLD WINDOW START CMP AL,LINKWS[BX] ; EQUAL TO NEW WINDOW START? JE SDET05 ; J IF YES ; SDGETS AL ; GET SLOT ADDR IN SI INC LINKOWS[BX] ; INCREMENT OLD WINDOW START AND LINKOWS[BX],7 ; MODULO 8 ; ; SOMETHING HAS BEEN ACKED - RESET RETRY COUNTER ; CMP L2RETRIES[BX],0 JE LEAVEIT MOV L2RETRIES[BX],1 ; MUSTN'T SET TO ZERO - COULD CAUSE ; PREMATURE RETRANSMIT LEAVEIT: CLI CALL Q_REM STI JZ ACKMSG ; NONE THERE!! ; CALL RELBUFF ; JMP SHORT ACKMSG SDET05: CMP AL,LINKNS[BX] ; IS N(S) = NEW WINDOW START? JE SDET10 ; JUMP IF IT IS ; ; NOT ALL I-FRAMES HAVE BEEN ACK'ED - RESTART TIMER ; MOV AL,L2TIME[BX] MOV AH,0 MOV L2TIMER[BX],AX RET SDET10: ; ; ALL FRAMES HAVE BEEN ACKED - CANCEL TIMER UNLESS RETRYING ; IF RETRYING, MUST ONLY CANCEL WHEN RR(F) RECEIVED ; CMP VER1FLAG[BX],1 JE SDET11 ; STOP TIMER IF LEVEL 1 CMP L2RETRIES[BX],0 JNE SDET12 ; RETRYING SDET11: MOV L2TIMER[BX],0 AND L2FLAGS[BX],NOT POLLSENT; CLEAR I(P) SET (IN CASE TALKING TO OLD BPQ!) SDET12: ; ; IF DISCONNECT REQUEST OUTSTANDING, AND NO FRAMES ON TX QUEUE, ; SEND DISC ; TEST L2FLAGS[BX],DISCPENDING JZ SDET13 ; NO DISC PENDING CMP TX_Q[BX],0 JNE SDET13 ; STILL MORE TO SEND AND L2FLAGS[BX],NOT DISCPENDING MOV L2TIMER[BX],1 ; USE TIMER TO SEND DISC MOV L2STATE[BX],4 ; DISCONNECTING SDET13: RET ; SDETX: ; ; SEE IF EXTERNAL L2 LINK ; PUSH BX CALL GETPORTTABLEENTRY MOV BP,BX ; PORT TO BP POP BX CMP DS:PORTTYPE[BP],EXTERNAL JNE NOTEXT CMP DS:PROTOCOL[BP],L2 JNE NOTEXT ; ; EXTERNAL DRIVER IS PROVIDING L2 FUNCTIONS: ; ; CALL IT TO SEE IF IT HAS BUFFER SPACE AVAILABLE, AND IF SO PASS MSG ; TO IT ; PUSHF MOV AH,4 ; STATUS CALL DS:PORT_EXT_ADDR[BP] LEA SI,TX_Q[BX] CALL Q_REM PUSHF MOV AH,8 ; L2 SEND ? CALL DS:PORT_EXT_ADDR[BP] RET NOTEXT: ; ; DONT SEND IF RESEQUENCING RECEIVED FRAMES - CAN CAUSE FRMR PROBLEMS ; CMP L2RESEQ_Q[BX],0 JNE SDET32A ; DONT SEND ; ; SEE IF AT WINDOW LIMIT ; ; CMP RECENT_REJ[BX],0 ; JNE SDET32A ; DONT SEND TILL WAIT TIMER EXPIRES MOV AL,LINKNS[BX] SUB AL,LINKOWS[BX] ; WINDOW START JNC SDET31 ; NO WRAP ADD AL,8 ; ALLOW FOR WRAP SDET31: CMP AL,LINKWINDOW[BX] ; LIMIT JC SDET33 ; OK SDET32A: RET ; CANT SEND ANY MORE YET SDET33: SDGETS SDTSLOT[BX] ; CALCULATE TX SLOT ADDR (IN SI) CMP WORD PTR [SI],0 ; IS NEXT SLOT EMPTY? JNE SDET20 ; J IF NOT (NO ROOM IN CCB) ; PUSH SI LEA SI,TX_Q[BX] CALL Q_REM POP SI JZ SDET20 ; J IF QUEUE EMPTY CALL Q_ADD ; PUT MESSAGE ADDR IN SLOT SDUPDS SDTSLOT[BX] ; UPDATE IT JMP SDETX ; SDET20: TEST L2FLAGS[BX],POLLSENT JNZ SDET50 ; P BIT OUTSTANDING - WAIT SDGETS LINKNS[BX] ; CALCULATE SLOT OFFSET CMP WORD PTR [SI],0 JZ SDET50 ; NOTHING TO SEND ; ; GET BUFFER FOR COPY OF MESSAGE - HAVE TO KEEP ORIGINAL FOR RETRIES ; MOV SI,[SI] ; GET BUFFER ADDR PUSH SI CALL GETBUFF POP SI JNZ SDETOK ; ; CANNOT SEND AN I-FRAME ; SDET50: RET SDETOK: PUSH DI ; SAVE BUFFER START ADDR PUSH SI ; SAVE MESSAGE ADDRESS CALL SETUPADDRESSES ; GET ADDRESSES FROM LINK TABLE ; ; DI NOW POINTS TO COMMAND BYTE ; ; GOING TO SEND I FRAME - WILL ACK ANY RECEIVED FRAMES ; MOV L2ACKREQ[BX],0 ; CLEAR ACK NEEDED MOV AX,T3 MOV L2SLOTIM[BX],AX ; SET FRAME SENT RECENTLY MOV KILLTIMER[BX],0 ; RESET IDLE CIRCUIT TIMER ; ; FLAG BUFFER TO CAUSE TIMER TO BE RESET AFTER SEND ; MOV AL,LINKNR[BX] ; GET CURRENT N(R) ROR AL,1 ; SHIFT IT TO TOP 3 BITS ROR AL,1 ROR AL,1 ROR AL,1 ; INSERT N(S) COUNT IN OR AL,LINKNS[BX] ; BITS 1-3 OF CONTROL BYTE ROL AL,1 INC LINKNS[BX] ; INCREMENT NS AND LINKNS[BX],7 ; ; SET P BIT IF END OF WINDOW OR NO MORE TO SEND ; CMP VER1FLAG[BX],1 JE SDET25 ; NO POLL BIT IF V1 MOV AH,LINKNS[BX] SUB AH,LINKOWS[BX] ; WINDOW START JNC SDET22 ; NO WRAP ADD AH,8 ; ALLOW FOR WRAP SDET22: CMP AH,LINKWINDOW[BX] ; LIMIT JNC SDET24 ; CANT SEND ANY MORE YET ; ; SEE IF MORE TO GO ; PUSH AX SDGETS LINKNS[BX] ; CALCULATE SLOT OFFSET POP AX CMP WORD PTR [SI],0 JNZ SDET25 ; MORE TO SEND ; SDET24: OR AL,PFBIT OR L2FLAGS[BX],POLLSENT SDET25: STOSB ; TO DATA (STARTING WITH PID) POP SI ; GET MESSAGE MOV CX,MSGLENGTH[SI] ; GET LENGTH ADD SI,5 ; SKIP CHAIN, PORT, LENGTH SUB CX,5 JC SDET32 JCXZ SDET32 ; SHOULD ALWAYS BE A PID, BUT BETTER SAFE THAN SORRY ; REP MOVSB ; COPY MESSAGE SDET32: MOV CX,DI POP DI OR BYTE PTR MSGDEST+6[DI],80H ; SET COMMAND SUB CX,DI MOV MSGLENGTH[DI],CX ; SET NEW LENGTH MOV L2TIMER[BX],ONEMINUTE ; (RE)SET TIMER ; ; FLAG BUFFER TO CAUSE TIMER TO BE RESET AFTER SEND ; MOV BUFFLEN-2[DI],BX MOV AL,LINKPORT[BX] MOV MSGPORT[DI],AL ; PUSH BX CALL GETPORTTABLEENTRY ; POINT TO PORT CALL PUT_ON_PORT_Q POP BX JMP SDETX ; SEE IF MORE ; ADJUSTFORDIGIS: ; ; ADJUST DI TO ALLOW FOR DIGIS IN MSG HEADER ; MOV CX,8 ; MAX DIGIS ADJDIGI00: TEST MSGORIGIN+6[DI],1 JNZ ADJDIGI10 ; END OF LIST ADD DI,7 SUB AX,7 ; LENGTH ; LOOP ADJDIGI00 ; MUST BE OK TO HAVE GOT THIS FAR ADJDIGI10: RET L2SETUPCROSSLINK: ; ; BX POINTS TO A NEIGHBOUR - FIND AN L2 SESSION FROM US TO IT, OR ; INITIATE A NEW ONE ; MOV AL,NEIGHBOUR_PORT[BX] MOV COMPAREPORT,AL ; SET PORT PUSH BX MOV DI,OFFSET COMPAREFIELD MOV SI,OFFSET MYCALL MOV CX,7 REP MOVSB LEA SI,NEIGHBOUR_CALL[BX] MOV CX,7 REP MOVSB ; MOV DI,OFFSET COMPAREFIELD CALL FINDLINKXX ; GET LINK FOR THIS ADDRESS PAIR (IN BX) ; JNZ L2SETUP10 ; NOT FOUND ; ; SESSION ALREADY EXISTS ; MOV LINKTYPE[BX],3 ; MAKE SURE IT KNOWS ITS A CROSSLINK MOV SI,BX POP BX MOV NEIGHBOUR_LINK[BX],SI MOV NEIGHBOUR[SI],BX RET L2SETUP10: ; ; SET UP NEW SESSION (OR RESET EXISTING ONE) ; CMP BX,0 JNE L2SETUP20 ; ; NO FREE ENTRIES ; POP BX RET L2SETUP20: ; ; COPY ADDRESS INFO TO LINK TABLE ; POP SI ; NEIGHBOUR TABLE MOV NEIGHBOUR_LINK[SI],BX MOV NEIGHBOUR[BX],SI MOV AL,NEIGHBOUR_PORT[SI] MOV LINKPORT[BX],AL ; SET PORT PUSH BX CALL GETPORTTABLEENTRY MOV BP,BX ; PORT TO BP POP BX ; ; IF ROUTE HAS A FRACK, SET IT ; MOV AL,NBOUR_FRACK[SI] OR AL,AL JNZ SETFRACK ; ; NO ROUTE VALUE, SO SET LINK VALUE ; MOV AL,DS:PORTT1[BP] SETFRACK: MOV L2TIME[BX],AL ; SET TIMER VALUE MOV TEMP,AL ; SAVE ; ; IF ROUTE HAS A WINDOW, SET IT ; MOV AL,NBOUR_MAXFRAME[SI] OR AL,AL JNZ SETMAXF ; ; NO ROUTE VALUE, SO SET LINK VALUE ; MOV AL,DS:PORTWINDOW[BP] SETMAXF: MOV LINKWINDOW[BX],AL MOV L2STATE[BX],2 PUSH SI LEA SI,NEIGHBOUR_CALL[SI] LEA DI,LINKCALL[BX] MOV CX,7 REP MOVSB PUSH SI MOV SI,OFFSET MYCALL LEA DI,OURCALL[BX] ; OUR CALL/ALIAS BEING USED MOV CX,7 REP MOVSB ; POP SI ; ; ADD ANY DIGI CALLS, AND ADJUST FRACK ; CMP BYTE PTR [SI],0 JE NODIGI MOV AL,TEMP ADD AL,AL ADD L2TIME[BX],AL MOV CX,7 REP MOVSB ; ADD DIGI CMP BYTE PTR [SI],0 JE NODIGI ADD L2TIME[BX],AL MOV CX,7 REP MOVSB ; ADD DIGIS NODIGI: MOV LINKTYPE[BX],3 ; CROSSLINK POP SI ; NEIGHBOUR CALL SENDSABM RET FINDLINK: LEA DI,MSGDEST[DI] FINDLINKXX: ; ; FIND LINK FOR AN ADDRESS PAIR (OUR CALL - FAR CALL) IN DI ; MOV BX,0 MOV SI,LINKS MOV CX,MAXLINKS FINDLK00: CMP BYTE PTR [SI],0 JNE FINDLK05 ; NOT A SPARE ENTRY CMP BX,0 JNE FINDLK10 ; ALREADY FOUND A SPARE MOV BX,SI ; POINTER TO FIRST FREE JMP SHORT FINDLK10 ; TRY NEXT ENTRY FINDLK05: MOV AL,LINKPORT[SI] CMP AL,COMPAREPORT JNE FINDLK10 ; WRONG PORT PUSH SI PUSH DI PUSH CX LEA DI,7[DI] ; ORIGIN FROM MESSAGE CALL COMPARECALLS ; COMPARE WITH LINKCALL POP CX POP DI POP SI JNE FINDLK10 PUSH SI PUSH DI PUSH CX ADD SI,7 ; OURCALL IN TABLE CALL COMPARECALLS ; COMPARE WITH DESTINATON IN MSG POP CX POP DI POP SI JE FINDLKRET ; YES FINDLK10: ADD SI,TYPE LINKTABLE LOOP FINDLK00 ; ; ENTRY NOT FOUND - BX HAS FIRST FREE ENTRY, OR ZERO IF TABLE FULL ; OR AL,1 ; SET NZ RET FINDLKRET: MOV BX,SI XOR AL,AL RET COMPARECALLS: ; ; COMPARE AX25 CALLSIGNS IN SI, DI IGNORING EXTRA BITS IN SSID ; MOV CX,6 REP CMPSB ; COMPARE JNE COMPCALLRET ; DONT MATCH LODSB MOV AH,[DI] AND AX,0001111000011110B ; MASK NON-SSID BITS CMP AL,AH COMPCALLRET: RET GETPORTWINDOW: PUSH BX MOV AL,LINKPORT[BX] CALL GETPORTTABLEENTRY MOV AL,PORTWINDOW[BX] POP BX RET GETPORTPACLEN: PUSH BX MOV AL,LINKPORT[BX] CALL GETPORTTABLEENTRY MOV AL,PORTPACLEN[BX] POP BX RET RR_OR_RNR: AND L2FLAGS[BX],NOT RNRSENT ; ; SET UP APPROPRIATE SUPER COMMAND ; CMP LINKTYPE[BX],3 JE CHKBUFFS ; NODE TO NODE - ONLY BUSY IF SHORT OF BUFFERS ; ; UP OR DOWN LINK - SEE IF SESSION IS BUSY ; CMP CIRCUITPOINTER[BX],0 JE CHKBUFFS ; NOT CONNECTED ; ; UPLINK WITH CIRCUIT ; PUSH BX ; SAVE LINK MOV BX,CIRCUITPOINTER[BX] ; TO CIRCUIT ENTRY CALL CHECKIFBUSY ; TARGET SESSION BUSY? POP BX TEST AL,L4BUSY JNZ SENDRNR ; BUSY CHKBUFFS: MOV AH,RR CMP QCOUNT,9 JBE SENDRNR ; NOT ENOUGH ; ; SEND REJ IF IN REJ STATE ; CMP L2STATE[BX],6 JNE HTIM142 ; OK MOV AH,REJ RET SENDRNR: MOV AH,RNR ; RUNNING SHORT OR L2FLAGS[BX],RNRSENT ; REMEMBER HTIM142: RET COUNTLINKS: ; ; COUNT LINKS ON PORT IN AL ; MOV SI,LINKS MOV CX,MAXLINKS MOV AH,0 COUNTL00: CMP BYTE PTR [SI],0 JE COUNTL10 ; SPARE ENTRY CMP AL,LINKPORT[SI] JNE COUNTL10 ; WRONG PORT INC AH COUNTL10: ADD SI,TYPE LINKTABLE LOOP COUNTL00 ; RET PUT_ON_PORT_Q: ; ; TIME STAMP IT ; IFDEF PCSWITCH MOV AX,WORD PTR MM MOV BUFFLEN-4[DI],AX ENDIF PUSH BX CMP TXPORT[BX],0 JE NORMALPORT ; ; NEED TO SEND TO DIFERENT PORT ; MOV AL,TXPORT[BX] MOV MSGPORT[DI],AL ; CHANGE HEADER (FOR KISS TX) CALL GETPORTTABLEENTRY NORMALPORT: LEA SI,PORTTX_Q[BX] CALL Q_ADD ; PUT ON QUEUE POP BX RET MHPROC: ; ; MAINTAIN MHEARD LIST ; CMP PORTMHEARD[BX],0 JE MHRET ; NOT ENABLED ; ; GET CONTROL BYTE ; PUSH DI MOV CX,8 ; MAX DIGIS CTRLLOOP: TEST BYTE PTR MSGCONTROL-1[DI],1 JNZ CTRLFOUND ADD DI,7 LOOP CTRLLOOP ; ; INVALID FRAME ; POP DI MHRET: RET CTRLFOUND: MOV AL,MSGCONTROL[DI] POP DI ; TEST AL,1 ; I FRAME JZ MHIFRAME AND AL,NOT PFBIT ; CLEAR P/F CMP AL,3 ; UI JNE MHRET ; ONLY USE I AND UI FRAMES ; MHIFRAME: ; ; LOOK FOR CALL IN LIST ; MOV SI,PORTMHEARD[BX] LEA DI,MSGORIGIN[DI] MOV CX,20 ; MAX ENTRIES MHF000: CMP BYTE PTR [SI],0 JE MHF120 ; EMPTY ENTRY FOUND - USE IT MHF005: PUSH CX PUSH DI PUSH SI CALL COMPARECALLS ; COMPARE WITH LIST POP SI POP DI POP CX JE MHF120 ; FOUND ADD SI,TYPE MHSTRUC LOOP MHF000 ; ; TABLE FULL AND ENTRY NOT FOUND - MOVE DOWN ONE, AND ADD TO TOP ; MOV CX,(19*TYPE MHSTRUC) JMP SHORT MHF130 MHF120: ; ; ENTRY FOUND - MOVE EARLIER ONES DOWN, AND PUT ON FRONT ; MOV AX,20 SUB AX,CX JZ MHF140 ; FIRST ENTRY MUL MHLEN MOV CX,AX MHF130: MOV SI,PORTMHEARD[BX] ADD SI,(TYPE MHSTRUC)-1 ADD SI,CX ; TO END + LEN-1 MOV DI,SI SUB SI,TYPE MHSTRUC ; TO END STD REP MOVSB CLD MHF140: MOV DI,PORTMHEARD[BX] MOV SI,BUFFER LEA SI,MSGORIGIN[SI] MOV DL,6[SI] ; SAVE LAST BYTE OF CALL (FOR DIGI CHK) MOV CX,7 REP MOVSB ; COPY CALL SUB DI,7 ; ; GET TIME FROM BIOS DATA AREA OR RTC ; IFDEF KANT MOV AL,1 OUT CLOCK_D,AL GETTIMELOOP: IN AL,CLOCK_D ; WAIT FOR NOT BUSY TEST AL,2 JZ OKTOREAD MOV AL,0 OUT CLOCK_D,AL MOV AL,1 OUT CLOCK_D,AL JMP GETTIMELOOP OKTOREAD: IN AL,CLOCK_HOUR+1 MOV CL,4 SHL AL,CL MOV CH,AL IN AL,CLOCK_HOUR AND AL,0FH ADD CH,AL ; HOURS TO CH MOV BYTE PTR MHTIME[DI],CH IN AL,CLOCK_MINUTE+1 MOV CL,4 SHL AL,CL MOV CH,AL MOV CH,AL IN AL,CLOCK_MINUTE AND AL,0FH ADD CH,AL ; MINS TO CH MOV BYTE PTR MHTIME+1[DI],CH IN AL,CLOCK_SECOND+1 MOV CL,4 SHL AL,CL MOV CH,AL IN AL,CLOCK_SECOND AND AL,0FH ADD CH,AL ; HOURS TO CH MOV BYTE PTR MHTIME+2[DI],CH MOV AL,0 OUT CLOCK_D,AL ENDIF IFDEF MSC MOV AL,HOURS MOV BYTE PTR MHTIME[DI],AL MOV AL,MINS MOV BYTE PTR MHTIME+1[DI],AL MOV AL,SECS MOV BYTE PTR MHTIME+2[DI],AL ENDIF IFDEF PCSWITCH MOV AL,HH MOV BYTE PTR MHTIME[DI],AL MOV AL,MM MOV BYTE PTR MHTIME+1[DI],AL MOV AL,SSECS MOV BYTE PTR MHTIME+2[DI],AL ENDIF MOV MHDIGI[DI],20H ; ASSUME NOT DIGI-ED TEST DL,1 JNZ MHRET1 ; LAST BIT SET, SO NO DIGIS ; ; THERE ARE DIGIS - IF DIGI-ED BIT IS SET ON FIRST, WE ARE NOT HEARING ; THIS PACKET DIRECT ; MOV SI,BUFFER TEST BYTE PTR MSGORIGIN+7+6[SI],80H JZ MHRET1 ; NOT DIGIED - MUST HAVE HEARD IT DIRECT MOV MHDIGI[DI],'*' MHRET1: RET CODE ENDS END