PR#3
PREFIX /A2OSX.SRC
LOMEM $C00
INC 1
AUTO 6
				.LIST OFF
				.OP	65C02
				.OR	$2000
				.TF /A2OSX.BOOT/SBIN/DHCPCLNT
*--------------------------------------
				.INB INC/MACROS.I
				.INB INC/A2OSX.I
				.INB INC/LIBTCPIP.I
*--------------------------------------
TIMEOUT.MAX		.EQ 100					10 sec.
*--------------------------------------
ZPIPCfgPtr		.EQ ZPBIN
ZPFrameBase		.EQ ZPBIN+2
ZPFramePtr		.EQ ZPBIN+4
*--------------------------------------
*			File Header (16 Bytes)
*--------------------------------------
CS.START		cld
				jmp (.1,x)
				.DA #$61				6502,Level 1 (65c02)
				.DA #1					BIN Layout Version 1
				.DA 0
				.DA CS.END-CS.START
				.DA DS.END-DS.START		Data Segment to Allocate
				.DA 0
				.DA 0
*--------------------------------------
* Relocation Table
*--------------------------------------
.1				.DA CS.INIT
				.DA CS.RUN
				.DA CS.DOEVENT
				.DA	CS.QUIT
L.LIBTCPIP		.DA LIBTCPIP
L.IPCFG			.DA IPCFG
L.Socket		.DA Socket
L.MSG.CFG1		.DA MSG.CFG1
L.MSG.CFG2		.DA MSG.CFG2
L.MSG.CFG.KO	.DA MSG.CFG.KO
L.MSG.CFG.OK	.DA MSG.CFG.OK
L.MSG.CFG.ND	.DA MSG.CFG.ND
L.MSG.CFG.NA	.DA MSG.CFG.NA
L.DHCP.DISC		.DA DHCP.DISC
L.DHCP.REQ		.DA DHCP.REQ
				.DA 0
*--------------------------------------
CS.INIT			>LDYA L.LIBTCPIP
				>SYSCALL SYS.LoadLibYA
				sta hLIBTCPIP
				
				>LIBCALL hLIBTCPIP,LIBTCPIP.GET.IPCFG
				bcs .9
				>STYA ZPIPCfgPtr
				
				lda (ZPIPCfgPtr)
				and #S.IPCFG.STATUS.OK
				bne .99					Already Configured, exit
				
				ldy #S.IPCFG.HDEV
				lda (ZPIPCfgPtr),y
				beq .98
				
				ldy #S.IPCFG-1
.1				lda (ZPIPCfgPtr),y
				sta IPCFG,y
				dey
				bne .1
				
				stz IPCFG

				>LDYA A2OSX.TIMER16
				>STYA DHCP.DISC.XID
				>STYA DHCP.REQ.XID
				>LDYA A2OSX.RANDOM16
				>STYA DHCP.DISC.XID+2
				>STYA DHCP.REQ.XID+2
				
				ldx #5		
.2				lda IPCFG+S.IPCFG.MAC,x
				sta DHCP.DISC.CHADDR,x
				sta DHCP.REQ.CHADDR,x
				dex
				bpl .2
				
				lda (pPs)
				ora #S.PS.F.EVENT		Now accept events
				sta (pPs)
				
				clc
.9				rts

.98				>LDYA L.MSG.CFG.ND
				bra .90
.99				>LDYA L.MSG.CFG.NA
.90				>SYSCALL SYS.PrintFYA
				lda #0
				sec
				rts
*--------------------------------------
CS.RUN			>PUSHW L.Socket
				>LIBCALL hLIBTCPIP,LIBTCPIP.SKT.NEW

				bcc	.1
				jmp CS.RUN.KO
				
.1				txa
				ldy #hSocket
				sta (pData),y
				
				>LDYA L.MSG.CFG1
				>SYSCALL SYS.PrintFYA

				jsr Init.Timeout
				
CS.RUN.SDISC	>PUSHWI DHCP.DISC.LEN
				>PUSHW L.DHCP.DISC
				jsr CS.RUN.SKT.SEND
				
				bcc .1
				jmp CS.RUN.KO

.1				lda #S.IPCFG.STATUS.SDISC
				sta IPCFG

CS.RUN.ROFFER	>SYSCALL SYS.Sleep
				
				jsr CS.RUN.SKT.RCVD
				bcc .1
				jsr Wait.Timeout
				bcc CS.RUN.ROFFER

				lda #1
				jmp CS.RUN.KO
				
.1				jsr CheckDHCPOffer
				
				bcs CS.RUN.ROFFER
				
				lda #S.IPCFG.STATUS.ROFFER
				sta IPCFG
			
CS.RUN.SREQ		ldx #3

.1				>PUSHB IPCFG+S.IPCFG.DHCPSRVR,x
				dex
				bpl .1
				
				>LDYA L.MSG.CFG2
				>SYSCALL SYS.PrintFYA

				>PUSHWI DHCP.REQ.LEN
				>PUSHW L.DHCP.REQ
				jsr CS.RUN.SKT.SEND
				bcs CS.RUN.KO

				lda #S.IPCFG.STATUS.SREQ
				sta IPCFG
				
CS.RUN.RACK		>SYSCALL SYS.Sleep
				
				jsr CS.RUN.SKT.RCVD
				bcc .1
				jsr Wait.Timeout
				bcc CS.RUN.RACK
				lda #2
				bra CS.RUN.KO
				
.1				jsr CheckDHCPAck
				bcs CS.RUN.RACK
								
CS.RUN.OK		lda #S.IPCFG.STATUS.OK
				sta IPCFG
				
				>PUSHW L.IPCFG
				>LIBCALL hLIBTCPIP,LIBTCPIP.SET.IPCFG

				ldx #3
.1				lda IPCFG+S.IPCFG.MASK,x
				>PUSHA
				dex
				bpl .1
				
				ldx #3
.2				lda IPCFG+S.IPCFG.IP,x
				>PUSHA
				dex
				bpl .2
				
				>LDYA L.MSG.CFG.OK
				>SYSCALL SYS.PrintFYA
				lda #0					Leave with NO ERROR
				sec
				rts
				
CS.RUN.KO		pha
				>PUSHA
				>LDYA L.MSG.CFG.KO
				>SYSCALL SYS.PrintFYA
				pla
				sec
				rts
*--------------------------------------
CS.RUN.SKT.SEND	ldy #hSocket
				>PUSHB (pData),y
				>LIBCALL hLIBTCPIP,LIBTCPIP.SKT.SEND
				rts
*--------------------------------------
CS.RUN.SKT.RCVD	ldy #hSocket
				lda (pData),y
				>LIBCALL hLIBTCPIP,LIBTCPIP.SKT.RCVDA
				bcs .9
				ldy #hFrame
				sta (pData),y
				>SYSCALL SYS.GetMemPtrA
				>STYA ZPFrameBase				
.9				rts
*--------------------------------------
CS.DOEVENT		lda (pEvent)
				bpl .1					is it a TIMER event?

				ldy #TimeOut
				lda (pData),y
				beq .9
				dec 
				sta (pData),y
.9				sec						do not discard TIMER event
				rts
				
.1				bit #S.EVT.F.KEY		is it a KEY event?
				beq .8
				
				ldy #S.EVT.hDEV			is Event from active IN device?
				lda (pEvent),y
				ldy #S.PS.hINDEV
				cmp (pPs),y
				bne .9
				
				ldy #S.EVT.DATAHI		is it an O or SAPPLE key ?
				lda (pEvent),y
				bne	.9
				
				ldy #S.EVT.DATALO	
				lda (pEvent),y
				cmp #$03				Ctrl-C
				bne .8
				
				lda #$FF
				ldy #bCTRLC
				sta (pData),y
				bra .8
				
.8				clc
				rts	
*--------------------------------------
CS.QUIT			ldy #hSocket
				lda (pData),y
				beq .1
				>LIBCALL hLIBTCPIP,LIBTCPIP.SKT.CLOSEA
				
.1				lda hLIBTCPIP
				>SYSCALL SYS.UnloadLibA
				clc
				rts
*--------------------------------------
CheckDHCPOffer	jsr CheckDHCPXID
				bcs .9
				
				>LDAXI S.DHCP.OPTIONS
				jsr SetFramePtr1AX
				
				ldy #2					DHCPOffer ?
				lda (ZPFramePtr),y
				cmp #S.DHCP.OPTIONS.DHCPOffer
				bne .9
				
				ldy #S.DHCP.YIADDR+3
				ldx #3
.1				lda (ZPFrameBase),y
				sta DHCP.REQ.OPT.REQIP,x
				dey
				dex
				bpl .1
				
				ldx #3
				ldy #S.IPCFG.IP+3
.2				lda DHCP.REQ.OPT.REQIP,x
				sta IPCFG,y
				dey
				dex
				bpl .2
				
				ldy #S.IP.SRC+3
				ldx #3
.3				lda (ZPFrameBase),y
				sta DHCP.REQ.OPT.SVRIP,x
				dey
				dex
				bpl .3

				ldx #3
				ldy #S.IPCFG.DHCPSRVR+3
.4				lda DHCP.REQ.OPT.SVRIP,x
				sta IPCFG,y
				dey
				dex
				bpl .4
				
.5				inc	ZPFramePtr				skip Option 53 (DHCPOffer:530102)
				bne .6
				inc ZPFramePtr+1
.6				lda (ZPFramePtr)
				sec
				adc ZPFramePtr				add option len + 1
				sta ZPFramePtr
				bcc .7
				inc ZPFramePtr+1
				
.7				lda (ZPFramePtr)
				cmp #S.DHCP.OPTIONS.END
				beq .8
				jsr GetDHCPOption	
				bra .5
.8				clc
				rts
				
.9				sec
				rts
*--------------------------------------
GetDHCPOption	cmp #S.DHCP.OPTIONS.MASK
				bne .1
				ldy #S.IPCFG.MASK
				bra GetDHCPOption.CopyIP
				
.1				cmp #S.DHCP.OPTIONS.GW
				bne .2
				ldy #S.IPCFG.GW
				bra GetDHCPOption.CopyIP
				
.2				cmp #S.DHCP.OPTIONS.DNS
				bne .3
				ldy #S.IPCFG.DNS1
				bra GetDHCPOption.CopyIP

.3				cmp #S.DHCP.OPTIONS.DOMAIN
				bne .9
				
				ldy #1
				ldx #$FF
.4				iny
				inx
				lda (ZPFramePtr),y
				sta UsrBuf256,x
				bne .4
				ldy #S.IPCFG.DOMAIN-1
				ldx #$FF
.5				iny
				inx
				lda UsrBuf256,x
				sta IPCFG,y
				bne .5
				
				
.9				rts
GetDHCPOption.CopyIP
				phy
				ldy #2
				ldx #0
.1				lda (ZPFramePtr),y
				sta UsrBuf256,x
				iny
				inx
				cpx #4
				bne .1
				ply
				ldx #0
.2				lda UsrBuf256,x
				sta IPCFG,y
				iny
				inx
				cpx #4
				bne .2
				rts
*--------------------------------------
CheckDHCPAck	jsr CheckDHCPXID
				bcs .9
				
				>LDAXI S.DHCP.OPTIONS
				jsr SetFramePtr1AX
				
				ldy #2					DHCPAck ?
				lda (ZPFramePtr),y
				cmp #S.DHCP.OPTIONS.DHCPAck
				bne .9
				
				clc
				rts
				
.9				sec
				rts
*--------------------------------------
CheckDHCPXID	ldy #S.DHCP.XID+3
				ldx #3
.1				lda (ZPFrameBase),y
				cmp DHCP.DISC.XID,x	same XID ?
				bne .9
				dey
				dex
				bpl .1
				clc
				rts
.9				sec
				rts
*--------------------------------------
SetFramePtr1AX	clc
				adc ZPFrameBase
				sta ZPFramePtr
				txa
				adc ZPFrameBase+1
				sta ZPFramePtr+1
				rts
*--------------------------------------
Init.Timeout	ldy #TimeOut
				lda #TIMEOUT.MAX
				sta (pData),y
				rts
*--------------------------------------
Wait.TimeOut	sec
				ldy #TimeOut
				lda (pData),y
				beq .9
				ldy #bCTRLC
				lda (pData),y
				bmi .9
				clc
.9				rts
*--------------------------------------
CS.END
LIBTCPIP		>PSTRING "libtcpip.o"
MSG.CFG1		>CSTRING "DHCPCLNT:Searching for DHCP servers...\n"
MSG.CFG2		>CSTRING "DHCPCLNT:Reply from DHCP Server at %d.%d.%d.%d, requesting...\n"
MSG.CFG.KO		>CSTRING "DHCPCLNT:Time Out [%h].\n"
MSG.CFG.OK		>CSTRING "DHCPCLNT:Success:[IP=%d.%d.%d.%d/%d.%d.%d.%d]\n"
MSG.CFG.ND		>CSTRING "DHCPCLNT:No Device, exiting.\n"
MSG.CFG.NA		>CSTRING "DHCPCLNT:TCPIP Already configured, exiting.\n"
hLIBTCPIP		.BS 1
IPCFG			.BS S.IPCFG
FrameLen		.BS 2
*--------------------------------------
Socket			.DA #S.SOCKET.SOCK.DGRAM
				.BS 3
				.HS 00.00.00.00			Socket.Src.Addr
				.DA UDP.PORT.DHCPC		Socket.Src.Port
				.HS FF.FF.FF.FF			Socket.Dst.Addr
				.DA UDP.PORT.DHCPS		Socket.Dst.Port
				.BS 16
*--------------------------------------
DHCP.DISC		.HS 01010600			OP,HTYPE,HLEN,HOPS
DHCP.DISC.XID	.BS 4
				.HS 0000				SECS
				.HS 0000				FLAGS
				.HS	00000000			CIADDR
DHCP.DISC.YIADDR	.HS 00000000
				.HS 00000000			SIADDR
				.HS 00000000			GIADDR
DHCP.DISC.CHADDR	.HS 00000000.00000000.00000000.00000000
				.BS 64					SNAME
				.BS 128					FILE
				.HS 63825363			COOKIE
				.HS 3501				OPT
				.DA #S.DHCP.OPTIONS.DHCPDiscover
				.HS 37040103060FFF
DHCP.DISC.LEN	.EQ *-DHCP.DISC
*--------------------------------------
DHCP.REQ		.HS 01010600			OP,HTYPE,HLEN,HOPS
DHCP.REQ.XID	.BS 4
				.HS 0000				SECS
				.HS 0000				FLAGS
				.HS	00000000			CIADDR
DHCP.REQ.YIADDR	.HS 00000000
				.HS 00000000			SIADDR
				.HS 00000000			GIADDR
DHCP.REQ.CHADDR	.HS 00000000.00000000.00000000.00000000
				.BS 64					SNAME
				.BS 128					FILE
				.HS 63825363			COOKIE
				.HS 3501				OPT
				.DA #S.DHCP.OPTIONS.DHCPRequest
				.HS 3204
DHCP.REQ.OPT.REQIP	.BS 4
				.HS 3604
DHCP.REQ.OPT.SVRIP	.BS 4
				.HS	FF
DHCP.REQ.LEN 	.EQ *-DHCP.REQ
*--------------------------------------
DS.START
TimeOut			.BS 1
bCTRLC			.BS 1
hSocket			.BS 1
hFrame			.BS 1
DS.END
MAN
SAVE SBIN/DHCPCLNT.S
ASM
