NEW
  AUTO 3,1
*/--------------------------------------
* # DNS.Clear
*  Clear DNS Cache
* **In:**
* ## RETURN VALUE
*\--------------------------------------
DNS.Clear		ldx #K.DNSCACHE.SIZE*S.DNSCACHE

.1				stz DNS.CACHE-1,x
				dex
				bne .1

				clc
				rts
*/--------------------------------------
* # DNS.Query
*  Query DNS for specified host
* **In:**
*   PUSHW = PTR to IP to fill with cached data
*	PUSHW = hostname PTR to PSTR
* ## RETURN VALUE
*   CC: hit: IP filled with address
*   CS: missed
*\--------------------------------------
DNS.Query		>PULLW ZPPtrDNS			Get host string
				>PULLW ZPPtrIP			Get IP address to fill

DNS.Query.I		jsr DNS.FIND.BY.NAME
				bcs DNS.REQUEST

				lda (ZPCachePtr)		get status...
				bpl .9					Pending...

				lda ZPCachePtr
				clc
				adc #S.DNSCACHE.IP
				sta ZPCachePtr
				bcc .1

				inc ZPCachePtr+1

.1				ldy #3

.2				lda (ZPCachePtr),y
				sta (ZPPtrIP),y
				dey
				bpl .2

				clc
				rts

.9				lda #ERR.DNS.PENDING
				sec
				rts
*--------------------------------------
DNS.REQUEST		lda hDNSSocket
				beq .99

				jsr DNS.CSTR2DNS		Y=DNS string len+0
				bcs .99

				iny
				lda /S.DNS.QTYPE.A
				sta DNS.MSG,y
				iny
				lda #S.DNS.QTYPE.A
				sta DNS.MSG,y
				iny
				lda /S.DNS.QCLASS.IN
				sta DNS.MSG,y
				iny
				lda #S.DNS.QCLASS.IN
				sta DNS.MSG,y
				iny

				sty DNS.MSG.LEN
				stz DNS.MSG.LEN+1

				>LDYA A2osX.RANDOM16
				>STYA DNS.MSG.ID
				>STYA DNS.TmpCache+S.DNSCACHE.ID

				lda #K.DNS.PENDING.TTL
				sta DNS.TmpCache+S.DNSCACHE.TTL
				stz DNS.TmpCache+S.DNSCACHE.TTL+1
				stz DNS.TmpCache+S.DNSCACHE.TTL+2
				stz DNS.TmpCache+S.DNSCACHE.TTL+3
				lda #S.DNSCACHE.STATUS.PENDING
				jsr DNS.ADD.I
				bcs .9

				jsr DNS.REQUEST.SEND
				bcs .99

				lda #ERR.DNS.PENDING
				sec
				rts

.99				lda #ERR.DNS.ERROR
				sec
.9				rts
*--------------------------------------
DNS.REQUEST.SEND
				>LDYAI UDP.PORT.DNS
				>STYA SA.REMOTE+S.SOCKADDR.PORT

				ldy #3

.1				lda IPCFG+S.IPCFG.DNS1,y
				sta SA.REMOTE+S.SOCKADDR.ADDR,y
				dey
				bpl .1

				jsr .4

				lda IPCFG+S.IPCFG.DNS2
				beq .8

				ldy #3

.2				lda IPCFG+S.IPCFG.DNS2,y
				sta SA.REMOTE+S.SOCKADDR.ADDR,y
				dey
				bpl .2

.4				>PUSHB hDNSSocket
				>PUSHW L.DNS.MSG
				>PUSHW DNS.MSG.LEN
				>PUSHW L.SA.REMOTE
				jmp SKT.SendTo

.8				clc
				rts
*--------------------------------------
DNS.CSTR2DNS	lda (ZPPtrDNS)
				beq .9

				>LDYA ZPPtrDNS
				>SYSCALL2 strlen

				tax
				bne .9

				cpy #K.DNS.MAXLEN-1
				bcs .9

				lda #0					Ending 0
				sta DNS.MSG.NAME+1,y

				phy						save len for later

				ldx #0
				dey

.1				lda (ZPPtrDNS),y
				and #$7f
				cmp #'.'
				beq .3

				cmp #'A'
				bcc .2

				cmp #'Z'+1
				bcs .2

				adc #$20

.2				inx
				bra .4

.3				txa
				ldx #0

.4				sta DNS.MSG.NAME+1,y
				dey
				bpl .1

				stx DNS.MSG.NAME
				pla						Get back Len
				sec						+1
				adc #S.DNS-S.UDP		compute offset next to NAME
				tay
*				clc
				rts

.9				sec
				rts
*/--------------------------------------
* # DNS.Add
*  Add a static DNS record
* **In:**
*  PUSHW = PTR to IP
*  PUSHW = hostname CSTR to Add
*\--------------------------------------
DNS.Add			>PULLW ZPPtrDNS			Get host string
				>PULLW ZPPtrIP			Get host IP address

				ldy #3

.1				lda (ZPPtrIP),y
				sta DNS.TmpCache+S.DNSCACHE.IP,y
				dey
				bpl .1

				stz DNS.TmpCache+S.DNSCACHE.TTL
				stz DNS.TmpCache+S.DNSCACHE.TTL+1
				stz DNS.TmpCache+S.DNSCACHE.TTL+2
				stz DNS.TmpCache+S.DNSCACHE.TTL+3

				lda #S.DNSCACHE.STATUS.RESOLVED+S.DNSCACHE.STATUS.STATIC

DNS.ADD.I		sta DNS.TmpCache
				jsr DNS.FIND.BY.NAME
				bcc .2					Found, go update...

				jsr DNS.FIND.FREE

				>LDYA ZPPtrDNS
				>SYSCALL2 strdup
				bcs .9

				txa
				ldy #S.DNSCACHE.hNAME
				sta (ZPCachePtr),y

.2				lda DNS.TmpCache
				sta (ZPCachePtr)

				ldy #S.DNSCACHE.ID

.3				lda DNS.TmpCache,y
				sta (ZPCachePtr),y
				iny
				cpy #S.DNSCACHE
				bne .3

				clc
.9				rts
*/--------------------------------------
* # DNS.GetCAche
*  Return a Ptr to DNS Cache Table
* **In:**
* ## RETURN VALUE
*   Y,A = PTR to DNS.CACHE
*\--------------------------------------
DNS.GetCAche	>LDYA L.DNS.CACHE
				>STYA ZPCachePtr

				clc
				rts
*--------------------------------------
DNS.FIND.BY.NAME
				jsr DNS.GetCAche

				ldx #K.DNSCACHE.SIZE

.1				lda (ZPCachePtr)
				beq .6					empty DNS cache entry?

				phx
				>PUSHW ZPPtrDNS
				ldy #S.DNSCACHE.hNAME
				lda (ZPCachePtr),y
				>SYSCALL2 GetMemPtr
				>PUSHYA
				>SYSCALL2 StrCaseCmp
				plx
				bcc .8

.6				jsr DNS.NextCache

				dex
				bne .1

				sec
.8				rts
*--------------------------------------
DNS.UPDATE.BY.ID
				jsr DNS.GetCAche

				ldx #K.DNSCACHE.SIZE

.1				lda (ZPCachePtr)
				beq .6					empty DNS cache entry?
				bmi .6					resolved ?

				ldy #S.DNSCACHE.ID
				lda (ZPCachePtr),y
				cmp DNS.TmpCache+S.DNSCACHE.ID
				bne .6
				iny
				lda (ZPCachePtr),y
				cmp DNS.TmpCache+S.DNSCACHE.ID+1
				bne .6

				lda #S.DNSCACHE.STATUS.RESOLVED
				sta (ZPCachePtr)
				ldy #S.DNSCACHE.TTL

.2				lda DNS.TmpCache,y
				sta (ZPCachePtr),y
				iny
				cpy #S.DNSCACHE
				bne .2

				clc
				rts

.6				jsr DNS.NextCache

				dex
				bne .1

				sec
				rts
*--------------------------------------
DNS.FIND.FREE	jsr DNS.GetCAche

				lda #$ff
				sta TmpDWord
				sta TmpDWord+1
				sta TmpDWord+2
				sta TmpDWord+3

				ldx #K.DNSCACHE.SIZE
.1				lda (ZPCachePtr)
				beq .8					empty DNS cache entry?

				bit #S.DNSCACHE.STATUS.STATIC+S.DNSCACHE.STATUS.PENDING
				bne .7					Static/Pending.....skip
				phx
				ldy #S.DNSCACHE.TTL
				ldx #3
				sec
.2				lda TmpDWord,x			is saved TTL greater then actual TTL?
				sbc (ZPCachePtr),y
				iny
				dex
				bpl .2

				bcc .6					no,

				ldy #S.DNSCACHE.TTL
				ldx #3

.3				lda (ZPCachePtr),y		Save new lowest TTL
				sta TmpDWord,x
				iny
				dex
				bpl .3

				>LDYA ZPCachePtr
				>STYA ZPTmpPtr1			save lowest TTL slot ...

.6				plx

.7				jsr DNS.NextCache

				dex
				bne .1					no empty slot found, discard lowest TTL

				>LDYA ZPTmpPtr1
				>STYA ZPCachePtr
				jsr DNS.FREE

.8				clc
				rts
*--------------------------------------
DNS.EXPIRE		jsr DNS.GetCAche

				ldx #K.DNSCACHE.SIZE
.1				lda (ZPCachePtr)
				beq .7					empty DNS cache entry?

				bit #S.DNSCACHE.STATUS.STATIC
				bne .7
				phx

				ldy #S.DNSCACHE.TTL

				ldx #4
				clc

.2				lda (ZPCachePtr),y
				sbc #0
				sta (ZPCachePtr),y
				iny
				dex
				bne .2

				bcs .6
				jsr DNS.FREE
.6				plx

.7				jsr DNS.NextCache

.8				dex
				bne .1

				clc
				rts
*--------------------------------------
DNS.FREE		ldy #S.DNSCACHE.hNAME
				lda (ZPCachePtr),y
				beq .1

				>SYSCALL2 FreeMem

.1				lda #0
				sta (ZPCachePtr)
DNS.FREE.RTS	rts
*--------------------------------------
DNS.POLL		lda hDNSSocket
				beq DNS.FREE.RTS

				jsr SKT.Recv
				bcs DNS.FREE.RTS

				sta hFrameIn
				>SYSCALL2 GetMemPtr
				>STYA ZPFrameInPtr

				ldy #S.DNS.F
				lda (ZPFrameInPtr),y
				and /S.DNS.F.QR
				beq .9

				ldy #S.DNS.ID
				lda (ZPFrameInPtr),y
				sta DNS.TmpCache+S.DNSCACHE.ID
				iny
				lda (ZPFrameInPtr),y
				sta DNS.TmpCache+S.DNSCACHE.ID+1
				ldy #S.DNS.ANCOUNT+1
				lda (ZPFrameInPtr),y
				beq .9

				pha						save Answer count...
				ldy #S.DNS.QDCOUNT+1
				lda (ZPFrameInPtr),y

				ldy #S.DNS				Point to DATA

				tax
				beq .3					no QUERY to skip

.1				lda (ZPFrameInPtr),y
				beq .2
				bpl	.11					Pointer ?

				iny						yes, skip 2 bytes
				iny
				bra .2

.11				tya
				sec
				adc (ZPFrameInPtr),y	Skip LEN+1 bytes
				tay
				bra .1

.2				iny
				iny
				iny						Skip QTYPE & QCLASS
				iny
				iny						next pos
.21				dex						skip another QUERY ?
				bne .1

				plx						get back answer count

.3				lda (ZPFrameInPtr),y
				beq .32
				bpl .31					Pointer ?
				iny						yes, skip 2 bytes
				iny
				bra .32

.31 			tya
				sec
				adc (ZPFrameInPtr),y	Skip LEN+1 bytes
				tay
				bra .3

.32				iny						skip S.DNS.QTYPE HIGH
				lda (ZPFrameInPtr),y
				cmp #S.DNS.QTYPE.A
				beq .40
				tya
				clc
				adc #7					skip CLASS,TTL+DATALENHIGH
				tay
				sec						skip DATALENLO
				adc (ZPFrameInPtr),y    	add DATALEN
				tay
				dex
				bne .3
				bra .9

.40				iny						skip QCLASS
				iny
				iny						next pos

				ldx #3

.4				lda (ZPFrameInPtr),y
				sta DNS.TmpCache+S.DNSCACHE.TTL,x
				iny
				dex
				bpl .4

				iny						skip DATALEN
				iny
				ldx #0

.5				lda (ZPFrameInPtr),y
				sta DNS.TmpCache+S.DNSCACHE.IP,x
				iny
				inx
				cpx #4
				bne .5

				jsr DNS.UPDATE.BY.ID

.9				jmp FRM.DiscardIn
*--------------------------------------
DNS.NextCache	lda ZPCachePtr
				clc
				adc #S.DNSCACHE
				sta ZPCachePtr
				bcc .8
				inc ZPCachePtr+1

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