NEW
  AUTO 3,1
				.LIST OFF	
*--------------------------------------
TCP.IN			jsr FRM.GetTargetSKT.TCPUDP

				jsr SKT.FindMatchingLocRem
				bcs TCP.IN.JMP.CLOSED	no socket, go discard

				ldy #S.SOCKET.PROTO
				lda (ZPPtrSKT),y
				cmp #S.IP.PROTOCOL.TCP
				bne TCP.IN.JMP.CLOSED	wrong protocol, go discard
			
				ldy #S.TCP.OPTIONS
				lda (ZPFrameInPtr),y
				and #S.TCP.OPTIONS.RST	RST ? go Kill this socket...
				bne TCP.IN.RST			...and discard frame
				
				ldy #S.SOCKET.TCP.S
				lda (ZPPtrSKT),y
				asl
				tax
				jmp (J.TCP.IN,x)
*--------------------------------------
TCP.IN.RST		lda SKT.TABLE,x
				jsr SKT.shutdown
*--------------------------------------
TCP.IN.JMP.CLOSED
				lda hFrameIn
				stz hFrameIn
				>SYSCALL2 FreeMem
				rts
*--------------------------------------
TCP.SENDCLOSE	ldx #0

.1				phx
				lda SKT.TABLE,x
				beq .8
				
				>SYSCALL2 GetMemPtr
				>STYA ZPPtrSKT

				ldy #S.SOCKET.AF
				lda (ZPPtrSKT),y
				cmp #AF.INET
				bne .8
				
				iny					#S.SOCKET.T
				
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.T.SEQPACKET
				bcc .8
				
				ldy #S.SOCKET.TCP.S
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.TCP.S.TIMEWT
				beq .4
				
				cmp #S.SOCKET.TCP.S.ESTBLSH
				bne .8
				
				jsr TCP.OUT
				
				bra .8
				
.4				ldy #S.SOCKET.SQ.hInMem
				lda (ZPPtrSKT),y
				>SYSCALL2 freemem
				
				ldy #S.SOCKET.SQ.hOutMem
				lda (ZPPtrSKT),y
				>SYSCALL2 freemem
				
				plx
				phx
				lda SKT.TABLE,x
				>SYSCALL2 freemem
				
				plx
				phx
				stz SKT.TABLE,x
				
.8				plx
				inx
				cpx #K.SKTTABLE.SIZE
				bne .1

.9				rts
*--------------------------------------
TCP.IN.JMP.LISTEN
				ldy #S.SOCKET.T			Create a new client socket
				lda (ZPPtrSKT),y
				tax						Same type a listening socket
				iny						#S.SOCKET.PROTO
				lda (ZPPtrSKT),y
				
				jsr SKT.Socket.I		get new socket in ZPTmpPtr1
				bcs TCP.IN.JMP.CLOSED

				jsr SKT.AddToQueueA		Queued successfully ?
				
				bcs TCP.IN.JMP.CLOSED	no, discard frame and new socket		

				jsr ARP.AddFromFrameInPtr
				
				lda ZPTmpPtr1
				sta ZPPtrSKT
				lda ZPTmpPtr1+1
				sta ZPPtrSKT+1

				jsr SKT.SetLocAddr
				jsr SKT.SetRemAddr

				jsr SKT.NewTCB
				bcs .99
				
				jsr TCP.IN.ACKTheSYN
				
				lda #S.TCP.OPTIONS.SYN+S.TCP.OPTIONS.ACK
				jsr TCP.OUT.SendOptA	SYN received, Send SYN.ACK
				bcs .9

				lda #S.SOCKET.TCP.S.SYNRCVD
				jmp SKT.StoreTCB.S
				
.9				lda #ERR.SKT.OOS
.99				rts
*--------------------------------------
TCP.IN.JMP.SYNSENT
				ldy #S.TCP.OPTIONS		SYN Send, only accept SYN.ACK packet, then Send ACK 
				lda (ZPFrameInPtr),y
				and #S.TCP.OPTIONS.SYN+S.TCP.OPTIONS.ACK
				cmp #S.TCP.OPTIONS.SYN+S.TCP.OPTIONS.ACK
				bne .9

				jsr SKT.GetTCB
				
				ldx #3
				ldy #S.TCP.ACKNUM+3

				sec						Check if ACK=OUTNEXTSEQ+1

.1				lda SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ,x
				adc #0
				sta	SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ,x 
				eor (ZPFrameInPtr),y
				bne .9
				dey
				dex
				bpl .1

				jsr TCP.IN.ACKTheSYN

				lda #S.TCP.OPTIONS.ACK
				jsr TCP.OUT.SendOptA	SYN.ACK recieved, Send, ACK
				bcs .9
				
				lda #S.SOCKET.TCP.S.ESTBLSH
				jmp SKT.StoreTCB.S
				
.9				lda #S.TCP.OPTIONS.RST
				jsr TCP.OUT.SendOptA
				
				ldx SKT.Index
				lda SKT.TABLE,x
				jmp SKT.shutdown
*--------------------------------------
TCP.IN.JMP.SYNRCVD
				ldy #S.TCP.OPTIONS		SYN Received, SYN.ACK Sent, only accept ACK packet
				lda (ZPFrameInPtr),y
				cmp #S.TCP.OPTIONS.ACK
				bne .8
				
				jsr SKT.GetTCB
			
				ldx #3
				ldy #S.TCP.ACKNUM+3

				sec

.1				lda	SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ,x 	Check if ACK=OUTNEXTSEQ+1
				adc #0
				sta SKT.Cache+S.SOCKET.TCP.OUTSEQNUM,x 		setup SEQNUM
				sta	SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ,x		...and update NEXTSEQ
				eor (ZPFrameInPtr),y
				bne .8
				dey
				dex
				bpl .1
				
				lda #S.SOCKET.TCP.S.ESTBLSH
				jmp SKT.StoreTCB.S
			
.8				clc
.9				rts
*--------------------------------------
TCP.IN.JMP.ESTBLSH
				jsr SKT.GetTCB

				ldy #S.TCP.OPTIONS
				lda (ZPFrameInPtr),y
				and #S.TCP.OPTIONS.ACK	Remote side ACKed data ?
				beq .1
				
				jsr SKT.AckDataToSktOut	Yes, Discard sent data
				jsr SKT.StoreTCB		and update SKT

.1				jsr TCP.IN.SetDataInPtrAndLen
				
				lda ZPDataInLen			Incoming Data in this frame ?
				ora ZPDataInLen+1
				beq .2					No data, ...

				jsr SKT.AddDataToSktIn	yes, queue data if there is room for....
				bcs .2

				jsr SKT.StoreTCB		success, update socket

*				jsr TCP.SetSocketTCPO.ACK	Try to ACK read DATA
				
*				jsr TCP.OUT.I			SKT.GetTCB already called 
				
.2				ldy #S.TCP.OPTIONS
				lda (ZPFrameInPtr),y
				and #S.TCP.OPTIONS.FIN
				beq .8

				jsr TCP.IN.ACKTheFIN
				lda #S.TCP.OPTIONS.FIN+S.TCP.OPTIONS.ACK
				jsr TCP.OUT.SendOptA	FIN received, Send FIN.ACK		
				bcs .9
				
				lda #S.SOCKET.TCP.S.CLWAIT
				jmp SKT.StoreTCB.S
				
.8				clc
.9				rts
*--------------------------------------
TCP.IN.JMP.CLWAIT
				clc						Wait for SKT.shutdown
				rts
*--------------------------------------
TCP.IN.JMP.LASTACK
				ldy #S.TCP.OPTIONS		only accept ACK packet
				lda (ZPFrameInPtr),y
				bit #S.TCP.OPTIONS.ACK
				beq .8
				
				ldy #S.SOCKET.TCP.S
				lda #S.SOCKET.TCP.S.TIMEWT
				sta (ZPPtrSKT),y
				
.8				clc
				rts
*--------------------------------------
TCP.IN.JMP.FINWT1
				jsr SKT.GetTCB
				
				ldy #S.TCP.OPTIONS		FIN sent, accept ACK or FIN/ACK packet
				lda (ZPFrameInPtr),y
				bit #S.TCP.OPTIONS.FIN
				bne .1

				lda #S.TCP.OPTIONS.FIN+S.TCP.OPTIONS.ACK
				jsr TCP.OUT.SendOptA	Send FIN.ACK		
				bcs .9

				lda #S.SOCKET.TCP.S.FINWT2
				jmp SKT.StoreTCB.S

.1				jsr TCP.IN.ACKTheFIN	FIN/ACK

				lda #S.TCP.OPTIONS.FIN+S.TCP.OPTIONS.ACK
				jsr TCP.OUT.SendOptA	Send FIN.ACK		
				bcs .9

				lda #S.SOCKET.TCP.S.TIMEWT
				jmp SKT.StoreTCB.S
				
*				clc
.9				rts
*--------------------------------------
TCP.IN.JMP.FINWT2
				ldy #S.TCP.OPTIONS		only accept FIN packet
				lda (ZPFrameInPtr),y

				bit #S.TCP.OPTIONS.FIN
				beq .8
				
				jsr SKT.GetTCB
				jsr TCP.IN.ACKTheFIN

				lda #S.TCP.OPTIONS.ACK
				jsr TCP.OUT.SendOptA	FIN received, Send ACK		
				bcs .9
			
				lda #S.SOCKET.TCP.S.TIMEWT
				jmp SKT.StoreTCB.S
				
.8				clc
.9				rts
*--------------------------------------
TCP.IN.JMP.CLOSING
				ldy #S.TCP.OPTIONS		only accept ACK packet
				lda (ZPFrameInPtr),y
				bit #S.TCP.OPTIONS.ACK
				beq .1
				
				ldy #S.SOCKET.TCP.S
				lda #S.SOCKET.TCP.S.TIMEWT
				sta (ZPPtrSKT),y
				
.1				clc
				rts
*--------------------------------------
TCP.IN.JMP.TIMEWT
				clc						Wait for TCP.Close
				rts
*--------------------------------------
TCP.IN.ACKTheSYN
				ldy #S.TCP.SEQNUM+3		Get Remote SEQ
				ldx #3
				
				sec
				
.3				lda (ZPFrameInPtr),y	Set OUTACK=SEQ+1 for new socket...
				adc #0
				sta SKT.Cache+S.SOCKET.TCP.INLASTSEQNUM,x
				sta SKT.Cache+S.SOCKET.TCP.OUTACKNUM,x
				dey
				dex
				bpl .3
				rts
*--------------------------------------
TCP.IN.ACKTheFIN
				jsr TCP.SetSocketTCPO.ACK
				
				ldx #3

				sec
				
.2				lda	SKT.Cache+S.SOCKET.TCP.INLASTSEQNUM,x
				adc #0
				sta	SKT.Cache+S.SOCKET.TCP.INLASTSEQNUM,x
				dex
				bpl .2

				ldx #3

				sec
				
.3				lda	SKT.Cache+S.SOCKET.TCP.OUTACKNUM,x
				adc #0
				sta	SKT.Cache+S.SOCKET.TCP.OUTACKNUM,x
				dex
				bpl .3

				rts
*--------------------------------------
TCP.IN.SetDataInPtrAndLen
				ldy #S.IP.TOTAL.LENGTH+1
				lda (ZPFrameInPtr),y
				sec
				sbc #S.IP-S.ETH.EII
				sta ZPDataInLen

				dey
				lda (ZPFrameInPtr),y
				sbc /S.IP-S.ETH.EII
				sta ZPDataInLen+1
				
				ldy #S.TCP.DATAOFFSET
				lda (ZPFrameInPtr),y
				and #$F0				Get TCP Header len in DWORD
				lsr
				lsr
				sta ZPDataInPtr			TMP Storage

				lda ZPDataInLen
				sec
				sbc ZPDataInPtr			TMP Storage
				sta ZPDataInLen
				
				bcs .1
				dec ZPDataInLen+1
				
.1				lda ZPFrameInPtr
				clc
				adc #S.IP
				pha
				
				lda ZPFrameInPtr+1
				adc /S.IP
				tax
				
				pla
				clc
				adc ZPDataInPtr			TMP Storage
				bcc .2
				
				inx
				
.2				sta ZPDataInPtr
				stx ZPDataInPtr+1
				
TCP.IN.RTS		rts
*--------------------------------------
TCP.OUT			jsr SKT.GetTCB 

TCP.OUT.I		lda SKT.Cache+S.SOCKET.TCP.OUTTOSEND+1
				ldy SKT.Cache+S.SOCKET.TCP.OUTTOSEND
				
				bne .1
			
				tax
				bne .1
				
*	Y,A=0 : no data to send		
		
				ldy #S.SOCKET.TCP.O
				lda (ZPPtrSKT),y
				bne TCP.OUT.SendOptA	a least an option...
				clc						No data, no flag....exit
				rts
						
.1				cpy #K.TCP.MSS
				pha
				sbc /K.TCP.MSS			OUTDATA > MSS ?
				pla
				bcc .2					no....keep data len

				>LDYAI K.TCP.MSS		yes send only MSS
				
.2				jsr TCP.NewFrame
				bcs TCP.IN.RTS

				jsr SKT.GetDataFromSktOut
								
				lda #S.TCP.OPTIONS.ACK+S.TCP.OPTIONS.PSH
				
				jsr TCP.SetSocketTCPO
				
				jsr TCP.OUT.Send
				
				bcs TCP.IN.RTS
				
				lda SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ+3
				clc
				adc ZPDataOutLen
				sta SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ+3
				
				lda SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ+2
				adc ZPDataOutLen+1
				sta SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ+2
				bcc .80
				inc SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ+1
				bne .80
				inc SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ
				
.80				jmp SKT.StoreTCB		exits with CC
*--------------------------------------
TCP.OUT.SendOptA
				jsr TCP.SetSocketTCPO

				>LDYAI 0
				jsr TCP.NewFrame
				bcs TCP.IN.RTS

				ldy #S.SOCKET.TCP.O
				lda (ZPPtrSKT),y

TCP.OUT.Send	ldy #S.TCP.OPTIONS
				sta (ZPFrameOutPtr),y
				
				bit #S.TCP.OPTIONS.ACK
				beq .2
				
				ldx #3
				ldy #S.TCP.ACKNUM+3
				
.1				lda SKT.Cache+S.SOCKET.TCP.OUTACKNUM,x
				sta (ZPFrameOutPtr),y
				dey
				dex
				bpl .1
				
.2				ldx #3
				ldy #S.TCP.SEQNUM+3
				
.3				lda SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ,x
				sta (ZPFrameOutPtr),y
				dey
				dex
				bpl .3
				
				ldy #S.TCP.WINDOW
				lda SKT.Cache+S.SOCKET.TCP.INFREE+1
				sta (ZPFrameOutPtr),y
				iny
				lda SKT.Cache+S.SOCKET.TCP.INFREE
				sta (ZPFrameOutPtr),y

				jsr FRM.SendIP
				bcs .9
				
				ldy #S.SOCKET.TCP.O
				lda #0
				sta (ZPPtrSKT),y

*				clc
.9				rts
*--------------------------------------
TCP.SetSocketTCPO.ACK
				lda #S.TCP.OPTIONS.ACK
TCP.SetSocketTCPO
				ldy #S.SOCKET.TCP.O
				ora (ZPPtrSKT),y
				sta (ZPPtrSKT),y
				rts
*--------------------------------------
TCP.NewFrame	ldx #S.IP.PROTOCOL.TCP
				jsr FRM.NewIP
				bcs .9
				
				jsr SKT.SetFrameOutDstIP

				jsr SKT.SetFrameOutTCPUDPPorts
				
				ldy #S.TCP.DATAOFFSET
				lda #$50				Header size = 5 DWORDS
				sta (ZPFrameOutPtr),y
				
				ldy #S.TCP.WINDOW
				lda SKT.Cache+S.SOCKET.TCP.INFREE+1
				sta (ZPFrameOutPtr),y
				iny
				lda SKT.Cache+S.SOCKET.TCP.INFREE
				sta (ZPFrameOutPtr),y
				
				clc
.9				rts
*--------------------------------------
MAN
SAVE USR/SRC/LIB/LIBTCPIP.S.TCP
LOAD USR/SRC/LIB/LIBTCPIP.S
ASM
