PAGE 56,132 ; Version 4.10f October 2008 ; ; Fix potential hangs if RNR lost .386 ; ; SEGMENT definitions and order ; ;* 32 Bit code _TEXT SEGMENT DWORD USE32 PUBLIC 'CODE' _TEXT ENDS ;* Contains 32 Bit data _BPQDATA SEGMENT DWORD PUBLIC 'DATA' _BPQDATA ENDS ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT OFFSET32 EQU _BPQDATA SEGMENT INCLUDE STRUCS.INC EXTRN QCOUNT:WORD,BUFFER:DWORD,SDCBYTE:BYTE,SDRBYTE:BYTE,PACLEN:WORD EXTRN ADJBUFFER:DWORD,_MYCALL:BYTE,MYALIAS:BYTE,_NETROMCALL:BYTE EXTRN NODECALL:BYTE,CURRENTPORT:BYTE,CURRENTPORTPTR:DWORD EXTRN NORMCALL:BYTE,SAVEPORT:BYTE EXTRN MAXLINKS:WORD,LINKS:DWORD,L2KILLTIME:WORD,T3:WORD EXTRN _FULL_CTEXT:BYTE,_CTEXTMSG:DWORD,_CTEXTLEN:WORD EXTRN APPLCALLTABLE:BYTE ONEMINUTE EQU 60*3 TENSECS EQU 10*3 THREESECS EQU 3*3 EXTRN REALTIMETICKS:WORD 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 ALIASMSG DB 0 NETROMMSG DB 0 ; Set if Message to NETROMCALL and L3ONLY Set NO_CTEXT DB 0 ; Set if call is in routes 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 CTPACLEN DD 0 ; PACLEN for CTEXT MHLEN DW TYPE MHSTRUC BADL2MSG DB 'BPQ32 Corrupt L2 Message Port=' BADL2PORT DB 'xx len=' BADL2COUNT DB 'xxxx',0 EXTRN BBS:BYTE,NODE:BYTE,APPLMASK:DWORD EXTRN ALIASPTR:DWORD,CMDALIAS:BYTE PUBLIC CQ,COMPAREFIELD,COMPAREPORT _BPQDATA ENDS _TEXT SEGMENT ; PUBLIC SDETX,L2TIMERPROC,L2ROUTINE,_L2SETUPCROSSLINK,RESET2 PUBLIC COMPARECALLS,FINDLINK,SENDSABM,GETPORTWINDOW,GETPORTPACLEN PUBLIC PUT_ON_PORT_Q,FINDLINKXX,CLEAROUTLINK EXTRN Q_REM: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 Q_IP_MSG:NEAR extrn _time:near extrn _DigiToMultiplePorts:near EXTRN ATTACHTOBBS:NEAR,TRACEFRAME:NEAR EXTRN SETUPUSERSESSION:NEAR ; ; CALCULATE TX SLOT OFFSET32 ; SDGETS MACRO A LEA ESI,FRAMES[EBX] ; TO START OF SLOTS FOR THIS GROUP ; MOVZX EAX,A ADD EAX,EAX ; *2 ADD EAX,EAX ; *4 ADD ESI,EAX ENDM ; ; UPDATE A TX SLOT POINTER ; SDUPDS MACRO A INC A AND A,7 ; MOD 8 ENDM PUBLIC L2TIMERPROC L2TIMERPROC: ; ; CHECK FOR TIMER EXPIRY OR BUSY CLEARED ; MOVZX ECX,MAXLINKS MOV EBX,LINKS PUBLIC HTIM00 HTIM00: CMP BYTE PTR [EBX],0 JNE SHORT HTIM01 JMP HTIM400 ; SPARE ENTRY PUBLIC HTIM01 HTIM01: PUSH EBX MOV AL,LINKPORT[EBX] CALL GETPORTTABLEENTRY MOV EBP,EBX POP EBX MOV AX,L2TIMER[EBX] OR AX,AX JZ SHORT HTIM100 ; NOT RUNNING DEC AX MOV L2TIMER[EBX],AX ; DECREMENT JNZ SHORT HTIM101 ; NOT EXPIRED CALL L2TIMEOUT ; TIMEOUT HAS OCCURED JMP SHORT HTIM101 PUBLIC HTIM100 HTIM100: ; ; TIMER NOT RUNNING - MAKE SURE STATE NOT BELOW 5 - IF ; IT IS, SOMETHING HAS GONE WRONG, AND LINK WILL HANG FOREVER ; CMP L2STATE[EBX],2 JE SHORT HTIM101 ; CONNECT - PROBABLY TO CQ CMP L2STATE[EBX],5 JAE SHORT HTIM101 ; OK MOV L2TIMER[EBX],2 ; ARBITRARY VALUE PUBLIC HTIM101 HTIM101: ; ; TEST FOR RNR SENT, AND NOT STILL BUSY ; TEST L2FLAGS[EBX],RNRSENT JZ SHORT NOTBSY ; RNR NOT SENT CALL RR_OR_RNR ; SEE IF STILL BUSY CMP AH,RNR JE SHORT NOTBSY ; STILL BUSY ; ; Just sending RR will hause a hang of RR is missed, and other end does not poll on Busy ; Try sending RR CP, so we will retry if not acked MOV L2ACKREQ[EBX],0 ; CLEAR ANY DELAYED ACK TIMER CMP L2RETRIES[EBX],0 JNE SHORT HTIM200 ; IF RR(P) OUTSTANDING WILl REPORT ANYWAY JMP HTIM40 ; Send RR(P) PUBLIC NOTBSY NOTBSY: CMP L2ACKREQ[EBX],0 ; DELAYED ACK TIMER JE SHORT HTIM200 ; NOT RUNNING CMP L2RETRIES[EBX],0 JNE SHORT HTIM200 ; DONT SEND RR RESPONSE WHILEST RR(P) OUTSTANDING DEC L2ACKREQ[EBX] JNZ SHORT HTIM200 ; STILL OK ; MOV AL,0 ; NO F BIT CALL SEND_RR_RESP PUBLIC HTIM200 HTIM200: ; ; CHECK FOR REJ TIMEOUT ; CMP REJTIMER[EBX],0 JE SHORT NOTREJTIMER DEC REJTIMER[EBX] JNZ SHORT NOTREJTIMER ; ; REJ HAS TIMED OUT (THIS MUST BE A VERSION 1 SESSION) ; ; ; CANCEL REJ STATE ; CMP L2STATE[EBX],6 ; REJ? JNE SHORT NOTREJTIMER MOV L2STATE[EBX],5 ; CLEAR REJ PUBLIC NOTREJTIMER NOTREJTIMER: CMP L2SLOTIM[EBX],0 JZ SHORT HTIM300 DEC L2SLOTIM[EBX] JNZ SHORT HTIM300 ; STILL OK JMP HTIM40 ; SEND RR/RNR(P) AS LINK VALIDATION PUBLIC HTIM300 HTIM300: INC KILLTIMER[EBX] MOV AX,L2KILLTIME OR AX,AX JZ SHORT HTIM400 ; ZERO = RUN FOR EVER CMP KILLTIMER[EBX],AX JB SHORT HTIM400 ; ; CIRCUIT HAS BEEN IDLE TOO LONG - SHUT IT DOWN ; MOV KILLTIMER[EBX],0 MOV L2TIMER[EBX],1 ; TO FORCE DISC MOV L2STATE[EBX],4 ; DISCONNECTING PUSH EBX PUSH ECX CALL INFORMPARTNER ; TELL OTHER LEVELS POP ECX POP EBX MOV CIRCUITPOINTER[EBX],0 PUBLIC HTIM400 HTIM400: ADD EBX,TYPE LINKTABLE LOOP HTIM00_J RET PUBLIC HTIM00_J HTIM00_J: JMP HTIM00 PUBLIC SEND_RR_RESP SEND_RR_RESP: PUSH EBX PUSH ECX ; ; SEND RR RESPONSE TO ACK OUTSTANDING FRAMES ; PUSH EAX ; F BIT CALL RR_OR_RNR ; GET COMMAND MOV AL,LINKNR[EBX] ; 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 ECX ; F BIT OR AL,CL ; CALL SETUPL2MESSAGE JZ SHORT HTIM143 ; NO BUFFERS ; OR BYTE PTR MSGORIGIN+6[EDI],80H ; SET RESPONSE CALL L2QUEUEFRAME PUBLIC HTIM143 HTIM143: MOV AX,T3 MOV L2SLOTIM[EBX],AX ; SET FRAME SENT RECENTLY CALL ACKMSG ; SEE IF STILL WAITING FOR ACK POP ECX POP EBX RET PUBLIC L2TIMEOUT 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 ; ; INC L2TIMEOUTS[EBP] ; FOR STATS CMP L2STATE[EBX],1 ; NO IDLE STATE JLE HTIMRET CMP L2STATE[EBX],4 JA HTIM30 ; LINK UP JE SHORT HTIM05 ; SEND DISC AGAIN CMP L2STATE[EBX],2 JE SHORT HTIM10 ; SEND SABM AGAIN ; ; FRMR ; INC L2RETRIES[EBX] MOV AL,PORTN2[EBP] CMP L2RETRIES[EBX],AL JL SHORT HTIM60 ; ; RETRIED N2 TIMES - RESET LINK ; MOV L2RETRIES[EBX],0 MOV L2STATE[EBX],2 JMP SENDSABM PUBLIC HTIM60 HTIM60: ; CALL SENDFRMR PUBLIC HTIMRET HTIMRET: RET PUBLIC HTIM05 HTIM05: ; ; DISCONNECTING ; INC L2RETRIES[EBX] MOV AL,PORTN2[EBP] CMP L2RETRIES[EBX],AL JL SHORT HTIM08 ; ; RETRIED N2 TIMES - JUST CLEAR OUT LINK ; PUSH EBX PUSH ECX CALL CLEAROUTLINK POP ECX POP EBX RET PUBLIC HTIM08 HTIM08: PUSH EBX PUSH ECX MOV AL,DISC OR PFBIT CALL L2SENDCOMMAND POP ECX POP EBX RET PUBLIC HTIM10 HTIM10: ; ; CONNECTING ; INC L2RETRIES[EBX] MOV AL,PORTN2[EBP] CMP L2RETRIES[EBX],AL JL SHORT HTIM12 ; ; RETRIED N2 TIMES - FAIL LINK ; PUSH EBX PUSH ECX CALL CONNECTFAILED ; TELL LEVEL 4 IT FAILED CALL CLEAROUTLINK POP ECX POP EBX RET PUBLIC HTIM12 HTIM12: PUBLIC SENDSABM SENDSABM: PUSH EBX PUSH ECX MOV AL,SABM OR PFBIT CALL L2SENDCOMMAND POP ECX POP EBX RET PUBLIC HTIM30 HTIM30: ; ; STATE 5 OR ABOVE ; ; SEND RR(P) UP TO N2 TIMES ; INC L2RETRIES[EBX] MOV AL,PORTN2[EBP] CMP L2RETRIES[EBX],AL JL SHORT HTIM40 ; ; RETRIED N2 TIMES - SEND A COUPLE OF DISCS AND THEN CLOSE ; PUSH EBX PUSH ECX CALL INFORMPARTNER ; TELL OTHER END ITS GONE SUB L2RETRIES[EBX],2 MOV L2STATE[EBX],4 ; CLOSING POP ECX POP EBX CALL HTIM08 RET ; PUBLIC HTIM40 HTIM40: CMP VER1FLAG[EBX],1 JE SHORT HTIMVER1 ; VERSION 1 TIMEOUT ; ; SEND RR/RNR/REJ(P) ; PUSH EBX PUSH ECX ; ; SEND RR COMMAND - EITHER AS LINK VALIDATION POLL OR FOLLOWING TIMEOUT ; MOV L2ACKREQ[EBX],0 ; CLEAR ACK NEEDED CALL RR_OR_RNR ; MOV L2STATE[EBX],5 ; CANCEL REJ - ACTUALLY GOING TO 'PENDING ACK' MOV AL,LINKNR[EBX] ; 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[EBX],POLLSENT CALL L2SENDCOMMAND MOV AX,T3 MOV L2SLOTIM[EBX],AX ; SET FRAME SENT RECENTLY POP ECX POP EBX RET PUBLIC HTIMVER1 HTIMVER1: ; ; RESET TO RESEND I FRAMES ; MOV AL,LINKOWS[EBX] MOV LINKNS[EBX],AL PUSH ECX CALL SDETX ; PREVENT FRMR (I HOPE) POP ECX RET PUBLIC SENDFRMR SENDFRMR: ; RESEND FRMR ; PUSH EBX PUSH ECX MOV AL,L2TIME[EBX] MOV AX,0 MOV L2TIMER[EBX],AX ; SET TIMER CALL GETBUFF JZ SHORT HTIM66 ; NO BUFFER - JUST PRETEND, AND SET TIMER PUSH EDI CALL SETUPADDRESSES ; SET UP ADDRESS STRING MOV AL,FRMR STOSB MOV AL,SDRBYTE ; MOVE REJECT C-BYTE STOSB MOV AL,LINKNR[EBX] ; 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[EBX] ; GET OUR N(S) SHL AL,1 ; SHIFT TO BITS 1-3 OR AL,AH ; COMBINE WITH N(S) STOSB MOV AL,SDREJF[EBX] ; MOVE REJECT FLAGS TO IDP STOSB MOV ECX,EDI POP EDI SUB ECX,EDI MOV MSGLENGTH[EDI],CX ; SET LENGTH ; OR BYTE PTR MSGORIGIN+6[EDI],80H ; SET RESPONSE CALL L2QUEUEFRAME PUBLIC HTIM66 HTIM66: POP ECX POP EBX RET PUBLIC CLEAROUTLINK CLEAROUTLINK: CALL CLEARL2QUEUES ; TO RELEASE ANY BUFFERS MOV EDI,EBX MOV ECX,TYPE LINKTABLE XOR AL,AL REP STOSB ; CLEAR OUT ENTRY RET PUBLIC RESET3 RESET3: RET extern _OutputDebugStringA@4:near, BYTE_TO_HEX:NEAR PUBLIC L2ROUTINE L2ROUTINE: ; ; LEVEL 2 PROCESSING ; ; BX = PORT CONTROL TABLE ; EDI = BUFFER ADDR ; CURRENTPORT = PORT NUMBER ; MOV BUFFER,EDI ; SAVE BUFFER ; Check for invalid length (< 22 7Header + 7Addr + 7Addr + CTL movzx EAX,MSGLENGTH[EDI] cmp eax,22 jae @f mov esi,edi mov edi,offset32 BADL2PORT MOV AL,MSGPORT[ESI] CALL BYTE_TO_HEX mov edi,offset32 BADL2COUNT MOV AL,BYTE PTR MSGLENGTH+1[ESI] CALL BYTE_TO_HEX MOV AL,BYTE PTR MSGLENGTH[ESI] CALL BYTE_TO_HEX push OFFSET32 BADL2MSG call _OutputDebugStringA@4 MOV EDI,BUFFER CALL RELBUFF RET @@: MOV AL,CURRENTPORT MOV COMPAREPORT,AL ; PORT FOR FIND LINK ROUTINES MOV SAVEPORT,AL ; FOR L3 ROUTINES ; MOV EBP,EBX ; PORT CONTROL ADD L2FRAMES[EBP],1 MOV ALIASMSG,0 MOV APPLMASK,0 MOV NETROMMSG,0 MOV MSGFLAG,0 ; CMD/RESP UNDEFINED ; ; Check for Corrupted Callsign in Origin ; (to keep MH list clean) ; MOV ECX,6 PUBLIC CHKL2LOOP CHKL2LOOP: CMP MSGORIGIN[EDI],40H ; SPACE SHIFTED BY ONE JB L2DISCARD INC EDI LOOP CHKL2LOOP SUB EDI,6 CALL TRACEFRAME ; TRACE MOV EDI,BUFFER CALL MHPROC MOV EDI,BUFFER ; ; CHECK THAT ALL DIGIS HAVE BEEN ACTIONED, ; AND ADJUST FOR DIGIPEATERS IF PRESENT ; MOV ECX,8 ; MAX DIGIS (NOT OUR LIMIT - AX25'S) PUBLIC L2DIGI00 L2DIGI00: TEST MSGORIGIN+6[EDI],1 JZ SHORT L2DIGI02 ; MORE TO COME ; JMP L2DIGI10 ; END OF LIST PUBLIC L2DIGI02 L2DIGI02: ADD EDI,7 ; TEST MSGORIGIN+6[EDI],80H ; REPEATED BIT JZ SHORT L2DIGI05 ; NOT SET LOOP L2DIGI00 ; ; MESSAGE CORRUPT - DISCARD IT ; JMP L2DISCARD PUBLIC L2DIGI05 L2DIGI05: ; ; FRAME HAS NOT BEEN REPEATED THROUGH CURRENT DIGI - ; SEE IF WE ARE MEANT TO DIGI IT ; PUSH EDI MOV ESI,OFFSET32 _MYCALL LEA EDI,MSGORIGIN[EDI] ; TO DIGI CALL CALL COMPARECALLS POP EDI JE SHORT L2DIGIPEAT ; WE MUST REPEAT IT ; PUSH EDI MOV ESI,OFFSET32 MYALIAS LEA EDI,MSGORIGIN[EDI] ; TO DIGI CALL CALL COMPARECALLS POP EDI JE SHORT L2DIGIPEAT ; WE MUST REPEAT IT PUSH EDI LEA ESI,PORTALIAS[EBP] LEA EDI,MSGORIGIN[EDI] ; TO DIGI CALL CALL COMPARECALLS POP EDI JE SHORT L2DIGIPEAT ; WE MUST REPEAT IT PUSH EDI LEA ESI,PORTALIAS2[EBP] LEA EDI,MSGORIGIN[EDI] ; TO DIGI CALL CALL COMPARECALLS POP EDI JE SHORT L2DIGIPEAT ; WE MUST REPEAT IT PUBLIC DISCARDIT DISCARDIT: JMP L2DISCARD PUBLIC L2DIGIPEAT L2DIGIPEAT: ; ; WE MAY HAVE DISABLED DIGIPEAT ALTOGETHER, (DIGIFLAG=0), ; OR ALLOW ALLOW ONLY UI FRAMES TO BE DIGIED (DIGIFLAG=-1) ; CMP DIGIFLAG[EBP],0 JE SHORT DISCARDIT OR MSGORIGIN+6[EDI],80H ; SET HAS BEEN REPEATED ; ; SEE IF UI FRAME ; PUBLIC FINDCTRL FINDCTRL: TEST MSGORIGIN+6[EDI],1 ; LAST CALL BIT? JNZ SHORT CHKCTRL ; YES ADD EDI,7 LOOP FINDCTRL JMP DISCARDIT ; DUFF PUBLIC CHKCTRL CHKCTRL: MOV AL,MSGORIGIN+7[EDI] ; CONTROL BYTE AND AL,0FFH-10H ; MASK OFF P/F BIT CMP AL,3 JNE NOT_UI_DIGI ; UI FRAME. IF DIGIMASK IS NON-ZERO, SEND TO ALL PORTS SET, OTHERWISE SEND TO DIGIPORT CMP DIGIMASK[EBP],0 JE OKTODIGI PUSH BUFFER push EBP CALL _DigiToMultiplePorts ADD ESP,8 JMP SHORT DISCARDIT PUBLIC NOT_UI_DIGI NOT_UI_DIGI: ; ; ONLY DIGI IF DIGIFLAG IS NOT -1 (UI ONLY) CMP DIGIFLAG[EBP],-1 JE SHORT DISCARDIT ; NOT UI FRAME PUBLIC OKTODIGI OKTODIGI: INC L2DIGIED[EBP] MOV AL,DIGIPORT[EBP] ; CROSSBAND DIGI ENABLED? OR AL,AL JZ SHORT NOTMAPPED ; NO PORT MAPPING DEFINED MOV EDI,BUFFER MOV MSGPORT[EDI],AL ; CHANGE PORT CALL GETPORTTABLEENTRY MOV CURRENTPORTPTR,EBX PUBLIC NOTMAPPED NOTMAPPED: JMP L2QUEUEONPORT ; SEND IT PUBLIC L2DIGI10 L2DIGI10: MOV ADJBUFFER,EDI ; ; GET CMD/RESP BITS ; MOV EDI,BUFFER MOV AH,MSGDEST+6[EDI] MOV AL,MSGORIGIN+6[EDI] ; GET COMMAND/RESPONSE BITS TEST AH,80H JNZ SHORT L2_CMD TEST AL,80H JNZ SHORT L2_RESP ; VALID COMBINATION PUBLIC L2_VER1 L2_VER1: ; MUST BE VERSION 1 OR MSGFLAG,VER1 JMP SHORT CHECKFORUS PUBLIC L2_RESP L2_RESP: OR MSGFLAG,RESP JMP SHORT CHECKFORUS PUBLIC L2_CMD L2_CMD: TEST AL,80H JNZ SHORT L2_VER1 ; BOTH SET - ASSUME VER 1 OR MSGFLAG,CMD ; SET COMMAND PUBLIC CHECKFORUS CHECKFORUS: ; ; SEE IF FOR AN ACTIVE LINK SESSION ; MOV EDI,ADJBUFFER ; BASE EXCLUDING DIGIS MOV AL,MSGCONTROL[EDI] MOV SDCBYTE,AL ; SAVE ; ; IF A UI, THERE IS NO SESSION ; MOV EDI,BUFFER CALL FINDLINK ; GET LINK FOR THIS ADDRESS PAIR (IN BX) JNZ SHORT NOSESSION JMP L2LINKACTIVE ; THERE IS AN ACTIVE SESSION PUBLIC NOSESSION NOSESSION: ; ; NOT FOR ACTIVE LINK - SEE IF ADDRESSED TO OUR NODE ADDR ; MOV AL,PORTL3FLAG[EBP] MOV NETROMMSG,AL ; Set if L3 only and call to NETROMCALL MOV EDI,BUFFER LEA EDI,MSGDEST[EDI] ; DEST FROM MESSAGE MOV ESI,OFFSET32 _NETROMCALL CALL COMPARECALLS ; COMPARE WITH LINKCALL JE L2FORUS ; NETROM Message to us ; CMP PORTL3FLAG[EBP],1 ; L3 Only Port? JE L2NOTFORUS ; If L3ONLY, only accept calls to NETROMCALL MOV NETROMMSG,0 ; FIRST TRY PORT ADDR/ALIAS ; TEST PORTBBSFLAG[EBP],1 JNZ SHORT PORTCALLISBBS ; PORT CALL/ALIAS ARE FOR BBS CMP NODE,0 JNE SHORT USINGNODE ; PORTCALLISBBS: ; ; NODE IS NOT ACTIVE, SO PASS CALLS TO PORTCALL/ALIAS TO BBS ; MOV APPLMASK,1 PUBLIC USINGNODE USINGNODE: MOV EDI,BUFFER LEA EDI,MSGDEST[EDI] ; DEST FROM MESSAGE LEA ESI,PORTCALL[EBP] CALL COMPARECALLS ; COMPARE WITH LINKCALL JE L2FORUS ; WE ARE TARGET ; MOV ALIASMSG,1 MOV EDI,BUFFER LEA EDI,MSGDEST[EDI] ; DEST FROM MESSAGE LEA ESI,PORTALIAS[EBP] MOV ECX,6 REP CMPSB ; ALLOW ANY SSID JE L2FORUS ; WE ARE TARGET ; CMP NODE,0 JE SHORT TRYBBS ; NOT USING NODE SYSTEM MOV ALIASMSG,0 MOV EDI,BUFFER LEA EDI,MSGDEST[EDI] ; DEST FROM MESSAGE MOV ESI,OFFSET32 _MYCALL CALL COMPARECALLS ; COMPARE WITH LINKCALL JE L2FORUS ; WE ARE TARGET MOV ALIASMSG,1 MOV EDI,BUFFER LEA EDI,MSGDEST[EDI] ; DEST FROM MESSAGE MOV ESI,OFFSET32 MYALIAS MOV ECX,6 REP CMPSB ; ALLOW ANY SSID JE L2FORUS ; 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 BBSBANNED[EBP],1 JE NOWTRYNODES PUBLIC TRYBBS TRYBBS: CMP BBS,0 JE SHORT NOWTRYNODES ; NOT USING BBS CALLS ; TRY APPLICATION CALLSIGNS/ALIASES MOV ALIASMSG,0 MOV APPLMASK,1 MOV ALIASPTR,OFFSET CMDALIAS MOV ECX,MAXAPPLS MOV EDX,OFFSET APPLCALLTABLE PUBLIC APPLCALLLOOP APPLCALLLOOP: LEA ESI,APPLCALL[EDX] CMP BYTE PTR [ESI],40H JE NEXTAPPL PUSH EDX PUSH ECX MOV EDI,BUFFER LEA EDI,MSGDEST[EDI] ; DEST FROM MESSAGE CALL COMPARECALLS ; COMPARE WITH LINKCALL POP ECX POP EDX JE L2FORUS ; WE ARE TARGET LEA ESI,APPLALIAS[EDX] CMP BYTE PTR [ESI],40H JE NEXTAPPL MOV EDI,BUFFER LEA EDI,MSGDEST[EDI] ; DEST FROM MESSAGE PUSH ECX MOV ECX,6 REP CMPSB ; ALLOW ANY SSID POP ECX JE L2FORUS ; WE ARE TARGET PUBLIC NEXTAPPL NEXTAPPL: ADD EDX,TYPE APPLCALLS SAL APPLMASK,1 ADD ALIASPTR,ALIASLEN LOOP APPLCALLLOOP JMP SHORT NOWTRYNODES PUBLIC NOWTRYNODES NOWTRYNODES: ; NOT FOR US - SEE IF 'NODES' OR IP/ARP BROADCAST MESSAGE MOV EDI,BUFFER PUSH EDI ; SAVE MOV ESI,OFFSET32 QSTCALL LEA EDI,MSGDEST[EDI] ; DEST CALL CALL COMPARECALLS POP EDI JE SHORT L2IPMSG ; BROADCAST ; CMP MSGPID[EDI],0CFH ; NETROM MSG? JNE SHORT L2NOTFORUS ; NO PUSH EDI ; SAVE MOV ESI,OFFSET32 NODECALL LEA EDI,MSGDEST[EDI] ; DEST CALL CALL COMPARECALLS POP EDI JNE L2DISCARD ; NOT TO NODES ; CMP MSGDATA[EDI],0FFH JNE L2DISCARD ; NOT CORRECT FORMAT? CALL PROCESSNODEMESSAGE JMP L2DISCARD PUBLIC L2IPMSG L2IPMSG: MOV EDI,BUFFER CALL Q_IP_MSG ; PASS WHOLE FRAME RET PUBLIC L2NOTFORUS 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 SHORT L2DISCARD ; NOT LINK SETUP ; ; LOOK FOR A CQ ENTRY IN OUR TABLES MATCHING TARGET CALL ; MOV EDI,BUFFER LEA ESI,MSGDEST[EDI] MOV EDI,OFFSET32 COMPAREFIELD MOV ECX,7 REP MOVSB MOV ESI,OFFSET32 CQ ; AX25 CQ MOV ECX,7 REP MOVSB ; MOV EDI,OFFSET32 COMPAREFIELD CALL FINDLINKXX ; GET LINK FOR THIS ADDRESS PAIR (IN BX) ; JNZ SHORT L2DISCARD ; ; MATCHING CIRCUIT FOUND - UPDATE CALLS, SET LINK ACTIVE, AND ; SEND CONNECTED MSG TO REMOTE STATION ; CALL SETUPNEWSESSION CMP L2STATE[EBX],5 ; SESSION SETUP SUCCESSFUL? JE SHORT CQSETUPOK JMP L2SENDDM ; FAILED - ? TOO MANY DIGIS, ETC PUBLIC CQSETUPOK CQSETUPOK: MOV LINKTYPE[EBX],2 ; DOWNLINK PUSH EBX CALL L2SENDUA POP EBX ; ; TELL PARTNER CONNECTION IS ESTABLISHED ; CALL GETBUFF ; WILL USE CQ MSG BUFFER EVENTUALLY JZ SHORT CQEXIT ; NO BUFFERS! MOV ESI,OFFSET32 CONNECTEDMSG MOV ECX,LCONNECTEDMSG CALL SENDCONNECTREPLY PUBLIC CQEXIT CQEXIT: RET PUBLIC L2DISCARD L2DISCARD: MOV EDI,BUFFER CALL RELBUFF RET PUBLIC L2FORUS L2FORUS: ; ; MESSAGE ADDRESSED TO OUR CALL OR ALIAS, BUT NOT FOR AN ACTIVE SESSION ; INC L2FRAMESFORUS[EBP] ; ; ONLY SABM IS ALLOWED IF NO SESSION ; MOV AL,SDCBYTE AND AL,NOT 10H ; MASK P/F CMP AL,3 JNE SHORT NOT_ADDR_UI PUBLIC ADDRUI ADDRUI: ; ; A UI ADDRESSED TO US - SHOULD ONLY BE FOR IP ; MOV EDI,ADJBUFFER CMP MSGPID[EDI],0CFH ; NETROM MSG? JNE SHORT NOTNRUI ; NO CMP MSGDATA[EDI],0FFH JNE SHORT NOTNRUI ; NOT CORRECT FORMAT? CALL PROCESSNODEMESSAGE JMP L2DISCARD PUBLIC NOTNRUI NOTNRUI: CMP MSGPID[EDI],0CDH JE SHORT TCP ; ARP CMP MSGPID[EDI],0CCH JE SHORT TCP ; TCP/IP CMP MSGPID[EDI],08H ; NOS FRAGMENTED AX25 TCP/IP JNE SHORT L2DISCARD PUBLIC TCP TCP: MOV EDI,BUFFER JMP L2IPMSG PUBLIC NOT_ADDR_UI NOT_ADDR_UI: ; CMP PortUIOnly[EBP], 0 ; Port is for UI only JNE IGNORESABM CMP AL,SABM JNE NOTSABM IF BLACKBITS ; ; CHECK BLACKLIST ; EXTRN CHECKBLACKLIST:NEAR MOV EDI,BUFFER LEA ESI,MSGORIGIN[EDI] ; ORIGIN FROM MESSAGE CALL CHECKBLACKLIST ; RETURN Z IF NODE IS IN LIST JZ SHORT IGNORESABM ; DONT ACCEPT ENDIF ; ; IF WE HAVE A PERMITTED CALLS LIST, SEE IF HE IS IN IT ; CMP PERMITTEDCALLS[EBP],0 JE SHORT CALLISOK ; NO LIMITS ; PUSH EBP MOV EBP,PERMITTEDCALLS[EBP] PUBLIC CHECKLOOP CHECKLOOP: MOV EDI,BUFFER LEA EDI,MSGORIGIN[EDI] ; ORIGIN FROM MESSAGE MOV ESI,EBP CMP BYTE PTR [ESI],0 JE SHORT ENDLIST MOV ECX,6 ; IGNORE SSID REP CMPSB JE SHORT CALLISINLIST ADD EBP,7 JMP CHECKLOOP PUBLIC ENDLIST ENDLIST: ; ; NOT IN LIST ; POP EBP PUBLIC IGNORESABM IGNORESABM: JMP L2DISCARD ; IGNORE IT ; PUBLIC CALLISINLIST CALLISINLIST: POP EBP PUBLIC CALLISOK CALLISOK: ; ; IF CALL REQUEST IS FROM A LOCKED NODE WITH QUALITY ZERO, IGNORE IT ; MOV AL,NETROMMSG MOV NO_CTEXT,AL MOV EDI,BUFFER LEA ESI,MSGORIGIN[EDI] PUSH EBX CALL _FINDNEIGHBOUR ; IS IT A NODE? JNE SHORT NOTNODE MOV NO_CTEXT,1 ; don't send CTEXT to known nodes CMP NEIGHBOUR_FLAG[EBX],1 JNE SHORT NOTNODE ; NOT LOCKED CMP NEIGHBOUR_QUAL[EBX],0 JNE SHORT NOTNODE ; NOT ZERO QUALITY POP EBX PUBLIC DISCARDJMP DISCARDJMP: JMP L2DISCARD ; IGNORE IT PUBLIC NOTNODE NOTNODE: POP EBX ; ; CHECK PORT CONNECT LIMITS ; CMP USERS[EBP],0 JE SHORT SABMOK ; NO LIMIT MOV AL,CURRENTPORT CALL COUNTLINKS CMP AH,USERS[EBP] JL SHORT L2SABM JMP L2SENDDM PUBLIC SABMOK SABMOK: JMP SHORT L2SABM PUBLIC NOTSABM NOTSABM: MOV ALIASMSG,0 MOV APPLMASK,0 ; ONLY DO BBS PROCESSING ON CONNECT ; ; IF COMMAND WITH P SET, SEND DM ; TEST MSGFLAG,CMD JZ SHORT DISCARDJMP ; RESPONSE TEST SDCBYTE,PFBIT JZ SHORT DISCARDJMP ; P NOT SET JMP L2SENDDM ; SEND DM IF NOT FOUND PUBLIC L2LINKACTIVE L2LINKACTIVE: ; ; MESSAGE ON AN ACTIVE LINK (IN BX) ; INC L2FRAMESFORUS[EBP] MOV AL,SDCBYTE AND AL,NOT 10H ; MASK P/F CMP AL,3 JNE SHORT NOTACTUI ; ; UI ON ACTIVE LINK - MUST BE IP DATAGRAM ; JMP ADDRUI PUBLIC NOTACTUI NOTACTUI: CMP AL,DISC JE SHORT L2_DISC ; DISCONNECT REQUEST ; CMP AL,SABM JE SHORT L2SABM_OLD ; LINK SETUP CALL L2_PROCESS RET PUBLIC L2_DISC 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 PUBLIC L2SABM_OLD L2SABM_OLD: ; ; SABM ON EXISTING SESSION - IF DISCONNECTING, REJECT ; CMP L2STATE[EBX],4 ; DISCONNECTING? JNE SHORT OLDSABMOK ; JMP L2SENDDM ; FAILED PUBLIC OLDSABMOK 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[EBX],0 ; RESET OF ACTIVE CIRCUIT? JE L2SENDUA ; No, so repeat UA CALL INFORMPARTNER ; SEND DISC TO OTHER END ; Drop through to reestablish link PUBLIC L2SABM L2SABM: ; ; SET UP NEW SESSION (OR RESET EXISTING ONE) ; CMP EBX,0 JNE SHORT L2SABM000 ; OK JMP L2SENDDM ; NO LINK ENTRIES - SEND DM RESPONSE ; PUBLIC L2SABM000 L2SABM000: CALL SETUPNEWSESSION CMP L2STATE[EBX],5 ; SETUP OK? JE SHORT SABM021 JMP L2SENDDM ; FAILED PUBLIC SABM021 SABM021: ; ; IF CONNECT TO BBS ADDRESS, SET UP BBS SESSION ; CMP APPLMASK,0 JNE SABM22 ; ATTACH TO APPL ; Send CTEXT if connect to Node/Port Alias, or Node/Port Call, and FULL_CTEXT set ; Dont sent to known nodes, or appl connects ; CMP NO_CTEXT,1 JE L2SENDUA CMP _FULL_CTEXT,1 JE SHORT SENDCT ; FOR ANY CONNECT CMP ALIASMSG,0 JE L2SENDUA PUBLIC SENDCT SENDCT: CMP _CTEXTLEN,0 JE L2SENDUA ; NOT DEFINED PUSH EBX CALL L2SENDUA ; SEND ACK POP EBX MOV ESI,_CTEXTMSG MOVZX EDX,_CTEXTLEN MOVZX EAX,PORTPACLEN[EBP] ; PACLEN FOR THIS PORT OR EAX,EAX JNZ @F MOVZX EAX,PACLEN ; DONT ALLOW ZERO! @@: mov CTPACLEN,EAX PUBLIC CTLOOP CTLOOP: push esi CALL GETBUFF pop esi JZ SHORT CTEXTRET ; NO BUFFERS MOV BUFFER,EDI ADD EDI,7 MOV AL,0F0H STOSB ; PID MOV ECX,EDX CMP EDX,CTPACLEN JBE @F MOV ECX,CTPACLEN @@: push ecx REP MOVSB pop ecx sub edx,ecx ; edx = bytes still to send MOV ECX,EDI MOV EDI,BUFFER SUB ECX,EDI MOV MSGLENGTH[EDI],CX push esi LEA ESI,TX_Q[EBX] CALL _Q_ADD ; SEND MESSAGE TO CALLER pop esi cmp edx,0 JG CTLOOP PUBLIC CTEXTRET CTEXTRET: RET PUBLIC SABM22 SABM22: ; CMP LINKTYPE[EBX],1 JNE L2SENDUA_JMP ; RESET OF DOWN/CROSSLINK CMP CIRCUITPOINTER[EBX],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 APPLMASK,0 JNE SHORT CALLTOBBS ; CALL TO BBS OR APPL CMP NODE,1 JE SHORT 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 EDI,BUFFER LEA ESI,LINKCALL[EBX] PUSH EBX CALL _FINDNEIGHBOUR ; IS IT A NODE? POP EBX JE L2SENDUA_JMP ; YES PUBLIC CALLTOBBS CALLTOBBS: PUSH EBX CALL SETUPUSERSESSION ; CREATE INCOMING L4 SESSION POP EBX JNZ BBSFAILED ; COULDNT ; ; NOW TRY A BBS CONNECT ; PUSH EBX ; SAVE LINK MOV EBX,CIRCUITPOINTER[EBX] ; SESSION MOV AL,PORTPACLEN[EBP] ; PACLEN FOR THIS PORT MOV SESSPACLEN[EBX],AL ; TO SESSION CMP APPLMASK,0 JE @F ;NOT APPL CONNECT ; IF APPL CONNECT, SEE IF APPL HAS AN ALIAS MOV ESI,ALIASPTR CMP BYTE PTR [ESI],20H JE @F ; NO ; ACCEPT THE CONNECT, THEN INVOKE THE ALIAS POP EBX PUSH EBX PUSH ESI CALL L2SENDUA ; TELL USER, AND PASS COMMAND TO HANDLER CALL GETBUFF POP ESI POP EBX JZ SHORT APNOBUF ; NO BUFFERS MOV BUFFER,EDI ADD EDI,7 MOV AL,0F0H STOSB ; PID MOV ECX,16 REP MOVSB MOV AL,0DH STOSB MOV ECX,EDI MOV EDI,BUFFER SUB ECX,EDI MOV MSGLENGTH[EDI],CX LEA ESI,RX_Q[EBX] CALL _Q_ADD ; SEND MESSAGE TO COMMAND HANDLER PUBLIC APNOBUF APNOBUF: RET @@: CALL ATTACHTOBBS ; AL = PACLEN POP EBX JZ SHORT L2SENDUA_JMP ; SUCCESS ; ; NO BBS AVAILABLE ; PUSH EBX MOV EBX,CIRCUITPOINTER[EBX] CALL CLEARSESSIONENTRY ; RELEASE SESSION POP EBX PUBLIC BBSFAILED BBSFAILED: CALL CLEAROUTLINK ; DELETE NEW SESSION PUBLIC L2SENDDM_JMP L2SENDDM_JMP: JMP L2SENDDM ; SEND BUSY PUBLIC L2SENDUA_JMP L2SENDUA_JMP: JMP L2SENDUA PUBLIC SETUPNEWSESSION SETUPNEWSESSION: ; ; COPY ADDRESS INFO TO LINK TABLE ; MOV EDI,BUFFER PUSH EDI LEA ESI,MSGORIGIN[EDI] LEA EDI,LINKCALL[EBX] MOV ECX,7 REP MOVSB AND BYTE PTR -1[EDI],00011110B ; MASK SSID POP EDI PUSH EDI LEA ESI,MSGDEST[EDI] ; DEST FROM MESSAGE LEA EDI,OURCALL[EBX] ; OUR CALL/ALIAS BEING USED MOV ECX,7 REP MOVSB ; AND BYTE PTR -1[EDI],00011110B ; MASK SSID POP EDI LEA ESI,MSGCONTROL[EDI] ; START OF DIGIS IF PRESENT LEA EDI,DIGIS[EBX] ; OUR CALL/ALIAS BEING USED PUSH EDI MOV ECX,MAXDIGIS*7 JCXZ NODIGIS XOR AL,AL REP STOSB ; CLEAR DIGI FIELD IN CASE RECONNECT PUBLIC NODIGIS NODIGIS: POP EDI ; ; COPY DIGIS IF PRESENT ; MOV AL,PORTT1[EBP] MOV L2TIME[EBX],AL ; SET L2 TIMOUT FOR NO DIGIS PUBLIC SABM010 SABM010: TEST BYTE PTR -1[ESI],1 JNZ SHORT SABM020 ; NONE ; ; THERE ARE DIGIS TO PROCESS - COPY TO WORK AREA, THEN COPY BACK ; MOV EDI,OFFSET32 TEMPDIGI MOV ECX,7*8 XOR AX,AX REP STOSB ; CLEAR (MAX 8 DIGIS, 7 BYTES EACH) SUB EDI,7 ; TO LAST TEMP FIELD PUBLIC SABM012 SABM012: MOV ECX,7 REP MOVSB AND BYTE PTR -1[EDI],01111110B ; MASK REPEATED AND LAST BITS TEST BYTE PTR -1[ESI],1 JNZ SHORT SABM014 ; END OF LIST SUB EDI,14 ; TO PREVIOUS JMP SABM012 PUBLIC SABM014 SABM014: ; ; LIST OF DIGI CALLS COMPLETE - COPY TO LINK CONTROL ENTRY ; MOV ESI,EDI SUB ESI,7 ; TO START OF LAST DIGI (BECOMES FIRST) LEA EDI,DIGIS[EBX] MOV AH,PORTMAXDIGIS[EBP] PUBLIC SABM016 SABM016: CMP BYTE PTR [ESI],0 JE SHORT SABM020 ; NO MORE CMP AH,0 JE SHORT SABM018 ; TOO MANY MOV ECX,7 REP MOVSB DEC AH MOV AL,PORTT1[EBP] ADD L2TIME[EBX],AL ; ADJUST TIMEOUT FOR DIGI'ED LINK ADD L2TIME[EBX],AL ; ADJUST TIMEOUT FOR DIGI'ED LINK JMP SABM016 ; LOOP PUBLIC SABM018 SABM018: CALL CLEAROUTLINK ; GET RID OF PART BUILT SESSION ENTRY RET PUBLIC SABM020 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[EBX],AL ; PUT IN CMP LINKTYPE[EBX],0 JNE SHORT SABM020X MOV LINKTYPE[EBX],1 ; UPLINK PUBLIC SABM020X SABM020X: MOV L2TIMER[EBX],0 ; CANCEL TIMER MOV AX,T3 MOV L2SLOTIM[EBX],AX ; SET FRAME SENT RECENTLY MOV AL,PORTWINDOW[EBP] MOV LINKWINDOW[EBX],AL CALL RESET2 ; RESET ALL FLAGS MOV L2STATE[EBX],5 ; ; IF VERSION 1 MSG, SET FLAG ; TEST MSGFLAG,VER1 JZ SHORT SABM020A ; NOMAL (VERSION 2) MOV VER1FLAG[EBX],1 PUBLIC SABM020A SABM020A: RET PUBLIC L2SENDUA L2SENDUA: MOV AL,UA JMP L2SENDRESP ; SEND UA PUBLIC L2SENDDM L2SENDDM: MOV AL,DM PUBLIC L2SENDRESP L2SENDRESP: ; ; QUEUE RESPONSE TO PORT CONTROL - MAY NOT HAVE A LINK ENTRY ; MOV EDI,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[EDI],AH LEA ECX,MSGCONTROL+1[EDI] ; END OF MESSAGE MOV EDI,BUFFER SUB ECX,EDI ; CALCULATE LENGTH MOV MSGLENGTH[EDI],CX ; SET UP BYTE COUNT CALL L2SWAPADDRESSES ; SWAP ADDRESSES AND SET RESP BITS PUBLIC L2QUEUEONPORT L2QUEUEONPORT: MOV EDI,BUFFER MOV EBX,CURRENTPORTPTR CALL PUT_ON_PORT_Q RET PUBLIC L2SWAPADDRESSES L2SWAPADDRESSES: ; ; EXCHANGE ORIGIN AND DEST, AND REVERSE DIGIS (IF PRESENT) ; MOV EDI,BUFFER LEA ESI,MSGORIGIN[EDI] LEA EDI,TEMPFIELD MOV ECX,7 REP MOVSB ; SAVE ORIGIN MOV EDI,BUFFER LEA ESI,MSGDEST[EDI] LEA EDI,MSGORIGIN[EDI] MOV ECX,7 REP MOVSB ; AND BYTE PTR -1[EDI],00011110B ; MASK SSID OR BYTE PTR -1[EDI],11100000B ; SET RESPONSE AND RESERVED MOV EDI,BUFFER LEA ESI,TEMPFIELD LEA EDI,MSGDEST[EDI] MOV ECX,7 REP MOVSB ; AND BYTE PTR -1[EDI],00011110B ; MASK SSID - C BIT ZERO FOR RESPONSE OR BYTE PTR -1[EDI],01100000B ; SET RESERVED ; ADD EDI,7 ; TO FIRST DIGI IF PRESENT TEST BYTE PTR -1[ESI],1 JNZ SHORT L2SWAPRET ; ; THERE ARE DIGIS TO PROCESS - COPY TO WORK AREA, THEN COPY BACK ; MOV ESI,EDI ; TO FIRST DIGI PUSH ESI ; SAVE MOV EDI,OFFSET32 TEMPDIGI MOV ECX,7*8 XOR AX,AX REP STOSB ; CLEAR (MAX 8 DIGIS, 7 BYTES EACH) SUB EDI,7 ; TO LAST TEMP FIELD PUBLIC L2SWAP000 L2SWAP000: MOV ECX,7 REP MOVSB AND BYTE PTR -1[EDI],01111110B ; MASK REPEATED AND LAST BITS TEST BYTE PTR -1[ESI],1 JNZ SHORT L2SWAP010 ; END OF LIST SUB EDI,14 ; TO PREVIOUS JMP L2SWAP000 PUBLIC L2SWAP010 L2SWAP010: MOV ESI,EDI SUB ESI,7 ; TO START OF LAST DIGI (NOW FIRST) POP EDI PUBLIC L2SWAP020 L2SWAP020: CMP BYTE PTR [ESI],0 JE SHORT L2SWAPRET ; NO MORE MOV ECX,7 REP MOVSB JMP L2SWAP020 ; LOOP PUBLIC L2SWAPRET L2SWAPRET: OR BYTE PTR -1[EDI],1 ; SET END OF ADDRESS BIT RET PUBLIC L2_PROCESS L2_PROCESS: ; ; PROCESS LEVEL 2 PROTOCOL STUFF ; ; SEE IF COMMAND OR RESPONSE ; TEST MSGFLAG,CMD JNZ SHORT L2_COMMAND ; ; RESPONSE OR VERSION 1 ; PUBLIC L2_RESPONSE L2_RESPONSE: ; ; IF RETRYING, MUST ONLY ACCEPT RESPONSES WITH F SET (UNLESS RUNNING V1) ; CMP VER1FLAG[EBX],1 JE SHORT HDRX09 ; VERSION 1 TEST SDCBYTE,PFBIT JZ SHORT HDRX10 ; F NOT SET - DONT RESET TIMER ; ; F SET - CAN CANCEL TIMER ; PUBLIC HDRX09 HDRX09: MOV L2TIMER[EBX],0 ; CANCEL LINK TIMER JMP SHORT HDRX10 PUBLIC L2_COMMAND L2_COMMAND: PUBLIC HDRX10 HDRX10: CMP L2STATE[EBX],3 JNE SHORT NOTFRMRSTATE ; ; FRMR STATE - IF C(P) SEND FRMR, ELSE IGNORE ; MOV AL,SDCBYTE AND AL,NOT PFBIT CMP AL,FRMR JE SHORT BOTHFRMR ; DONT EXCHANGE FOR EVER! TEST MSGFLAG,CMD JZ SHORT FRMRDISCARD ; RESPONSE TEST SDCBYTE,PFBIT JZ SHORT FRMRDISCARD ; ; SEND FRMR AGAIN ; JMP SDFRMR PUBLIC FRMRDISCARD FRMRDISCARD: JMP L2DISCARD PUBLIC BOTHFRMR BOTHFRMR: JMP SDUF80 ; SEND SABM PUBLIC NOTFRMRSTATE NOTFRMRSTATE: CMP L2STATE[EBX],5 ; LINK OK? JB SHORT 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 SHORT NOTIFRM JMP SDIFRM ; J IF AN I-FRAME PUBLIC NOTIFRM NOTIFRM: TEST AL,2 JZ SHORT NOTUFRM JMP SDUFRM ; J IF UNNUMBERED FORMAT PUBLIC NOTUFRM NOTUFRM: AND AL,0FH ; ELSE SUPERVISORY, MASK OFF N(R) AND P-BIT CMP AL,RR JNE SHORT NOTRR JMP SDSFRM ; J IF 'RECEIVE READY' PUBLIC NOTRR NOTRR: CMP AL,RNR JNE SHORT NOTRNR JMP SDSFRM ; J IF 'RECEIVE NOT READY' PUBLIC NOTRNR NOTRNR: CMP AL,REJ JNE SHORT SDRX50 ; INC L2REJCOUNT[EBP] ; JMP SDSFRM ; ; UNRECOGNISABLE COMMAND ; PUBLIC SDRX50 SDRX50: MOV AL,SDCBYTE MOV SDRBYTE,AL ; SAVE FOR FRMR RESPONSE OR SDREJF[EBX],SDINVC ; SET INVALID COMMAND REJECT CALL SDFRMR ; PROCESS FRAME REJECT CONDITION RET ; NORMAL DISCONNECT MODE ; ; COULD BE UA, DM - SABM AND DISC HANDLED ABOVE ; PUBLIC SDNDM SDNDM: MOV AL,SDCBYTE ; GET FRAME CONTROL BYTE AND AL,0FFH-10H ; MASK P/F CMP AL,UA JE SHORT SDND40 CMP AL,DM JE SHORT SDND30 CMP AL,FRMR JNE SHORT NOTFRMR JMP SDUF80 PUBLIC NOTFRMR NOTFRMR: JMP L2DISCARD ; ANY OTHER - IGNORE ; PUBLIC SDND30 SDND30: ; ; DM RESPONSE - IF TO SABM, SEND BUSY MSG ; CMP L2STATE[EBX],2 ; CONNECTING? JNE SHORT SDND35 ; NO - CLEAR OUT LINK PUSH EBX CALL CONNECTREFUSED ; SEND MESSAGE IF DOWNLINK POP EBX PUBLIC SDND35 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 INFORMPARTNER ; SEND DISC TO OTHER END CALL CLEAROUTLINK RET PUBLIC SDND40 SDND40: ; ; UA RECEIVED ; CMP L2STATE[EBX],2 ; RESPONSE TO SABM? JNE SHORT SDND42 ; NO ; ; RESPONSE TO SABM - SET LINK UP ; CALL RESET2X ; LEAVE QUEUED STUFF MOV L2STATE[EBX],5 MOV L2TIMER[EBX],0 ; CANCEL TIMER MOV L2RETRIES[EBX],0 MOV AX,T3 MOV L2SLOTIM[EBX],AX ; SET FRAME SENT RECENTLY ; ; IF VERSION 1 MSG, SET FLAG ; TEST MSGFLAG,VER1 JZ SHORT SDND41 ; NORMAL (VERSION 2) MOV VER1FLAG[EBX],1 PUBLIC SDND41 SDND41: ; TELL PARTNER CONNECTION IS ESTABLISHED MOV ESI,OFFSET32 CONNECTEDMSG MOV ECX,LCONNECTEDMSG PUSH EBX MOV EDI,BUFFER CALL SENDCONNECTREPLY POP EBX RET PUBLIC SDND42 SDND42: CMP L2STATE[EBX],4 ; DISCONNECTING? JE SHORT SDND35 ; CLEAR OUT LINK ; ; UA, BUT NOT IN STATE 2 OR 4 - IGNORE ; JMP L2DISCARD PUBLIC SDSF20 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 ; PUBLIC SDSFRM SDSFRM: CMP SDREJF[EBX],0 ; ARE ANY REJECT FLAGS SET? JNE SHORT SDSF20 ; J IF YES PUBLIC SDSF10 SDSF10: CALL SDNRCHK ; CHECK RECEIVED N(R) CMP SDREJF[EBX],0 ; ARE ANY REJECT FLAGS SET? JNE SHORT SDSF20 ; J IF YES ; ; VALID RR/RNR RECEIVED ; AND L2FLAGS[EBX],NOT RNRSET ; CLEAR RNR MOV AL,SDCBYTE ; GET CONTROL BYTE AND AL,0FH CMP AL,RNR ; IS COMMAND RNR? JNE SHORT SDSF15 ; NO OR L2FLAGS[EBX],RNRSET ; SET OTHER END CANT RECEIVE PUBLIC SDSF15 SDSF15: TEST MSGFLAG,CMD JNZ SHORT SDSF17 ; ALWAYS REPLY TO RR COMMAND TEST SDCBYTE,PFBIT JNZ SHORT SDSF16 ; RESPONSE WITH F SET - RESET N(S) ; ; RESPONSE WITHOUT P/F DONT RESET N(S) (UNLESS V1) ; CMP VER1FLAG[EBX],1 JE SHORT SDSF16 JMP L2DISCARD PUBLIC SDSF16 SDSF16: ; ; RESPONSE WITH P/F - MUST BE REPLY TO POLL FOLLOWING TIMEOUT OR I(P) ; AND L2FLAGS[EBX],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 SHORT SDSF16A ; RESET NS ; CMP L2RETRIES[EBX],0 ; RETRYING? JE SHORT SDSF16B ; NO, SO PROBABLY REPLY TO REPEATED ; RR(P), DELAYED IN LINK LEVEL CODE PUBLIC SDSF16A SDSF16A: PUSH EAX 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 POP EAX ; KEEP COMMAND IN AL MOV L2RETRIES[EBX],0 MOV L2TIMER[EBX],0 ; WILL RESTART TIMER WHEN RETRY SENT PUBLIC SDSF16B SDSF16B: CMP AL,RNR JNE @F ; ; Dont Clear timer on receipt of RNR(F), spec says should poll for clearing of busy, ; and loss of subsequent RR will cause hang. Perhaps should set slightly longer time?? ; Timer may have been cleared earlier, so restart it MOV AL,L2TIME[EBX] MOV AH,0 MOV L2TIMER[EBX],AX ; SET TIMER @@: JMP L2DISCARD ; ; RR/RNR/REJ COMMAND - SEND RESPONSE ; PUBLIC SDSF17 SDSF17: ; ; FIRST PROCESS RESEQ QUEUE ; ; PUSH BUFFER ; CALL PROCESS_RESEQ ; POP BUFFER ; ; IGNORE IF AN 'F' HAS BEEN SENT RECENTLY ; MOV DX,REALTIMETICKS SUB DX,LAST_F_TIME[EBX] CMP DX,15 ; 1.5 SECS JB SHORT SDSF16B ; DISCARD CALL RR_OR_RNR MOV AL,LINKNR[EBX] ; 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 PUBLIC SDCB10 SDCB10: MOV L2ACKREQ[EBX],0 ; CANCEL DELAYED ACK MOV CX,T3 MOV L2SLOTIM[EBX],CX ; SET FRAME SENT RECENTLY PUSH EBX CALL L2SENDRESP POP EBX ; ; SAVE TIME IF 'F' SENT' ; TEST SDCBYTE,10H JZ SHORT SDSF18 MOV DX,REALTIMETICKS MOV LAST_F_TIME[EBX],DX PUBLIC SDSF18 SDSF18: RET PUBLIC RESETNS RESETNS: MOV AH,LINKNS[EBX] MOV LINKNS[EBX],AL ; RESET N(S) SUB AH,AL ; FRAMES TO RESEND AND AH,7 ; MODULO SEVEN CMP LINKTYPE[EBX],3 JNE SHORT RESETNSRET PUSH EBX MOV EBX,NEIGHBOUR[EBX] OR EBX,EBX JZ SHORT NONEIGHBOUR ; WOT!! MOVZX EAX,AH ADD NBOUR_RETRIES[EBX],EAX PUBLIC NONEIGHBOUR NONEIGHBOUR: POP EBX PUBLIC RESETNSRET RESETNSRET: RET ; PROCESS AN UNSEQUENCED COMMAND (IN LINK UP STATES) ; PUBLIC SDUFRM SDUFRM: CMP AL,UA JE SHORT SDUF75 ; DISCARD - PROBABLY REPEAT OF ; ACK OF SABM CMP AL,FRMR JE SHORT SDUF80 ; CMP AL,DM JE SHORT SDUF70 ; DM RESPONSE - SESSION MUST HAVE GONE ; ; UNDEFINED COMMAND ; JMP SDFRMR ; SEND FRAME REJECT PUBLIC SDUF70 SDUF70: ; ; SEE IF CROSSLINK ACTIVE ; CALL INFORMPARTNER ; SEND DISC TO OTHER END ; ; CLEAR OUT TABLE ENTRY ; CALL CLEAROUTLINK ; CLEAR OUT ENTRY PUBLIC SDUF75 SDUF75: JMP L2DISCARD PUBLIC SDUF80 SDUF80: ; ; FRAME REJECT RECEIVED - LOG IT AND RESET LINK ; CALL RESET2 ; RESET SESSION CALL L2DISCARD ; RELEASE MESSAGE MOV L2STATE[EBX],2 ; INITIALISING MOV L2ACKREQ[EBX],0 ; DONT SEND ANYTHING ELSE MOV L2RETRIES[EBX],0 ; ALLOW FULL RETRY COUNT FOR SABM INC L2FRMRRX[EBP] MOV AL,SABM OR PFBIT CALL L2SENDCOMMAND ; SEND COMMAND RET ; ;*** PROCESS AN INFORMATION FRAME ; PUBLIC SDIFRM SDIFRM: CMP SDREJF[EBX],0 ; ARE ANY REJECT FLAGS SET? JNE SHORT SDIF40 ; J IF YES CALL SDNRCHK ; CHECK RECEIVED N(R) CMP SDREJF[EBX],0 ; ARE ANY REJECT FLAGS SET? JNE SHORT SDIF40 ; J IF YES MOV SESSACTIVE[EBX],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[EBX] ; EQUAL TO OUR N(R)? JE SHORT 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 ; INC L2OUTOFSEQ[EBP] ; MOV L2STATE[EBX],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[EBX],1 JNE SHORT VER2REJ ; VERSION 1 TIMEOUT ; MOV REJTIMER[EBX],TENSECS PUBLIC VER2REJ VER2REJ: ; ; SET ACK REQUIRED TIMER - REJ WILL BE SENT WHEN IT EXPIRES ; MOV L2ACKREQ[EBX],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 ; PUBLIC PUT_ON_RESEQ PUT_ON_RESEQ: ; MOV ESI,L2RESEQ_Q[EBX] ; ;CHECK_FRAME_LOOP: ; ; CMP ESI,0 ; JE SHORT NOTONQUEUE ; ; CMP AL,BUFFLEN-2[ESI] ; JE SHORT MSGONQUEUE ; ; MOV ESI,[ESI] ; FOLLOW CHAIN ; ; JMP CHECK_FRAME_LOOP ; ;NOTONQUEUE: ;!!! LEA ESI,L2RESEQ_Q[EBX] ;!!! MOV EDI,BUFFER ;!!! MOV BUFFLEN-2[EDI],AL ; PUT SEQNO ON END ;!!! CALL _Q_ADD ; ADD TO CHAIN ; ;!!! JMP SHORT CHECKPF PUBLIC MSGONQUEUE MSGONQUEUE: ; ; ALREADY HAVE A COPY - DISCARD IT ; CALL L2DISCARD JMP SHORT CHECKPF ; PUBLIC SDIF40 SDIF40: CALL SDFRMR ; PROCESS FRAME REJECT CONDITION RET PUBLIC SDIF05 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[EBX],0 ; JE SHORT 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 SHORT 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[EBX],0 ; JNE SHORT RESEQ_EXIT ; ; RESEQ Q IS EMPTY ; ; CMP L2STATE[EBX],6 ; REJ? ; JNE SHORT SDIF02 ; ; MOV L2STATE[EBX],5 ; CLEAR REJ ; ;SDIF02: ; ; JMP SDIF15 ; SEND REJ(F) ; ;RESEQ_EXIT: ; ; RET ; ;OK_TO_PROC: ; ; IN SEQUENCE FRAME - CANCEL REJ ; CMP L2STATE[EBX],6 ; REJ? JNE SHORT SDIF02 ; MOV L2STATE[EBX],5 ; CLEAR REJ AND L2FLAGS[EBX],NOT REJSENT ; PUBLIC SDIF02 SDIF02: ; CALL PROC_I_FRAME ; ; IF P SET, SEND RR(F) ; PUBLIC CHECKPF CHECKPF: TEST L2FLAGS[EBX],REJSENT JNZ SHORT CHECKX ; DONT SEND ANOTHER TILL REJ IS CANCELLED TEST SDCBYTE,PFBIT JNZ SHORT SDIF15 PUBLIC CHECKX CHECKX: RET PUBLIC SDIF15 SDIF15: CMP L2STATE[EBX],6 JNE SHORT NOTREJSTATE OR L2FLAGS[EBX],REJSENT PUBLIC NOTREJSTATE NOTREJSTATE: MOV L2ACKREQ[EBX],0 ; CANCEL RR NEEDED MOV AL,PFBIT CALL SEND_RR_RESP ; ; RECORD TIME ; MOV DX,REALTIMETICKS MOV LAST_F_TIME[EBX],DX RET PUBLIC SDIF20 SDIF20: JMP L2DISCARD ; I FIELD TOO BIG ?? SHOULD BE FRMR PUBLIC PROC_I_FRAME PROC_I_FRAME: INC LINKNR[EBX] ; ELSE INCREMENT OUR N(R) AND LINKNR[EBX],7 ; MODULO 8 ; ; ATTACH I FRAMES TO LINK TABLE RX QUEUE - ONLY DATA IS ADDED (NOT ADDRESSES) ; MOV EDI,BUFFER ; ; IF DISC PENDING SET, IGNORE FRAME ; TEST L2FLAGS[EBX],DISCPENDING JZ SHORT SDIF06 ; NO DISC PENDING CALL L2DISCARD RET PUBLIC SDIF06 SDIF06: MOVZX EAX,MSGLENGTH[EDI] SUB EAX,22 ; STATION ADDRESSES AND CONTROL CALL ADJUSTFORDIGIS ; ADJUSTS EDI AND AX FOR ANY DIGIS PRESENT CMP MSGPID[EDI],0CCH JE SHORT IF_IP CMP MSGPID[EDI],0CDH JE SHORT IF_IP CMP MSGPID[EDI],08H ; NOS FRAGMENTED IP JNE SHORT NOT_IF_IP ; ; FRAGMENTED MESSAGE ; PUSH EDI LEA ESI,L2FRAG_Q[EBX] MOV EDI,BUFFER CALL _Q_ADD POP EDI CMP MSGPID+1[EDI],0 JNE SHORT SDIF12 ; NOT LAST ; ; THERE IS A WHOLE MESSAGE ON FRAG_Q - PASS TO IP ; PUSH EBX PUSH EBP LEA ESI,L2FRAG_Q[EBX] PUBLIC FRAGLOOP FRAGLOOP: PUSH ESI CALL Q_REM JZ SHORT NOMOREFRAGS CALL Q_IP_MSG POP ESI JMP FRAGLOOP PUBLIC NOMOREFRAGS NOMOREFRAGS: POP ESI POP EBP POP EBX JMP SHORT SDIF12 PUBLIC IF_IP IF_IP: PUSH EBX PUSH EBP CALL L2IPMSG POP EBP POP EBX JMP SHORT SDIF12 PUBLIC NOT_IF_IP NOT_IF_IP: LEA ESI,MSGPID[EDI] ; START OF 'REAL' DATA MOV EDI,BUFFER LEA EDI,7[EDI] ; TO DATA IN INTERNAL MESSAGE MOV ECX,EAX JCXZ SDIF10 ; NO PID?? CMP ECX,257 JA SDIF20 ; TOO BIG REP MOVSB PUBLIC SDIF10 SDIF10: ADD EAX,7 ; HEADER LENGTH MOV EDI,BUFFER MOV MSGLENGTH[EDI],AX LEA ESI,RX_Q[EBX] MOV EDI,BUFFER CALL _Q_ADD PUBLIC SDIF12 SDIF12: MOV AL,PORTT2[EBP] MOV L2ACKREQ[EBX],AL ; SET RR NEEDED MOV KILLTIMER[EBX],0 ; RESET IDLE LINK TIMER RET ; ; L2 RESEQUENCE CODE. MAINLY FOR WHEN WE DO SREJ BUT WILL SAVE ; SOME RETRIES EVEN WITHOUT IT ; PUBLIC CHECK_RESEQ CHECK_RESEQ: ; ; SEE IF ANYTHING ON RESEQ QUEUE TO PROCESS ; LEA ESI,L2RESEQ_Q[EBX] MOV EDI,[ESI] MOV AL,LINKNR[EBX] ; WHAT WE WANT PUBLIC FIND_FRAME_LOOP FIND_FRAME_LOOP: CMP EDI,0 JE SHORT NOTFOUND CMP AL,BUFFLEN-2[EDI] JE SHORT FOUNDMESSAGE MOV ESI,EDI ; SAVE PREVIOUS IN CHAIN MOV EDI,[EDI] ; FOLLOW CHAIN JMP FIND_FRAME_LOOP PUBLIC NOTFOUND NOTFOUND: RET PUBLIC FOUNDMESSAGE FOUNDMESSAGE: ; ; REMOVE IT FROM QUEUE,AND PROCESS IT ; ; ESI IS PREVIOUS IN QUEUE ; MOV AX,[EDI] ; NEXT IN CHAIN MOV [ESI],AX ; CHAIN TO PREVIOUS MOV BUFFER,EDI ; SAVE ADDRESS INC L2RESEQ[EBP] 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. ; PUBLIC RESET2 RESET2: CALL CLEARL2QUEUES PUBLIC RESET2X RESET2X: XOR AL,AL MOV SDREJF[EBX],AL ; CLEAR FRAME REJECT FLAGS MOV LINKWS[EBX],AL ; CLEAR WINDOW POINTERS MOV LINKOWS[EBX],AL MOV LINKNR[EBX],AL ; CLEAR N(R) MOV LINKNS[EBX],AL ; CLEAR N(S) MOV SDTSLOT[EBX],AL MOV L2STATE[EBX],5 ; RESET STATE MOV L2FLAGS[EBX],0 RET PUBLIC CLEARL2QUEUES CLEARL2QUEUES: ; ; GET RID OF ALL FRAMES THAT ARE QUEUED ; LEA ESI,FRAMES[EBX] MOV ECX,8 PUBLIC SDSN10 SDSN10: PUSH ESI PUSH ECX CALL Q_REM JZ SHORT SDSN15 ; NONE THERE ; CALL RELBUFF PUBLIC SDSN15 SDSN15: POP ECX POP ESI ADD ESI,4 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 ; PUBLIC SDSN20 SDSN20: LEA ESI,TX_Q[EBX] CALL SDSN50 LEA ESI,RX_Q[EBX] CALL SDSN50 LEA ESI,L2RESEQ_Q[EBX] CALL SDSN50 RET ; ; RELEASE BUFFERS CHAINED TO ESI ; PUBLIC SDSN50 SDSN50: PUSH ESI CALL Q_REM JZ SHORT SDSN30 ; FINISHED CALL RELBUFF POP ESI JMP SHORT SDSN50 PUBLIC SDSN30 SDSN30: POP ESI 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 ; PUBLIC SDNRCHK 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[EBX] ; N(R) >= WINDOW START? JC SHORT 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[EBX] ; N(R) <= WINDOW END? JC SHORT SDNR20 ; J IF YES JE SHORT SDNR20 ; J IF YES PUBLIC SDNR10 SDNR10: ; ; N(R) ABOVE N(S) - DOES COUNT WRAP? ; MOV AH,AL ; KEEP TRACK OF RECEIVED N(R) MOV AL,LINKNS[EBX] ; GET WINDOW END CMP AL,LINKWS[EBX] ; WINDOW START > WINDOW END? JNC SHORT SDNR40 ; J IF NOT (ERROR) MOV AL,AH ; RESTORE RECEIVED N(R) ; ; RECEIVED N(R) IS VALID ; PUBLIC SDNR20 SDNR20: MOV LINKWS[EBX],AL ; NEW WINDOW START = RECEIVED N(R) CALL ACKMSG RET ; PUBLIC SDNR30 SDNR30: ; ; N(R) LESS THAN WINDOW START - ONLY OK IF WINDOW WRAPS ; CMP AL,LINKNS[EBX] ; N(R) <= WINDOW END? JC SHORT SDNR20 ; J IF YES JE SHORT SDNR20 ; J IF YES ; ; RECEIVED N(R) IS INVALID ; PUBLIC SDNR40 SDNR40: OR SDREJF[EBX],SDNRER ; FLAG A REJECT CONDITION MOV AL,SDCBYTE MOV SDRBYTE,AL ; SAVE FOR FRMR RESPONSE RET ; FRAME REJECT CONDITION - SEND FRMR RESPONSE ; PUBLIC SDFRMR SDFRMR: INC L2FRMRTX[EBP] MOV L2STATE[EBX],3 ; ENTER FRMR STATE MOV AL,L2TIME[EBX] MOV AH,0 MOV L2TIMER[EBX],AX ; SET TIMER MOV EDI,ADJBUFFER MOV MSGCONTROL[EDI],FRMR ; CONTROL BYTE = FRMR MOV AL,SDRBYTE ; MOVE REJECT C-BYTE MOV MSGCONTROL+1[EDI],AL MOV AL,LINKNR[EBX] ; 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[EBX] ; GET OUR N(S) SHL AL,1 ; SHIFT TO BITS 1-3 OR AL,AH ; COMBINE WITH N(S) MOV MSGCONTROL+2[EDI],AL ; STORE MOV AL,SDREJF[EBX] ; MOVE REJECT FLAGS TO IDP MOV MSGCONTROL+3[EDI],AL LEA ECX,MSGCONTROL+4[EDI] ; END OF MESSAGE MOV EDI,BUFFER SUB ECX,EDI ; CALCULATE LENGTH MOV MSGLENGTH[EDI],CX ; SET UP BYTE COUNT CALL L2SWAPADDRESSES ; SWAP ADDRESSES AND SET RESP BITS CALL L2QUEUEONPORT ; SEND DIRECT TO PORT ; RET ; PUBLIC L2SENDCOMMAND L2SENDCOMMAND: ; ; SEND COMMAND IN AL ; CALL SETUPL2MESSAGE JZ SHORT L2NOBUFFS ; NO BUFFERS - SET TIMER TO FORCE RETRY ; OR BYTE PTR MSGDEST+6[EDI],80H ; SET COMMAND PUSH EAX CALL L2QUEUEFRAME POP EAX TEST AL,PFBIT ; RESPONSE EXPECTED? JZ SHORT L2SCRET ; NO MOV L2TIMER[EBX],ONEMINUTE ; SET TIMER ; ; FLAG BUFFER TO CAUSE TIMER TO BE RESET AFTER SEND ; MOV BUFFLEN-4[EDI],EBX RET PUBLIC L2NOBUFFS L2NOBUFFS: TEST AL,PFBIT ; RESPONSE EXPECTED? JZ SHORT L2SCRET ; NO MOV L2TIMER[EBX],10*3 ; SET TIMER ; PUBLIC L2SCRET L2SCRET: RET PUBLIC SETUPL2MESSAGE SETUPL2MESSAGE: PUSH EAX CALL GETBUFF POP EAX JZ SHORT L2SETUPCMD99 ; NO BUFFER - JUST PRETEND, AND SET TIMER PUSH EDI CALL SETUPADDRESSES ; SET UP ADDRESS STRING STOSB ; COMMAND BYTE MOV ECX,EDI POP EDI SUB ECX,EDI MOV MSGLENGTH[EDI],CX ; SET LENGTH ; PUBLIC L2SETUPCMD99 L2SETUPCMD99: RET PUBLIC L2QUEUEFRAME L2QUEUEFRAME: ; ; QUEUE IT FOR TRANSMISSION ; PUSH EBX MOV AL,LINKPORT[EBX] MOV MSGPORT[EDI],AL CALL GETPORTTABLEENTRY ; POINT TO PORT CALL PUT_ON_PORT_Q POP EBX RET PUBLIC SETUPADDRESSES SETUPADDRESSES: ; ; COPY ADDRESSES FROM LINK TABLE TO MESSAGE BUFFER ; LEA ESI,LINKCALL[EBX] LEA EDI,MSGDEST[EDI] ; MOV ECX,14 REP MOVSB ; COPY DEST AND ORIGIN OR BYTE PTR -1[EDI],60H ; SET FIXED BITS OR BYTE PTR -8[EDI],60H ; MOV ECX,MAXDIGIS JCXZ SETUPEND ; DIGIS NOT ALLOWED PUBLIC SETUPADDRESS00 SETUPADDRESS00: CMP BYTE PTR [ESI],0 ; END OF LIST JE SHORT SETUPEND PUSH ECX MOV ECX,7 REP MOVSB ; COPY CALLSIGN POP ECX LOOP SETUPADDRESS00 ; COPY ANOTHER CALL PUBLIC SETUPEND SETUPEND: OR BYTE PTR -1[EDI],1 ; SET END OF ADDRESSES ; ; RETURN EDI POINTING TO COMMAND BYTE LOCATION ; RET PUBLIC ACKMSG ACKMSG: ; ; RELEASE ANY ACKNOWLEDGED FRAMES ; MOV AL,LINKOWS[EBX] ; GET OLD WINDOW START CMP AL,LINKWS[EBX] ; EQUAL TO NEW WINDOW START? JE SHORT SDET05 ; J IF YES ; SDGETS AL ; GET SLOT ADDR IN ESI INC LINKOWS[EBX] ; INCREMENT OLD WINDOW START AND LINKOWS[EBX],7 ; MODULO 8 ; ; SOMETHING HAS BEEN ACKED - RESET RETRY COUNTER ; CMP L2RETRIES[EBX],0 JE SHORT LEAVEIT MOV L2RETRIES[EBX],1 ; MUSTN'T SET TO ZERO - COULD CAUSE ; PREMATURE RETRANSMIT PUBLIC LEAVEIT LEAVEIT: CALL Q_REM JZ SHORT ACKMSG ; NONE THERE!! ; CALL RELBUFF ; JMP SHORT ACKMSG PUBLIC SDET05 SDET05: CMP AL,LINKNS[EBX] ; IS N(S) = NEW WINDOW START? JE SHORT SDET10 ; JUMP IF IT IS ; ; NOT ALL I-FRAMES HAVE BEEN ACK'ED - RESTART TIMER ; MOV AL,L2TIME[EBX] MOV AH,0 MOV L2TIMER[EBX],AX RET PUBLIC SDET10 SDET10: ; ; ALL FRAMES HAVE BEEN ACKED - CANCEL TIMER UNLESS RETRYING ; IF RETRYING, MUST ONLY CANCEL WHEN RR(F) RECEIVED ; CMP VER1FLAG[EBX],1 JE SHORT SDET11 ; STOP TIMER IF LEVEL 1 CMP L2RETRIES[EBX],0 JNE SHORT SDET12 ; RETRYING PUBLIC SDET11 SDET11: MOV L2TIMER[EBX],0 AND L2FLAGS[EBX],NOT POLLSENT; CLEAR I(P) SET (IN CASE TALKING TO OLD BPQ!) PUBLIC SDET12 SDET12: ; ; IF DISCONNECT REQUEST OUTSTANDING, AND NO FRAMES ON TX QUEUE, ; SEND DISC ; TEST L2FLAGS[EBX],DISCPENDING JZ SHORT SDET13 ; NO DISC PENDING CMP TX_Q[EBX],0 JNE SHORT SDET13 ; STILL MORE TO SEND AND L2FLAGS[EBX],NOT DISCPENDING MOV L2TIMER[EBX],1 ; USE TIMER TO SEND DISC MOV L2STATE[EBX],4 ; DISCONNECTING PUBLIC SDET13 SDET13: RET ; PUBLIC SDETX SDETX: ; ; SEE IF EXTERNAL L2 LINK ; PUSH EBX CALL GETPORTTABLEENTRY MOV EBP,EBX ; PORT TO BP POP EBX CMP PORTTYPE[EBP],EXTERNAL JNE SHORT NOTEXT CMP PROTOCOL[EBP],L2 JNE SHORT NOTEXT ; ; EXTERNAL DRIVER IS PROVIDING L2 FUNCTIONS: ; ; CALL IT TO SEE IF IT HAS BUFFER SPACE AVAILABLE, AND IF SO PASS MSG ; TO IT ; IF 0 PUSHF MOV AH,4 ; STATUS CALL PORT_EXT_ADDR[EBP] LEA ESI,TX_Q[EBX] CALL Q_REM PUSHF MOV AH,8 ; L2 SEND ? CALL PORT_EXT_ADDR[EBP] ENDIF RET PUBLIC NOTEXT NOTEXT: ; ; DONT SEND IF RESEQUENCING RECEIVED FRAMES - CAN CAUSE FRMR PROBLEMS ; CMP L2RESEQ_Q[EBX],0 JNE SHORT SDET32A ; DONT SEND ; ; SEE IF AT WINDOW LIMIT ; ; CMP RECENT_REJ[EBX],0 ; JNE SHORT SDET32A ; DONT SEND TILL WAIT TIMER EXPIRES MOV AL,LINKNS[EBX] SUB AL,LINKOWS[EBX] ; WINDOW START JNC SHORT SDET31 ; NO WRAP ADD AL,8 ; ALLOW FOR WRAP PUBLIC SDET31 SDET31: CMP AL,LINKWINDOW[EBX] ; LIMIT JC SHORT SDET33 ; OK PUBLIC SDET32A SDET32A: RET ; CANT SEND ANY MORE YET PUBLIC SDET33 SDET33: SDGETS SDTSLOT[EBX] ; CALCULATE TX SLOT ADDR (IN ESI) CMP WORD PTR [ESI],0 ; IS NEXT SLOT EMPTY? JNE SHORT SDET20 ; J IF NOT (NO ROOM IN CCB) ; PUSH ESI LEA ESI,TX_Q[EBX] CALL Q_REM POP ESI JZ SHORT SDET20 ; J IF QUEUE EMPTY CALL _Q_ADD ; PUT MESSAGE ADDR IN SLOT SDUPDS SDTSLOT[EBX] ; UPDATE IT JMP SDETX ; PUBLIC SDET20 SDET20: TEST L2FLAGS[EBX],POLLSENT JNZ SHORT SDET50 ; P BIT OUTSTANDING - WAIT SDGETS LINKNS[EBX] ; CALCULATE SLOT OFFSET32 CMP DWORD PTR [ESI],0 JZ SHORT SDET50 ; NOTHING TO SEND ; ; GET BUFFER FOR COPY OF MESSAGE - HAVE TO KEEP ORIGINAL FOR RETRIES ; MOV ESI,[ESI] ; GET BUFFER ADDR PUSH ESI CALL GETBUFF POP ESI JNZ SHORT SDETOK ; ; CANNOT SEND AN I-FRAME ; PUBLIC SDET50 SDET50: RET PUBLIC SDETOK SDETOK: PUSH EDI ; SAVE BUFFER START ADDR PUSH ESI ; SAVE MESSAGE ADDRESS CALL SETUPADDRESSES ; GET ADDRESSES FROM LINK TABLE ; ; EDI NOW POINTS TO COMMAND BYTE ; ; GOING TO SEND I FRAME - WILL ACK ANY RECEIVED FRAMES ; MOV L2ACKREQ[EBX],0 ; CLEAR ACK NEEDED MOV AX,T3 MOV L2SLOTIM[EBX],AX ; SET FRAME SENT RECENTLY MOV KILLTIMER[EBX],0 ; RESET IDLE CIRCUIT TIMER ; ; FLAG BUFFER TO CAUSE TIMER TO BE RESET AFTER SEND ; MOV AL,LINKNR[EBX] ; GET CURRENT N(R) ROR AL,4 ; SHIFT IT TO TOP 3 BITS OR AL,LINKNS[EBX] ; BITS 1-3 OF CONTROL BYTE ROL AL,1 INC LINKNS[EBX] ; INCREMENT NS AND LINKNS[EBX],7 ; ; SET P BIT IF END OF WINDOW OR NO MORE TO SEND ; CMP VER1FLAG[EBX],1 JE SHORT SDET25 ; NO POLL BIT IF V1 MOV AH,LINKNS[EBX] SUB AH,LINKOWS[EBX] ; WINDOW START JNC SHORT SDET22 ; NO WRAP ADD AH,8 ; ALLOW FOR WRAP PUBLIC SDET22 SDET22: CMP AH,LINKWINDOW[EBX] ; LIMIT JNC SHORT SDET24 ; CANT SEND ANY MORE YET ; ; SEE IF MORE TO GO ; PUSH EAX SDGETS LINKNS[EBX] ; CALCULATE SLOT OFFSET POP EAX CMP DWORD PTR [ESI],0 JNZ SHORT SDET25 ; MORE TO SEND ; PUBLIC SDET24 SDET24: OR AL,PFBIT OR L2FLAGS[EBX],POLLSENT PUBLIC SDET25 SDET25: STOSB ; TO DATA (STARTING WITH PID) POP ESI ; GET MESSAGE MOVZX ECX,MSGLENGTH[ESI] ; GET LENGTH ADD ESI,7 ; SKIP CHAIN, PORT, LENGTH SUB ECX,7 JC SHORT SDET32 JCXZ SDET32 ; SHOULD ALWAYS BE A PID, BUT BETTER SAFE THAN SORRY ; REP MOVSB ; COPY MESSAGE PUBLIC SDET32 SDET32: MOV ECX,EDI POP EDI OR BYTE PTR MSGDEST+6[EDI],80H ; SET COMMAND SUB ECX,EDI MOV MSGLENGTH[EDI],CX ; SET NEW LENGTH MOV L2TIMER[EBX],ONEMINUTE ; (RE)SET TIMER ; ; FLAG BUFFER TO CAUSE TIMER TO BE RESET AFTER SEND ; MOV BUFFLEN-4[EDI],EBX MOV AL,LINKPORT[EBX] MOV MSGPORT[EDI],AL ; PUSH EBX CALL GETPORTTABLEENTRY ; POINT TO PORT CALL PUT_ON_PORT_Q POP EBX JMP SDETX ; SEE IF MORE ; PUBLIC ADJUSTFORDIGIS ADJUSTFORDIGIS: ; ; ADJUST EDI TO ALLOW FOR DIGIS IN MSG HEADER ; MOV ECX,8 ; MAX DIGIS PUBLIC ADJDIGI00 ADJDIGI00: TEST MSGORIGIN+6[EDI],1 JNZ SHORT ADJDIGI10 ; END OF LIST ADD EDI,7 SUB AX,7 ; LENGTH ; LOOP ADJDIGI00 ; MUST BE OK TO HAVE GOT THIS FAR PUBLIC ADJDIGI10 ADJDIGI10: RET PUBLIC _L2SETUPCROSSLINK _L2SETUPCROSSLINK: ; ; BX POINTS TO A NEIGHBOUR - FIND AN L2 SESSION FROM US TO IT, OR ; INITIATE A NEW ONE ; MOV AL,NEIGHBOUR_PORT[EBX] MOV COMPAREPORT,AL ; SET PORT PUSH EBX MOV EDI,OFFSET32 COMPAREFIELD MOV ESI,OFFSET32 _NETROMCALL MOV ECX,7 REP MOVSB LEA ESI,NEIGHBOUR_CALL[EBX] MOV ECX,7 REP MOVSB ; MOV EDI,OFFSET32 COMPAREFIELD CALL FINDLINKXX ; GET LINK FOR THIS ADDRESS PAIR (IN BX) ; JNZ SHORT L2SETUP10 ; NOT FOUND ; ; SESSION ALREADY EXISTS ; MOV LINKTYPE[EBX],3 ; MAKE SURE IT KNOWS ITS A CROSSLINK MOV ESI,EBX POP EBX MOV NEIGHBOUR_LINK[EBX],ESI MOV NEIGHBOUR[ESI],EBX RET PUBLIC L2SETUP10 L2SETUP10: ; ; SET UP NEW SESSION (OR RESET EXISTING ONE) ; CMP EBX,0 JNE SHORT L2SETUP20 ; ; NO FREE ENTRIES ; POP EBX RET PUBLIC L2SETUP20 L2SETUP20: ; ; COPY ADDRESS INFO TO LINK TABLE ; POP ESI ; NEIGHBOUR TABLE MOV NEIGHBOUR_LINK[ESI],EBX MOV NEIGHBOUR[EBX],ESI MOV AL,NEIGHBOUR_PORT[ESI] MOV LINKPORT[EBX],AL ; SET PORT PUSH EBX CALL GETPORTTABLEENTRY MOV EBP,EBX ; PORT TO BP POP EBX ; ; IF ROUTE HAS A FRACK, SET IT ; MOV AL,NBOUR_FRACK[ESI] OR AL,AL JNZ SHORT SETFRACK ; ; NO ROUTE VALUE, SO SET LINK VALUE ; MOV AL,PORTT1[EBP] PUBLIC SETFRACK SETFRACK: MOV L2TIME[EBX],AL ; SET TIMER VALUE MOV TEMP,AL ; SAVE ; ; IF ROUTE HAS A WINDOW, SET IT ; MOV AL,NBOUR_MAXFRAME[ESI] OR AL,AL JNZ SHORT SETMAXF ; ; NO ROUTE VALUE, SO SET LINK VALUE ; MOV AL,PORTWINDOW[EBP] PUBLIC SETMAXF SETMAXF: MOV LINKWINDOW[EBX],AL MOV L2STATE[EBX],2 PUSH ESI LEA ESI,NEIGHBOUR_CALL[ESI] LEA EDI,LINKCALL[EBX] MOV ECX,7 REP MOVSB PUSH ESI MOV ESI,OFFSET32 _NETROMCALL LEA EDI,OURCALL[EBX] ; OUR CALL/ALIAS BEING USED MOV ECX,7 REP MOVSB ; POP ESI ; ; ADD ANY DIGI CALLS, AND ADJUST FRACK ; CMP BYTE PTR [ESI],0 JE SHORT NODIGI MOV AL,TEMP ADD AL,AL ADD L2TIME[EBX],AL MOV ECX,7 REP MOVSB ; ADD DIGI CMP BYTE PTR [ESI],0 JE SHORT NODIGI ADD L2TIME[EBX],AL MOV ECX,7 REP MOVSB ; ADD DIGIS PUBLIC NODIGI NODIGI: MOV LINKTYPE[EBX],3 ; CROSSLINK POP ESI ; NEIGHBOUR CALL SENDSABM RET PUBLIC FINDLINK FINDLINK: LEA EDI,MSGDEST[EDI] PUBLIC FINDLINKXX FINDLINKXX: ; ; FIND LINK FOR AN ADDRESS PAIR (OUR CALL - FAR CALL) IN EDI ; MOV EBX,0 MOV ESI,LINKS MOVZX ECX,MAXLINKS PUBLIC FINDLK00 FINDLK00: CMP BYTE PTR [ESI],0 JNE SHORT FINDLK05 ; NOT A SPARE ENTRY CMP EBX,0 JNE SHORT FINDLK10 ; ALREADY FOUND A SPARE MOV EBX,ESI ; POINTER TO FIRST FREE JMP SHORT FINDLK10 ; TRY NEXT ENTRY PUBLIC FINDLK05 FINDLK05: MOV AL,LINKPORT[ESI] CMP AL,COMPAREPORT JNE SHORT FINDLK10 ; WRONG PORT PUSH ESI PUSH EDI PUSH ECX LEA EDI,7[EDI] ; ORIGIN FROM MESSAGE CALL COMPARECALLS ; COMPARE WITH LINKCALL POP ECX POP EDI POP ESI JNE SHORT FINDLK10 PUSH ESI PUSH EDI PUSH ECX ADD ESI,7 ; OURCALL IN TABLE CALL COMPARECALLS ; COMPARE WITH DESTINATON IN MSG POP ECX POP EDI POP ESI JE SHORT FINDLKRET ; YES PUBLIC FINDLK10 FINDLK10: ADD ESI,TYPE LINKTABLE LOOP FINDLK00 ; ; ENTRY NOT FOUND - BX HAS FIRST FREE ENTRY, OR ZERO IF TABLE FULL ; OR AL,1 ; SET NZ RET PUBLIC FINDLKRET FINDLKRET: MOV EBX,ESI XOR AL,AL RET PUBLIC COMPARECALLS COMPARECALLS: ; ; COMPARE AX25 CALLSIGNS IN ESI, EDI IGNORING EXTRA BITS IN SSID ; MOV ECX,6 REP CMPSB ; COMPARE JNE SHORT COMPCALLRET ; DONT MATCH LODSB MOV AH,[EDI] AND AX,0001111000011110B ; MASK NON-SSID BITS CMP AL,AH PUBLIC COMPCALLRET COMPCALLRET: RET PUBLIC GETPORTWINDOW GETPORTWINDOW: PUSH EBX MOV AL,LINKPORT[EBX] CALL GETPORTTABLEENTRY MOV AL,PORTWINDOW[EBX] POP EBX RET PUBLIC GETPORTPACLEN GETPORTPACLEN: PUSH EBX MOV AL,LINKPORT[EBX] CALL GETPORTTABLEENTRY MOV AL,PORTPACLEN[EBX] POP EBX RET PUBLIC RR_OR_RNR RR_OR_RNR: AND L2FLAGS[EBX],NOT RNRSENT ; ; SET UP APPROPRIATE SUPER COMMAND ; CMP LINKTYPE[EBX],3 JE SHORT CHKBUFFS ; NODE TO NODE - ONLY BUSY IF SHORT OF BUFFERS ; ; UP OR DOWN LINK - SEE IF SESSION IS BUSY ; CMP CIRCUITPOINTER[EBX],0 JE SHORT CHKBUFFS ; NOT CONNECTED ; ; UPLINK WITH CIRCUIT ; PUSH EBX ; SAVE LINK MOV EBX,CIRCUITPOINTER[EBX] ; TO CIRCUIT ENTRY CALL CHECKIFBUSYL2 ; TARGET SESSION BUSY? POP EBX TEST AL,L4BUSY JNZ SHORT SENDRNR ; BUSY PUBLIC CHKBUFFS CHKBUFFS: MOV AH,RR CMP QCOUNT,20 JBE SHORT SENDRNR ; NOT ENOUGH ; ; SEND REJ IF IN REJ STATE ; CMP L2STATE[EBX],6 JNE SHORT HTIM142 ; OK MOV AH,REJ RET PUBLIC SENDRNR SENDRNR: MOV AH,RNR ; RUNNING SHORT OR L2FLAGS[EBX],RNRSENT ; REMEMBER PUBLIC HTIM142 HTIM142: RET PUBLIC COUNTLINKS COUNTLINKS: ; ; COUNT LINKS ON PORT IN AL ; MOV ESI,LINKS MOVZX ECX,MAXLINKS MOV AH,0 PUBLIC COUNTL00 COUNTL00: CMP BYTE PTR [ESI],0 JE SHORT COUNTL10 ; SPARE ENTRY CMP AL,LINKPORT[ESI] JNE SHORT COUNTL10 ; WRONG PORT INC AH PUBLIC COUNTL10 COUNTL10: ADD ESI,TYPE LINKTABLE LOOP COUNTL00 ; RET PUBLIC PUT_ON_PORT_Q PUT_ON_PORT_Q: ; ; TIME STAMP IT ; push ecx push edx push 0 call _time add esp,4 pop edx pop ecx MOV BUFFLEN-8[EDI],EAX PUSH EBX CMP TXPORT[EBX],0 JE SHORT NORMALPORT ; ; NEED TO SEND TO DIFERENT PORT ; MOV AL,TXPORT[EBX] MOV MSGPORT[EDI],AL ; CHANGE HEADER (FOR KISS TX) CALL GETPORTTABLEENTRY PUBLIC NORMALPORT NORMALPORT: LEA ESI,PORTTX_Q[EBX] CALL _Q_ADD ; PUT ON QUEUE POP EBX RET PUBLIC MHPROC MHPROC: ; ; MAINTAIN MHEARD LIST ; CMP PORTMHEARD[EBX],0 JE SHORT MHRET ; NOT ENABLED ; ; GET CONTROL BYTE ; PUSH EDI MOV ECX,8 ; MAX DIGIS PUBLIC CTRLLOOP CTRLLOOP: TEST BYTE PTR MSGCONTROL-1[EDI],1 JNZ SHORT CTRLFOUND ADD EDI,7 LOOP CTRLLOOP ; ; INVALID FRAME ; POP EDI PUBLIC MHRET MHRET: RET PUBLIC CTRLFOUND CTRLFOUND: MOV AL,MSGCONTROL[EDI] POP EDI ; ; Allow All frames to update MH ; TEST AL,1 ; I FRAME ; JZ SHORT MHIFRAME ; AND AL,NOT PFBIT ; CLEAR P/F ; CMP AL,3 ; UI ; JNE SHORT MHRET ; ONLY USE I AND UI FRAMES ; ; PUBLIC MHIFRAME ;MHIFRAME: ; ; LOOK FOR CALL IN LIST ; MOV ESI,PORTMHEARD[EBX] LEA EDI,MSGORIGIN[EDI] MOV ECX,MHENTRIES ; MAX ENTRIES PUBLIC MHF000 MHF000: CMP BYTE PTR [ESI],0 JE SHORT MHF120 ; EMPTY ENTRY FOUND - USE IT PUBLIC MHF005 MHF005: PUSH ECX PUSH EDI PUSH ESI CALL COMPARECALLS ; COMPARE WITH LIST POP ESI POP EDI POP ECX JE SHORT MHF120 ; FOUND ADD ESI,TYPE MHSTRUC LOOP MHF000 ; ; TABLE FULL AND ENTRY NOT FOUND - MOVE DOWN ONE, AND ADD TO TOP ; MOV ECX,((MHENTRIES-1)*TYPE MHSTRUC) JMP SHORT MHF130 PUBLIC MHF120 MHF120: ; ; ENTRY FOUND - MOVE EARLIER ONES DOWN, AND PUT ON FRONT ; MOV EAX,MHENTRIES SUB EAX,ECX JZ SHORT MHF140 ; FIRST ENTRY MUL MHLEN MOV ECX,EAX PUBLIC MHF130 MHF130: MOV ESI,PORTMHEARD[EBX] ADD ESI,(TYPE MHSTRUC)-1 ADD ESI,ECX ; TO END + LEN-1 MOV EDI,ESI SUB ESI,TYPE MHSTRUC ; TO END STD REP MOVSB CLD PUBLIC MHF140 MHF140: MOV EDI,PORTMHEARD[EBX] MOV ESI,BUFFER LEA ESI,MSGORIGIN[ESI] MOV DL,6[ESI] ; SAVE LAST BYTE OF CALL (FOR DIGI CHK) MOV ECX,7 REP MOVSB ; COPY CALL SUB EDI,7 ; ; GET TIME FROM BIOS push edx push 0 call _time add esp,4 pop edx MOV DWORD PTR MHTIME[EDI],EAX MOV MHDIGI[EDI],20H ; ASSUME NOT DIGI-ED TEST DL,1 JNZ SHORT 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 ESI,BUFFER TEST BYTE PTR MSGORIGIN+7+6[ESI],80H JZ SHORT MHRET1 ; NOT DIGIED - MUST HAVE HEARD IT DIRECT MOV MHDIGI[EDI],'*' PUBLIC MHRET1 MHRET1: RET CHECKIFBUSYL2: ; ; RETURN TOP BIT OF AL SET IF SESSION PARTNER IS BUSY ; MOV AH,0 PUSH ESI MOV ESI,EBX ; COUNT QUEUED USES ESI CMP L4CROSSLINK[EBX],0 ; CONNECTED? JNE CHECKBPARTNER ; ; IF NOT CONNECTED, CHECK L4 AND L2 TX QUEUES ; (TO STOP TERMINAL KILLING NODE BY SENDING LOTS ; OF COMMANDS TO CMD HANDLER) ; CALL COUNT_QUEUED_FRAMES ; ; COUNT NUMBER OF FRAMES QUEUED ON A SESSION (IN SI) ; RETURN TOTAL IN AL, NUMBER QUEUED ABOVE LINK IN AH (FOR HOST MODE TESTS) ; JMP SHORT CHECKBTEST ; CHECKBPARTNER: MOV ESI,L4CROSSLINK[EBX] ; TO PARTNER CALL COUNT_QUEUED_FRAMES ; FRAMES NOT ACKED CHECKBTEST: MOV AH,AL CMP AL,10 JBE SHORT CHECKBRET ; NOT BUSY ; ; NUMBER QUEUED = WINDOW - STOP SENDING ; MOV AL,L4BUSY POP ESI RET CHECKBRET: MOV AL,0 POP ESI RET _TEXT ENDS END