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.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	Send RST
				
				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.OUTSENTSEQ,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
				.DO IPDEBUG=1
				jsr DEBUG.IPID
				.FIN
				jsr SKT.GetTCB

				ldy #S.TCP.OPTIONS
				lda (ZPFrameInPtr),y
				and #S.TCP.OPTIONS.ACK	Remote side ACKed data ?
				beq .4
* Ack sent data 
				ldy #S.TCP.ACKNUM+3		Get new ACK number from FrameIn...
				ldx #3					Substract old ACK from socket

				sec

.1				lda (ZPFrameInPtr),y
				pha
				sbc SKT.Cache+S.SOCKET.TCP.OUTSENTSEQ,x
				sta TmpDWord,x
				pla						....and Set SEQ = new SEQ
				sta SKT.Cache+S.SOCKET.TCP.OUTSENTSEQ,x
				dey
				dex
				bpl .1

				lda TmpDWord+3
				ldx TmpDWord+2
				bne .2
				tay
				beq .4

.2				pha

				clc
				adc SKT.Cache+S.SOCKET.TCP.OUTTAIL
				sta SKT.Cache+S.SOCKET.TCP.OUTTAIL

				txa
				adc SKT.Cache+S.SOCKET.TCP.OUTTAIL+1
				and /K.TCP.WSIZE-1
				sta SKT.Cache+S.SOCKET.TCP.OUTTAIL+1
				
				pla
				
				clc
				adc SKT.Cache+S.SOCKET.TCP.OUTFREE
				sta SKT.Cache+S.SOCKET.TCP.OUTFREE
				
				txa
				adc SKT.Cache+S.SOCKET.TCP.OUTFREE+1
				sta SKT.Cache+S.SOCKET.TCP.OUTFREE+1

				lda SKT.Cache+S.SOCKET.TCP.OUTUSED
				sec
				sbc TmpDWord+3
				sta SKT.Cache+S.SOCKET.TCP.OUTUSED
				lda SKT.Cache+S.SOCKET.TCP.OUTUSED+1
				sbc TmpDWord+2
				sta SKT.Cache+S.SOCKET.TCP.OUTUSED+1

*				jsr SKT.StoreTCB
* Store incoming data
.4				jsr TCP.IN.SetDataInPtrAndLen
				
				lda ZPDataInLen			Incoming Data in this frame ?
				ora ZPDataInLen+1
				beq .7					No data, ...

				ldy #S.TCP.SEQNUM+3
				ldx #3

.5				lda (ZPFrameInPtr),y
				eor SKT.Cache+S.SOCKET.TCP.INSEQNUM,x
				bne .9					Missed a frame.....

				dey
				dex
				bpl .5

				jsr SKT.AddDataToSktIn	yes, queue data if there is room for....
				bcs .9					Should never appends....

				lda SKT.Cache+S.SOCKET.TCP.INSEQNUM+3
*				clc
				adc ZPDataInLen
				sta SKT.Cache+S.SOCKET.TCP.INSEQNUM+3

				lda SKT.Cache+S.SOCKET.TCP.INSEQNUM+2
				adc ZPDataInLen+1
				sta SKT.Cache+S.SOCKET.TCP.INSEQNUM+2
				bcc .6
				inc SKT.Cache+S.SOCKET.TCP.INSEQNUM+1
				bne .6
				inc SKT.Cache+S.SOCKET.TCP.INSEQNUM

.6				jsr SKT.StoreTCB		update socket
				
				jsr TCP.SetSocketTCPO.ACK	...and ack data
				
.7				ldy #S.TCP.OPTIONS
				lda (ZPFrameInPtr),y
				and #S.TCP.OPTIONS.FIN
				beq .8

				lda #S.SOCKET.TCP.S.CLWAIT
				ldy #S.SOCKET.TCP.S
				sta (ZPPtrSKT),y
				
				jsr TCP.IN.ACKTheFIN
				lda #S.TCP.OPTIONS.FIN+S.TCP.OPTIONS.ACK
				jsr TCP.SetSocketTCPO	FIN received, Send FIN.ACK		
				
.8				jsr TCP.OUT				Send ACK as soon as possible

.9				
*				clc
*				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 ACK packet
				lda (ZPFrameInPtr),y

				bit #S.TCP.OPTIONS.ACK
				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.INSEQNUM,x
				dey
				dex
				bpl .3

				rts
*--------------------------------------
TCP.IN.ACKTheFIN
				jsr TCP.SetSocketTCPO.ACK
				
				ldx #3
				
.1				inc	SKT.Cache+S.SOCKET.TCP.INSEQNUM,x
				bne .8
				dex
				bpl .1

.8				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.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 SKT.GetTCB
				jsr TCP.OUT
				
				bra .8
				
.4				ldy #S.SOCKET.SQ.hInMem
				lda (ZPPtrSKT),y
				beq .5
				.DO AUXPIPE=1
				>SYSCALL2 FreeStkObj
				.ELSE
				>SYSCALL2 freemem
				.FIN
				
.5				ldy #S.SOCKET.SQ.hOutMem
				lda (ZPPtrSKT),y
				beq .6

				.DO AUXPIPE=1
				>SYSCALL2 FreeStkObj
				.ELSE
				>SYSCALL2 freemem
				.FIN
				
.6				plx
				phx
				lda SKT.TABLE,x
				stz SKT.TABLE,x
				>SYSCALL2 freemem
				
.8				plx
				inx
				cpx #K.SKTTABLE.SIZE
				bne .1

.9				rts
*--------------------------------------
TCP.OUT			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
.9				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 .9

				jsr SKT.GetDataFromSktOut
								
				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
				
				lda #S.TCP.OPTIONS.ACK+S.TCP.OPTIONS.PSH
				
				jsr TCP.OUT.Send
				
				bcs .9
				
				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.OUT.Send.9

				ldy #S.SOCKET.TCP.INFREE+1
				lda (ZPPtrSKT),y
				tax
				dey
				lda (ZPPtrSKT),y
				
				ldy #S.TCP.WINDOW+1
				sta (ZPFrameOutPtr),y
				dey
				txa
				sta (ZPFrameOutPtr),y

				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.INSEQNUM,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

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

*				clc
TCP.OUT.Send.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
				
				clc
.9				rts
*--------------------------------------
				.DO IPDEBUG=1
DEBUG.IPID		ldy #S.IP.IDENTIFICATION
				lda (ZPFrameInPtr),y
				>PUSHA
				iny
				lda (ZPFrameInPtr),y
				>PUSHA
				>PUSHBI 2
				>LDYA L.MSG.IPID
				>SYSCALL printf
				rts
				.FIN
*--------------------------------------
MAN
SAVE USR/SRC/LIB/LIBTCPIP.S.TCP
LOAD USR/SRC/LIB/LIBTCPIP.S
ASM
