NEW
  AUTO 3,1
*/--------------------------------------
* # Socket
* Create a new socket
* ## C
* `hFD socket(short int type, short int protocol);`
* ## ASM
* `>PUSHB type`
* `>PUSHB protocol`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.socket`
* ## RETURN VALUE
* CC: A = hSOCKET
* CS: A = EC
*\--------------------------------------
SKT.Socket		>PULLA					get protocol (RAW)
				pha
				>PULLA
				tax
				pla
SKT.Socket.I	jmp (J.SKT.Socket,x)

SKT.Socket.RAW	ldy #S.SOCKET
				bra SKT.Socket.DSOCK
SKT.Socket.DGRAM
				lda #S.IP.PROTOCOL.UDP
				ldy #S.SOCKET
SKT.Socket.DSOCK
				stx FD.DSOCK+S.SOCKET.T		save type
				sta FD.DSOCK+S.SOCKET.PROTO		ICMP,UDP,TCP

				jsr SKT.Socket.FindFree
				bcs SKT.Socket.RTS

				ldy #0

.1				lda FD.DSOCK,y
				sta (ZPTmpPtr1),y
				iny
				cpy #FD.DSOCK.SIZE
				bne .1

				bra SKT.Socket.ZERO

SKT.Socket.SEQPKT
SKT.Socket.STREAM
				lda #S.IP.PROTOCOL.TCP
				ldy #S.SOCKET.TCP

				stx FD.SSOCK+S.SOCKET.T		save type
				sta FD.SSOCK+S.SOCKET.PROTO

				jsr SKT.Socket.FindFree
				bcs SKT.Socket.RTS

				ldy #0

.1				lda FD.SSOCK,y
				sta (ZPTmpPtr1),y
				iny
				cpy #FD.SSOCK.SIZE
				bne .1

SKT.Socket.ZERO	lda #0

.1				sta (ZPTmpPtr1),y
				iny
				cpy TmpDWord
				bne .1

				txa
				clc
SKT.Socket.RTS	rts
*--------------------------------------
SKT.Socket.FindFree
				sty TmpDWord			Y = socket.size

				ldx #1

.1				lda FDs.pHI-1,x
				beq .2

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

				lda #E.OOH
*				sec
				rts

.2				stx .8+1

*				lda #0					Y,A = socket.size
				>SYSCALL2 GetMem
				bcs SKT.Socket.RTS

				>STYA ZPTmpPtr1

.8				ldx #$FF				SELF MODIFIED
				sta FDs.pHI-1,x
				tya
				sta FDs.pLO-1,x

*				clc
				rts
*/--------------------------------------
* # Bind
* bind a name to a socket
* ## C
* `int bind(hFD fd, const struct sockaddr *addr);`
* ## ASM
* `>PUSHB fd`
* `>PUSHW addr`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.socket`
* ## RETURN VALUE
* CC: A = hSOCKET
* CS: A = EC
*\--------------------------------------
SKT.bind		jsr SKT.PullLocAddr
				jsr SKT.PullhFD

				lda SKT.LOC.ADDR+S.SOCKADDR.PORT
				ora SKT.LOC.ADDR+S.SOCKADDR.PORT+1
				bne .1

				jsr GetDynPort

				sta SKT.LOC.ADDR+S.SOCKADDR.PORT
				stx SKT.LOC.ADDR+S.SOCKADDR.PORT+1

.1				ldx #1

.2				lda FDs.pHI-1,x
				beq .7

				sta ZPTmpPtr1+1
				lda FDs.pLO-1,x
				sta ZPTmpPtr1

				lda (ZPTmpPtr1)
				cmp #S.FD.T.DSOCK
				beq .4
				
				cmp #S.FD.T.SSOCK
				bne .7

				ldy #S.SOCKET.AF
				lda (ZPTmpPtr1),y
				cmp #AF.INET
				bne .7

				ldy #S.SOCKET.LOC.ADDR

.4				lda (ZPTmpPtr1),y
				cmp SKT.LOC.ADDR+S.SOCKADDR.ADDR-S.SOCKET.LOC.ADDR,y
				bne .7

				iny
				cpy #S.SOCKET.LOC.PORT+2
				bne .4

				lda #ERR.SKT.BUSY
*				sec
				rts

.7				inx
				cpx #K.FD.MAX+1
				bne .2

				jmp SKT.SetLocAddr
*/--------------------------------------
* # Connect
* Initiate a connection on a socket
* ## C
* `int connect(hFD fd, const struct sockaddr *addr);`
* ## ASM
* `>PUSHB fd`
* `>PUSHW addr`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.socket`
* ## RETURN VALUE
* CC: A = hSOCKET
* CS: A = EC
*\--------------------------------------
SKT.connect		jsr SKT.PullRemAddr
				jsr SKT.PullhFD

				ldy #S.SOCKET.T
				lda (ZPPtrSKT),y
				tax
				jmp (J.SKT.connect,x)

SKT.connect.RAW
SKT.connect.DGRAM
				jmp SKT.SetRemAddr

SKT.connect.STREAM
SKT.connect.SEQPKT
				ldy #S.SOCKET.TCP.S
				lda (ZPPtrSKT),y
				beq .1

				cmp #S.SOCKET.TCP.S.ESTBLSH
				beq SKT.listen.8
				bcs .9

				cmp #S.SOCKET.TCP.S.OPENED
				beq .2

				cmp #S.SOCKET.TCP.S.SYNSENT
				beq .99

.9				lda #ERR.SKT.BAD
				sec
				rts

.1				jsr SKT.SetRemAddr
				jsr SKT.NewTCB
				bcs SKT.listen.RTS

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

.2				lda #S.TCP.OPTIONS.SYN
				jsr TCP.OUT.SendOptA	Send SYN
				bcs .99

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

.99				lda #ERR.SKT.NOCONN
				sec
				rts
*/--------------------------------------
* # Listen
* Listen for connections on a socket
* ## C
* `int listen(hFD fd);`
* ## ASM
* `lda fd`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.listen`
* ## RETURN VALUE
* CS: A = EC
*\--------------------------------------
SKT.listen		jsr SKT.GetFD

				ldy #S.SOCKET.T
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.T.SEQPKT
				bcc SKT.listen.9

				ldy #S.SOCKET.TCP.S
				lda (ZPPtrSKT),y
				bne SKT.listen.9

				lda #S.SOCKET.TCP.S.LISTEN
				sta (ZPPtrSKT),y

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

SKT.listen.8	clc
				rts

SKT.listen.9	lda #ERR.SKT.BAD
				sec
SKT.listen.RTS	rts
*/--------------------------------------
* # Accept
* Accept a connection on a socket
* ## C
* `hFD Accept(hFD fd);`
* ## ASM
* `lda fd`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.accept`
* ## RETURN VALUE
* A = hSocket
*\--------------------------------------
SKT.Accept		jsr SKT.GetFD

				ldy #S.SOCKET.O
				lda (ZPPtrSKT),y
				and #S.SOCKET.O.ACCEPTCONN
				beq SKT.listen.9
*--------------------------------------
SKT.GetFromQueue
				ldy #S.SOCKET.HQ.TAIL
				lda (ZPPtrSKT),y
				iny						#S.SOCKET.HQ.HEAD
				cmp (ZPPtrSKT),y
				beq .9					CS

				pha
				inc
				cmp #S.SOCKET.HQ.MAX
				bne .1

				lda #0

.1				dey						#S.SOCKET.HQ.TAIL
				sta (ZPPtrSKT),y

				pla
				clc
				adc #S.SOCKET.HQ
				tay
				lda (ZPPtrSKT),y

*				clc

.9				rts
*/--------------------------------------
* # Shutdown
* Close socket
* ## C
* `int shutdown(int fd);`
* ## ASM
* `lda fd`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.shutdown`
* ## RETURN VALUE
*\--------------------------------------
SKT.shutdown	pha
				jsr SKT.GetFD

				ldy #S.SOCKET.O
				lda (ZPPtrSKT),y
				and #S.SOCKET.O.ACCEPTCONN
				bne SKT.shutdown.HQ

				ldy #S.SOCKET.T
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.T.SEQPKT
				bcc	SKT.shutdown.HQ

				bne .15
				
.11				jsr SKT.GetFromQueue
				bcs .15
				
				>SYSCALL2 FreeMem
				bcc .11

.15				ldy #S.SOCKET.TCP.S
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.TCP.S.CLWAIT
				bne .10

				lda	#S.SOCKET.TCP.S.TIMEWT

				sta (ZPPtrSKT),y
				pla
				clc
				rts
*--------------------------------------
.10				pla
				jsr SKT.GetTCB
				ldy #S.SOCKET.TCP.S
				lda (ZPPtrSKT),y

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

				jsr TCP.OUT.SendFINACK

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

.1				cmp #S.SOCKET.TCP.S.FINWT2
				bne .2

				jsr TCP.OUT.SendFINACK

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

.2				lda #S.TCP.OPTIONS.RST
				jsr TCP.OUT.SendOptA	Send RST

.3				lda #S.SOCKET.TCP.S.TIMEWT
				jmp SKT.StoreTCB.S
*--------------------------------------
SKT.shutdown.HQ	jsr SKT.GetFromQueue
				bcs .1

				>SYSCALL2 FreeMem

				bra SKT.shutdown.HQ

.1				pla					get hFD...
*--------------------------------------
SKT.FreeFD		tax
				lda FDs.pHI-1,x
				stz FDs.pHI-1,x
				ldy FDs.pLO-1,x
				>SYSCALL2 Free
				rts
*/--------------------------------------
* # Read (STREAM)
* ## C
* `int skt.read(hFD fd, void *buf, int count);`
* ## ASM
* `>PUSHB fd`
* `>PUSHW buf`
* `>PUSHW count`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.read`
* ## RETURN VALUE
* CC: Y,A = bytes read
* CS: A = EC
*\--------------------------------------
SKT.Read 		jsr SKT.PullhFDDataInPtrLen

				jsr SKT.GetTCB

				ldy #S.SOCKET.TCP.INUSED
				lda (ZPPtrSKT),y
				tax
				iny
				ora (ZPPtrSKT),y
				beq .8					no data, go check SKT status

				cpx ZPDataInLen			XA = Data in pipe
				lda (ZPPtrSKT),y
				sbc ZPDataInLen+1
				bcs SKT.GetDataFromSktIn	more data in pipe, get full buffer of data

				stx ZPDataInLen			less data than INUSED, Get only INUSED data
				lda (ZPPtrSKT),y
				sta ZPDataInLen+1
				bra SKT.GetDataFromSktIn

.8				jsr SKT.CheckStream
				bcs .99					I/O error

				lda #E.NODATA
				sec
.99				rts
*--------------------------------------
* In:
*  Src : hInMem/INTAIL
*  Dst : ZPDataOutPtr/ZPDataOutLen
* Out:
*  Y,A = bytes read
*--------------------------------------
SKT.GetDataFromSktIn
				ldy #S.SOCKET.SQ.hInMem
				lda (ZPPtrSKT),y
				.DO AUXPIPE=1
				>SYSCALL2 GetStkObjPtr
				.ELSE
				>SYSCALL2 GetMemPtr
				.FIN
				sty ZPTmpPtr1

*				clc
				adc SKT.Cache+S.SOCKET.TCP.INTAIL+1
				sta ZPTmpPtr1+1

				jsr SKT.GetNotDataInLen
				pha

				.DO AUXPIPE=1
				jsr SKT.SetupZPCode
				.FIN
				ldy SKT.Cache+S.SOCKET.TCP.INTAIL

.1				inx						Check if room left in dest buffer
				bne .2

				pla
				inc
				beq .8

				pha

.2				.DO AUXPIPE=1
				jsr ZPCode
				.ELSE
				lda (ZPTmpPtr1),y
				.FIN
				sta (ZPDataInPtr)
				inc ZPDataInPtr
				bne .3

				inc ZPDataInPtr+1

.3				iny
				bne .1

				inc ZPTmpPtr1+1

				inc SKT.Cache+S.SOCKET.TCP.INTAIL+1
				lda SKT.Cache+S.SOCKET.TCP.INTAIL+1
				cmp /K.TCP.WSIZE
				bne .1

				stz SKT.Cache+S.SOCKET.TCP.INTAIL+1
				lda ZPTmpPtr1+1
*				sec
				sbc /K.TCP.WSIZE
				sta ZPTmpPtr1+1
				bra .1

.8				sty SKT.Cache+S.SOCKET.TCP.INTAIL

*				>ADC16 SKT.Cache+S.SOCKET.TCP.INFREE,ZPDataInLen
				ldx #S.SOCKET.TCP.INFREE
				jsr SKT.AddDataInLenAtSktX

*				>SBC16 SKT.Cache+S.SOCKET.TCP.INUSED,ZPDataInLen
				ldx #S.SOCKET.TCP.INUSED
				jsr SKT.SubDataInLenAtSktX

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

				jsr SKT.StoreTCB

				lda #S.TCP.OPTIONS.ACK
				jsr TCP.SetSocketTCPO

				>LDYA ZPDataInLen
				clc
				rts
*--------------------------------------
* From TCP.IN
* Src : ZPDataInPtr/ZPDataInLen
* Dst : hInMem/INHEAD
*--------------------------------------
SKT.AddDataToSktIn
				lda SKT.Cache+S.SOCKET.TCP.INFREE
				sec
				sbc ZPDataInLen
				tax
				lda SKT.Cache+S.SOCKET.TCP.INFREE+1
				sbc ZPDataInLen+1
				bcc .9					Not enough room in Q

				stx SKT.Cache+S.SOCKET.TCP.INFREE
				sta SKT.Cache+S.SOCKET.TCP.INFREE+1

				ldy #S.SOCKET.SQ.hInMem
				lda (ZPPtrSKT),y

				.DO AUXPIPE=1
				>SYSCALL2 GetStkObjPtr
				.ELSE
				>SYSCALL2 GetMemPtr
				.FIN

				sty ZPTmpPtr1

*				clc
				adc SKT.Cache+S.SOCKET.TCP.INHEAD+1
				sta ZPTmpPtr1+1

				jsr SKT.GetNotDataInLen
				pha
				ldy SKT.Cache+S.SOCKET.TCP.INHEAD

.1				.DO AUXPIPE=1
				sta IO.SETWRITEAUX
				.FIN

.2				inx
				bne .3

				pla
				inc
				beq .8

				pha

.3				lda (ZPDataInPtr)
				sta (ZPTmpPtr1),y
				inc ZPDataInPtr
				bne .4

				inc ZPDataInPtr+1

.4				iny
				bne .2

				.DO AUXPIPE=1
				sta IO.CLRWRITEAUX
				.FIN

				inc ZPTmpPtr1+1
				inc SKT.Cache+S.SOCKET.TCP.INHEAD+1
				lda SKT.Cache+S.SOCKET.TCP.INHEAD+1
				cmp /K.TCP.WSIZE
				bne .1

				stz SKT.Cache+S.SOCKET.TCP.INHEAD+1
				lda ZPTmpPtr1+1
*				sec
				sbc /K.TCP.WSIZE
				sta ZPTmpPtr1+1
				bra .1

.9				sec
				rts

.8				.DO AUXPIPE=1
				sta IO.CLRWRITEAUX
				.FIN
				sty SKT.Cache+S.SOCKET.TCP.INHEAD

*				>ADC16 SKT.Cache+S.SOCKET.TCP.INUSED,ZPDataInLen
				ldx #S.SOCKET.TCP.INUSED
				jsr SKT.AddDataInLenAtSktX

				clc
				rts
*/--------------------------------------
* # Write (STREAM)
* ## C
* `int skt.write(hFD fd, const void *buf, int count);`
* ## ASM
* `>PUSHB fd`
* `>PUSHW buf`
* `>PUSHW count`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.write`
* ## RETURN VALUE
* CC: Y,A = bytes written
* CS: A = EC
*\--------------------------------------
SKT.Write		jsr SKT.PullhFDDataInPtrLen

				jsr SKT.CheckStream
				bcs .99

				jsr SKT.GetTCB

				ldx SKT.Cache+S.SOCKET.TCP.OUTFREE
				cpx ZPDataInLen
				lda SKT.Cache+S.SOCKET.TCP.OUTFREE+1
				sbc ZPDataInLen+1
				bcs SKT.AddDataToSktOut

				lda #E.NODATA			Not enough room in Q,no data transfered
				sec
.99				rts
*--------------------------------------
* Src : ZPDataInPtr/ZPDataInLen
* Dst : hOutMem/OUTHEAD
*--------------------------------------
SKT.AddDataToSktOut
				ldy #S.SOCKET.SQ.hOutMem
				lda (ZPPtrSKT),y

				.DO AUXPIPE=1
				>SYSCALL2 GetStkObjPtr
				.ELSE
				>SYSCALL2 GetMemPtr
				.FIN

				sty ZPTmpPtr1

*				clc

				adc SKT.Cache+S.SOCKET.TCP.OUTHEAD+1
				sta ZPTmpPtr1+1

				ldy SKT.Cache+S.SOCKET.TCP.OUTHEAD

				jsr SKT.GetNotDataInLen
				pha
				
.1				.DO AUXPIPE=1
				sta IO.SETWRITEAUX
				.FIN

.2				inx
				bne .3

				pla
				inc
				beq .8

				pha

.3				lda (ZPDataInPtr)
				sta (ZPTmpPtr1),y

				inc ZPDataInPtr
				bne .4

				inc ZPDataInPtr+1

.4				iny
				bne .2

				inc ZPTmpPtr1+1
				.DO AUXPIPE=1
				sta IO.CLRWRITEAUX
				.FIN
				inc SKT.Cache+S.SOCKET.TCP.OUTHEAD+1
				lda SKT.Cache+S.SOCKET.TCP.OUTHEAD+1
				cmp /K.TCP.WSIZE
				bne .1

				stz SKT.Cache+S.SOCKET.TCP.OUTHEAD+1

				lda ZPTmpPtr1+1
*				sec
				sbc /K.TCP.WSIZE
				sta ZPTmpPtr1+1
				bra .1

.8				.DO AUXPIPE=1
				sta IO.CLRWRITEAUX
				.FIN
				sty SKT.Cache+S.SOCKET.TCP.OUTHEAD

*				>SBC16 SKT.Cache+S.SOCKET.TCP.OUTFREE,ZPDataInLen
				ldx #S.SOCKET.TCP.OUTFREE
				jsr SKT.SubDataInLenAtSktX

*				>ADC16 SKT.Cache+S.SOCKET.TCP.OUTUSED,ZPDataInLen
				ldx #S.SOCKET.TCP.OUTUSED
				jsr SKT.AddDataInLenAtSktX

*				>ADC16 SKT.Cache+S.SOCKET.TCP.OUTTOSEND,ZPDataInLen
				ldx #S.SOCKET.TCP.OUTTOSEND
				jsr SKT.AddDataInLenAtSktX

				jsr SKT.StoreTCB

				>LDYA ZPDataInLen
				clc
				rts
*--------------------------------------
SKT.AddDataInLenAtSktX
				clc
				lda SKT.Cache,x
				adc ZPDataInLen
				sta SKT.Cache,x
				inx
				lda SKT.Cache,x
				adc ZPDataInLen+1
				sta SKT.Cache,x
				rts
*--------------------------------------
SKT.SubDataInLenAtSktX
				sec
				lda SKT.Cache,x
				sbc ZPDataInLen
				sta SKT.Cache,x
				inx
				lda SKT.Cache,x
				sbc ZPDataInLen+1
				sta SKT.Cache,x
				rts
*--------------------------------------
* From TCP.OUT
* Src : hOutMem/OUTTAIL
* Dst : ZPDataOutPtr/ZPDataOutLen
*--------------------------------------
SKT.GetDataFromSktOut
				ldy #S.SOCKET.SQ.hOutMem
				lda (ZPPtrSKT),y

				.DO AUXPIPE=1
				>SYSCALL2 GetStkObjPtr
				.ELSE
				>SYSCALL2 GetMemPtr
				.FIN

				sty ZPTmpPtr1

*				clc
				adc SKT.Cache+S.SOCKET.TCP.OUTTAILSENT+1
				sta ZPTmpPtr1+1
				lda ZPDataOutLen
				eor #$FF
				tax

				lda ZPDataOutLen+1
				eor #$FF
				pha

				.DO AUXPIPE=1
				jsr SKT.SetupZPCode
				.FIN

				ldy SKT.Cache+S.SOCKET.TCP.OUTTAILSENT

.1				inx
				bne .2

				pla
				inc
				beq .8

				pha

.2				.DO AUXPIPE=1
				jsr ZPCode
				.ELSE
				lda (ZPTmpPtr1),y
				.FIN
				sta (ZPDataOutPtr)
				inc ZPDataOutPtr
				bne .3

				inc ZPDataOutPtr+1

.3				iny
				bne .1

				inc ZPTmpPtr1+1
				inc SKT.Cache+S.SOCKET.TCP.OUTTAILSENT+1
				lda SKT.Cache+S.SOCKET.TCP.OUTTAILSENT+1
				cmp /K.TCP.WSIZE
				bne .1

				stz SKT.Cache+S.SOCKET.TCP.OUTTAILSENT+1

				lda ZPTmpPtr1+1
*				sec
				sbc /K.TCP.WSIZE
				sta ZPTmpPtr1+1
				bra .1

.8				sty SKT.Cache+S.SOCKET.TCP.OUTTAILSENT

				>SBC16 SKT.Cache+S.SOCKET.TCP.OUTTOSEND,ZPDataOutLen

				clc
				rts
*/--------------------------------------
* # RecvFrom (RAW,DGRAM)
* ## C
* `hMem recvfrom(hFD fd, struct sockaddr *addr);`
* ## ASM
* `>PUSHB fd`
* `>PUSHW addr`		(RecvFrom)
* `>LIBCALL hLIBTCPIP,LIBTCPIP.Recv`
* ## RETURN VALUE
* CC: A = hMem
* CS: A = EC
*\--------------------------------------
SKT.RecvFrom	>PULLW ZPTmpPtr1		addr
				>PULLA
				sec
				.HS 90					BCC
*/--------------------------------------
* # Recv (RAW,DGRAM,SEQPKT)
* ## C
* `hMem recv(hFD fd);`
* ## ASM
* `lda fd`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.Recv`
* ## RETURN VALUE
* CC: A = hMem
* CS: A = EC
*\--------------------------------------
SKT.Recv		clc
				php
				jsr SKT.GetFD

				ldy #S.SOCKET.T
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.T.SEQPKT
				bcc .10					RAW,DGRAM

				bne .98					STREAM

				jsr SKT.GetFromQueue	SEQPKT
				bcs .1

				pha
				>SYSCALL2 GetMemPtr
				>STYA ZPFrameInPtr

				jsr TCP.IN.SetDataInPtrAndLen

				jsr SKT.GetTCB

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

				jsr SKT.StoreTCB
				
				lda #S.TCP.OPTIONS.ACK
*				jsr TCP.OUT.SendOptA
				jsr TCP.SetSocketTCPO
				
				pla
				plp
				clc
				rts

.1				jsr SKT.CheckTCP
				bcs .91

.90				lda #E.NODATA
.91				plp
				sec
				rts

.98				plp
.99				lda #ERR.SKT.BAD
				sec
				rts
*--------------------------------------
.10				jsr SKT.GetFromQueue
				bcs .90

				plp						if CS, RecvFrom
				bcc .9					CC, Recv : Exit with CC and A=hFrame

				pha
				>SYSCALL2 GetMemPtr
				>STYA ZPFrameInPtr

				ldy #S.IP.SRC

.2				lda (ZPFrameInPtr),y
				sta SA.REMOTE+S.SOCKADDR.ADDR-S.IP.SRC,y
				iny
				cpy #S.IP.SRC+4
				bne .2

				ldy #S.IP.PROTOCOL
				lda (ZPFrameInPtr),y
				cmp #S.IP.PROTOCOL.ICMP
				bne .3

				ldy #S.ICMP.IDENTIFIER
				bra .7

.3				cmp #S.IP.PROTOCOL.TCP
				beq .6

				cmp #S.IP.PROTOCOL.UDP
				bne .8

.6				ldy #S.TCPUDP.SRCPORT

.7				lda (ZPFrameInPtr),y
				sta SA.REMOTE+S.SOCKADDR+1
				iny
				lda (ZPFrameInPtr),y
				sta SA.REMOTE+S.SOCKADDR

.8				ldy #S.SOCKADDR-1

.80				lda SA.REMOTE,y
				sta (ZPTmpPtr1),y
				dey
				bpl .80

				pla
				clc
.9				rts
*/--------------------------------------
* # SendTo (RAW,DGRAM,SEQPKT)
* ## C
* `int skt.sendto(hFD fd, const void *buf, int count, const struct sockaddr *addr);`
* ## ASM
* `>PUSHB fd`
* `>PUSHW buf`
* `>PUSHWI count`
* `>PUSHW addr`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.sendto`
* ## RETURN VALUE
* CC: Y,A = bytes written
* CS: A = EC
*\--------------------------------------
SKT.SendTo		jsr SKT.PullRemAddr
*/--------------------------------------
* # Send (RAW,DGRAM,SEQPKT)
* ## C
* `int skt.send(hFD fd, const void *buf, int count);`
* ## ASM
* `>PUSHB fd`
* `>PUSHW buf`
* `>PUSHWI count`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.send`
* ## RETURN VALUE
* CC: Y,A = bytes written
* CS: A = EC
*\--------------------------------------
SKT.Send		jsr SKT.PullhFDDataInPtrLen

				ldy #S.SOCKET.T
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.T.STREAM
			bcs *	
				tax
				jmp (J.SKT.send,x)
*--------------------------------------
SKT.Send.RAW	ldy #S.SOCKET.PROTO
				lda (ZPPtrSKT),y
				tax
				>LDYA ZPDataInLen
				jsr FRM.NewIP
				bcc SKT.Send.8

				rts
*--------------------------------------
SKT.Send.DGRAM	ldx #S.IP.PROTOCOL.UDP
				>LDYA ZPDataInLen
				jsr FRM.NewIP
				bcs SKT.Send.9

				jsr SKT.SetFrameOutTCPUDPPorts

SKT.Send.8		jsr SKT.SetFrameOutDstIP
				jsr SKT.CopyDataInToOut
				clc						Queue if fail
				jmp FRM.SendIP
*--------------------------------------
SKT.Send.SEQPKT	jsr SKT.CheckTCP
				bcs SKT.Send.9

				>LDYA ZPDataInLen
				jsr TCP.NewFrame
				bcs SKT.Send.9

				jsr SKT.GetTCB

				jsr SKT.CopyDataInToOut

				jmp TCP.OUT.SEQSEND
*--------------------------------------
SKT.Send.STREAM	lda #ERR.SKT.BAD
				sec
SKT.Send.9		rts
*/--------------------------------------
* # GetSockOpt
* Set Socket Options
* ## C
* `int getsockopt(hFD fd);`
* ## ASM
* `lda fd`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.GetSockOpt`
* ## RETURN VALUE
*\--------------------------------------
SKT.getsockopt	jsr SKT.GetFD
				ldy #S.SOCKET.O
				lda (ZPPtrSKT),y
*				clc
				rts
*/--------------------------------------
* # SetSockOpt
* Set Socket Options
* ## C
* `int setsockopt(hFD fd, short int opts);`
* ## ASM
* `>PUSHB fd`
* `>PUSHB opts`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.SetSockOpt`
* ## RETURN VALUE
*\--------------------------------------
SKT.setsockopt	>PULLA
				pha

				jsr SKT.PullhFD

				pla
				ldy #S.SOCKET.O
				sta (ZPPtrSKT),y
*				clc
				rts
*/--------------------------------------
* # EOF
* End Of File
* ## C
* `int eof(hFD fd);`
* ## ASM
* `lda fd`
* `>LIBCALL hLIBTCPIP,LIBTCPIP.EOF`
* ## RETURN VALUE
* CC : A = 0 if some data, A = $ff if EOF
* CS : A = Socket Error
*\--------------------------------------
SKT.EOF			jsr SKT.GetFD

				ldy #S.SOCKET.TCP.INUSED
				lda (ZPPtrSKT),y
				iny
				ora (ZPPtrSKT),y
				bne .8					some DATA...

				jsr SKT.CheckStream
				bcs .9

				lda #$ff				no DATA, EOF = true
*				clc
				rts

.8				lda #0					...EOF = false

*				clc
.9				rts
*--------------------------------------
SKT.CheckStream	lda #S.SOCKET.T.STREAM

				ldy #S.SOCKET.T
				cmp (ZPPtrSKT),y
				bne SKT.BAD

SKT.CheckTCP	ldy #S.SOCKET.O
				lda (ZPPtrSKT),y
				and #S.SOCKET.O.ACCEPTCONN
				bne SKT.BAD

				ldy #S.SOCKET.TCP.S
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.TCP.S.ESTBLSH
				beq .8

				bcc .9

				lda #MLI.E.IO
*				sec
				rts

.8				lda #0
				clc
				rts

.9				lda #ERR.SKT.NOCONN
				sec
				rts

SKT.BAD			lda #ERR.SKT.BAD
				sec
				rts
*--------------------------------------
SKT.PullhFDDataInPtrLen
				>PULLW ZPDataInLen		!!!use DataInPtr/Len
				>PULLW ZPDataInPtr		!!!DataOut trashed when sending ACK in TCP.OUT

SKT.PullhFD		>PULLA

SKT.GetFD		tax
				lda FDs.pHI-1,x
				ldy FDs.pLO-1,x

				>STYA ZPPtrSKT
				rts
*--------------------------------------
SKT.PullLocAddr	clc
				.HS B0					BCS
*--------------------------------------
SKT.PullRemAddr	sec
				>PULLW ZPTmpPtr1
				ldy #S.SOCKADDR-1

				ldx #S.SOCKADDR-1
				bcc .1

				ldx #S.SOCKADDR+S.SOCKADDR-1

.1				lda (ZPTmpPtr1),y
				sta SKT.LOC.ADDR,x
				dex
				dey
				bpl .1

				rts
*--------------------------------------
SKT.SetLocAddr	ldy #S.SOCKET.LOC.PORT+1

.1				lda SKT.LOC.ADDR+S.SOCKADDR.ADDR-S.SOCKET.LOC.ADDR,y
				sta (ZPPtrSKT),y
				dey
				cpy #S.SOCKET.LOC.ADDR
				bcs .1

				rts
*--------------------------------------
SKT.SetRemAddr	ldy #S.SOCKET.REM.PORT+1

.1				lda SKT.REM.ADDR+S.SOCKADDR.ADDR-S.SOCKET.REM.ADDR,y
				sta (ZPPtrSKT),y
				dey
				cpy #S.SOCKET.REM.ADDR
				bcs .1

				rts
*--------------------------------------
*  SKT.REM.ADDR = Incoming Frame SRC
*  SKT.LOC.ADDR = Incoming Frame DST
*--------------------------------------
SKT.FindMatchingLocRem
				ldx #1

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

				ldy #S.SOCKET.PROTO
				lda (ZPPtrSKT),y

				ldy #S.IP.PROTOCOL
				cmp (ZPFrameInPtr),y
				bne .8

				ldy #S.SOCKET.LOC.ADDR

.2				lda (ZPPtrSKT),y
				bne .4

				ldy #S.SOCKET.LOC.PORT	bound to 0.0.0.0,check only LOC port

.3				lda (ZPPtrSKT),y

.4				cmp SKT.LOC.ADDR+S.SOCKADDR.ADDR-S.SOCKET.LOC.ADDR,y
				bne .8

				iny
				cpy #S.SOCKET.LOC.PORT+2
				bne .3

				ldy #S.SOCKET.O
				lda (ZPPtrSKT),y
				and #S.SOCKET.O.ACCEPTCONN
				beq .6

				ldy #S.TCP.OPTIONS		Listening, only SYN packet....
				lda (ZPFrameInPtr),y
				cmp #S.TCP.OPTIONS.SYN
				beq .7					SYN received on a LISTEN socket, ok

				bne .8					bad packet for this listening

.6				lda SKT.REM.ADDR+S.SOCKADDR.ADDR
				cmp #$ff				incoming frame is FF.FF.FF.FF, Broadcast ?
				bne .41

*				ldy #S.SOCKET.O
				lda (ZPPtrSKT),y
				and #S.SOCKET.O.BROADCAST
				bne .43
*				sec
				rts						this socket does not accept broadcast

.41				ldy #S.SOCKET.REM.ADDR

				lda (ZPPtrSKT),y
				bne .44

.43				ldy #S.SOCKET.REM.PORT	Frame is Broadcast, or listening is 0.0.0.0 check port only

.42				lda (ZPPtrSKT),y

.44				cmp SKT.REM.ADDR+S.SOCKADDR.ADDR-S.SOCKET.REM.ADDR,y
				bne .8					wrong remote host, exit....

				iny
				cpy #S.SOCKET.REM.PORT+2
				bne .42

.7				clc						x = hFD
				rts

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

*				sec
				rts
*--------------------------------------
SKT.AddToQueueA pha
				ldy #S.SOCKET.HQ.HEAD
				lda (ZPPtrSKT),y
				tax
				inc
				cmp #S.SOCKET.HQ.MAX
				bne .1

				lda #0

.1				dey						#S.SOCKET.HQ.TAIL
				cmp (ZPPtrSKT),y
				beq .9					Queue full!!

				iny						#S.SOCKET.HQ.HEAD
				sta (ZPPtrSKT),y
				txa
				clc
				adc #S.SOCKET.HQ
				tay

				pla
				sta (ZPPtrSKT),y
				clc
				rts

.9				pla						dicard hFrame
*				sec
				rts
*--------------------------------------
SKT.NewTCB		ldx #S.SOCKET.TCP.INSEQNUM

.1				stz SKT.Cache,x
				inx
				cpx #S.SOCKET.TCP
				bne .1

				ldx #3

.2				lda A2osX.T16,x
				sta SKT.Cache+S.SOCKET.TCP.OUTNEXTSEQ,x
				dex
				bpl .2

				ldy #S.SOCKET.T
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.T.SEQPKT
				bcc .8

				tax

				>LDYAI K.TCP.WSIZE
				>STYA SKT.Cache+S.SOCKET.TCP.INFREE

				cpx #S.SOCKET.T.STREAM
				bcc .8

				.DO AUXPIPE=1
				>SYSCALL2 NewStkObj
				.ELSE
				>SYSCALL2 getmem
				.FIN
				bcs .9

				txa
				ldy #S.SOCKET.SQ.hInMem
				sta (ZPPtrSKT),y

				>LDYAI K.TCP.WSIZE
				>STYA SKT.Cache+S.SOCKET.TCP.OUTFREE

				.DO AUXPIPE=1
				>SYSCALL2 NewStkObj
				.ELSE
				>SYSCALL2 getmem
				.FIN
				bcs .9

				txa
				ldy #S.SOCKET.SQ.hOutMem
				sta (ZPPtrSKT),y
.8
*				clc
.9				rts
*--------------------------------------
SKT.GetTCB	 	ldy #S.SOCKET.TCP.INSEQNUM

.1				lda (ZPPtrSKT),y
				sta SKT.Cache,y
				iny
				cpy #S.SOCKET.TCP
				bne .1

				rts
*--------------------------------------
SKT.StoreTCB.S	ldy #S.SOCKET.TCP.S
				sta (ZPPtrSKT),y

SKT.StoreTCB 	ldy #S.SOCKET.TCP.INSEQNUM

.1				lda SKT.Cache,y
				sta (ZPPtrSKT),y
				iny
				cpy #S.SOCKET.TCP
				bne .1

				clc
				rts
*--------------------------------------
SKT.SetFrameOutDstIP
				ldx #3

				ldy #S.SOCKET.REM.ADDR
				lda (ZPPtrSKT),y
				beq .3					Socket Bound to 0.0.0.0...

.1				lda (ZPPtrSKT),y
				pha
				iny
				dex
				bpl .1

				ldy #S.IP.DST+3
				ldx #3

.2				pla
				sta (ZPFrameOutPtr),y
				dey
				dex
				bpl .2

				rts
.3				ldy #S.IP.DST+3			...sent to provided SentTo ADDR

.4				lda SKT.REM.ADDR+S.SOCKADDR.ADDR,x
				sta (ZPFrameOutPtr),y
				dey
				dex
				bpl .4

				rts
*--------------------------------------
SKT.SetFrameOutTCPUDPPorts
				ldy #S.SOCKET.LOC.PORT
				lda (ZPPtrSKT),y
				tax
				iny
				lda (ZPPtrSKT),y
 				ldy #S.TCPUDP.SRCPORT
				sta (ZPFrameOutPtr),y
				iny
				txa
				sta (ZPFrameOutPtr),y

				ldy #S.SOCKET.REM.PORT
				lda (ZPPtrSKT),y
				beq .1

				tax
				iny
				lda (ZPPtrSKT),y
				bra .2

.1				lda SKT.REM.ADDR+S.SOCKADDR.PORT+1
				ldx SKT.REM.ADDR+S.SOCKADDR.PORT

.2 				ldy #S.TCPUDP.DSTPORT
				sta (ZPFrameOutPtr),y
				iny
				txa
				sta (ZPFrameOutPtr),y

				rts
*--------------------------------------
SKT.GetNotDataInLen
				lda ZPDataInLen
				eor #$FF
				tax

				lda ZPDataInLen+1
				eor #$FF
				rts
*--------------------------------------
SKT.CopyDataInToOut
				lda ZPDataInPtr+1
				pha
				lda ZPDataOutPtr+1
				pha

				jsr SKT.GetNotDataInLen
				pha
				ldy #0

.1				inx
				bne .2

				pla
				inc
				beq .9

				pha

.2				lda (ZPDataInPtr),y
				sta (ZPDataOutPtr),y
				iny
				bne .1

				inc ZPDataInPtr+1
				inc ZPDataOutPtr+1
				bne .1

.9				pla
				sta ZPDataOutPtr+1
				pla
				sta ZPDataInPtr+1
				rts
*--------------------------------------
				.DO AUXPIPE=1
SKT.SetupZPCode	ldy #ZP.CODE.Len-1

.1				lda ZP.CODE,y
				sta ZPCode,y
				dey
				bpl .1

				rts
				.FIN
*--------------------------------------
MAN
SAVE usr/src/lib/libtcpip.s.skt
LOAD usr/src/lib/libtcpip.s
ASM
