NEW
  AUTO 3,1
*/--------------------------------------
* # ARP.Clear
*  Clear ARP Cache
* ## ASM
* ## RETURN VALUE
*\--------------------------------------
ARP.Clear		jsr ARP.GetCache

ARP.Clear.I		lda #0
				tay

.2				sta (ZPCachePtr),y
				iny
				cpy #K.ARPCACHE.SIZE*S.ARPCACHE
				bne .2

				clc
.9				rts
*/--------------------------------------
* # ARP.Query
*  Query ARP Cache and returns HW address
* ## ASM
*  PUSHW PTR to MAC (to fill)
*  PUSHW PTR to IP
* ## RETURN VALUE
*  CC: hit: MAC filled
*  CS: missed
*\--------------------------------------
ARP.Query		jsr ARP.GetIP

				>PULLW ZPPtrMAC			MAC

				jsr ARP.QUERY.I
				bcs .9

				ldy #5

.2				lda ARP.TmpCache+S.ARPCACHE.MAC,y
				sta (ZPPtrMAC),y
				dey
				bpl .2

*				clc
.9				rts
*/--------------------------------------
* # ARP.Add
*  Add a static ARP cache record
* ## ASM
*  PUSHW PTR to MAC
*  PUSHW PTR to IP
*\--------------------------------------
ARP.Add			jsr ARP.GetIP

				>PULLW ZPPtrMAC			MAC

				ldy #5

.2				lda (ZPPtrMAC),y
				sta ARP.TmpCache+S.ARPCACHE.MAC,y
				dey
				bpl .2

				stz ARP.TmpCache+S.ARPCACHE.TTL
				stz ARP.TmpCache+S.ARPCACHE.TTL+1

				lda #S.ARPCACHE.S.RESOLVED+S.ARPCACHE.S.STATIC

ARP.ADD.I		sta ARP.TmpCache

				jsr ARP.FIND.BY.IP
				bcc .1

				jsr ARP.FIND.FREE

.1				ldy #S.ARPCACHE-1

.2				lda ARP.TmpCache,y
				sta (ZPCachePtr),y
				dey
				bpl .2

				clc
				rts
*/--------------------------------------
* # ARP.GetCache
*  Return a Ptr to ARP Cache Table
* ## ASM
* ## RETURN VALUE
*   Y,A = PTR to ARP.CACHE
*\--------------------------------------
ARP.GetCache	lda hARPCache
				>SYSCALL2 GetMemPtr
				bcs .9
				>STYA ZPCachePtr
.9				rts
*--------------------------------------
*				PRIVATE
*--------------------------------------
ARP.IN			ldy #S.ARP.TPA+3
				ldx #3

.1				lda (ZPFrameInPtr),y
				cmp IPCFG+S.IPCFG.IP,x
				bne ARP.IN.EXIT
				dey
				dex
				bpl .1

				ldy #S.ARP.OPERATION+1	HI byte
				lda (ZPFrameInPtr),y
				cmp #S.ARP.OPERATION.REQ
				beq ARP.IN.REQ

				cmp #S.ARP.OPERATION.REP
				beq ARP.IN.REP

ARP.IN.EXIT		jmp FRM.DiscardIn

ARP.IN.REQ		ldy #S.ARP.SPA+3
				ldx #3

.1				lda (ZPFrameInPtr),y
				sta ARP.REP.TPA,x
				dey
				dex
				bpl .1

				ldy #S.ARP.SHA+5
				ldx #5

.2				lda (ZPFrameInPtr),y
				sta ARP.REP.DSTMAC,x
				sta ARP.REP.THA,x
				dey
				dex
				bpl .2

				>LDYA L.ARP.REP
				jsr ARP.Send
				bra ARP.IN.EXIT

ARP.IN.REP		lda #K.ARP.TTL
				sta ARP.TmpCache+S.ARPCACHE.TTL
				lda /K.ARP.TTL
				sta ARP.TmpCache+S.ARPCACHE.TTL+1

				ldy #S.ARP.SPA+3
				jsr ARP.GetIPFromFrameInPtrY

				ldy #S.ARP.SHA+5
				jsr ARP.GetMacFromFrameInPtrY

				lda #S.ARPCACHE.S.RESOLVED
				jsr ARP.ADD.I
				bra ARP.IN.EXIT
*--------------------------------------
ARP.QUERY.I		jsr ARP.FIND.BY.IP
				bcs .3					send an ARP request

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

				ldy #S.ARPCACHE.MAC

.2				lda (ZPCachePtr),y
				sta ARP.TmpCache,y
				iny
				cpy #S.ARPCACHE.MAC+6
				bne .2

				ldy #S.ARPCACHE.TTL
				lda #K.ARP.TTL
				sta (ZPCachePtr),y
				iny
				lda /K.ARP.TTL
				sta (ZPCachePtr),y

				clc
				rts

.3				ldx #3

.4				lda ARP.TmpCache+S.ARPCACHE.IP,x
				sta ARP.REQ.TPA,x
				dex
				bpl .4

				>LDYA L.ARP.REQ
				jsr ARP.Send
				bcs .99

				lda #K.ARP.PENDING.TTL
				sta ARP.TmpCache+S.ARPCACHE.TTL
				stz ARP.TmpCache+S.ARPCACHE.TTL+1
				lda #S.ARPCACHE.S.PENDING
				jsr ARP.ADD.I

.9				lda #ERR.ARP.PENDING
				sec
.99				rts
*--------------------------------------
ARP.FIND.BY.IP	jsr ARP.GetCache

				ldx #K.ARPCACHE.SIZE
.1				lda (ZPCachePtr)
				beq .3

				ldy #S.ARPCACHE.IP

.2				lda ARP.TmpCache,y
				cmp (ZPCachePtr),y
				bne .3

				iny
				cpy #S.ARPCACHE.IP+4
				bne .2

				clc
				rts

.3				jsr ARP.NextCache

				dex
				bne .1

				sec
				rts
*--------------------------------------
ARP.FIND.FREE	jsr ARP.GetCache

				lda #$ff
				sta TmpDWord
				sta TmpDWord+1

				ldx #K.ARPCACHE.SIZE

.1				lda (ZPCachePtr)
				beq .8
				bpl .6

				ldy #S.ARPCACHE.TTL
				lda (ZPCachePtr),y
				sec
				sbc TmpDWord
				iny
				lda (ZPCachePtr),y
				sbc TmpDWord+1
				bcc .6

				lda (ZPCachePtr),y
				sta TmpDWord+1
				dey
				lda (ZPCachePtr),y
				sta TmpDWord
				>LDYA ZPCachePtr
				>STYA ZPTmpPtr1			save lowest TTL slot ...

.6				jsr ARP.NextCache

				dex
				bne .1

				>LDYA ZPTmpPtr1
				>STYA ZPCachePtr
				lda #0
				sta (ZPCachePtr)

.8				clc
				rts
*--------------------------------------
ARP.EXPIRE		jsr ARP.GetCache

				ldx #K.ARPCACHE.SIZE

.1				lda (ZPCachePtr)
				beq .2

				and #S.ARPCACHE.S.STATIC
				bne .2

				ldy #S.ARPCACHE.TTL
				sec
				lda (ZPCachePtr),y
				sbc #1
				sta (ZPCachePtr),y
				iny
				lda (ZPCachePtr),y
				sbc #0
				sta (ZPCachePtr),y
				bcs .2

				lda #0
				sta (ZPCachePtr)

.2				jsr ARP.NextCache

				dex
				bne .1

				rts
*--------------------------------------
ARP.NextCache	lda ZPCachePtr
				clc
				adc #S.ARPCACHE
				sta ZPCachePtr
				bcc .8
				inc ZPCachePtr+1

.8				rts
*--------------------------------------
ARP.GetIP		>PULLW ZPPtrIP

				ldy #3

.1				lda (ZPPtrIP),y
				sta ARP.TmpCache+S.ARPCACHE.IP,y
				dey
				bpl .1

				rts
*--------------------------------------
ARP.AddFromFrameInPtr
				ldy #S.IP.SRC+3
				jsr ARP.GetIPFromFrameInPtrY

				ldy #S.ETH.SRCMAC+5
				jsr ARP.GetMacFromFrameInPtrY

				lda #K.ARP.TTL
				sta ARP.TmpCache+S.ARPCACHE.TTL
				lda /K.ARP.TTL
				sta ARP.TmpCache+S.ARPCACHE.TTL+1
				lda #S.ARPCACHE.S.RESOLVED
				jmp ARP.ADD.I
*--------------------------------------
ARP.GetIPFromFrameInPtrY
				ldx #3

.1				lda (ZPFrameInPtr),y
				sta ARP.TmpCache+S.ARPCACHE.IP,x
				dey
				dex
				bpl .1

				rts
*--------------------------------------
ARP.GetMacFromFrameInPtrY
				ldx #5

.1				lda (ZPFrameInPtr),y
				sta ARP.TmpCache+S.ARPCACHE.MAC,x
				dey
				dex
				bpl .1

				rts
*--------------------------------------
ARP.Send		>STYA IOCTL+S.IOCTL.BUFPTR
				>LDYAI S.ARP
				>STYA IOCTL+S.IOCTL.BYTECNT
				jmp FRM.Send.IOCTL
*--------------------------------------
MAN
SAVE usr/src/lib/libtcpip.s.arp
LOAD usr/src/lib/libtcpip.s
ASM
