NEW
  AUTO 3,1
*/--------------------------------------
* # Socket
* Create a new socket
* ## C
* `hFD socket(short int type, short int protocol);`
* ## ASM
* **In:**
* `>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 #0

.1				lda SKT.TABLE,x
				beq .2

				inx
				cpx #K.SKTTABLE.SIZE
				bne .1

				lda #E.OOH
*				sec
				rts

.2				stx .8+1

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

				>STYA ZPTmpPtr1

				txa

.8				ldy #$FF				SELF MODIFIED
				sta SKT.TABLE,y

*				clc
				rts
*/--------------------------------------
* # Bind
* bind a name to a socket
* ## C
* `int bind(hFD fd, const struct sockaddr *addr);`
* ## ASM
* **In:**
* `>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 #0

.2				lda SKT.TABLE,x
				beq .7

				phx
				>SYSCALL2 GetMemPtr
				>STYA ZPTmpPtr1
				plx

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

				ldy #S.SOCKET.LOC.ADDR

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

				lda #ERR.SKT.BUSY
*				sec
				rts

.7				inx
				cpx #K.SKTTABLE.SIZE
				bne .2

				jmp SKT.SetLocAddr
*/--------------------------------------
* # Connect
* Initiate a connection on a socket
* ## C
* `int connect(hFD fd, const struct sockaddr *addr);`
* ## ASM
* **In:**
* `>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
* **In:**
* `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
* **In:**
* `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
* **In:**
* `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.LISTEN

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

				ldy #S.SOCKET.TCP.S
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.TCP.S.TIMEWT
				bcs .7

				pla

				jsr SKT.GetTCB
				ldy #S.SOCKET.TCP.S
				lda (ZPPtrSKT),y
				cmp #S.SOCKET.TCP.S.ESTBLSH
				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.FINWT1
				jmp SKT.StoreTCB.S

.1				cmp #S.SOCKET.TCP.S.CLWAIT
				beq .3

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

.3				lda #S.SOCKET.TCP.S.TIMEWT
				jmp SKT.StoreTCB.S

.7				pla
.8				clc
.9				rts
*--------------------------------------
SKT.shutdown.LISTEN
SKT.shutdown.DGRAM
.1				jsr SKT.GetFromQueue
				bcs .3

				>SYSCALL2 FreeMem
				bra .1

.3				pla					get hFD...

				ldx #0

.4				cmp SKT.TABLE,x
				beq .5

				inx
				cpx #K.SKTTABLE.SIZE
				bne .4

.5				stz SKT.TABLE,x
				>SYSCALL2 freemem
*				clc
SKT.shutdown.RTS
				rts
*/--------------------------------------
* # Read (STREAM)
* ## C
* `int skt.read(hFD fd, void *buf, int count);`
* ## ASM
* **In:**
* `>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

				ldy #S.SOCKET.TCP.INUSED
				lda (ZPPtrSKT),y
				tax
				iny
				ora (ZPPtrSKT),y
				beq .7					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

.7				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
				jsr SKT.GetTCB
				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

				jsr SKT.StoreTCB
				jsr TCP.SetSocketTCPO.ACK 	ACK=1 -> send WSIZE

				>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 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 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 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
* **In:**
* `>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 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 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 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,SEQPKT)
* ## C
* `hMem recvfrom(hFD fd, struct sockaddr *addr);`
* ## ASM
* **In:**
* `>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
* **In:**
* `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 .99					STREAM

				jsr SKT.GetFromQueue	SEQPKT
				bcc .1

				jsr SKT.CheckTCP
				bcs .91

.90				lda #E.NODATA
				plp
				sec
				rts

.10				jsr SKT.GetFromQueue
				bcs .90

.1				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				lda #S.SOCKADDR-1

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

				pla
				clc
.9				rts

.99				lda #ERR.SKT.BAD
.91				plp
				sec
				rts
*/--------------------------------------
* # SendTo (RAW,DGRAM,SEQPKT)
* ## C
* `int skt.sendto(hFD fd, const void *buf, int count, const struct sockaddr *addr);`
* ## ASM
* **In:**
* `>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
* **In:**
* `>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
				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
* **In:**
* `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
* **In:**
* `>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
* **In:**
* `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
*/--------------------------------------
* # GetTable
* Get socket table
* ## C
* `void * gettable();`
* ## ASM
* **In:**
* `>LIBCALL hLIBTCPIP,LIBTCPIP.GetTable`
* ## RETURN VALUE
*\--------------------------------------
SKT.GetTable	>LDYA L.SKT.Table
				clc
				rts
*--------------------------------------
SKT.PullhFDDataInPtrLen
				>PULLW ZPDataInLen		!!!use DataInPtr/Len
				>PULLW ZPDataInPtr		!!!DataOut trashed when sending ACK in TCP.OUT

SKT.PullhFD		>PULLA

SKT.GetFD		>SYSCALL2 GetMemPtr
				>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 #0

.1				lda SKT.TABLE,x
				beq .8

				phx
				jsr SKT.GetFD
				plx

				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				stx SKT.Index			x = SKT.TABLE index
				clc
				rts

.8				inx
				cpx #K.SKTTABLE.SIZE
				bne .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.TIMER16,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
