; (c)opyright 2014-2017 ; Sven Oliver ("SvOlli") Moll ; and Individual Computers .include "rrnetmk3.inc" IP_PACKAGE_DHCP_MSG_TYPE := IP_PACKAGE_UDP_PAYLOAD + $00 IP_PACKAGE_DHCP_HW_TYPE := IP_PACKAGE_UDP_PAYLOAD + $01 IP_PACKAGE_DHCP_HW_ADDR_LEN := IP_PACKAGE_UDP_PAYLOAD + $02 IP_PACKAGE_DHCP_HOPS := IP_PACKAGE_UDP_PAYLOAD + $03 IP_PACKAGE_DHCP_TRANSACTION_ID := IP_PACKAGE_UDP_PAYLOAD + $04 IP_PACKAGE_DHCP_SECONDS_ELAPSED := IP_PACKAGE_UDP_PAYLOAD + $08 IP_PACKAGE_DHCP_BOOTP_FLAGS := IP_PACKAGE_UDP_PAYLOAD + $0A IP_PACKAGE_DHCP_CLIENT_IP := IP_PACKAGE_UDP_PAYLOAD + $0C IP_PACKAGE_DHCP_YOUR_IP := IP_PACKAGE_UDP_PAYLOAD + $10 IP_PACKAGE_DHCP_NEXT_IP := IP_PACKAGE_UDP_PAYLOAD + $14 IP_PACKAGE_DHCP_RELAY_IP := IP_PACKAGE_UDP_PAYLOAD + $18 IP_PACKAGE_DHCP_CLIENT_MAC := IP_PACKAGE_UDP_PAYLOAD + $1C IP_PACKAGE_DHCP_CLIENT_PADDING := IP_PACKAGE_UDP_PAYLOAD + $22 IP_PACKAGE_DHCP_SERVER_HOSTNAME := IP_PACKAGE_UDP_PAYLOAD + $2C IP_PACKAGE_DHCP_BOOT_FILENAME := IP_PACKAGE_UDP_PAYLOAD + $6C IP_PACKAGE_DHCP_MAGIC_COOKIE := IP_PACKAGE_UDP_PAYLOAD + $EC IP_PACKAGE_DHCP_OPTION_START := IP_PACKAGE_UDP_PAYLOAD + $F0 .export IP_PACKAGE_DHCP_NEXT_IP .export IP_PACKAGE_DHCP_BOOT_FILENAME DHCP_OPTION_REQUEST_IP := 50 DHCP_OPTION_LEASE_TIME := 51 DHCP_OPTION_MSG_TYPE := 53 DHCP_OPTION_DISCOVER := 1 DHCP_OPTION_OFFER := 2 DHCP_OPTION_REQUEST := 3 DHCP_OPTION_DECLINE := 4 DHCP_OPTION_ACK := 5 DHCP_OPTION_NAK := 6 DHCP_OPTION_SERVER_ID := 54 DHCP_OPTION_REQUEST_LIST := 55 DHCP_OPTION_REQUEST_SUBNET_MASK := 1 DHCP_OPTION_REQUEST_ROUTER := 3 DHCP_OPTION_REQUEST_DNS := 6 DHCP_OPTION_RENEWAL_TIME := 58 DHCP_OPTION_REBINDING_TIME := 59 DHCP_OPTION_END := 255 .segment "CODE" dhcp_create_package_discover: jsr dhcp_create_package_base ldx #(dhcp_discover_options_end-dhcp_discover_options_start-1) : lda dhcp_discover_options_start,x sta IP_PACKAGE_DHCP_OPTION_START,x dex bpl :- lda #dhcp_create_package_discover jsr recall_after_2s jsr udp_send_dhcp_package jmp receive_loop dhcp_create_package_request: jsr dhcp_create_package_base lda #DHCP_OPTION_MSG_TYPE sta IP_PACKAGE_DHCP_OPTION_START+$00 lda #$01 sta IP_PACKAGE_DHCP_OPTION_START+$01 lda #DHCP_OPTION_REQUEST sta IP_PACKAGE_DHCP_OPTION_START+$02 lda #DHCP_OPTION_REQUEST_IP sta IP_PACKAGE_DHCP_OPTION_START+$03 lda #$04 sta IP_PACKAGE_DHCP_OPTION_START+$04 ldx #$03 : lda RAM_IP_ADDRESS,x sta IP_PACKAGE_DHCP_OPTION_START+$05,x dex bpl :- lda #DHCP_OPTION_SERVER_ID sta IP_PACKAGE_DHCP_OPTION_START+$09 lda #$04 sta IP_PACKAGE_DHCP_OPTION_START+$0A ldx #$03 : lda IP_ADDRESS_REMOTE,x sta IP_PACKAGE_DHCP_OPTION_START+$0B,x dex bpl :- lda #DHCP_OPTION_END sta IP_PACKAGE_DHCP_OPTION_START+$0F lda #dhcp_create_package_request jsr recall_after_2s jsr udp_send_dhcp_package jmp receive_loop dhcp_create_package_base: ;setup mac addresses ldx #$05 : lda ROM_MAC_ADDR,x sta ETHER_FRAME_SRC_MAC,x lda #$ff sta ETHER_FRAME_DEST_MAC,x dex bpl :- ;setup type + header len + diff svc ;setup package id + flags + ttl + protocol ldx #(dhcp_ip_header_end-dhcp_ip_header_start-1) : lda dhcp_ip_header_start,x sta ETHER_FRAME_TYPE,x ;; TODO dex bpl :- ;setup ports lda #$00 ldx #BOOTPC_PORT sta IP_PACKAGE_UDP_SRC_PORT+0 stx IP_PACKAGE_UDP_SRC_PORT+1 ldx #BOOTPS_PORT sta IP_PACKAGE_UDP_DEST_PORT+0 stx IP_PACKAGE_UDP_DEST_PORT+1 ;clean length and checksum lda #$00 ldx #$03 : sta IP_PACKAGE_UDP_LENGTH,x dex bpl :- ;dhcp lda #$01 sta IP_PACKAGE_DHCP_MSG_TYPE sta IP_PACKAGE_DHCP_HW_TYPE lda #$06 sta IP_PACKAGE_DHCP_HW_ADDR_LEN lda #$00 sta IP_PACKAGE_DHCP_HOPS ;lda #$00 sta IP_PACKAGE_DHCP_SECONDS_ELAPSED+0 sta IP_PACKAGE_DHCP_SECONDS_ELAPSED+1 ldx #$80 stx IP_PACKAGE_DHCP_BOOTP_FLAGS+0 sta IP_PACKAGE_DHCP_BOOTP_FLAGS+1 ; zero out all 4 ip address fields + mac + padding + hostname + filename ldx #$00 : sta IP_PACKAGE_DHCP_CLIENT_IP,x inx cpx #$e0 bcc :- jsr set_random16 lda RANDOM16+0 sta IP_PACKAGE_DHCP_TRANSACTION_ID+0 sta IP_PACKAGE_DHCP_TRANSACTION_ID+2 lda RANDOM16+1 sta IP_PACKAGE_DHCP_TRANSACTION_ID+1 sta IP_PACKAGE_DHCP_TRANSACTION_ID+3 ldx #$05 : lda ROM_MAC_ADDR,x sta IP_PACKAGE_DHCP_CLIENT_MAC,x dex bpl :- ;copy dhcp magic cookie + dhcp options (discover only) ldx #$03 : lda dhcp_magic_cookie,x sta IP_PACKAGE_DHCP_MAGIC_COOKIE,x dex bpl :- rts handle_dhcp_package: jsr calculate_ip_header_checksum lda #$ff cmp TEMP_A_16+0 bne @err_header_chk cmp TEMP_A_16+1 bne @err_header_chk jsr calculate_udp_checksum lda #$ff cmp TEMP_A_16+0 bne @err_udp_chk cmp TEMP_A_16+1 bne @err_udp_chk lda RANDOM16+0 cmp IP_PACKAGE_DHCP_TRANSACTION_ID+0 bne @done cmp IP_PACKAGE_DHCP_TRANSACTION_ID+2 bne @done lda RANDOM16+1 cmp IP_PACKAGE_DHCP_TRANSACTION_ID+1 bne @done cmp IP_PACKAGE_DHCP_TRANSACTION_ID+3 bne @done ldx #$03 : lda IP_PACKAGE_DHCP_YOUR_IP,x sta RAM_IP_ADDRESS,x dex bpl :- lda #IP_PACKAGE_DHCP_OPTION_START sta AREA_START+1 @option_loop: ldy #$00 lda (AREA_START),y cmp #DHCP_OPTION_MSG_TYPE beq @handle_dhcp_msg_type cmp #DHCP_OPTION_SERVER_ID beq @get_server_id cmp #DHCP_OPTION_END beq @option_end @option_continue: clc ldy #$01 lda (AREA_START),y adc #$02 jsr advance_area_start_a bne @option_loop ; branches always @err_udp_chk: lda #$03 .byte $2c @err_header_chk: lda #$02 sta $d020 @done: jmp receive_loop @option_end: lda DHCP_STATE cmp #DHCP_STATE_REQUEST bne @done jmp dhcp_create_package_request @handle_dhcp_msg_type: iny ; Y=1 (offset of size) lda (AREA_START),y cmp #$01 ; msg type of server should be 1 byte bne @done iny ; Y=2 (offset of type) lda (AREA_START),y cmp #DHCP_OPTION_ACK bne @noack ; lame way that should keep the ip address while being idle lda #dhcp_create_package_request jsr recall_after_2m lda #DHCP_STATE_ACK jsr set_dhcp_state jsr print_hw_info ; check if $0380-$03FF contains a valid filename to load via TFTP ; then replace DHCP supplied filename with $0380-$03FF jsr calculate_filename_checksum cmp FILENAME_CHECKSUM bne :+ jsr tftp_replace_filename bmi @c64_boot_file : ; check if filename ends with ".prg" (or skip check if no filename at all) ldy #$03 ldx #$00 lda IP_PACKAGE_DHCP_BOOT_FILENAME,x beq @noack : inx lda IP_PACKAGE_DHCP_BOOT_FILENAME,x bne :- : dex lda IP_PACKAGE_DHCP_BOOT_FILENAME,x ora #$20 ; to ascii lowercase cmp @dot_prg,y bne @noack dey bpl :- @c64_boot_file: jmp tftp_request_file @dot_prg: .byte $2e,$70,$72,$67 ; ".prg" in ascii lowercase @noack: cmp #DHCP_OPTION_OFFER bne @done lda #DHCP_STATE_REQUEST jsr set_dhcp_state jmp @option_continue @get_server_id: iny ; Y=1 (offset of size) lda (AREA_START),y cmp #$04 ; ip address of server should be 4 bytes bne @done iny ; Y=2 (offset of ip address) ldx #$00 : lda (AREA_START),y sta IP_ADDRESS_REMOTE,x iny inx cpx #$04 bcc :- jmp @option_continue ; finish up and send udp package udp_send_dhcp_package: ;setup total len ;setup package len jsr dhcp_set_package_vectors udp_send_package: jsr udp_set_package_sizes jsr area_align_end_16 jsr set_ip_header_checksum jsr set_udp_checksum jsr area_set_start jsr area_get_size ; write area size to x/a tay jmp cs8900a_send_ip_frame_16 ; needs size from x/y dhcp_set_package_vectors: lda #IP_PACKAGE_DHCP_OPTION_START sta AREA_END+1 ldy #$00 : lda (AREA_END),y inc AREA_END+0 bne :+ inc AREA_END+1 : cmp #$ff bne :-- jmp area_set_start udp_set_package_sizes: sec lda AREA_END+0 sbc AREA_START+0 sta IP_PACKAGE_UDP_LENGTH+1 lda AREA_END+1 sbc AREA_START+1 sta IP_PACKAGE_UDP_LENGTH+0 sec lda IP_PACKAGE_UDP_LENGTH+1 sbc #$22 sta IP_PACKAGE_UDP_LENGTH+1 bcs :+ dec IP_PACKAGE_UDP_LENGTH+0 : clc lda IP_PACKAGE_UDP_LENGTH+1 adc #$14 sta IP_HEADER_TOTAL_LEN+1 lda IP_PACKAGE_UDP_LENGTH+0 adc #$00 sta IP_HEADER_TOTAL_LEN+0 rts dhcp_ip_header_start: .byte $08,$00 .byte $45,$00 .byte $00,$00 .byte $34,$12 .byte $40,$00 .byte $40 .byte $11 .byte $00,$00 ; placeholder for checksum .byte $00,$00,$00,$00 ; src ip .byte $ff,$ff,$ff,$ff ; dest ip dhcp_ip_header_end: dhcp_magic_cookie: .byte $63,$82,$53,$63 dhcp_discover_options_start: .byte DHCP_OPTION_MSG_TYPE .byte $01 .byte DHCP_OPTION_DISCOVER .byte DHCP_OPTION_REQUEST_LIST .byte $02 .byte DHCP_OPTION_REQUEST_SUBNET_MASK .byte DHCP_OPTION_REQUEST_ROUTER .byte DHCP_OPTION_END dhcp_discover_options_end: set_dhcp_state: sta DHCP_STATE print_dhcp_state: jsr print .byte $02,$13,$1A,"dhcp:",$00 lda DHCP_STATE asl asl asl tay ldx #$08 : lda @dhcp_text,y jsr BSOUT iny dex bne :- rts .segment "GAPDATA" @dhcp_text: .byte "OFF " .byte "NO LINK " .byte "DISCOVER" .byte "REQUEST " .byte "ACK " ; DHCP code end