NEW
  AUTO 3,1
*--------------------------------------
TCP.IN			jsr FRM.GetTargetSKT.TCPUDP
				jsr SKT.FindMatchingLocRem
				bcs TCP.IN.JMP.DISCARD	no socket, 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 #S.SOCKET.TCP.S.TIMEWT
				ldy #S.SOCKET.TCP.S
				sta (ZPPtrSKT),y
*--------------------------------------
TCP.IN.JMP.CLOSED
TCP.IN.JMP.OPENED
TCP.IN.JMP.DISCARD
				clc
				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.DISCARD

				jsr SKT.AddToQueueA		Queued successfully ?
				bcs TCP.IN.JMP.DISCARD	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 .9

				jsr TCP.IN.ACKTheSYN

				lda #S.SOCKET.TCP.S.OPENED
				jsr SKT.StoreTCB.S

				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				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

				jsr TCP.OUT.SendACK		SYN.ACK received, 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

				jmp TCP.IN.RST
*--------------------------------------
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
				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

				bcc .7					ACK > SENT SEQ ????

				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 .90					Missed a frame.....

				dey
				dex
				bpl .5

				ldy #S.SOCKET.T
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.T.STREAM
				bne .52

				jsr SKT.AddDataToSktIn	yes, queue data if there is room for....
				bcc .6

				rts

.52				lda hFrameIn
				jsr SKT.AddToQueueA
				bcs .99

				stz hFrameIn			DON'T DISCARD

.6				lda ZPDataInLen
				ldy ZPDataInLen+1
				ldx #S.SOCKET.TCP.INSEQNUM
				jsr TCP.AddAYToSktCacheAtX

				jsr SKT.StoreTCB		update socket

.7				ldy #S.TCP.OPTIONS
				lda (ZPFrameInPtr),y
				and #S.TCP.OPTIONS.FIN
				beq .8

				jsr TCP.IN.ACKTheFIN

				jsr TCP.OUT.SendFINACK

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

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

.80				clc
.99				rts

.90
*				lda #S.TCP.OPTIONS.ACK	Send 3 ACK for last SEQ number
*				jsr TCP.OUT.SendOptA

*				lda #S.TCP.OPTIONS.ACK
*				jsr TCP.OUT.SendOptA

				lda #S.TCP.OPTIONS.ACK
.91				jmp TCP.OUT.SendOptA
*--------------------------------------
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 TCP.IN.JMP.CLWAIT

				jsr SKT.GetTCB

*				jsr TCP.OUT.SendACK

				lda #S.SOCKET.TCP.S.CLWAIT
				jmp SKT.StoreTCB.S
*--------------------------------------
TCP.IN.JMP.FINWT1
				ldy #S.TCP.OPTIONS		FIN sent, accept ACK or FIN/ACK packet
				lda (ZPFrameInPtr),y
				bit #S.TCP.OPTIONS.FIN
				bne TCP.IN.2TIMEWT		FIN/ACK

				jsr SKT.GetTCB
				lda #S.SOCKET.TCP.S.FINWT2
				jmp SKT.StoreTCB.S
*--------------------------------------
TCP.IN.JMP.FINWT2
				ldy #S.TCP.OPTIONS		FIN sent & ACKed, awaiting FIN
				lda (ZPFrameInPtr),y

				bit #S.TCP.OPTIONS.FIN
				beq TCP.IN.JMP.TIMEWT

TCP.IN.2TIMEWT	jsr SKT.GetTCB

				jsr TCP.IN.ACKTheFIN

				jsr TCP.OUT.SendACK		FIN received, Send ACK
				bcs TCP.IN.JMP.TIMEWT.RTS

				lda #S.SOCKET.TCP.S.TIMEWT
				jmp SKT.StoreTCB.S
*--------------------------------------
TCP.IN.JMP.CLOSING

* Wait for SKT.Shutdown

TCP.IN.JMP.TIMEWT
				clc						Wait for TCP.SendClose
TCP.IN.JMP.TIMEWT.RTS
				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
				sta SKT.Cache+S.SOCKET.TCP.INACKNUM,x
				dey
				dex
				bpl .3

				rts
*--------------------------------------
TCP.IN.ACKTheFIN
				ldx #3

.1				inc	SKT.Cache+S.SOCKET.TCP.INACKNUM,x
				bne .2

				dex
				bpl .1

.2				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 #1

.1				phx
				lda FDs.pHI-1,x
				beq .8

				ldy FDs.pLO-1,x
				>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.SEQPKT
				bcc .8

				tax

				ldy #S.SOCKET.TCP.S
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.TCP.S.TIMEWT
				beq .4

				cmp #S.SOCKET.TCP.S.ESTBLSH
				bne .3

				cpx #S.SOCKET.T.SEQPKT
				beq .2

				jsr TCP.OUT
				bra .8
				
.2				ldy #S.SOCKET.TCP.O
				lda (ZPPtrSKT),y
				and #S.TCP.OPTIONS.ACK
				beq .8
				
				jsr SKT.GetTCB
				jsr TCP.OUT.SendOpt
				bra .8

.3				cmp #S.SOCKET.TCP.S.OPENED
				bne .8

				jsr SKT.GetTCB
				lda #S.TCP.OPTIONS.SYN
				jsr TCP.OUT.SendOptA	Send SYN
				bcs .8					failed ARP lookup....

				lda #S.SOCKET.TCP.S.SYNSENT
				jsr SKT.StoreTCB.S
				bra .8
*--------------------------------------
.4				cpx #S.SOCKET.T.SEQPKT
				bne .6

.5				jsr SKT.GetFromQueue
				bcs .7

				>SYSCALL2 FreeMem
				bra .5

.6				ldy #S.SOCKET.SQ.hInMem
				jsr TCP.SENDCLOSE.PIPE

				ldy #S.SOCKET.SQ.hOutMem
				jsr TCP.SENDCLOSE.PIPE

.7				pla
				pha

				jsr SKT.FreeFD

.8				plx

				inx
				cpx #K.FD.MAX+1
				bcc .1

				clc
				rts

TCP.SENDCLOSE.PIPE
				lda (ZPPtrSKT),y
				beq .8

				.DO AUXPIPE=1
				>SYSCALL2 FreeStkObj
				.ELSE
				>SYSCALL2 freemem
				.FIN
.8				rts
*--------------------------------------
TCP.OUT			jsr SKT.GetTCB

				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.SendOpt		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

TCP.OUT.SEQSEND	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 TCP.OUT.Send.RTS

				lda ZPDataOutLen
				ldy ZPDataOutLen+1
				ldx #S.SOCKET.TCP.OUTNEXTSEQ
				jsr TCP.AddAYToSktCacheAtX

				jmp SKT.StoreTCB		exits with CC
*--------------------------------------
TCP.OUT.SendFINACK
				lda #S.TCP.OPTIONS.FIN+S.TCP.OPTIONS.ACK
				jsr TCP.OUT.SendOptA	Send FIN/ACK
				bcs .9

				ldx #3

.1				inc	SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ,x
				bne .9

				dex
				bpl .1

.9				rts
*--------------------------------------
TCP.OUT.SendACK	lda #S.TCP.OPTIONS.ACK

TCP.OUT.SendOptA
				jsr TCP.SetSocketTCPO

TCP.OUT.SendOpt	>LDYAI 0
				jsr TCP.NewFrame
				bcs TCP.OUT.Send.RTS

				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

*				sec						DONT Queue if fail
*				.HS 90					BCC

TCP.OUT.Send	clc						Queue if fail

				php

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

				plp						Get back Queue status

				jsr FRM.SendIP
				bcs TCP.OUT.Send.RTS

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

*				clc
TCP.OUT.Send.RTS
				rts
*--------------------------------------
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
*--------------------------------------
TCP.AddAYToSktCacheAtX
				clc
				adc SKT.Cache+3,x
				sta SKT.Cache+3,x
				tya
				adc SKT.Cache+2,x
				sta SKT.Cache+2,x
				bcc .8

				inc SKT.Cache+1,x
				bne .8

				inc SKT.Cache,x

.8				rts
*--------------------------------------
MAN
SAVE usr/src/lib/libtcpip.s.tcp
LOAD usr/src/lib/libtcpip.s
ASM
