	include	masmdefs.hsm
	include model.hsm

screen		macro spot
		push	ax				;SCREEN
		push	ds				;SCREEN
		mov	ax, 0B800h			;SCREEN
		mov	ds, ax				;SCREEN
		db	0FEh				;inc byte ptr []
		db	06h
		dw	&spot&*2			;SCREEN
		pop	ds				;SCREEN
		pop	ax				;SCREEN
		endm

codedef BOOTP1
datadef

	public	_oldpack
	public	_end_wpack
	public	_your_ip
	public	_server_ip
	public	_gateway_ip
	public	_server_hw
	public	_vendor

cstart  BOOTP1
cproc   newpack

	jmp	around
	db	"PKT DRVR"
	db	0
	db	"BOOTP by Bruce Campbell"
	db	0
handle	label	word
	dw	0
upcall:
	db	09Ah
upoff	label	word
	dw	0
upseg	label	word
	dw	0
	ret

_your_ip	label	word
	dw	0
_your_ip2	label	word
	dw	0
_server_ip	label	word
	dw	0
_server_ip2	label	word
	dw	0
_gateway_ip	label	word
	dw	0
_gateway_ip2	label	word
	dw	0

_server_hw	label	word
	dw	0
_server_hw2	label	word
	dw	0
_vendor		label	word
	db	60 dup(0)

around:
	sti
	cmp	ah, 2				;access
	jnz	not_acc
;
;	access		DS:SI points to access type
;			CX is length of access flag
;			ES:DI points to upcall
;
;	carry clear on success, AX = handle
;
	cmp	cx, 2
	jnz	do_old2
	push	ax
	mov	ax,[si]
	cmp	ax,0008			;ip packet ?
	pop	ax
	jnz	do_old2
	push	di
	push	es
	call	callpkt			;do the access
	pop	es
	pop	di
	jc	doneboot2		;it failed
	mov	cs:handle,ax
	mov	cs:upoff,di
	mov	cs:upseg,es
doneboot2:
	jmp	doneboot
do_old2:
	jmp	do_old
not_acc:
	cmp	ah, 3				;release
	jnz	not_rel
;
;	release		BX is handle to release
;
	cmp	bx,cs:handle			;does it match ?
	jnz	do_old3
	call	callpkt				;do the release
	jc	doneboot3			;it failed
	mov	cs:handle,0
	mov	cs:upoff,0
	mov	cs:upseg,0
doneboot3:
	jmp	doneboot
do_old3:
	jmp	do_old
not_bp:
	pop	ax
	jmp	do_old
not_rel:
	cmp	ah, 4				;transmit
	jnz	do_old3
;
;	transmit		DS:SI len CX is packet
;
	cmp	cx,342				;a bootp is 342 bytes
	jnz	do_old3
	push	ax
	mov	ax,[si+12]			;get type
	cmp	ax,0008				;bootp has IP type
	jnz	not_bp1
	mov	ax,[si]
	cmp	ax,0FFFFh
	jnz	not_bp1
	mov	ax,[si+2]
	cmp	ax,0FFFFh
	jnz	not_bp1
	mov	ax,[si+4]
	cmp	ax,0FFFFh
	jnz	not_bp1
	mov	ax,[si+34]
	cmp	ax,4400h			;bootp client
	jnz	not_bp1
	mov	ax,[si+36]			;bootp server
	cmp	ax,4300h
	jnz	not_bp1
	mov	al,[si+42]			;bootp operation
	cmp	al,1
not_bp1:
	jnz	not_bp
	mov	ax,cs:upoff
	or	ax,cs:upseg
	jz	not_bp				;no upcall set yet
	pop	ax
	push	si
	push	ds
	call	callpkt
	pop	ds
	pop	si
	jnc	tranworked
	jmp	doneboot
tranworked:
	pushf
	push	ax
	push	bx
	push	cx
	push	dx
	push	di
	push	si
	push	bp
	push	ds
	push	es

	mov	ax,0		;allocate
	mov	bx,cs:handle
	mov	cx,342

	push	si
	push	ds
	call	upcall
	pop	ds
	pop	si

	mov	ax,es
	or	ax,di
	jnz	okbuf
	jmp	nobuf

okbuf:
	push	di
	mov	cx,342
	cld
	rep	movsb
	pop	di

	mov	ax,es
	mov	ds,ax
	mov	si,di

	mov	byte ptr [si+42],2	;bootp reply

	mov	ax,[si+6]
	mov	[si+0],ax
	mov	ax,[si+8]
	mov	[si+2],ax
	mov	ax,[si+10]
	mov	[si+4],ax

	mov	ax,0
	mov	[si+6],ax
	mov	ax,cs:_server_hw
	mov	[si+8],ax
	mov	ax,cs:_server_hw2
	mov	[si+10],ax

	mov	ax,[si+54]
	mov	[si+30],ax
	mov	ax,[si+56]
	mov	[si+32],ax

	mov	ax,[si+54]
	or	ax,[si+56]		;does client know IP address ?
	jnz	ip_known

	mov	ax,cs:_your_ip
	mov	[si+58],ax
	mov	[si+30],ax
	mov	ax,cs:_your_ip2
	mov	[si+60],ax
	mov	[si+32],ax

ip_known:

	mov	ax,cs:_server_ip
	mov	[si+62],ax
	mov	[si+26],ax
	mov	ax,cs:_server_ip2
	mov	[si+64],ax
	mov	[si+28],ax

	mov	ax,cs:_gateway_ip
	mov	[si+66],ax
	mov	ax,cs:_gateway_ip2
	mov	[si+68],ax

	mov	word ptr [si+34],04300h
	mov	word ptr [si+36],04400h

	mov	word ptr [si+40],0		;udp checksum
	mov	word ptr [si+24],0		;ip checksum

	mov	ax,[si+278]			;get the magic thing
	cmp	ax,08263h
	jnz	no_magic
	mov	ax,[si+280]			;get the magic thing
	cmp	ax,06353h
	jnz	no_magic

	push	si
	push	ds

	push	ds
	pop	es

	mov	di,si
	add	di,282

	push	cs
	pop	ds

	mov	cx,60
	mov	si,offset _vendor

	cld
	rep	movsb

	pop	ds
	pop	si

	push	si
	add	si, 14
	mov	cx, 20
	call	_inchksum
	pop	si

	not	AX
	mov	word ptr [si+24],AX		;ip checksum

no_magic:
	mov	ax,1		;process
	mov	bx,cs:handle
	mov	cx,342

	call	upcall

nobuf:

	pop	es
	pop	ds
	pop	bp
	pop	si
	pop	di
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	popf
	jmp	doneboot
do_old:
	call	callpkt
doneboot:
	db	0CAh,02,00			;retf 2

callpkt:
	pushf
	db	09Ah
_oldpack	label	dword
	dd	0	
	ret

cendp   newpack

cproc	inchksum

        mov     BL, CL

        shr     CX, 1                   ; group into words
        xor     DX, DX                  ; set checksum to 0
        cld
        clc

deloop: lodsw
        adc     DX, AX
        loop    deloop

        adc     DX, 0                   ; only two necessary
        adc     DX, 0

remain: and     BL, 1
        jz      done

        xor     AH, AH
        lodsb
        add     DX, AX
        adc     DX, 0
        adc     DX, 0

done:   mov     AX,DX           ; result into ax
	ret

cendp   inchksum


cproc	endwww
_end_wpack	label	word
	dw	offset	_end_wpack
cendp	endwww

cpublic bopen

	mov	DX,+@AB+0[BP]
	mov	AX,03D00h
	int	21h
	jnc	b_ok
	mov	ax,0FFFFh
b_ok:

creturn bopen

lbuf	label	byte
	dd	0

cpublic	bread

	push	DS
	mov	BX,+@AB+0[BP]
	mov	CX,1
	push	CS
	pop	DS
	mov	DX,offset lbuf
	mov	AX,03F00h
	int	21h
	jc	r_fail
	cmp	ax,1
	jnz	r_fail
	mov	al,cs:lbuf
	jmp	r_ok
r_fail:
	mov	ax,0FFFFh
r_ok:
	pop	DS

creturn	bread

cpublic	bclose

	mov	BX,+@AB+0[BP]
	mov	AX,03E00h
	int	21h

creturn	bclose

cend    BOOTP1

	end
